Skip to content

Commit fc0b8cc

Browse files
author
Ruaridh Williamson
committed
🔨 Refactor quadratic objective handling
1 parent 742d8bc commit fc0b8cc

File tree

2 files changed

+62
-8
lines changed

2 files changed

+62
-8
lines changed

pyomo/solvers/plugins/solvers/cplex_direct.py

+27-8
Original file line numberDiff line numberDiff line change
@@ -538,8 +538,6 @@ def _set_objective(self, obj):
538538
self._vars_referenced_by_obj = ComponentSet()
539539
self._objective = None
540540

541-
self._solver_model.objective.set_linear([(i, 0.0) for i in range(len(self._pyomo_var_to_solver_var_map.values()))])
542-
543541
if obj.active is False:
544542
raise ValueError('Cannot add inactive objective to solver.')
545543

@@ -560,12 +558,33 @@ def _set_objective(self, obj):
560558
self._solver_model.objective.set_sense(sense)
561559
if hasattr(self._solver_model.objective, 'set_offset'):
562560
self._solver_model.objective.set_offset(cplex_expr.offset)
563-
if len(cplex_expr.coefficients) != 0:
564-
self._solver_model.objective.set_linear(list(zip(cplex_expr.variables, cplex_expr.coefficients)))
565-
if len(cplex_expr.q_coefficients) != 0:
566-
self._solver_model.objective.set_quadratic_coefficients(list(zip(cplex_expr.q_variables1,
567-
cplex_expr.q_variables2,
568-
cplex_expr.q_coefficients)))
561+
562+
linear_objective_already_exists = any(self._solver_model.objective.get_linear())
563+
quadratic_objective_already_exists = self._solver_model.objective.get_num_quadratic_nonzeros()
564+
565+
contains_linear_terms = any(cplex_expr.coefficients)
566+
contains_quadratic_terms = any(cplex_expr.q_coefficients)
567+
num_cols = len(self._pyomo_var_to_solver_var_map)
568+
569+
if linear_objective_already_exists or contains_linear_terms:
570+
self._solver_model.objective.set_linear([(i, 0.0) for i in range(num_cols)])
571+
572+
if contains_linear_terms:
573+
self._solver_model.objective.set_linear(list(zip(cplex_expr.variables, cplex_expr.coefficients)))
574+
575+
if quadratic_objective_already_exists or contains_quadratic_terms:
576+
self._solver_model.objective.set_quadratic([0] * num_cols)
577+
578+
if contains_quadratic_terms:
579+
self._solver_model.objective.set_quadratic_coefficients(
580+
list(
581+
zip(
582+
cplex_expr.q_variables1,
583+
cplex_expr.q_variables2,
584+
cplex_expr.q_coefficients
585+
)
586+
)
587+
)
569588
self._objective = obj
570589
self._vars_referenced_by_obj = referenced_vars
571590

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import pyutilib.th as unittest
2+
3+
from pyomo.environ import *
4+
from pyomo.opt import *
5+
6+
try:
7+
import cplex
8+
9+
cplexpy_available = True
10+
except ImportError:
11+
cplexpy_available = False
12+
13+
14+
@unittest.skipIf(not cplexpy_available, "The 'cplex' python bindings are not available")
15+
class TestQuadraticObjective(unittest.TestCase):
16+
def test_quadratic_objective_is_set(self):
17+
model = ConcreteModel()
18+
model.X = Var(bounds=(-2, 2))
19+
model.Y = Var(bounds=(-2, 2))
20+
model.O = Objective(expr=model.X ** 2 + model.Y ** 2)
21+
model.C1 = Constraint(expr=model.Y >= 2 * model.X - 1)
22+
model.C2 = Constraint(expr=model.Y >= -model.X + 2)
23+
opt = SolverFactory("cplex_persistent")
24+
opt.set_instance(model)
25+
opt.solve()
26+
27+
self.assertAlmostEqual(model.X.value, 1, places=3)
28+
self.assertAlmostEqual(model.Y.value, 1, places=3)
29+
30+
del model.O
31+
model.O = Objective(expr=model.X ** 2)
32+
opt.set_objective(model.O)
33+
opt.solve()
34+
self.assertAlmostEqual(model.X.value, 0, places=3)
35+
self.assertAlmostEqual(model.Y.value, 2, places=3)

0 commit comments

Comments
 (0)