Skip to content

Commit ffe3521

Browse files
authored
Merge pull request #393 from arcondello/fix/Model.objective-setter
Fix modifying Model.objective directly
2 parents 38810e4 + 99aead4 commit ffe3521

3 files changed

Lines changed: 54 additions & 24 deletions

File tree

dwave/optimization/model.py

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -119,28 +119,6 @@ class Model(_Graph):
119119
>>> model = flow_shop_scheduling(processing_times=processing_times)
120120
"""
121121

122-
objective: typing.Optional[ArraySymbol]
123-
"""Objective to be minimized.
124-
125-
Examples:
126-
This example prints the value of the objective of a model representing
127-
the simple polynomial, :math:`y = i^2 - 4i`, for a state with value
128-
:math:`i=2.0`.
129-
130-
>>> from dwave.optimization import Model
131-
...
132-
>>> model = Model()
133-
>>> i = model.integer(lower_bound=-5, upper_bound=5)
134-
>>> c = model.constant(4)
135-
>>> y = i**2 - c*i
136-
>>> model.minimize(y)
137-
>>> with model.lock():
138-
... model.states.resize(1)
139-
... i.set_state(0, 2.0)
140-
... print(f"Objective = {model.objective.state(0)}")
141-
Objective = -4.0
142-
"""
143-
144122
states: States
145123
"""States of the model.
146124
@@ -154,9 +132,37 @@ class Model(_Graph):
154132
"""
155133

156134
def __init__(self):
157-
self.objective = None
135+
self._objective = None
158136
self.states = States(self)
159137

138+
@property
139+
def objective(self) -> typing.Optional[ArraySymbol]:
140+
"""Objective to be minimized.
141+
142+
Examples:
143+
This example prints the value of the objective of a model representing
144+
the simple polynomial, :math:`y = i^2 - 4i`, for a state with value
145+
:math:`i=2.0`.
146+
147+
>>> from dwave.optimization import Model
148+
...
149+
>>> model = Model()
150+
>>> i = model.integer(lower_bound=-5, upper_bound=5)
151+
>>> c = model.constant(4)
152+
>>> y = i**2 - c*i
153+
>>> model.minimize(y)
154+
>>> with model.lock():
155+
... model.states.resize(1)
156+
... i.set_state(0, 2.0)
157+
... print(f"Objective = {model.objective.state(0)}")
158+
Objective = -4.0
159+
"""
160+
return self._objective
161+
162+
@objective.setter
163+
def objective(self, value: ArraySymbol):
164+
self.minimize(value)
165+
160166
def binary(self, shape: typing.Optional[_ShapeLike] = None) -> BinaryVariable:
161167
r"""Create a binary symbol as a decision variable.
162168
@@ -463,7 +469,7 @@ def lock(self) -> contextlib.AbstractContextManager:
463469
def minimize(self, value: ArraySymbol):
464470
# inherit the docstring from _Graph
465471
super().minimize(value)
466-
self.objective = value
472+
self._objective = value
467473

468474
# dev note: the typing is underspecified, but it would be quite complex to fully
469475
# specify the linear/quadratic so let's leave it alone for now.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
fixes:
3+
- |
4+
Fix setting or mutating ``Model.objective``.
5+
Until dwave-optimization 0.6.4, it was possible to set the objective of
6+
a ``Model`` directly. However, in 0.6.4 and 0.6.5 doing so would result
7+
in that change not being reflected in serialized models. This fix
8+
restores support for setting or mutating ``Model.objective`` directly.

tests/test_model.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,22 @@ def test_minimize(self):
361361
model.minimize(model.constant([[7]]))
362362
self.assertEqual(model.objective.state(), 7)
363363

364+
def test_objective(self):
365+
model = Model()
366+
367+
x = model.list(5)
368+
model.objective = x.sum() # the same as minimize
369+
model.objective += 1
370+
371+
# setting in this way should survive serialization
372+
with model.to_file() as f:
373+
copy = model.from_file(f)
374+
self.assertIs(type(model.objective), type(copy.objective))
375+
376+
# It cannot be set to the wrong type
377+
with self.assertRaises(TypeError):
378+
model.objective = "hello"
379+
364380
def test_remove_unused_symbols(self):
365381
with self.subTest("all unused"):
366382
model = Model()

0 commit comments

Comments
 (0)