diff --git a/pyomo/solvers/plugins/solvers/cplex_direct.py b/pyomo/solvers/plugins/solvers/cplex_direct.py index badca14f825..eb74f513c76 100644 --- a/pyomo/solvers/plugins/solvers/cplex_direct.py +++ b/pyomo/solvers/plugins/solvers/cplex_direct.py @@ -549,8 +549,6 @@ def _set_objective(self, obj): self._vars_referenced_by_obj = ComponentSet() self._objective = None - self._solver_model.objective.set_linear([(i, 0.0) for i in range(len(self._pyomo_var_to_solver_var_map.values()))]) - if obj.active is False: raise ValueError('Cannot add inactive objective to solver.') @@ -571,12 +569,33 @@ def _set_objective(self, obj): self._solver_model.objective.set_sense(sense) if hasattr(self._solver_model.objective, 'set_offset'): self._solver_model.objective.set_offset(cplex_expr.offset) - if len(cplex_expr.coefficients) != 0: - self._solver_model.objective.set_linear(list(zip(cplex_expr.variables, cplex_expr.coefficients))) - if len(cplex_expr.q_coefficients) != 0: - self._solver_model.objective.set_quadratic_coefficients(list(zip(cplex_expr.q_variables1, - cplex_expr.q_variables2, - cplex_expr.q_coefficients))) + + linear_objective_already_exists = any(self._solver_model.objective.get_linear()) + quadratic_objective_already_exists = self._solver_model.objective.get_num_quadratic_nonzeros() + + contains_linear_terms = any(cplex_expr.coefficients) + contains_quadratic_terms = any(cplex_expr.q_coefficients) + num_cols = len(self._pyomo_var_to_solver_var_map) + + if linear_objective_already_exists or contains_linear_terms: + self._solver_model.objective.set_linear([(i, 0.0) for i in range(num_cols)]) + + if contains_linear_terms: + self._solver_model.objective.set_linear(list(zip(cplex_expr.variables, cplex_expr.coefficients))) + + if quadratic_objective_already_exists or contains_quadratic_terms: + self._solver_model.objective.set_quadratic([0] * num_cols) + + if contains_quadratic_terms: + self._solver_model.objective.set_quadratic_coefficients( + list( + zip( + cplex_expr.q_variables1, + cplex_expr.q_variables2, + cplex_expr.q_coefficients + ) + ) + ) self._objective = obj self._vars_referenced_by_obj = referenced_vars diff --git a/pyomo/solvers/tests/checks/test_CPLEXPersistent.py b/pyomo/solvers/tests/checks/test_CPLEXPersistent.py new file mode 100644 index 00000000000..51ff1ab7e43 --- /dev/null +++ b/pyomo/solvers/tests/checks/test_CPLEXPersistent.py @@ -0,0 +1,35 @@ +import pyutilib.th as unittest + +from pyomo.environ import * +from pyomo.opt import * + +try: + import cplex + + cplexpy_available = True +except ImportError: + cplexpy_available = False + + +@unittest.skipIf(not cplexpy_available, "The 'cplex' python bindings are not available") +class TestQuadraticObjective(unittest.TestCase): + def test_quadratic_objective_is_set(self): + model = ConcreteModel() + model.X = Var(bounds=(-2, 2)) + model.Y = Var(bounds=(-2, 2)) + model.O = Objective(expr=model.X ** 2 + model.Y ** 2) + model.C1 = Constraint(expr=model.Y >= 2 * model.X - 1) + model.C2 = Constraint(expr=model.Y >= -model.X + 2) + opt = SolverFactory("cplex_persistent") + opt.set_instance(model) + opt.solve() + + self.assertAlmostEqual(model.X.value, 1, places=3) + self.assertAlmostEqual(model.Y.value, 1, places=3) + + del model.O + model.O = Objective(expr=model.X ** 2) + opt.set_objective(model.O) + opt.solve() + self.assertAlmostEqual(model.X.value, 0, places=3) + self.assertAlmostEqual(model.Y.value, 2, places=3)