Skip to content

Commit

Permalink
Backwards compatibility; add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mrmundt committed Feb 1, 2024
1 parent a2a5513 commit 2c8a4d8
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 13 deletions.
43 changes: 42 additions & 1 deletion pyomo/contrib/solver/tests/unit/test_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,18 @@

from pyomo.common import unittest
import pyomo.environ as pyo
from pyomo.contrib.solver.util import collect_vars_and_named_exprs, get_objective
from pyomo.contrib.solver.util import (
collect_vars_and_named_exprs,
get_objective,
check_optimal_termination,
assert_optimal_termination,
SolverStatus,
LegacyTerminationCondition,
)
from pyomo.contrib.solver.results import Results, SolutionStatus, TerminationCondition
from typing import Callable
from pyomo.common.gsl import find_GSL
from pyomo.opt.results import SolverResults


class TestGenericUtils(unittest.TestCase):
Expand Down Expand Up @@ -73,3 +82,35 @@ def test_get_objective_raise(self):
model.OBJ2 = pyo.Objective(expr=model.x[1] - 4 * model.x[2])
with self.assertRaises(ValueError):
get_objective(model)

def test_check_optimal_termination_new_interface(self):
results = Results()
results.solution_status = SolutionStatus.optimal
results.termination_condition = (
TerminationCondition.convergenceCriteriaSatisfied
)
# Both items satisfied
self.assertTrue(check_optimal_termination(results))
# Termination condition not satisfied
results.termination_condition = TerminationCondition.iterationLimit
self.assertFalse(check_optimal_termination(results))
# Both not satisfied
results.solution_status = SolutionStatus.noSolution
self.assertFalse(check_optimal_termination(results))

def test_check_optimal_termination_condition_legacy_interface(self):
results = SolverResults()
results.solver.status = SolverStatus.ok
results.solver.termination_condition = LegacyTerminationCondition.optimal
self.assertTrue(check_optimal_termination(results))
results.solver.termination_condition = LegacyTerminationCondition.unknown
self.assertFalse(check_optimal_termination(results))
results.solver.termination_condition = SolverStatus.aborted
self.assertFalse(check_optimal_termination(results))

# TODO: Left off here; need to make these tests
def test_assert_optimal_termination_new_interface(self):
pass

def test_assert_optimal_termination_legacy_interface(self):
pass
50 changes: 38 additions & 12 deletions pyomo/contrib/solver/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,20 @@
from pyomo.common.collections import ComponentMap
from pyomo.common.timing import HierarchicalTimer
from pyomo.core.expr.numvalue import NumericConstant
from pyomo.opt.results.solver import (
SolverStatus,
TerminationCondition as LegacyTerminationCondition,
)


from pyomo.contrib.solver.results import TerminationCondition, SolutionStatus


def get_objective(block):
"""
Get current active objective on a block. If there is more than one active,
return an error.
"""
obj = None
for o in block.component_data_objects(
Objective, descend_into=True, active=True, sort=True
Expand All @@ -37,8 +47,6 @@ def get_objective(block):


def check_optimal_termination(results):
# TODO: Make work for legacy and new results objects.
# Look at the original version of this function to make that happen.
"""
This function returns True if the termination condition for the solver
is 'optimal'.
Expand All @@ -51,11 +59,21 @@ def check_optimal_termination(results):
-------
`bool`
"""
if results.solution_status == SolutionStatus.optimal and (
results.termination_condition
== TerminationCondition.convergenceCriteriaSatisfied
):
return True
if hasattr(results, 'solution_status'):
if results.solution_status == SolutionStatus.optimal and (
results.termination_condition
== TerminationCondition.convergenceCriteriaSatisfied
):
return True
else:
if results.solver.status == SolverStatus.ok and (
results.solver.termination_condition == LegacyTerminationCondition.optimal
or results.solver.termination_condition
== LegacyTerminationCondition.locallyOptimal
or results.solver.termination_condition
== LegacyTerminationCondition.globallyOptimal
):
return True
return False


Expand All @@ -70,12 +88,20 @@ def assert_optimal_termination(results):
results : Pyomo Results object returned from solver.solve
"""
if not check_optimal_termination(results):
msg = (
'Solver failed to return an optimal solution. '
'Solution status: {}, Termination condition: {}'.format(
results.solution_status, results.termination_condition
if hasattr(results, 'solution_status'):
msg = (
'Solver failed to return an optimal solution. '
'Solution status: {}, Termination condition: {}'.format(
results.solution_status, results.termination_condition
)
)
else:
msg = (
'Solver failed to return an optimal solution. '
'Solver status: {}, Termination condition: {}'.format(
results.solver.status, results.solver.termination_condition
)
)
)
raise RuntimeError(msg)


Expand Down

0 comments on commit 2c8a4d8

Please sign in to comment.