15"""A solver independent library for modeling optimization problems.
17Example use to model the optimization problem:
23 model = mathopt.Model(name='my_model')
24 x = model.add_binary_variable(name='x')
25 y = model.add_variable(lb=0.0, ub=2.5, name='y')
26 # We can directly use linear combinations of variables ...
27 model.add_linear_constraint(x + y <= 1.5, name='c')
28 # ... or build them incrementally.
29 objective_expression = 0
30 objective_expression += 2 * x
31 objective_expression += y
32 model.maximize(objective_expression)
34 # May raise a RuntimeError on invalid input or internal solver errors.
35 result = mathopt.solve(model, mathopt.SolverType.GSCIP)
37 if result.termination.reason not in (mathopt.TerminationReason.OPTIMAL,
38 mathopt.TerminationReason.FEASIBLE):
39 raise RuntimeError(f'model failed to solve: {result.termination}')
41 print(f'Objective value: {result.objective_value()}')
42 print(f'Value for variable x: {result.variable_values()[x]}')
46from typing
import Iterator, Optional, Tuple, Union
49from typing_extensions
import Self
66 """Tracks updates to an optimization model from a ModelStorage.
68 Do not instantiate directly, instead create through
69 ModelStorage.add_update_tracker().
71 Querying an UpdateTracker after calling Model.remove_update_tracker will
72 result in a model_storage.UsedUpdateTrackerAfterRemovalError.
76 x = mod.add_variable(0.0, 1.0, True, 'x')
77 y = mod.add_variable(0.0, 1.0, True, 'y')
78 tracker = mod.add_update_tracker()
79 mod.set_variable_ub(x, 3.0)
80 tracker.export_update()
81 => "variable_updates: {upper_bounds: {ids: [0], values[3.0] }"
82 mod.set_variable_ub(y, 2.0)
83 tracker.export_update()
84 => "variable_updates: {upper_bounds: {ids: [0, 1], values[3.0, 2.0] }"
85 tracker.advance_checkpoint()
86 tracker.export_update()
88 mod.set_variable_ub(y, 4.0)
89 tracker.export_update()
90 => "variable_updates: {upper_bounds: {ids: [1], values[4.0] }"
91 tracker.advance_checkpoint()
92 mod.remove_update_tracker(tracker)
100 """Do not invoke directly, use Model.add_update_tracker() instead."""
105 self, *, remove_names: bool =
False
106 ) -> Optional[model_update_pb2.ModelUpdateProto]:
107 """Returns changes to the model since last call to checkpoint/creation."""
109 self.
_diff_id, remove_names=remove_names
113 """Track changes to the model only after this function call."""
122 """An optimization model.
124 The objective function of the model can be linear or quadratic, and some
125 solvers can only handle linear objective functions. For this reason Model has
126 three versions of all objective setting functions:
127 * A generic one (e.g. maximize()), which accepts linear or quadratic
129 * a quadratic version (e.g. maximize_quadratic_objective()), which also
130 accepts linear or quadratic expressions and can be used to signal a
131 quadratic objective is possible, and
132 * a linear version (e.g. maximize_linear_objective()), which only accepts
133 linear expressions and can be used to avoid solve time errors for solvers
134 that do not accept quadratic objectives.
137 name: A description of the problem, can be empty.
138 objective: A function to maximize or minimize.
139 storage: Implementation detail, do not access directly.
140 _variable_ids: Maps variable ids to Variable objects.
141 _linear_constraint_ids: Maps linear constraint ids to LinearConstraint
145 __slots__ = (
"_elemental",)
151 primary_objective_name: str =
"",
154 model_name=name, primary_objective_name=primary_objective_name
168 lb: float = -math.inf,
169 ub: float = math.inf,
170 is_integer: bool =
False,
172 ) -> variables_mod.Variable:
173 """Adds a decision variable to the optimization model.
176 lb: The new variable must take at least this value (a lower bound).
177 ub: The new variable must be at most this value (an upper bound).
178 is_integer: Indicates if the variable can only take integer values
179 (otherwise, the variable can take any continuous value).
180 name: For debugging purposes only, but nonempty names must be distinct.
183 A reference to the new decision variable.
186 variable_id = self.
_elemental.add_element(enums.ElementType.VARIABLE, name)
187 result = variables_mod.Variable(self.
_elemental, variable_id)
188 result.lower_bound = lb
189 result.upper_bound = ub
190 result.integer = is_integer
194 self, *, lb: float = -math.inf, ub: float = math.inf, name: str =
""
195 ) -> variables_mod.Variable:
196 return self.
add_variable(lb=lb, ub=ub, is_integer=
True, name=name)
199 return self.
add_variable(lb=0.0, ub=1.0, is_integer=
True, name=name)
202 self, var_id: int, *, validate: bool =
True
203 ) -> variables_mod.Variable:
204 """Returns the Variable for the id var_id, or raises KeyError."""
205 if validate
and not self.
_elemental.element_exists(
206 enums.ElementType.VARIABLE, var_id
208 raise KeyError(f
"Variable does not exist with id {var_id}.")
209 return variables_mod.Variable(self.
_elemental, var_id)
212 """Returns true if a Variable with this id is in the model."""
213 return self.
_elemental.element_exists(enums.ElementType.VARIABLE, var_id)
216 """Returns the number of variables in the model."""
217 return self.
_elemental.get_num_elements(enums.ElementType.VARIABLE)
220 """Returns the id of the next variable created in the model."""
221 return self.
_elemental.get_next_element_id(enums.ElementType.VARIABLE)
224 """If the next variable id would be less than `var_id`, sets it to `var_id`."""
225 self.
_elemental.ensure_next_element_id_at_least(
226 enums.ElementType.VARIABLE, var_id
230 """Removes this variable from the model."""
232 if not self.
_elemental.delete_element(enums.ElementType.VARIABLE, var.id):
233 raise ValueError(f
"Variable with id {var.id} was not in the model.")
235 def variables(self) -> Iterator[variables_mod.Variable]:
236 """Yields the variables in the order of creation."""
237 var_ids = self.
_elemental.get_elements(enums.ElementType.VARIABLE)
239 for var_id
in var_ids:
240 yield variables_mod.Variable(self.
_elemental, int(var_id))
250 def maximize(self, obj: variables_mod.QuadraticTypes) ->
None:
251 """Sets the objective to maximize the provided expression `obj`."""
255 """Sets the objective to maximize the provided linear expression `obj`."""
259 """Sets the objective to maximize the provided quadratic expression `obj`."""
262 def minimize(self, obj: variables_mod.QuadraticTypes) ->
None:
263 """Sets the objective to minimize the provided expression `obj`."""
267 """Sets the objective to minimize the provided linear expression `obj`."""
271 """Sets the objective to minimize the provided quadratic expression `obj`."""
275 self, obj: variables_mod.QuadraticTypes, *, is_maximize: bool
277 """Sets the objective to optimize the provided expression `obj`."""
282 self, obj: variables_mod.LinearTypes, *, is_maximize: bool
284 """Sets the objective to optimize the provided linear expression `obj`."""
285 self.
objective.set_to_linear_expression(obj)
289 self, obj: variables_mod.QuadraticTypes, *, is_maximize: bool
291 """Sets the objective to optimize the provided quadratic expression `obj`."""
292 self.
objective.set_to_quadratic_expression(obj)
296 """Yields variable coefficient pairs for variables with nonzero objective coefficient in undefined order."""
300 """Yields the quadratic terms with nonzero objective coefficient in undefined order."""
301 yield from self.
objective.quadratic_terms()
312 expr: Optional[variables_mod.LinearTypes] =
None,
313 is_maximize: bool =
False,
315 """Adds an additional objective to the model."""
317 enums.ElementType.AUXILIARY_OBJECTIVE, name
320 enums.IntAttr1.AUXILIARY_OBJECTIVE_PRIORITY, (obj_id,), priority
324 result.set_to_linear_expression(expr)
325 result.is_maximize = is_maximize
329 self, expr: variables_mod.LinearTypes, *, priority: int, name: str =
""
331 """Adds an additional objective to the model that is maximizaition."""
333 priority=priority, name=name, expr=expr, is_maximize=
True
338 self, expr: variables_mod.LinearTypes, *, priority: int, name: str =
""
340 """Adds an additional objective to the model that is minimizaition."""
342 priority=priority, name=name, expr=expr, is_maximize=
False
347 """Removes an auxiliary objective from the model."""
350 enums.ElementType.AUXILIARY_OBJECTIVE, obj.id
353 f
"Auxiliary objective with id {obj.id} is not in the model."
357 """Returns true if the model has an auxiliary objective with id `obj_id`."""
359 enums.ElementType.AUXILIARY_OBJECTIVE, obj_id
363 """Returns the id of the next auxiliary objective added to the model."""
365 enums.ElementType.AUXILIARY_OBJECTIVE
369 """Returns the number of auxiliary objectives in this model."""
370 return self.
_elemental.get_num_elements(enums.ElementType.AUXILIARY_OBJECTIVE)
373 """If the next auxiliary objective id would be less than `obj_id`, sets it to `obj_id`."""
374 self.
_elemental.ensure_next_element_id_at_least(
375 enums.ElementType.AUXILIARY_OBJECTIVE, obj_id
379 self, obj_id: int, *, validate: bool =
True
381 """Returns the auxiliary objective with this id.
383 If there is no objective with this id, an exception is thrown if validate is
384 true, and an invalid AuxiliaryObjective is returned if validate is false
385 (later interactions with this object will cause unpredictable errors). Only
386 set validate=False if there is a known performance problem.
389 obj_id: The id of the auxiliary objective to look for.
390 validate: Set to false for more speed, but fails to raise an exception if
391 the objective is missing.
394 KeyError: If `validate` is True and there is no objective with this id.
397 raise KeyError(f
"Model has no auxiliary objective with id {obj_id}")
401 """Returns the auxiliary objectives in the model in the order of creation."""
402 ids = self.
_elemental.get_elements(enums.ElementType.AUXILIARY_OBJECTIVE)
404 for aux_obj_id
in ids:
416 bounded_expr: Optional[Union[bool, variables_mod.BoundedLinearTypes]] =
None,
418 lb: Optional[float] =
None,
419 ub: Optional[float] =
None,
420 expr: Optional[variables_mod.LinearTypes] =
None,
422 ) -> linear_constraints_mod.LinearConstraint:
423 """Adds a linear constraint to the optimization model.
425 The simplest way to specify the constraint is by passing a one-sided or
426 two-sided linear inequality as in:
427 * add_linear_constraint(x + y + 1.0 <= 2.0),
428 * add_linear_constraint(x + y >= 2.0), or
429 * add_linear_constraint((1.0 <= x + y) <= 2.0).
431 Note the extra parenthesis for two-sided linear inequalities, which is
432 required due to some language limitations (see
433 https://peps.python.org/pep-0335/ and https://peps.python.org/pep-0535/).
434 If the parenthesis are omitted, a TypeError will be raised explaining the
435 issue (if this error was not raised the first inequality would have been
436 silently ignored because of the noted language limitations).
438 The second way to specify the constraint is by setting lb, ub, and/or expr
440 * add_linear_constraint(expr=x + y + 1.0, ub=2.0),
441 * add_linear_constraint(expr=x + y, lb=2.0),
442 * add_linear_constraint(expr=x + y, lb=1.0, ub=2.0), or
443 * add_linear_constraint(lb=1.0).
444 Omitting lb is equivalent to setting it to -math.inf and omiting ub is
445 equivalent to setting it to math.inf.
447 These two alternatives are exclusive and a combined call like:
448 * add_linear_constraint(x + y <= 2.0, lb=1.0), or
449 * add_linear_constraint(x + y <= 2.0, ub=math.inf)
450 will raise a ValueError. A ValueError is also raised if expr's offset is
454 bounded_expr: a linear inequality describing the constraint. Cannot be
455 specified together with lb, ub, or expr.
456 lb: The constraint's lower bound if bounded_expr is omitted (if both
457 bounder_expr and lb are omitted, the lower bound is -math.inf).
458 ub: The constraint's upper bound if bounded_expr is omitted (if both
459 bounder_expr and ub are omitted, the upper bound is math.inf).
460 expr: The constraint's linear expression if bounded_expr is omitted.
461 name: For debugging purposes only, but nonempty names must be distinct.
464 A reference to the new linear constraint.
466 norm_ineq = normalized_inequality.as_normalized_linear_inequality(
467 bounded_expr, lb=lb, ub=ub, expr=expr
470 enums.ElementType.LINEAR_CONSTRAINT, name
473 result = linear_constraints_mod.LinearConstraint(self.
_elemental, lin_con_id)
474 result.lower_bound = norm_ineq.lb
475 result.upper_bound = norm_ineq.ub
476 for var, coefficient
in norm_ineq.coefficients.items():
477 result.set_coefficient(var, coefficient)
481 """Returns true if a linear constraint with this id is in the model."""
483 enums.ElementType.LINEAR_CONSTRAINT, con_id
487 """Returns the number of linear constraints in the model."""
488 return self.
_elemental.get_num_elements(enums.ElementType.LINEAR_CONSTRAINT)
491 """Returns the id of the next linear constraint created in the model."""
492 return self.
_elemental.get_next_element_id(enums.ElementType.LINEAR_CONSTRAINT)
495 """If the next linear constraint id would be less than `con_id`, sets it to `con_id`."""
496 self.
_elemental.ensure_next_element_id_at_least(
497 enums.ElementType.LINEAR_CONSTRAINT, con_id
501 self, con_id: int, *, validate: bool =
True
502 ) -> linear_constraints_mod.LinearConstraint:
503 """Returns the LinearConstraint for the id con_id."""
504 if validate
and not self.
_elemental.element_exists(
505 enums.ElementType.LINEAR_CONSTRAINT, con_id
507 raise KeyError(f
"Linear constraint does not exist with id {con_id}.")
508 return linear_constraints_mod.LinearConstraint(self.
_elemental, con_id)
511 self, lin_con: linear_constraints_mod.LinearConstraint
515 enums.ElementType.LINEAR_CONSTRAINT, lin_con.id
518 f
"Linear constraint with id {lin_con.id} was not in the model."
521 def linear_constraints(
523 ) -> Iterator[linear_constraints_mod.LinearConstraint]:
524 """Yields the linear constraints in the order of creation."""
525 lin_con_ids = self.
_elemental.get_elements(enums.ElementType.LINEAR_CONSTRAINT)
527 for lin_con_id
in lin_con_ids:
528 yield linear_constraints_mod.LinearConstraint(
533 self, lin_con: linear_constraints_mod.LinearConstraint
534 ) -> Iterator[variables_mod.Variable]:
535 """Yields the variables with nonzero coefficient for this linear constraint."""
537 enums.DoubleAttr2.LINEAR_CONSTRAINT_COEFFICIENT, 0, lin_con.id
539 for var_id
in keys[:, 1]:
540 yield variables_mod.Variable(self.
_elemental, int(var_id))
543 self, var: variables_mod.Variable
544 ) -> Iterator[linear_constraints_mod.LinearConstraint]:
545 """Yields the linear constraints with nonzero coefficient for this variable."""
547 enums.DoubleAttr2.LINEAR_CONSTRAINT_COEFFICIENT, 1, var.id
549 for lin_con_id
in keys[:, 0]:
550 yield linear_constraints_mod.LinearConstraint(
556 ) -> Iterator[linear_constraints_mod.LinearConstraintMatrixEntry]:
557 """Yields the nonzero elements of the linear constraint matrix in undefined order."""
559 enums.DoubleAttr2.LINEAR_CONSTRAINT_COEFFICIENT
562 enums.DoubleAttr2.LINEAR_CONSTRAINT_COEFFICIENT, keys
564 for i
in range(len(keys)):
565 yield linear_constraints_mod.LinearConstraintMatrixEntry(
566 linear_constraint=linear_constraints_mod.LinearConstraint(
569 variable=variables_mod.Variable(self.
_elemental, int(keys[i, 1])),
570 coefficient=float(coefs[i]),
579 bounded_expr: Optional[
582 variables_mod.BoundedLinearTypes,
583 variables_mod.BoundedQuadraticTypes,
587 lb: Optional[float] =
None,
588 ub: Optional[float] =
None,
589 expr: Optional[variables_mod.QuadraticTypes] =
None,
592 """Adds a quadratic constraint to the optimization model.
594 The simplest way to specify the constraint is by passing a one-sided or
595 two-sided quadratic inequality as in:
596 * add_quadratic_constraint(x * x + y + 1.0 <= 2.0),
597 * add_quadratic_constraint(x * x + y >= 2.0), or
598 * add_quadratic_constraint((1.0 <= x * x + y) <= 2.0).
600 Note the extra parenthesis for two-sided linear inequalities, which is
601 required due to some language limitations (see add_linear_constraint for
604 The second way to specify the constraint is by setting lb, ub, and/or expr
606 * add_quadratic_constraint(expr=x * x + y + 1.0, ub=2.0),
607 * add_quadratic_constraint(expr=x * x + y, lb=2.0),
608 * add_quadratic_constraint(expr=x * x + y, lb=1.0, ub=2.0), or
609 * add_quadratic_constraint(lb=1.0).
610 Omitting lb is equivalent to setting it to -math.inf and omiting ub is
611 equivalent to setting it to math.inf.
613 These two alternatives are exclusive and a combined call like:
614 * add_quadratic_constraint(x * x + y <= 2.0, lb=1.0), or
615 * add_quadratic_constraint(x * x+ y <= 2.0, ub=math.inf)
616 will raise a ValueError. A ValueError is also raised if expr's offset is
620 bounded_expr: a quadratic inequality describing the constraint. Cannot be
621 specified together with lb, ub, or expr.
622 lb: The constraint's lower bound if bounded_expr is omitted (if both
623 bounder_expr and lb are omitted, the lower bound is -math.inf).
624 ub: The constraint's upper bound if bounded_expr is omitted (if both
625 bounder_expr and ub are omitted, the upper bound is math.inf).
626 expr: The constraint's quadratic expression if bounded_expr is omitted.
627 name: For debugging purposes only, but nonempty names must be distinct.
630 A reference to the new quadratic constraint.
632 norm_quad = normalized_inequality.as_normalized_quadratic_inequality(
633 bounded_expr, lb=lb, ub=ub, expr=expr
636 enums.ElementType.QUADRATIC_CONSTRAINT, name
638 for var, coef
in norm_quad.linear_coefficients.items():
640 enums.DoubleAttr2.QUADRATIC_CONSTRAINT_LINEAR_COEFFICIENT,
641 (quad_con_id, var.id),
644 for key, coef
in norm_quad.quadratic_coefficients.items():
646 enums.SymmetricDoubleAttr3.QUADRATIC_CONSTRAINT_QUADRATIC_COEFFICIENT,
647 (quad_con_id, key.first_var.id, key.second_var.id),
650 if norm_quad.lb > -math.inf:
652 enums.DoubleAttr1.QUADRATIC_CONSTRAINT_LOWER_BOUND,
656 if norm_quad.ub < math.inf:
658 enums.DoubleAttr1.QUADRATIC_CONSTRAINT_UPPER_BOUND,
665 """Returns true if a quadratic constraint with this id is in the model."""
667 enums.ElementType.QUADRATIC_CONSTRAINT, con_id
671 """Returns the number of quadratic constraints in the model."""
672 return self.
_elemental.get_num_elements(enums.ElementType.QUADRATIC_CONSTRAINT)
675 """Returns the id of the next quadratic constraint created in the model."""
677 enums.ElementType.QUADRATIC_CONSTRAINT
681 """If the next quadratic constraint id would be less than `con_id`, sets it to `con_id`."""
682 self.
_elemental.ensure_next_element_id_at_least(
683 enums.ElementType.QUADRATIC_CONSTRAINT, con_id
687 self, con_id: int, *, validate: bool =
True
689 """Returns the constraint for the id, or raises KeyError if not in model."""
690 if validate
and not self.
_elemental.element_exists(
691 enums.ElementType.QUADRATIC_CONSTRAINT, con_id
693 raise KeyError(f
"Quadratic constraint does not exist with id {con_id}.")
697 self, quad_con: quadratic_constraints.QuadraticConstraint
699 """Deletes the constraint with id, or raises ValueError if not in model."""
702 enums.ElementType.QUADRATIC_CONSTRAINT, quad_con.id
705 f
"Quadratic constraint with id {quad_con.id} was not in the model."
710 ) -> Iterator[quadratic_constraints.QuadraticConstraint]:
711 """Yields the quadratic constraints in the order of creation."""
713 enums.ElementType.QUADRATIC_CONSTRAINT
716 for quad_con_id
in quad_con_ids:
725 quadratic_constraints.QuadraticConstraint,
726 variables_mod.Variable,
730 """Yields the linear coefficients for all quadratic constraints in the model."""
732 enums.DoubleAttr2.QUADRATIC_CONSTRAINT_LINEAR_COEFFICIENT
735 enums.DoubleAttr2.QUADRATIC_CONSTRAINT_LINEAR_COEFFICIENT, keys
737 for i
in range(len(keys)):
742 variables_mod.Variable(self.
_elemental, int(keys[i, 1])),
750 quadratic_constraints.QuadraticConstraint,
751 variables_mod.Variable,
752 variables_mod.Variable,
756 """Yields the quadratic coefficients for all quadratic constraints in the model."""
758 enums.SymmetricDoubleAttr3.QUADRATIC_CONSTRAINT_QUADRATIC_COEFFICIENT
761 enums.SymmetricDoubleAttr3.QUADRATIC_CONSTRAINT_QUADRATIC_COEFFICIENT,
764 for i
in range(len(keys)):
769 variables_mod.Variable(self.
_elemental, int(keys[i, 1])),
770 variables_mod.Variable(self.
_elemental, int(keys[i, 2])),
781 indicator: Optional[variables_mod.Variable] =
None,
782 activate_on_zero: bool =
False,
783 implied_constraint: Optional[
784 Union[bool, variables_mod.BoundedLinearTypes]
786 implied_lb: Optional[float] =
None,
787 implied_ub: Optional[float] =
None,
788 implied_expr: Optional[variables_mod.LinearTypes] =
None,
791 """Adds an indicator constraint to the model.
793 If indicator is None or the variable equal to indicator is deleted from
794 the model, the model will be considered invalid at solve time (unless this
795 constraint is also deleted before solving). Likewise, the variable indicator
796 must be binary at solve time for the model to be valid.
798 If implied_constraint is set, you may not set implied_lb, implied_ub, or
802 indicator: The variable whose value determines if implied_constraint must
804 activate_on_zero: If true, implied_constraint must hold when indicator is
805 zero, otherwise, the implied_constraint must hold when indicator is one.
806 implied_constraint: A linear constraint to conditionally enforce, if set.
807 If None, that information is instead passed via implied_lb, implied_ub,
809 implied_lb: The lower bound of the condtionally enforced linear constraint
810 (or -inf if None), used only when implied_constraint is None.
811 implied_ub: The upper bound of the condtionally enforced linear constraint
812 (or +inf if None), used only when implied_constraint is None.
813 implied_expr: The linear part of the condtionally enforced linear
814 constraint (or 0 if None), used only when implied_constraint is None. If
815 expr has a nonzero offset, it is subtracted from lb and ub.
816 name: For debugging purposes only, but nonempty names must be distinct.
819 A reference to the new indicator constraint.
822 enums.ElementType.INDICATOR_CONSTRAINT, name
824 if indicator
is not None:
826 enums.VariableAttr1.INDICATOR_CONSTRAINT_INDICATOR,
831 enums.BoolAttr1.INDICATOR_CONSTRAINT_ACTIVATE_ON_ZERO,
835 implied_inequality = normalized_inequality.as_normalized_linear_inequality(
836 implied_constraint, lb=implied_lb, ub=implied_ub, expr=implied_expr
839 enums.DoubleAttr1.INDICATOR_CONSTRAINT_LOWER_BOUND,
841 implied_inequality.lb,
844 enums.DoubleAttr1.INDICATOR_CONSTRAINT_UPPER_BOUND,
846 implied_inequality.ub,
848 for var, coef
in implied_inequality.coefficients.items():
850 enums.DoubleAttr2.INDICATOR_CONSTRAINT_LINEAR_COEFFICIENT,
851 (ind_con_id, var.id),
858 """Returns true if an indicator constraint with this id is in the model."""
860 enums.ElementType.INDICATOR_CONSTRAINT, con_id
864 """Returns the number of indicator constraints in the model."""
865 return self.
_elemental.get_num_elements(enums.ElementType.INDICATOR_CONSTRAINT)
868 """Returns the id of the next indicator constraint created in the model."""
870 enums.ElementType.INDICATOR_CONSTRAINT
874 """If the next indicator constraint id would be less than `con_id`, sets it to `con_id`."""
875 self.
_elemental.ensure_next_element_id_at_least(
876 enums.ElementType.INDICATOR_CONSTRAINT, con_id
880 self, con_id: int, *, validate: bool =
True
882 """Returns the IndicatorConstraint for the id con_id."""
883 if validate
and not self.
_elemental.element_exists(
884 enums.ElementType.INDICATOR_CONSTRAINT, con_id
886 raise KeyError(f
"Indicator constraint does not exist with id {con_id}.")
890 self, ind_con: indicator_constraints.IndicatorConstraint
894 enums.ElementType.INDICATOR_CONSTRAINT, ind_con.id
897 f
"Indicator constraint with id {ind_con.id} was not in the model."
902 ) -> Iterator[indicator_constraints.IndicatorConstraint]:
903 """Yields the indicator constraints in the order of creation."""
905 enums.ElementType.INDICATOR_CONSTRAINT
908 for ind_con_id
in ind_con_ids:
919 """Returns a Model equivalent to the input model proto."""
921 model._elemental = cpp_elemental.CppElemental.from_model_proto(proto)
924 def export_model(self, *, remove_names: bool =
False) -> model_pb2.ModelProto:
925 """Returns a protocol buffer equivalent to this model.
928 remove_names: When true, remove all names for the ModelProto.
936 """Creates an UpdateTracker registered on this model to view changes."""
940 """Stops tracker from getting updates on changes to this model.
942 An error will be raised if tracker was not created by this Model or if
943 tracker has been previously removed.
945 Using (via checkpoint or update) an UpdateTracker after it has been removed
946 will result in an error.
949 tracker: The UpdateTracker to unregister.
952 KeyError: The tracker was created by another model or was already removed.
957 """Raises a ValueError if the model of var_or_constraint is not self."""
960 f
"Expected element from model named: '{self._elemental.model_name}',"
961 f
" but observed element {e} from model named:"
962 f
" '{e.elemental.model_name}'."