Skip to content

Commit

Permalink
🔨 Refactor quadratic objective handling
Browse files Browse the repository at this point in the history
  • Loading branch information
ruaridhw committed May 21, 2020
1 parent 742d8bc commit fc0b8cc
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 8 deletions.
35 changes: 27 additions & 8 deletions pyomo/solvers/plugins/solvers/cplex_direct.py
Original file line number Diff line number Diff line change
Expand Up @@ -538,8 +538,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.')

Expand All @@ -560,12 +558,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

Expand Down
35 changes: 35 additions & 0 deletions pyomo/solvers/tests/checks/test_CPLEXPersistent.py
Original file line number Diff line number Diff line change
@@ -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)

0 comments on commit fc0b8cc

Please sign in to comment.