Skip to content

Commit

Permalink
Remove slack referrences; fix broken unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mrmundt committed Jan 18, 2024
1 parent af7d287 commit 7fa02de
Show file tree
Hide file tree
Showing 6 changed files with 9 additions and 57 deletions.
8 changes: 0 additions & 8 deletions pyomo/contrib/solver/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions pyomo/contrib/solver/ipopt.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down Expand Up @@ -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,
Expand Down
27 changes: 1 addition & 26 deletions pyomo/contrib/solver/solution.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -129,7 +108,6 @@ def __init__(
self,
primals: Optional[MutableMapping],
duals: Optional[MutableMapping],
slacks: Optional[MutableMapping],
reduced_costs: Optional[MutableMapping],
):
"""
Expand All @@ -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(
Expand Down
5 changes: 2 additions & 3 deletions pyomo/contrib/solver/tests/solvers/test_ipopt.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
20 changes: 4 additions & 16 deletions pyomo/contrib/solver/tests/unit/test_results.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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.*'
Expand All @@ -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()
Expand All @@ -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()
Expand Down Expand Up @@ -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])
2 changes: 0 additions & 2 deletions pyomo/contrib/solver/tests/unit/test_solution.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()

0 comments on commit 7fa02de

Please sign in to comment.