Skip to content

Commit 26e4970

Browse files
authored
Merge pull request #3163 from Robbybp/cyipopt-no-obj
Allow CyIpopt to solve problems without objectives
2 parents 8946534 + 0e9a6a2 commit 26e4970

File tree

2 files changed

+28
-5
lines changed

2 files changed

+28
-5
lines changed

pyomo/contrib/pynumero/algorithms/solvers/cyipopt_solver.py

+18-5
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
from pyomo.common.deprecation import relocated_module_attribute
2525
from pyomo.common.dependencies import attempt_import, numpy as np, numpy_available
2626
from pyomo.common.tee import redirect_fd, TeeStream
27+
from pyomo.common.modeling import unique_component_name
28+
from pyomo.core.base.objective import Objective
2729

2830
# Because pynumero.interfaces requires numpy, we will leverage deferred
2931
# imports here so that the solver can be registered even when numpy is
@@ -332,11 +334,22 @@ def solve(self, model, **kwds):
332334
grey_box_blocks = list(
333335
model.component_data_objects(egb.ExternalGreyBoxBlock, active=True)
334336
)
335-
if grey_box_blocks:
336-
# nlp = pyomo_nlp.PyomoGreyBoxNLP(model)
337-
nlp = pyomo_grey_box.PyomoNLPWithGreyBoxBlocks(model)
338-
else:
339-
nlp = pyomo_nlp.PyomoNLP(model)
337+
# if there is no objective, add one temporarily so we can construct an NLP
338+
objectives = list(model.component_data_objects(Objective, active=True))
339+
if not objectives:
340+
objname = unique_component_name(model, "_obj")
341+
objective = model.add_component(objname, Objective(expr=0.0))
342+
try:
343+
if grey_box_blocks:
344+
# nlp = pyomo_nlp.PyomoGreyBoxNLP(model)
345+
nlp = pyomo_grey_box.PyomoNLPWithGreyBoxBlocks(model)
346+
else:
347+
nlp = pyomo_nlp.PyomoNLP(model)
348+
finally:
349+
# We only need the objective to construct the NLP, so we delete
350+
# it from the model ASAP
351+
if not objectives:
352+
model.del_component(objective)
340353

341354
problem = cyipopt_interface.CyIpoptNLP(
342355
nlp,

pyomo/contrib/pynumero/algorithms/solvers/tests/test_cyipopt_solver.py

+10
Original file line numberDiff line numberDiff line change
@@ -316,3 +316,13 @@ def test_hs071_evalerror_old_cyipopt(self):
316316
msg = "Error in AMPL evaluation"
317317
with self.assertRaisesRegex(PyNumeroEvaluationError, msg):
318318
res = solver.solve(m, tee=True)
319+
320+
def test_solve_without_objective(self):
321+
m = create_model1()
322+
m.o.deactivate()
323+
m.x[2].fix(0.0)
324+
m.x[3].fix(4.0)
325+
solver = pyo.SolverFactory("cyipopt")
326+
res = solver.solve(m, tee=True)
327+
pyo.assert_optimal_termination(res)
328+
self.assertAlmostEqual(m.x[1].value, 9.0)

0 commit comments

Comments
 (0)