diff --git a/pyomo/contrib/gdpopt/loa.py b/pyomo/contrib/gdpopt/loa.py index 8e36bebfd22..3f9db839b93 100644 --- a/pyomo/contrib/gdpopt/loa.py +++ b/pyomo/contrib/gdpopt/loa.py @@ -147,7 +147,8 @@ def _setup_augmented_penalty_objective(self, discrete_problem_util_block): # Set up augmented penalty objective discrete_objective.deactivate() # placeholder for OA objective - discrete_problem_util_block.oa_obj = Objective(sense=minimize) + discrete_problem_util_block.oa_obj = Objective() + discrete_problem_util_block.oa_obj.sense = discrete_objective.sense return discrete_objective diff --git a/pyomo/contrib/gdpopt/tests/test_gdpopt.py b/pyomo/contrib/gdpopt/tests/test_gdpopt.py index 5a0fc30cf37..68a1ebb4fe4 100644 --- a/pyomo/contrib/gdpopt/tests/test_gdpopt.py +++ b/pyomo/contrib/gdpopt/tests/test_gdpopt.py @@ -40,6 +40,7 @@ Integers, LogicalConstraint, maximize, + minimize, Objective, RangeSet, TransformationFactory, @@ -322,6 +323,48 @@ def test_complain_when_no_algorithm_specified(self): ): SolverFactory('gdpopt').solve(m) + def test_loa_augmented_penalty_objective_preserves_objective_sense(self): + for sense in (minimize, maximize): + m = ConcreteModel() + m.GDPopt_utils = Block() + m.x = Var(bounds=(0, 1)) + m.obj = Objective(expr=m.x, sense=sense) + + solver = SolverFactory('gdpopt.loa') + original_obj = solver._setup_augmented_penalty_objective(m.GDPopt_utils) + + self.assertIs(original_obj, m.obj) + self.assertFalse(m.obj.active) + self.assertEqual(m.GDPopt_utils.oa_obj.sense, sense) + + @unittest.skipUnless( + SolverFactory(mip_solver).available(), "MIP solver not available" + ) + def test_LOA_maximize_matches_minimize_negated_objective(self): + def build_model(maximize_objective): + m = ConcreteModel() + m.x = Var(bounds=(0, 10)) + m.disjunction = Disjunction(expr=[[m.x == 1], [m.x == 9]]) + if maximize_objective: + m.obj = Objective(expr=m.x, sense=maximize) + else: + m.obj = Objective(expr=-m.x) + return m + + for maximize_objective in (False, True): + m = build_model(maximize_objective) + results = SolverFactory('gdpopt.loa').solve( + m, + mip_solver=mip_solver, + nlp_solver=nlp_solver, + init_algorithm='no_init', + ) + + self.assertEqual( + results.solver.termination_condition, TerminationCondition.optimal + ) + self.assertAlmostEqual(value(m.x), 9) + @unittest.skipIf( not LOA_solvers_available, "Required subsolvers %s are not available" % (LOA_solvers,),