Sometimes constraints are not satisfied with NL Writer V2 with export_defined_variables=True
Summary
There are cases when constraints are not satisfied in MINLP problems when using latest main (4a5bf8a2417246dc000df56576df9925d3497f90), but the problem is reported as feasible and optimal after solve. The problem only occurs for some solvers that use NL Writer and with export_defined_variables=True.
The following example shows the problem, but only couenne gives the wrong answer. See #3235 for some more discussion of this. I have also seen the same issue for mindpty using ipopt and cbc, but for some reason this example works fine for mindtpy and I have not yet managed to replicate the mindtpy issue on a manageably small problem.
Steps to reproduce the issue
The following code replicates the problem
from pyomo.environ import *
def create_model():
model = ConcreteModel()
model.p1 = Var(within=PositiveReals, bounds=(1, 2))
model.p2 = Var(within=PositiveReals, bounds=(1, 2))
model.t1 = Var(within=Boolean, bounds=(0, 1))
model.t2 = Var(within=Boolean, bounds=(0, 1))
model.f_expr = Expression(expr =
(model.p1*model.t1 + model.p2*model.t2)
)
model.const_t = Constraint(expr=(model.t1 + model.t2 == 1))
model.const2 = Constraint(expr=(model.f_expr <= 1.0))
# just maximize the the expression we are constraining to <= 1
model.OBJ = Objective(expr=model.f_expr, sense=maximize)
return model
def solve(solver, export_defined_variables):
model = create_model()
opt = SolverFactory(solver)
try:
name = opt.name
sol = opt.options.solver
except AttributeError:
name = opt.__class__.__name__
sol = ""
try:
if solver == "mindtpy":
if not export_defined_variables:
# not sure how to switch this off for mindtpy
return
optResult = opt.solve(model, mip_solver="cbc")
else:
optResult = opt.solve(model, export_defined_variables=export_defined_variables)
solverOutput = optResult["Solver"][0]
termCond = solverOutput["Termination condition"]
if termCond != "optimal":
raise Exception(f"Termination condition: {termCond}")
except Exception as e:
print(f"{name}:{sol}:export_defined_variables:{export_defined_variables} {e}")
return
print(f"{name}:{sol}:export_defined_variables:{export_defined_variables} {value(model.OBJ)}")
for export_defined_variables in [False, True]:
for solver in ["ipopt", "scip", "bonmin", "couenne", "mindtpy"]:
solve(solver, export_defined_variables)
Output:
ipopt:None:export_defined_variables:False 1.0000000089123255
scip:None:export_defined_variables:False 1.0
asl:bonmin:export_defined_variables:False 1.0000000099900264
asl:couenne:export_defined_variables:False 1.0000000099900361
ipopt:None:export_defined_variables:True 1.0000000089123255
scip:None:export_defined_variables:True 1.0
asl:bonmin:export_defined_variables:True 1.0000000099900264
asl:couenne:export_defined_variables:True 2.0
MindtPySolver::export_defined_variables:True 1.0000000081382578
Information on your system
Pyomo version: main (4a5bf8a2417246dc000df56576df9925d3497f90) Python version: 3.11.6 Operating system: Red Hat Enterprise Linux release 8.8 (Ootpa) How Pyomo was installed (PyPI, conda, source): PyPI Solver (if applicable): see above, all solvers were downloaded from the AMPL Portal (https://portal.ampl.com/user/ampl/download)