diff --git a/pyomo/contrib/solver/base.py b/pyomo/contrib/solver/base.py index 962d35582a1..0b33f8a5648 100644 --- a/pyomo/contrib/solver/base.py +++ b/pyomo/contrib/solver/base.py @@ -435,9 +435,6 @@ def solve( if hasattr(model, 'dual') and model.dual.import_enabled(): for c, val in results.solution_loader.get_duals().items(): model.dual[c] = val - if hasattr(model, 'slack') and model.slack.import_enabled(): - for c, val in results.solution_loader.get_slacks().items(): - model.slack[c] = val if hasattr(model, 'rc') and model.rc.import_enabled(): for v, val in results.solution_loader.get_reduced_costs().items(): model.rc[v] = val @@ -448,11 +445,6 @@ def solve( if hasattr(model, 'dual') and model.dual.import_enabled(): for c, val in results.solution_loader.get_duals().items(): legacy_soln.constraint[symbol_map.getSymbol(c)] = {'Dual': val} - if hasattr(model, 'slack') and model.slack.import_enabled(): - for c, val in results.solution_loader.get_slacks().items(): - symbol = symbol_map.getSymbol(c) - if symbol in legacy_soln.constraint: - legacy_soln.constraint[symbol]['Slack'] = val if hasattr(model, 'rc') and model.rc.import_enabled(): for v, val in results.solution_loader.get_reduced_costs().items(): legacy_soln.variable['Rc'] = val diff --git a/pyomo/contrib/solver/ipopt.py b/pyomo/contrib/solver/ipopt.py index 47436d9d11f..6ab40fd3924 100644 --- a/pyomo/contrib/solver/ipopt.py +++ b/pyomo/contrib/solver/ipopt.py @@ -372,7 +372,7 @@ def solve(self, model, **kwds): if process.returncode != 0: results.termination_condition = TerminationCondition.error - results.solution_loader = SolutionLoader(None, None, None, None) + results.solution_loader = SolutionLoader(None, None, None) else: with open(basename + '.sol', 'r') as sol_file: timer.start('parse_sol') @@ -481,7 +481,7 @@ def _parse_solution( ) if res.solution_status == SolutionStatus.noSolution: - res.solution_loader = SolutionLoader(None, None, None, None) + res.solution_loader = SolutionLoader(None, None, None) else: res.solution_loader = ipoptSolutionLoader( sol_data=sol_data, diff --git a/pyomo/contrib/solver/solution.py b/pyomo/contrib/solver/solution.py index ae47491c310..18fd96759cf 100644 --- a/pyomo/contrib/solver/solution.py +++ b/pyomo/contrib/solver/solution.py @@ -17,31 +17,10 @@ from pyomo.common.collections import ComponentMap from pyomo.core.staleflag import StaleFlagManager from .sol_reader import SolFileData -from pyomo.repn.plugins.nl_writer import NLWriterInfo, AMPLRepn +from pyomo.repn.plugins.nl_writer import NLWriterInfo from pyomo.core.expr.numvalue import value from pyomo.core.expr.visitor import replace_expressions -# CHANGES: -# - `load` method: should just load the whole thing back into the model; load_solution = True -# - `load_variables` -# - `get_variables` -# - `get_constraints` -# - `get_objective` -# - `get_slacks` -# - `get_reduced_costs` - -# duals is how much better you could get if you weren't constrained. -# dual value of 0 means that the constraint isn't actively constraining anything. -# high dual value means that it is costing us a lot in the objective. -# can also be called "shadow price" - -# bounds on variables are implied constraints. -# getting a dual on the bound of a variable is the reduced cost. -# IPOPT calls these the bound multipliers (normally they are reduced costs, though). ZL, ZU - -# slacks are... something that I don't understand -# but they are necessary somewhere? I guess? - class SolutionLoaderBase(abc.ABC): def load_vars( @@ -129,7 +108,6 @@ def __init__( self, primals: Optional[MutableMapping], duals: Optional[MutableMapping], - slacks: Optional[MutableMapping], reduced_costs: Optional[MutableMapping], ): """ @@ -139,14 +117,11 @@ def __init__( maps id(Var) to (var, value) duals: dict maps Constraint to dual value - slacks: dict - maps Constraint to slack value reduced_costs: dict maps id(Var) to (var, reduced_cost) """ self._primals = primals self._duals = duals - self._slacks = slacks self._reduced_costs = reduced_costs def get_primals( diff --git a/pyomo/contrib/solver/tests/solvers/test_ipopt.py b/pyomo/contrib/solver/tests/solvers/test_ipopt.py index c1aecba05fc..9638d94bdda 100644 --- a/pyomo/contrib/solver/tests/solvers/test_ipopt.py +++ b/pyomo/contrib/solver/tests/solvers/test_ipopt.py @@ -45,13 +45,12 @@ def test_ipopt_config(self): config = ipoptConfig() self.assertTrue(config.load_solution) self.assertIsInstance(config.solver_options, ConfigDict) - print(type(config.executable)) self.assertIsInstance(config.executable, ExecutableData) # Test custom initialization - solver = SolverFactory('ipopt_v2', save_solver_io=True) - self.assertTrue(solver.config.save_solver_io) + solver = SolverFactory('ipopt_v2', executable='/path/to/exe') self.assertFalse(solver.config.tee) + self.assertTrue(solver.config.executable.startswith('/path')) # Change value on a solve call # model = self.create_model() diff --git a/pyomo/contrib/solver/tests/unit/test_results.py b/pyomo/contrib/solver/tests/unit/test_results.py index e7d02751f7d..927ab64ee12 100644 --- a/pyomo/contrib/solver/tests/unit/test_results.py +++ b/pyomo/contrib/solver/tests/unit/test_results.py @@ -82,6 +82,8 @@ def test_declared_items(self): 'solver_version', 'termination_condition', 'timing_info', + 'solver_log', + 'solver_configuration' } actual_declared = res._declared self.assertEqual(expected_declared, actual_declared) @@ -101,7 +103,7 @@ def test_uninitialized(self): self.assertIsInstance(res.extra_info, ConfigDict) self.assertIsNone(res.timing_info.start_timestamp) self.assertIsNone(res.timing_info.wall_time) - res.solution_loader = solution.SolutionLoader(None, None, None, None) + res.solution_loader = solution.SolutionLoader(None, None, None) with self.assertRaisesRegex( RuntimeError, '.*does not currently have a valid solution.*' @@ -115,10 +117,6 @@ def test_uninitialized(self): RuntimeError, '.*does not currently have valid reduced costs.*' ): res.solution_loader.get_reduced_costs() - with self.assertRaisesRegex( - RuntimeError, '.*does not currently have valid slacks.*' - ): - res.solution_loader.get_slacks() def test_results(self): m = pyo.ConcreteModel() @@ -136,13 +134,10 @@ def test_results(self): rc = {} rc[id(m.x)] = (m.x, 5) rc[id(m.y)] = (m.y, 6) - slacks = {} - slacks[m.c1] = 7 - slacks[m.c2] = 8 res = results.Results() res.solution_loader = solution.SolutionLoader( - primals=primals, duals=duals, slacks=slacks, reduced_costs=rc + primals=primals, duals=duals, reduced_costs=rc ) res.solution_loader.load_vars() @@ -172,10 +167,3 @@ def test_results(self): self.assertNotIn(m.x, rc2) self.assertAlmostEqual(rc[id(m.y)][1], rc2[m.y]) - slacks2 = res.solution_loader.get_slacks() - self.assertAlmostEqual(slacks[m.c1], slacks2[m.c1]) - self.assertAlmostEqual(slacks[m.c2], slacks2[m.c2]) - - slacks2 = res.solution_loader.get_slacks([m.c2]) - self.assertNotIn(m.c1, slacks2) - self.assertAlmostEqual(slacks[m.c2], slacks2[m.c2]) diff --git a/pyomo/contrib/solver/tests/unit/test_solution.py b/pyomo/contrib/solver/tests/unit/test_solution.py index dc53f1e4543..1ecba45b32a 100644 --- a/pyomo/contrib/solver/tests/unit/test_solution.py +++ b/pyomo/contrib/solver/tests/unit/test_solution.py @@ -27,7 +27,5 @@ def test_solution_loader_base(self): self.assertEqual(self.instance.get_primals(), None) with self.assertRaises(NotImplementedError): self.instance.get_duals() - with self.assertRaises(NotImplementedError): - self.instance.get_slacks() with self.assertRaises(NotImplementedError): self.instance.get_reduced_costs()