From 595e23518120e66c001e676f6bc0df55cd490d75 Mon Sep 17 00:00:00 2001 From: John Siirola Date: Mon, 24 Jul 2023 15:16:49 -0600 Subject: [PATCH 1/3] Xpress: only fall back on the LP results processor if there is no NLP status --- .../solvers/plugins/solvers/xpress_direct.py | 166 +++++++++--------- 1 file changed, 84 insertions(+), 82 deletions(-) diff --git a/pyomo/solvers/plugins/solvers/xpress_direct.py b/pyomo/solvers/plugins/solvers/xpress_direct.py index f7ada793d04..a14a6e5e9fb 100644 --- a/pyomo/solvers/plugins/solvers/xpress_direct.py +++ b/pyomo/solvers/plugins/solvers/xpress_direct.py @@ -436,98 +436,100 @@ def _get_nlp_results(self, results, soln): # was convex if (xprob_attrs.originalmipents > 0) or (xprob_attrs.originalsets > 0): return self._get_mip_results(results, soln) - else: + elif not xprob_attrs.xslp_nlpstatus: + # If there is no NLP solver status, process the result + # using the LP results processor. return self._get_lp_results(results, soln) - else: - # The problem was non-linear - status = xprob_attrs.xslp_nlpstatus - solstatus = xprob_attrs.xslp_solstatus - have_soln = False - optimal = False # *globally* optimal? - if status == xp.nlp_unstarted: - results.solver.status = SolverStatus.unknown - results.solver.termination_message = ( - "Non-convex model solve was not start" - ) - results.solver.termination_condition = TerminationCondition.unknown - soln.status = SolutionStatus.unknown - elif status == xp.nlp_locally_optimal: - # This is either xp.nlp_locally_optimal or xp.nlp_solution - # we must look at the solstatus to figure out which - if solstatus in [2, 3]: - results.solver.status = SolverStatus.ok - results.solver.termination_message = ( - "Non-convex model was solved to local optimality" - ) - results.solver.termination_condition = ( - TerminationCondition.locallyOptimal - ) - soln.status = SolutionStatus.locallyOptimal - else: - results.solver.status = SolverStatus.ok - results.solver.termination_message = ( - "Feasible solution found for non-convex model" - ) - results.solver.termination_condition = TerminationCondition.feasible - soln.status = SolutionStatus.feasible - have_soln = True - elif status == xp.nlp_globally_optimal: - results.solver.status = SolverStatus.ok - results.solver.termination_message = ( - "Non-convex model was solved to global optimality" - ) - results.solver.termination_condition = TerminationCondition.optimal - soln.status = SolutionStatus.optimal - have_soln = True - optimal = True - elif status == xp.nlp_locally_infeasible: - results.solver.status = SolverStatus.ok - results.solver.termination_message = ( - "Non-convex model was proven to be locally infeasible" - ) - results.solver.termination_condition = TerminationCondition.noSolution - soln.status = SolutionStatus.unknown - elif status == xp.nlp_infeasible: - results.solver.status = SolverStatus.ok - results.solver.termination_message = ( - "Non-conex model was proven to be infeasible" - ) - results.solver.termination_condition = TerminationCondition.infeasible - soln.status = SolutionStatus.infeasible - elif status == xp.nlp_unbounded: # locally unbounded! + + # The problem was non-linear + status = xprob_attrs.xslp_nlpstatus + solstatus = xprob_attrs.xslp_solstatus + have_soln = False + optimal = False # *globally* optimal? + if status == xp.nlp_unstarted: + results.solver.status = SolverStatus.unknown + results.solver.termination_message = ( + "Non-convex model solve was not start" + ) + results.solver.termination_condition = TerminationCondition.unknown + soln.status = SolutionStatus.unknown + elif status == xp.nlp_locally_optimal: + # This is either xp.nlp_locally_optimal or xp.nlp_solution + # we must look at the solstatus to figure out which + if solstatus in [2, 3]: results.solver.status = SolverStatus.ok results.solver.termination_message = ( - "Non-convex model is locally unbounded" + "Non-convex model was solved to local optimality" ) - results.solver.termination_condition = TerminationCondition.unbounded - soln.status = SolutionStatus.unbounded - elif status == xp.nlp_unfinished: - results.solver.status = SolverStatus.ok - results.solver.termination_message = ( - "Non-convex solve not finished (numerical issues?)" + results.solver.termination_condition = ( + TerminationCondition.locallyOptimal ) - results.solver.termination_condition = TerminationCondition.unknown - soln.status = SolutionStatus.unknown - have_soln = True + soln.status = SolutionStatus.locallyOptimal else: - results.solver.status = SolverStatus.error + results.solver.status = SolverStatus.ok results.solver.termination_message = ( - "Error for non-convex model: " + str(status) + "Feasible solution found for non-convex model" ) - results.solver.termination_condition = TerminationCondition.error - soln.status = SolutionStatus.error + results.solver.termination_condition = TerminationCondition.feasible + soln.status = SolutionStatus.feasible + have_soln = True + elif status == xp.nlp_globally_optimal: + results.solver.status = SolverStatus.ok + results.solver.termination_message = ( + "Non-convex model was solved to global optimality" + ) + results.solver.termination_condition = TerminationCondition.optimal + soln.status = SolutionStatus.optimal + have_soln = True + optimal = True + elif status == xp.nlp_locally_infeasible: + results.solver.status = SolverStatus.ok + results.solver.termination_message = ( + "Non-convex model was proven to be locally infeasible" + ) + results.solver.termination_condition = TerminationCondition.noSolution + soln.status = SolutionStatus.unknown + elif status == xp.nlp_infeasible: + results.solver.status = SolverStatus.ok + results.solver.termination_message = ( + "Non-conex model was proven to be infeasible" + ) + results.solver.termination_condition = TerminationCondition.infeasible + soln.status = SolutionStatus.infeasible + elif status == xp.nlp_unbounded: # locally unbounded! + results.solver.status = SolverStatus.ok + results.solver.termination_message = ( + "Non-convex model is locally unbounded" + ) + results.solver.termination_condition = TerminationCondition.unbounded + soln.status = SolutionStatus.unbounded + elif status == xp.nlp_unfinished: + results.solver.status = SolverStatus.ok + results.solver.termination_message = ( + "Non-convex solve not finished (numerical issues?)" + ) + results.solver.termination_condition = TerminationCondition.unknown + soln.status = SolutionStatus.unknown + have_soln = True + else: + results.solver.status = SolverStatus.error + results.solver.termination_message = ( + "Error for non-convex model: " + str(status) + ) + results.solver.termination_condition = TerminationCondition.error + soln.status = SolutionStatus.error - results.problem.upper_bound = None - results.problem.lower_bound = None - try: - if xprob_attrs.objsense > 0.0 or optimal: # minimizing - results.problem.upper_bound = xprob_attrs.xslp_objval - if xprob_attrs.objsense < 0.0 or optimal: # maximizing - results.problem.lower_bound = xprob_attrs.xslp_objval - except (XpressDirect.XpressException, AttributeError): - pass + results.problem.upper_bound = None + results.problem.lower_bound = None + try: + if xprob_attrs.objsense > 0.0 or optimal: # minimizing + results.problem.upper_bound = xprob_attrs.xslp_objval + if xprob_attrs.objsense < 0.0 or optimal: # maximizing + results.problem.lower_bound = xprob_attrs.xslp_objval + except (XpressDirect.XpressException, AttributeError): + pass - return have_soln + return have_soln def _solve_model(self): xprob = self._solver_model From ff40919eff5dc048cb0fc0d3aba4275d4533ac73 Mon Sep 17 00:00:00 2001 From: John Siirola Date: Mon, 24 Jul 2023 15:33:23 -0600 Subject: [PATCH 2/3] Apply black --- pyomo/solvers/plugins/solvers/xpress_direct.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/pyomo/solvers/plugins/solvers/xpress_direct.py b/pyomo/solvers/plugins/solvers/xpress_direct.py index a14a6e5e9fb..18668afd2e5 100644 --- a/pyomo/solvers/plugins/solvers/xpress_direct.py +++ b/pyomo/solvers/plugins/solvers/xpress_direct.py @@ -436,7 +436,7 @@ def _get_nlp_results(self, results, soln): # was convex if (xprob_attrs.originalmipents > 0) or (xprob_attrs.originalsets > 0): return self._get_mip_results(results, soln) - elif not xprob_attrs.xslp_nlpstatus: + elif xprob_attrs.lpstatus and not xprob_attrs.xslp_nlpstatus: # If there is no NLP solver status, process the result # using the LP results processor. return self._get_lp_results(results, soln) @@ -448,9 +448,7 @@ def _get_nlp_results(self, results, soln): optimal = False # *globally* optimal? if status == xp.nlp_unstarted: results.solver.status = SolverStatus.unknown - results.solver.termination_message = ( - "Non-convex model solve was not start" - ) + results.solver.termination_message = "Non-convex model solve was not start" results.solver.termination_condition = TerminationCondition.unknown soln.status = SolutionStatus.unknown elif status == xp.nlp_locally_optimal: @@ -498,9 +496,7 @@ def _get_nlp_results(self, results, soln): soln.status = SolutionStatus.infeasible elif status == xp.nlp_unbounded: # locally unbounded! results.solver.status = SolverStatus.ok - results.solver.termination_message = ( - "Non-convex model is locally unbounded" - ) + results.solver.termination_message = "Non-convex model is locally unbounded" results.solver.termination_condition = TerminationCondition.unbounded soln.status = SolutionStatus.unbounded elif status == xp.nlp_unfinished: @@ -513,8 +509,8 @@ def _get_nlp_results(self, results, soln): have_soln = True else: results.solver.status = SolverStatus.error - results.solver.termination_message = ( - "Error for non-convex model: " + str(status) + results.solver.termination_message = "Error for non-convex model: " + str( + status ) results.solver.termination_condition = TerminationCondition.error soln.status = SolutionStatus.error From fcac472f85a0a731d394bf31b4cea8bf53d2dc16 Mon Sep 17 00:00:00 2001 From: John Siirola Date: Mon, 24 Jul 2023 16:32:26 -0600 Subject: [PATCH 3/3] NFX: fix typos --- pyomo/solvers/plugins/solvers/xpress_direct.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pyomo/solvers/plugins/solvers/xpress_direct.py b/pyomo/solvers/plugins/solvers/xpress_direct.py index 18668afd2e5..aa5a4ba1b4e 100644 --- a/pyomo/solvers/plugins/solvers/xpress_direct.py +++ b/pyomo/solvers/plugins/solvers/xpress_direct.py @@ -448,7 +448,9 @@ def _get_nlp_results(self, results, soln): optimal = False # *globally* optimal? if status == xp.nlp_unstarted: results.solver.status = SolverStatus.unknown - results.solver.termination_message = "Non-convex model solve was not start" + results.solver.termination_message = ( + "Non-convex model solve was not started" + ) results.solver.termination_condition = TerminationCondition.unknown soln.status = SolutionStatus.unknown elif status == xp.nlp_locally_optimal: @@ -490,7 +492,7 @@ def _get_nlp_results(self, results, soln): elif status == xp.nlp_infeasible: results.solver.status = SolverStatus.ok results.solver.termination_message = ( - "Non-conex model was proven to be infeasible" + "Non-convex model was proven to be infeasible" ) results.solver.termination_condition = TerminationCondition.infeasible soln.status = SolutionStatus.infeasible