Another option is to express the problem in AMPL, and then use any non-linear solvers such as bonmin, ipopt (both open source) that gets shipped with AMPL. AMPL also has a rich python API as well where you formulate the problem in AMPL and then pass data from python data structures (rather than having a .dat
file in native AMPL).
https://amplpy.readthedocs.io/en/latest/
AMPL now offers a full fledge community edition license and can be downloaded from https://ampl.com/start-free-now/
If you want to use AMPL with python, then follow the first link to install individual solvers. Its very easy to do that.
Below is the formulation in AMPL. I personally like AMPL for its expressiveness and its succinct syntax.
squared_objective.mod
var a >= 0 integer;
var b >= 0 integer;
var c >= 0 integer;
var d >= 0 integer;
subject to a_b_constraint:
a + b <= 3000;
subject to c_d_constraint:
c + d <= 2000;
subject to a_c_constraint:
a + c = 500;
subject to b_d_constraint:
b + d = 2000;
minimize obj_fn:
(-2*a + 1.5*b + 3*c + 6.5*d - 2000) * (-2*a + 1.5*b + 3*c + 6.5*d - 2000);
Now, you can use any non-linear solver such as bonmin, ipopt, even cbc is also able to solve.
using gurobi options solver gurobiasl;
results in:
ampl: options solver gurobiasl;
ampl: solve;
Gurobi 10.0.1: optimal solution; objective 0
2 simplex iterations
1 branch-and-cut nodes
ampl: display obj_fn;
obj_fn = 0
ampl: display a; display b; display c; display d;
a = 500
b = 2000
c = 0
d = 0
Any other non-linear solver pointed above will work just fine
Now, using python API of AMPL:
from amplpy import AMPL
ampl = AMPL()
ampl.set_option("solver", "cbc")
# OR ampl.set_option("solver", "gurobiasl")
# OR ampl.set_option("solver", "ipopt")
# community edition of Gurobi gets shipped with AMPL !
ampl.read("../squared_objective.mod")
ampl.solve()
assert ampl.get_value("solve_result") == "solved"
# objective function value
ampl.getObjective("obj_fn").value()
# optimal value = 0
# decision variable values
ampl.getValue("a") # a = 500
ampl.getValue("b") # b = 2000
ampl.getValue("c") # c = 0
ampl.getValue("d") # d = 0
Use can easily use python data structures such as list, dictionaries and then pass data to your AMPL program
https://amplpy.readthedocs.io/en/latest/quick-start.html#load-the-data-using-pandas-objects
https://amplpy.readthedocs.io/en/latest/quick-start.html#load-the-data-using-lists-and-dictionaries