-
Notifications
You must be signed in to change notification settings - Fork 26
Description
I have a problem which I have simplified to a simple case with two continuous and one binary variable. There are no constraints (other than variable bounds) and while the objective is nonconvex, it is monotonic. I get the correct optimal solution with bonmin and MindtPy, but not consistently with SHOT. When I say not consistently, I mean that the results are sensitive to the exact algebraic representation I use in Pyomo.
I am very interested in using SHOT both for convex and nonconvex MINLP problems. Any thoughts on this would be greatly appreciated :-)
I am using a build of the following commit:
commit 033622c6f9989d48caf7eefe430d292286544711
Merge: 77da53f edd04d7
Author: Stefan Vigerske <[email protected]>
Date: Mon Jun 27 14:50:10 2022 +0200
and I tried using both CBC and CPLEX MIP solvers (with slightly different results).
The following is the output from the different solvers (objective and variable values), for various different representations of the same problem. Note: when y==1.0 [optimum value], the value of the objective does not depend on x1. However this does not seem be the cause of this issue. I tried adding a small offset, so that the objective is always influenced by x1 and this caused bonmin and MindtPy to always give the same value for x1, as expected, but the behaviour of SHOT was still the same):
{'min': False, 'divide': False}
SHOT_CBC: OBJ: 2.0, x1: 0.5, x2: 0.1, y: 0.0
SHOT_CPLEX:OBJ: 6.5, x1: 0.6, x2: 0.2, y: 1.0
bonmin: OBJ: 13.0, x1: 0.6, x2: 0.1, y: 1.0
MindtPy: OBJ: 13.0, x1: 0.5, x2: 0.1, y: 1.0
{'min': False, 'divide': True}
SHOT_CBC: OBJ: 2.0, x1: 0.5, x2: 0.1, y: 0.0
SHOT_CPLEX:OBJ: 6.5, x1: 0.6, x2: 0.2, y: 1.0
bonmin: OBJ: 13.0, x1: 0.6, x2: 0.1, y: 1.0
MindtPy: OBJ: 13.0, x1: 0.6, x2: 0.1, y: 1.0
{'min': True, 'divide': False}
SHOT_CBC: OBJ: -2.0, x1: 0.5, x2: 0.1, y: 0.0
SHOT_CPLEX:OBJ: -2.0, x1: 0.5, x2: 0.1, y: 0.0
bonmin: OBJ: -13.0, x1: 0.6, x2: 0.1, y: 1.0
MindtPy: OBJ: -13.0, x1: 0.5, x2: 0.1, y: 1.0
{'min': True, 'divide': True}
SHOT_CBC: OBJ: -13.0, x1: 0.5, x2: 0.1, y: 1.0
SHOT_CPLEX:OBJ: -13.0, x1: 0.5, x2: 0.1, y: 1.0
bonmin: OBJ: -13.0, x1: 0.6, x2: 0.1, y: 1.0
MindtPy: OBJ: -13.0, x1: 0.6, x2: 0.1, y: 1.0
and this is the self-contained code to replicate:
import pyomo.environ as pyo
import pyomo.contrib.mindtpy.MindtPy as mindtpy
def create_model(min=False, divide=False):
model = pyo.ConcreteModel()
model.x1 = pyo.Var(domain=pyo.NonNegativeReals, bounds=(0.5, 0.6))
model.x2 = pyo.Var(domain=pyo.NonNegativeReals, bounds=(0.1, 0.2))
model.y = pyo.Var(domain=pyo.Boolean, initialize=1)
y_mult = 1.3
if divide:
obj = (1 - model.y) / model.x1 + model.y * y_mult / model.x2
else:
obj = (1 - model.y) * (model.x1 ** -1) + model.y * y_mult * (model.x2 ** -1)
if min:
model.OBJ = pyo.Objective(expr = -1 * obj, sense=pyo.minimize)
else:
model.OBJ = pyo.Objective(expr = obj, sense=pyo.maximize)
return model
solvers = {}
shotCbc = pyo.SolverFactory("SHOT")
shotCbc.options["Dual.MIP.Solver"] = 2
solvers["SHOT_CBC"] = shotCbc
shotCplex = pyo.SolverFactory("SHOT")
shotCplex.options["Dual.MIP.Solver"] = 0
solvers["SHOT_CPLEX"] = shotCplex
solvers["bonmin"] = pyo.SolverFactory("bonmin")
mindtpy_solver = mindtpy.MindtPySolver()
mindtpy_solver.CONFIG["mip_solver"] = "cbc"
solvers["MindtPy"] = mindtpy_solver
params = [
{"min": False, "divide": False},
{"min": False, "divide": True},
{"min": True, "divide": False},
{"min": True, "divide": True},
]
results = {}
for p in params:
cur_res = {}
for name, sol in solvers.items():
model = create_model(**p)
sol.solve(model, tee=True)
cur_res[name] = model
results[str(p)] = cur_res
for p, res in results.items():
print(p)
for name, r in res.items():
print(f" {name}:{' '*(10-len(name))}OBJ: {pyo.value(r.OBJ):.1f}, x1: {pyo.value(r.x1):.1f}, x2: {pyo.value(r.x2):.1f}, y: {pyo.value(r.y):.1f}")