Skip to content

Commit

Permalink
fix appsi auto-update when unfixing a variable and changing its bound
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelbynum committed Sep 18, 2023
1 parent 376a2f7 commit 5a29cfa
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 6 deletions.
10 changes: 5 additions & 5 deletions pyomo/contrib/appsi/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -1406,17 +1406,17 @@ def update(self, timer: HierarchicalTimer = None):
vars_to_update = list()
for v in vars_to_check:
_v, lb, ub, fixed, domain_interval, value = self._vars[id(v)]
if lb is not v._lb:
vars_to_update.append(v)
elif ub is not v._ub:
vars_to_update.append(v)
elif (fixed is not v.fixed) or (fixed and (value != v.value)):
if (fixed is not v.fixed) or (fixed and (value != v.value)):
vars_to_update.append(v)
if self.update_config.treat_fixed_vars_as_params:
for c in self._referenced_variables[id(v)][0]:
cons_to_remove_and_add[c] = None
if self._referenced_variables[id(v)][2] is not None:
need_to_set_objective = True
elif lb is not v._lb:
vars_to_update.append(v)
elif ub is not v._ub:
vars_to_update.append(v)
elif domain_interval != v.domain.get_interval():
vars_to_update.append(v)
self.update_variables(vars_to_update)
Expand Down
30 changes: 29 additions & 1 deletion pyomo/contrib/appsi/solvers/tests/test_persistent_solvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -563,8 +563,8 @@ def test_mutable_quadratic_objective(
def test_fixed_vars(
self, name: str, opt_class: Type[PersistentSolver], only_child_vars
):
opt: PersistentSolver = opt_class(only_child_vars=only_child_vars)
for treat_fixed_vars_as_params in [True, False]:
opt: PersistentSolver = opt_class(only_child_vars=only_child_vars)
opt.update_config.treat_fixed_vars_as_params = treat_fixed_vars_as_params
if not opt.available():
raise unittest.SkipTest
Expand Down Expand Up @@ -1281,6 +1281,34 @@ def test_bug_1(self, name: str, opt_class: Type[PersistentSolver], only_child_va
self.assertEqual(res.termination_condition, TerminationCondition.optimal)
self.assertAlmostEqual(res.best_feasible_objective, 3)

@parameterized.expand(input=_load_tests(all_solvers, only_child_vars_options))
def test_bug_2(self, name: str, opt_class: Type[PersistentSolver], only_child_vars):
"""
This test is for a bug where an objective containing a fixed variable does
not get updated properly when the variable is unfixed.
"""
for fixed_var_option in [True, False]:
opt: PersistentSolver = opt_class(only_child_vars=only_child_vars)
if not opt.available():
raise unittest.SkipTest
opt.update_config.treat_fixed_vars_as_params = fixed_var_option

m = pe.ConcreteModel()
m.x = pe.Var(bounds=(-10, 10))
m.y = pe.Var()
m.obj = pe.Objective(expr=3*m.y - m.x)
m.c = pe.Constraint(expr=m.y >= m.x)

m.x.fix(1)
res = opt.solve(m)
self.assertAlmostEqual(res.best_feasible_objective, 2, 5)

m.x.unfix()
m.x.setlb(-9)
m.x.setub(9)
res = opt.solve(m)
self.assertAlmostEqual(res.best_feasible_objective, -18, 5)


@unittest.skipUnless(cmodel_available, 'appsi extensions are not available')
class TestLegacySolverInterface(unittest.TestCase):
Expand Down

0 comments on commit 5a29cfa

Please sign in to comment.