14"""An interface for in memory storage of optimization problems."""
18from typing
import Iterator, Optional, Type, TypeVar
26@dataclasses.dataclass(frozen=True)
28 __slots__ =
"linear_constraint_id",
"variable_id",
"coefficient"
29 linear_constraint_id: int
36@dataclasses.dataclass(frozen=True)
38 __slots__ =
"variable_id",
"coefficient"
45@dataclasses.dataclass(frozen=True)
47 """An ordered pair of ints used as a key for quadratic terms.
49 QuadraticTermIdKey.id1 <= QuadraticTermIdKey.id2.
52 __slots__ =
"id1",
"id2"
57 """Ints a and b will be ordered internally."""
62 object.__setattr__(self,
"id1", id1)
63 object.__setattr__(self,
"id2", id2)
68@dataclasses.dataclass(frozen=True)
70 """Represents an id-indexed quadratic term."""
72 __slots__ =
"id_key",
"coefficient"
73 id_key: QuadraticTermIdKey
78 """Tracks updates to an optimization model from a ModelStorage.
80 Do not instantiate directly, instead create through
81 ModelStorage.add_update_tracker().
83 Interacting with an update tracker after it has been removed from the model
84 will result in an UsedUpdateTrackerAfterRemovalError error.
87 mod = model_storage.ModelStorage()
88 x = mod.add_variable(0.0, 1.0, True, 'x')
89 y = mod.add_variable(0.0, 1.0, True, 'y')
90 tracker = mod.add_update_tracker()
91 mod.set_variable_ub(x, 3.0)
92 tracker.export_update()
93 => "variable_updates: {upper_bounds: {ids: [0], values[3.0] }"
94 mod.set_variable_ub(y, 2.0)
95 tracker.export_update()
96 => "variable_updates: {upper_bounds: {ids: [0, 1], values[3.0, 2.0] }"
97 tracker.advance_checkpoint()
98 tracker.export_update()
100 mod.set_variable_ub(y, 4.0)
101 tracker.export_update()
102 => "variable_updates: {upper_bounds: {ids: [1], values[4.0] }"
103 tracker.advance_checkpoint()
104 mod.remove_update_tracker(tracker)
110 """Returns changes to the model since last call to checkpoint/creation, or None if no changes occurred."""
115 """Track changes to the model only after this function call."""
119class UsedUpdateTrackerAfterRemovalError(RuntimeError):
123 "Attempted to use update tracker after removing it from model storage."
128 """Raised by ModelStorage when a bad variable id is given."""
131 super().
__init__(f
"Unexpected variable id: {variable_id}")
132 self.
id = variable_id
136 """Raised by ModelStorage when a bad linear constraint id is given."""
139 super().
__init__(f
"Unexpected linear constraint id: {linear_constraint_id}")
140 self.
id = linear_constraint_id
144 """An interface for in memory storage of an optimization model.
146 Most users should not use this class directly and use Model defined in
149 Stores an mixed integer programming problem of the form:
152 s.t. lb_c <= A * x <= ub_c
154 x_i integer for i in I
156 where x is a vector of n decision variables, d is a number, lb_v, ub_v, and c
157 are vectors of n numbers, lb_c and ub_c are vectors of m numbers, A is a
158 m by n matrix, and I is a subset of {1,..., n}.
160 Each of the n variables and m constraints have an integer id that you use to
161 get/set the problem data (c, A, lb_c etc.). Ids begin at zero and increase
162 sequentially. They are not reused after deletion. Note that if a variable is
163 deleted, your model has nonconsecutive variable ids.
165 For all methods taking an id (e.g. set_variable_lb), providing a bad id
166 (including the id of a deleted variable) will raise a BadVariableIdError or
167 BadLinearConstraintIdError. Further, the ModelStorage instance is assumed to
168 be in a bad state after any such error and there are no guarantees on further
171 All implementations must have a constructor taking a str argument for the
172 model name with a default value of the empty string.
174 Any ModelStorage can be exported to model_pb2.ModelProto, the format consumed
175 by MathOpt solvers. Changes to a model can be exported to a
176 model_update_pb2.ModelUpdateProto with an UpdateTracker, see the UpdateTracker
177 documentation for details.
179 When solving this optimization problem we will additionally require that:
180 * No numbers are NaN,
181 * c, d, and A are all finite,
182 * lb_c and lb_v are not +inf,
183 * ub_c and ub_v are not -inf,
184 but those assumptions are not checked or enforced here (NaNs and infinite
185 values can be used anywhere).
194 def add_variable(self, lb: float, ub: float, is_integer: bool, name: str) -> int:
239 """Yields the variable ids in order of creation."""
280 """Yields the linear constraint ids in order of creation."""
285 self, linear_constraint_id: int, variable_id: int, lb: float
291 self, linear_constraint_id: int, variable_id: int
297 """Yields the linear constraints with nonzero coefficient for a variable in undefined order."""
302 self, linear_constraint_id: int
304 """Yields the variables with nonzero coefficient in a linear constraint in undefined order."""
310 ) -> Iterator[LinearConstraintMatrixIdEntry]:
311 """Yields the nonzero elements of the linear constraint matrix in undefined order."""
316 """Clears objective coefficients and offset. Does not change direction."""
328 """Yields the nonzero linear objective terms in undefined order."""
333 self, first_variable_id: int, second_variable_id: int, value: float
335 """Sets the objective coefficient for the product of two variables.
337 The ordering of the input variables does not matter.
340 first_variable_id: The first variable in the product.
341 second_variable_id: The second variable in the product.
342 value: The value of the coefficient.
345 BadVariableIdError if first_variable_id or second_variable_id are not in
351 self, first_variable_id: int, second_variable_id: int
353 """Gets the objective coefficient for the product of two variables.
355 The ordering of the input variables does not matter.
358 first_variable_id: The first variable in the product.
359 second_variable_id: The second variable in the product.
362 BadVariableIdError if first_variable_id or second_variable_id are not in
366 The value of the coefficient.
371 """Yields the nonzero quadratic objective terms in undefined order."""
375 self, variable_id: int
377 """Yields the variables multiplying a variable in the objective function.
379 Variables are returned in an unspecified order.
381 For example, if variables x and y have ids 0 and 1 respectively, and the
382 quadratic portion of the objective is x^2 + 2 x*y, then
383 get_quadratic_objective_adjacent_variables(0) = (0, 1).
386 variable_id: Function yields the variables multiplying variable_id in the
390 The variables multiplying variable_id in the objective function.
393 BadVariableIdError if variable_id is not in the model.
418 """Creates a StorageUpdateTracker registered with self to view model changes."""
423 """Stops tracker from getting updates on model changes in self.
425 An error will be raised if tracker is not a StorageUpdateTracker created by
426 this Model that has not previously been removed.
428 Using an UpdateTracker (via checkpoint or export_update) after it has been
429 removed will result in an error.
432 tracker: The StorageUpdateTracker to unregister.
435 KeyError: The tracker was created by another model or was already removed.
440ModelStorageImpl = TypeVar(
"ModelStorageImpl", bound=ModelStorage)
441ModelStorageImplClass = Type[ModelStorageImpl]