14"""Methods for building and solving model_builder models.
16The following two sections describe the main
17methods for building and solving those models.
19* [`Model`](#model_builder.Model): Methods for creating
20models, including variables and constraints.
21* [`Solver`](#model_builder.Solver): Methods for solving
22a model and evaluating solutions.
24Additional methods for solving Model models:
26* [`Constraint`](#model_builder.Constraint): A few utility methods for modifying
27 constraints created by `Model`.
28* [`LinearExpr`](#model_builder.LinearExpr): Methods for creating constraints
29 and the objective from large arrays of coefficients.
31Other methods and functions listed are primarily used for developing OR-Tools,
32rather than for solving specific optimization problems.
38from typing
import Callable, Optional, Union
48NumberT = Union[int, float, numbers.Real, np.number]
49IntegerT = Union[int, numbers.Integral, np.integer]
50LinearExprT = Union[mbh.LinearExpr, NumberT]
51ConstraintT = Union[mbh.BoundedLinearExpression, bool]
52_IndexOrSeries = Union[pd.Index, pd.Series]
53_VariableOrConstraint = Union[
"LinearConstraint", mbh.Variable]
56AffineExpr = mbh.AffineExpr
57BoundedLinearExpression = mbh.BoundedLinearExpression
58FlatExpr = mbh.FlatExpr
59LinearExpr = mbh.LinearExpr
60SolveStatus = mbh.SolveStatus
61Variable = mbh.Variable
65 bounded_expr: Union[bool, mbh.BoundedLinearExpression],
66 helper: mbh.ModelBuilderHelper,
69 """Creates a new linear constraint in the helper.
71 It handles boolean values (which might arise in the construction of
72 BoundedLinearExpressions).
74 If bounded_expr is a Boolean value, the created constraint is different.
75 In that case, the constraint will be immutable and marked as under-specified.
76 It will be always feasible or infeasible whether the value is True or False.
79 bounded_expr: The bounded expression used to create the constraint.
80 helper: The helper to create the constraint.
81 name: The name of the constraint to be created.
84 LinearConstraint: a constraint in the helper corresponding to the input.
87 TypeError: If constraint is an invalid type.
89 if isinstance(bounded_expr, bool):
92 helper.set_constraint_name(c.index, name)
95 helper.set_constraint_lower_bound(c.index, 0.0)
96 helper.set_constraint_upper_bound(c.index, 0.0)
99 helper.set_constraint_lower_bound(c.index, 1)
100 helper.set_constraint_upper_bound(c.index, -1)
102 if isinstance(bounded_expr, mbh.BoundedLinearExpression):
105 helper.add_terms_to_constraint(c.index, bounded_expr.vars, bounded_expr.coeffs)
106 helper.set_constraint_lower_bound(c.index, bounded_expr.lower_bound)
107 helper.set_constraint_upper_bound(c.index, bounded_expr.upper_bound)
110 helper.set_constraint_name(c.index, name)
112 raise TypeError(f
"invalid type={type(bounded_expr).__name__!r}")
116 bounded_expr: Union[bool, mbh.BoundedLinearExpression],
117 helper: mbh.ModelBuilderHelper,
122 """Creates a new enforced linear constraint in the helper.
124 It handles boolean values (which might arise in the construction of
125 BoundedLinearExpressions).
127 If bounded_expr is a Boolean value, the linear part of the constraint is
129 In that case, the constraint will be immutable and marked as under-specified.
130 Its linear part will be always feasible or infeasible whether the value is
134 bounded_expr: The bounded expression used to create the constraint.
135 helper: The helper to create the constraint.
136 var: the variable used in the indicator
137 value: the value used in the indicator
138 name: The name of the constraint to be created.
141 EnforcedLinearConstraint: a constraint in the helper corresponding to the
145 TypeError: If constraint is an invalid type.
147 if isinstance(bounded_expr, bool):
150 c.indicator_variable = var
151 c.indicator_value = value
153 helper.set_enforced_constraint_name(c.index, name)
156 helper.set_enforced_constraint_lower_bound(c.index, 0.0)
157 helper.set_enforced_constraint_upper_bound(c.index, 0.0)
160 helper.set_enforced_constraint_lower_bound(c.index, 1)
161 helper.set_enforced_constraint_upper_bound(c.index, -1)
163 if isinstance(bounded_expr, mbh.BoundedLinearExpression):
165 c.indicator_variable = var
166 c.indicator_value = value
167 helper.add_terms_to_enforced_constraint(
168 c.index, bounded_expr.vars, bounded_expr.coeffs
170 helper.set_enforced_constraint_lower_bound(c.index, bounded_expr.lower_bound)
171 helper.set_enforced_constraint_upper_bound(c.index, bounded_expr.upper_bound)
173 helper.set_constraint_name(c.index, name)
176 raise TypeError(f
"invalid type={type(bounded_expr).__name__!r}")
180 """Stores a linear equation.
183 x = model.new_num_var(0, 10, 'x')
184 y = model.new_num_var(0, 10, 'y')
186 linear_constraint = model.add(x + 2 * y == 5)
191 helper: mbh.ModelBuilderHelper,
193 index: Optional[IntegerT] =
None,
194 is_under_specified: bool =
False,
196 """LinearConstraint constructor.
199 helper: The pybind11 ModelBuilderHelper.
200 index: If specified, recreates a wrapper to an existing linear constraint.
201 is_under_specified: indicates if the constraint was created by
205 self.
__index = helper.add_linear_constraint()
208 self.
__helper: mbh.ModelBuilderHelper = helper
216 """Returns the index of the constraint in the helper."""
220 def helper(self) -> mbh.ModelBuilderHelper:
221 """Returns the ModelBuilderHelper instance."""
246 return constraint_name
247 return f
"linear_constraint#{self.__index}"
250 def name(self, name: str) ->
None:
255 """Returns True if the constraint is under specified.
257 Usually, it means that it was created by model.add(False) or model.add(True)
258 The effect is that modifying the constraint will raise an exception.
263 """Raises an exception if the constraint is under specified."""
266 f
"Constraint {self.index} is under specified and cannot be modified"
274 f
"LinearConstraint({self.name}, lb={self.lower_bound},"
275 f
" ub={self.upper_bound},"
276 f
" var_indices={self.helper.constraint_var_indices(self.index)},"
277 f
" coefficients={self.helper.constraint_coefficients(self.index)})"
281 """Sets the coefficient of the variable in the constraint."""
283 self.
__helper.set_constraint_coefficient(self.
__index, var.index, coeff)
285 def add_term(self, var: Variable, coeff: NumberT) ->
None:
286 """Adds var * coeff to the constraint."""
288 self.
__helper.safe_add_term_to_constraint(self.
__index, var.index, coeff)
291 """Clear all terms of the constraint."""
297 """Stores an enforced linear equation, also name indicator constraint.
300 x = model.new_num_var(0, 10, 'x')
301 y = model.new_num_var(0, 10, 'y')
302 z = model.new_bool_var('z')
304 enforced_linear_constraint = model.add_enforced(x + 2 * y == 5, z, False)
309 helper: mbh.ModelBuilderHelper,
311 index: Optional[IntegerT] =
None,
312 is_under_specified: bool =
False,
314 """EnforcedLinearConstraint constructor.
317 helper: The pybind11 ModelBuilderHelper.
318 index: If specified, recreates a wrapper to an existing linear constraint.
319 is_under_specified: indicates if the constraint was created by
323 self.
__index = helper.add_enforced_linear_constraint()
325 if not helper.is_enforced_linear_constraint(index):
327 f
"the given index {index} does not refer to an enforced linear"
332 self.
__helper: mbh.ModelBuilderHelper = helper
337 """Returns the index of the constraint in the helper."""
341 def helper(self) -> mbh.ModelBuilderHelper:
342 """Returns the ModelBuilderHelper instance."""
365 enforcement_var_index = (
366 self.
__helper.enforced_constraint_indicator_variable_index(self.
__index)
370 @indicator_variable.setter
372 self.
__helper.set_enforced_constraint_indicator_variable_index(
380 @indicator_value.setter
382 self.
__helper.set_enforced_constraint_indicator_value(self.
__index, value)
388 return constraint_name
389 return f
"enforced_linear_constraint#{self.__index}"
392 def name(self, name: str) ->
None:
397 """Returns True if the constraint is under specified.
399 Usually, it means that it was created by model.add(False) or model.add(True)
400 The effect is that modifying the constraint will raise an exception.
405 """Raises an exception if the constraint is under specified."""
408 f
"Constraint {self.index} is under specified and cannot be modified"
416 f
"EnforcedLinearConstraint({self.name}, lb={self.lower_bound},"
417 f
" ub={self.upper_bound},"
418 f
" var_indices={self.helper.enforced_constraint_var_indices(self.index)},"
419 f
" coefficients={self.helper.enforced_constraint_coefficients(self.index)},"
420 f
" indicator_variable={self.indicator_variable}"
421 f
" indicator_value={self.indicator_value})"
425 """Sets the coefficient of the variable in the constraint."""
427 self.
__helper.set_enforced_constraint_coefficient(
431 def add_term(self, var: Variable, coeff: NumberT) ->
None:
432 """Adds var * coeff to the constraint."""
434 self.
__helper.safe_add_term_to_enforced_constraint(
439 """Clear all terms of the constraint."""
445 """Methods for building a linear model.
447 Methods beginning with:
449 * ```new_``` create integer, boolean, or interval variables.
450 * ```add_``` create new constraints and add them to the model.
454 self.
__helper: mbh.ModelBuilderHelper = mbh.ModelBuilderHelper()
457 """Returns a clone of the current model."""
459 clone.helper.overwrite_model(self.
helper)
469 self, constraints: Optional[_IndexOrSeries] =
None
471 if constraints
is None:
482 self, variables: Optional[_IndexOrSeries] =
None
484 if variables
is None:
489 """Gets all linear constraints in the model."""
492 name=
"linear_constraint",
496 self, constraints: Optional[_IndexOrSeries] =
None
498 """Gets the expressions of all linear constraints in the set.
500 If `constraints` is a `pd.Index`, then the output will be indexed by the
501 constraints. If `constraints` is a `pd.Series` indexed by the underlying
502 dimensions, then the output will be indexed by the same underlying
506 constraints (Union[pd.Index, pd.Series]): Optional. The set of linear
507 constraints from which to get the expressions. If unspecified, all
508 linear constraints will be in scope.
511 pd.Series: The expressions of all linear constraints in the set.
515 func=
lambda c: mbh.FlatExpr(
519 for var_id
in c.helper.constraint_var_indices(c.index)
521 c.helper.constraint_coefficients(c.index),
528 self, constraints: Optional[_IndexOrSeries] =
None
530 """Gets the lower bounds of all linear constraints in the set.
532 If `constraints` is a `pd.Index`, then the output will be indexed by the
533 constraints. If `constraints` is a `pd.Series` indexed by the underlying
534 dimensions, then the output will be indexed by the same underlying
538 constraints (Union[pd.Index, pd.Series]): Optional. The set of linear
539 constraints from which to get the lower bounds. If unspecified, all
540 linear constraints will be in scope.
543 pd.Series: The lower bounds of all linear constraints in the set.
546 func=
lambda c: c.lower_bound,
551 self, constraints: Optional[_IndexOrSeries] =
None
553 """Gets the upper bounds of all linear constraints in the set.
555 If `constraints` is a `pd.Index`, then the output will be indexed by the
556 constraints. If `constraints` is a `pd.Series` indexed by the underlying
557 dimensions, then the output will be indexed by the same underlying
561 constraints (Union[pd.Index, pd.Series]): Optional. The set of linear
562 constraints. If unspecified, all linear constraints will be in scope.
565 pd.Series: The upper bounds of all linear constraints in the set.
568 func=
lambda c: c.upper_bound,
573 """Gets all variables in the model."""
580 self, variables: Optional[_IndexOrSeries] =
None
582 """Gets the lower bounds of all variables in the set.
584 If `variables` is a `pd.Index`, then the output will be indexed by the
585 variables. If `variables` is a `pd.Series` indexed by the underlying
586 dimensions, then the output will be indexed by the same underlying
590 variables (Union[pd.Index, pd.Series]): Optional. The set of variables
591 from which to get the lower bounds. If unspecified, all variables will
595 pd.Series: The lower bounds of all variables in the set.
598 func=
lambda v: v.lower_bound,
603 self, variables: Optional[_IndexOrSeries] =
None
605 """Gets the upper bounds of all variables in the set.
608 variables (Union[pd.Index, pd.Series]): Optional. The set of variables
609 from which to get the upper bounds. If unspecified, all variables will
613 pd.Series: The upper bounds of all variables in the set.
616 func=
lambda v: v.upper_bound,
623 self, lb: NumberT, ub: NumberT, is_integer: bool, name: Optional[str]
625 """Create an integer variable with domain [lb, ub].
628 lb: Lower bound of the variable.
629 ub: Upper bound of the variable.
630 is_integer: Indicates if the variable must take integral values.
631 name: The name of the variable.
634 a variable whose domain is [lb, ub].
642 self, lb: NumberT, ub: NumberT, name: Optional[str] =
None
644 """Create an integer variable with domain [lb, ub].
647 lb: Lower bound of the variable.
648 ub: Upper bound of the variable.
649 name: The name of the variable.
652 a variable whose domain is [lb, ub].
655 return self.
new_var(lb, ub,
True, name)
658 self, lb: NumberT, ub: NumberT, name: Optional[str] =
None
660 """Create an integer variable with domain [lb, ub].
663 lb: Lower bound of the variable.
664 ub: Upper bound of the variable.
665 name: The name of the variable.
668 a variable whose domain is [lb, ub].
671 return self.
new_var(lb, ub,
False, name)
674 """Creates a 0-1 variable with the given name."""
680 """Declares a constant variable."""
681 return self.
new_var(value, value,
False,
None)
687 lower_bounds: Union[NumberT, pd.Series] = -math.inf,
688 upper_bounds: Union[NumberT, pd.Series] = math.inf,
689 is_integral: Union[bool, pd.Series] =
False,
691 """Creates a series of (scalar-valued) variables with the given name.
694 name (str): Required. The name of the variable set.
695 index (pd.Index): Required. The index to use for the variable set.
696 lower_bounds (Union[int, float, pd.Series]): Optional. A lower bound for
697 variables in the set. If a `pd.Series` is passed in, it will be based on
698 the corresponding values of the pd.Series. Defaults to -inf.
699 upper_bounds (Union[int, float, pd.Series]): Optional. An upper bound for
700 variables in the set. If a `pd.Series` is passed in, it will be based on
701 the corresponding values of the pd.Series. Defaults to +inf.
702 is_integral (bool, pd.Series): Optional. Indicates if the variable can
703 only take integer values. If a `pd.Series` is passed in, it will be
704 based on the corresponding values of the pd.Series. Defaults to False.
707 pd.Series: The variable set indexed by its corresponding dimensions.
710 TypeError: if the `index` is invalid (e.g. a `DataFrame`).
711 ValueError: if the `name` is not a valid identifier or already exists.
712 ValueError: if the `lowerbound` is greater than the `upperbound`.
713 ValueError: if the index of `lower_bound`, `upper_bound`, or `is_integer`
714 does not match the input index.
716 if not isinstance(index, pd.Index):
717 raise TypeError(
"Non-index object is used as index")
718 if not name.isidentifier():
719 raise ValueError(f
"name={name!r} is not a valid identifier")
721 mbn.is_a_number(lower_bounds)
722 and mbn.is_a_number(upper_bounds)
723 and lower_bounds > upper_bounds
726 f
"lower_bound={lower_bounds} is greater than"
727 f
" upper_bound={upper_bounds} for variable set={name!r}"
730 isinstance(is_integral, bool)
732 and mbn.is_a_number(lower_bounds)
733 and mbn.is_a_number(upper_bounds)
734 and math.isfinite(lower_bounds)
735 and math.isfinite(upper_bounds)
736 and math.ceil(lower_bounds) > math.floor(upper_bounds)
739 f
"ceil(lower_bound={lower_bounds})={math.ceil(lower_bounds)}"
740 f
" is greater than floor({upper_bounds}) = {math.floor(upper_bounds)}"
741 f
" for variable set={name!r}"
765 lower_bounds: Union[NumberT, pd.Series] = -math.inf,
766 upper_bounds: Union[NumberT, pd.Series] = math.inf,
768 """Creates a series of continuous variables with the given name.
771 name (str): Required. The name of the variable set.
772 index (pd.Index): Required. The index to use for the variable set.
773 lower_bounds (Union[int, float, pd.Series]): Optional. A lower bound for
774 variables in the set. If a `pd.Series` is passed in, it will be based on
775 the corresponding values of the pd.Series. Defaults to -inf.
776 upper_bounds (Union[int, float, pd.Series]): Optional. An upper bound for
777 variables in the set. If a `pd.Series` is passed in, it will be based on
778 the corresponding values of the pd.Series. Defaults to +inf.
781 pd.Series: The variable set indexed by its corresponding dimensions.
784 TypeError: if the `index` is invalid (e.g. a `DataFrame`).
785 ValueError: if the `name` is not a valid identifier or already exists.
786 ValueError: if the `lowerbound` is greater than the `upperbound`.
787 ValueError: if the index of `lower_bound`, `upper_bound`, or `is_integer`
788 does not match the input index.
790 return self.
new_var_series(name, index, lower_bounds, upper_bounds,
False)
796 lower_bounds: Union[NumberT, pd.Series] = -math.inf,
797 upper_bounds: Union[NumberT, pd.Series] = math.inf,
799 """Creates a series of integer variables with the given name.
802 name (str): Required. The name of the variable set.
803 index (pd.Index): Required. The index to use for the variable set.
804 lower_bounds (Union[int, float, pd.Series]): Optional. A lower bound for
805 variables in the set. If a `pd.Series` is passed in, it will be based on
806 the corresponding values of the pd.Series. Defaults to -inf.
807 upper_bounds (Union[int, float, pd.Series]): Optional. An upper bound for
808 variables in the set. If a `pd.Series` is passed in, it will be based on
809 the corresponding values of the pd.Series. Defaults to +inf.
812 pd.Series: The variable set indexed by its corresponding dimensions.
815 TypeError: if the `index` is invalid (e.g. a `DataFrame`).
816 ValueError: if the `name` is not a valid identifier or already exists.
817 ValueError: if the `lowerbound` is greater than the `upperbound`.
818 ValueError: if the index of `lower_bound`, `upper_bound`, or `is_integer`
819 does not match the input index.
821 return self.
new_var_series(name, index, lower_bounds, upper_bounds,
True)
828 """Creates a series of Boolean variables with the given name.
831 name (str): Required. The name of the variable set.
832 index (pd.Index): Required. The index to use for the variable set.
835 pd.Series: The variable set indexed by its corresponding dimensions.
838 TypeError: if the `index` is invalid (e.g. a `DataFrame`).
839 ValueError: if the `name` is not a valid identifier or already exists.
840 ValueError: if the `lowerbound` is greater than the `upperbound`.
841 ValueError: if the index of `lower_bound`, `upper_bound`, or `is_integer`
842 does not match the input index.
847 """Rebuilds a variable object from the model and its index."""
854 linear_expr: LinearExprT,
855 lb: NumberT = -math.inf,
856 ub: NumberT = math.inf,
857 name: Optional[str] =
None,
858 ) -> LinearConstraint:
859 """Adds the constraint: `lb <= linear_expr <= ub` with the given name."""
862 self.
__helper.set_constraint_name(ct.index, name)
863 if mbn.is_a_number(linear_expr):
864 self.
__helper.set_constraint_lower_bound(ct.index, lb - linear_expr)
865 self.
__helper.set_constraint_upper_bound(ct.index, ub - linear_expr)
866 elif isinstance(linear_expr, LinearExpr):
867 flat_expr = mbh.FlatExpr(linear_expr)
869 self.
__helper.set_constraint_lower_bound(ct.index, lb - flat_expr.offset)
870 self.
__helper.set_constraint_upper_bound(ct.index, ub - flat_expr.offset)
871 self.
__helper.add_terms_to_constraint(
872 ct.index, flat_expr.vars, flat_expr.coeffs
877 f
" Model.add_linear_constraint({type(linear_expr).__name__!r})"
882 self, ct: Union[ConstraintT, pd.Series], name: Optional[str] =
None
883 ) -> Union[LinearConstraint, pd.Series]:
884 """Adds a `BoundedLinearExpression` to the model.
887 ct: A [`BoundedLinearExpression`](#boundedlinearexpression).
888 name: An optional name.
891 An instance of the `Constraint` class.
893 Note that a special treatment is done when the argument does not contain any
894 variable, and thus evaluates to True or False.
896 `model.add(True)` will create a constraint 0 <= empty sum <= 0.
897 The constraint will be marked as under specified, and cannot be modified
900 `model.add(False)` will create a constraint inf <= empty sum <= -inf. The
901 constraint will be marked as under specified, and cannot be modified
904 you can check the if a constraint is under specified by reading the
905 `LinearConstraint.is_under_specified` property.
907 if isinstance(ct, mbh.BoundedLinearExpression):
909 elif isinstance(ct, bool):
911 elif isinstance(ct, pd.Series):
918 for (i, expr)
in zip(ct.index, ct)
922 raise TypeError(f
"Not supported: Model.add({type(ct).__name__!r})")
925 """Rebuilds a linear constraint object from the model and its index."""
932 linear_expr: LinearExprT,
935 lb: NumberT = -math.inf,
936 ub: NumberT = math.inf,
937 name: Optional[str] =
None,
938 ) -> EnforcedLinearConstraint:
939 """Adds the constraint: `ivar == ivalue => lb <= linear_expr <= ub` with the given name."""
941 ct.indicator_variable = ivar
942 ct.indicator_value = ivalue
944 self.
__helper.set_constraint_name(ct.index, name)
945 if mbn.is_a_number(linear_expr):
946 self.
__helper.set_constraint_lower_bound(ct.index, lb - linear_expr)
947 self.
__helper.set_constraint_upper_bound(ct.index, ub - linear_expr)
948 elif isinstance(linear_expr, LinearExpr):
949 flat_expr = mbh.FlatExpr(linear_expr)
951 self.
__helper.set_constraint_lower_bound(ct.index, lb - flat_expr.offset)
952 self.
__helper.set_constraint_upper_bound(ct.index, ub - flat_expr.offset)
953 self.
__helper.add_terms_to_constraint(
954 ct.index, flat_expr.vars, flat_expr.coeffs
959 f
" Model.add_enforced_linear_constraint({type(linear_expr).__name__!r})"
965 ct: Union[ConstraintT, pd.Series],
966 var: Union[Variable, pd.Series],
967 value: Union[bool, pd.Series],
968 name: Optional[str] =
None,
969 ) -> Union[EnforcedLinearConstraint, pd.Series]:
970 """Adds a `ivar == ivalue => BoundedLinearExpression` to the model.
973 ct: A [`BoundedLinearExpression`](#boundedlinearexpression).
974 var: The indicator variable
975 value: the indicator value
976 name: An optional name.
979 An instance of the `Constraint` class.
981 Note that a special treatment is done when the argument does not contain any
982 variable, and thus evaluates to True or False.
984 model.add_enforced(True, ivar, ivalue) will create a constraint 0 <= empty
987 model.add_enforced(False, var, value) will create a constraint inf <=
990 you can check the if a constraint is always false (lb=inf, ub=-inf) by
991 calling EnforcedLinearConstraint.is_always_false()
993 if isinstance(ct, mbh.BoundedLinearExpression):
999 and isinstance(var, Variable)
1000 and isinstance(value, bool)
1003 ct, self.
__helper, var, value, name
1005 elif isinstance(ct, pd.Series):
1018 for (i, expr)
in zip(ct.index, ct)
1022 raise TypeError(f
"Not supported: Model.add_enforced({type(ct).__name__!r}")
1025 self, index: IntegerT
1026 ) -> EnforcedLinearConstraint:
1027 """Rebuilds an enforced linear constraint object from the model and its index."""
1032 """Minimizes the given objective."""
1036 """Maximizes the given objective."""
1039 def __optimize(self, linear_expr: LinearExprT, maximize: bool) ->
None:
1040 """Defines the objective."""
1041 self.
helper.clear_objective()
1042 self.
__helper.set_maximize(maximize)
1043 if mbn.is_a_number(linear_expr):
1044 self.
helper.set_objective_offset(linear_expr)
1045 elif isinstance(linear_expr, Variable):
1046 self.
helper.set_var_objective_coefficient(linear_expr.index, 1.0)
1047 elif isinstance(linear_expr, LinearExpr):
1048 flat_expr = mbh.FlatExpr(linear_expr)
1050 self.
helper.set_objective_offset(flat_expr.offset)
1051 var_indices = [var.index
for var
in flat_expr.vars]
1052 self.
helper.set_objective_coefficients(var_indices, flat_expr.coeffs)
1056 f
" Model.minimize/maximize({type(linear_expr).__name__!r})"
1061 """Returns the fixed offset of the objective."""
1064 @objective_offset.setter
1066 self.
__helper.set_objective_offset(value)
1069 """Returns the expression to optimize."""
1070 variables: list[Variable] = []
1071 coefficients: list[numbers.Real] = []
1073 coeff = self.
__helper.var_objective_coefficient(variable.index)
1075 variables.append(variable)
1076 coefficients.append(coeff)
1081 """Clears all solution hints."""
1084 def add_hint(self, var: Variable, value: NumberT) ->
None:
1085 """Adds var == value as a hint to the model.
1088 var: The variable of the hint
1089 value: The value of the hint
1091 Note that variables must not appear more than once in the list of hints.
1097 options: mbh.MPModelExportOptions = mbh.MPModelExportOptions()
1098 options.obfuscate = obfuscate
1102 options: mbh.MPModelExportOptions = mbh.MPModelExportOptions()
1103 options.obfuscate = obfuscate
1107 options: mbh.MPModelExportOptions = mbh.MPModelExportOptions()
1108 options.obfuscate = obfuscate
1112 """Exports the optimization model to a ProtoBuf format."""
1113 return mbh.to_mpmodel_proto(self.
__helper)
1116 """Reads a model from a MPS string."""
1120 """Reads a model from a .mps file."""
1124 """Reads a model from a LP string.
1126 Note that this code is very limited, and will not support any real lp.
1127 It is only intented to be use to parse test lp problems.
1130 lp_string: The LP string to import.
1133 True if the import was successful.
1138 """Reads a model from a .lp file.
1140 Note that this code is very limited, and will not support any real lp.
1141 It is only intented to be use to parse test lp problems.
1144 lp_file: The LP file to import.
1147 True if the import was successful.
1152 """Reads a model from a proto file."""
1153 return self.
__helper.read_model_from_proto_file(proto_file)
1156 """Writes a model to a proto file."""
1157 return self.
__helper.write_model_to_proto_file(proto_file)
1163 """Returns the number of variables in the model."""
1168 """The number of constraints in the model."""
1173 """The name of the model."""
1182 """Returns the model builder helper."""
1187 """Main solver class.
1189 The purpose of this class is to search for a solution to the model provided
1190 to the solve() method.
1192 Once solve() is called, this class allows inspecting the solution found
1193 with the value() method, as well as general statistics about the solve
1198 self.
__solve_helper: mbh.ModelSolverHelper = mbh.ModelSolverHelper(solver_name)
1202 """Checks whether the requested solver backend was found."""
1207 """Sets a time limit for the solve() call."""
1211 """Sets parameters specific to the solver backend."""
1215 """Controls the solver backend logs."""
1218 def solve(self, model: Model) -> SolveStatus:
1219 """Solves a problem and passes each solution to the callback if not null."""
1228 """Stops the current search asynchronously."""
1231 def value(self, expr: LinearExprT) -> np.double:
1232 """Returns the value of a linear expression after solve."""
1235 if mbn.is_a_number(expr):
1237 elif isinstance(expr, LinearExpr):
1240 raise TypeError(f
"Unknown expression {type(expr).__name__!r}")
1242 def values(self, variables: _IndexOrSeries) -> pd.Series:
1243 """Returns the values of the input variables.
1245 If `variables` is a `pd.Index`, then the output will be indexed by the
1246 variables. If `variables` is a `pd.Series` indexed by the underlying
1247 dimensions, then the output will be indexed by the same underlying
1251 variables (Union[pd.Index, pd.Series]): The set of variables from which to
1255 pd.Series: The values of all variables in the set.
1265 """Returns the reduced cost of the input variables.
1267 If `variables` is a `pd.Index`, then the output will be indexed by the
1268 variables. If `variables` is a `pd.Series` indexed by the underlying
1269 dimensions, then the output will be indexed by the same underlying
1273 variables (Union[pd.Index, pd.Series]): The set of variables from which to
1277 pd.Series: The reduced cost of all variables in the set.
1287 """Returns the reduced cost of a linear expression after solve."""
1293 """Returns the dual values of the input constraints.
1295 If `constraints` is a `pd.Index`, then the output will be indexed by the
1296 constraints. If `constraints` is a `pd.Series` indexed by the underlying
1297 dimensions, then the output will be indexed by the same underlying
1301 constraints (Union[pd.Index, pd.Series]): The set of constraints from
1302 which to get the dual values.
1305 pd.Series: The dual_values of all constraints in the set.
1315 """Returns the dual value of a linear constraint after solve."""
1321 """Returns the activity of a linear constraint after solve."""
1328 """Returns the value of the objective after solve."""
1335 """Returns the best lower (upper) bound found when min(max)imizing."""
1342 """Returns additional information of the last solve.
1344 It can describe why the model is invalid.
1358 """Returns the indices of `obj` as a `pd.Index`."""
1359 if isinstance(obj, pd.Series):
1366 func: Callable[[_VariableOrConstraint], NumberT],
1367 values: _IndexOrSeries,
1369 """Returns the attributes of `values`.
1372 func: The function to call for getting the attribute data.
1373 values: The values that the function will be applied (element-wise) to.
1376 pd.Series: The attribute values.
1379 data=[func(v)
for v
in values],
1385 value_or_series: Union[bool, NumberT, pd.Series], index: pd.Index
1387 """Returns a pd.Series of the given index with the corresponding values.
1390 value_or_series: the values to be converted (if applicable).
1391 index: the index of the resulting pd.Series.
1394 pd.Series: The set of values with the given index.
1397 TypeError: If the type of `value_or_series` is not recognized.
1398 ValueError: If the index does not match.
1400 if mbn.is_a_number(value_or_series)
or isinstance(value_or_series, bool):
1401 result = pd.Series(data=value_or_series, index=index)
1402 elif isinstance(value_or_series, pd.Series):
1403 if value_or_series.index.equals(index):
1404 result = value_or_series
1406 raise ValueError(
"index does not match")
1408 raise TypeError(
"invalid type={type(value_or_series).__name!r}")
1413 var_or_series: Union[
"Variable", pd.Series], index: pd.Index
1415 """Returns a pd.Series of the given index with the corresponding values.
1418 var_or_series: the variables to be converted (if applicable).
1419 index: the index of the resulting pd.Series.
1422 pd.Series: The set of values with the given index.
1425 TypeError: If the type of `value_or_series` is not recognized.
1426 ValueError: If the index does not match.
1428 if isinstance(var_or_series, Variable):
1429 result = pd.Series(data=var_or_series, index=index)
1430 elif isinstance(var_or_series, pd.Series):
1431 if var_or_series.index.equals(index):
1432 result = var_or_series
1434 raise ValueError(
"index does not match")
1436 raise TypeError(
"invalid type={type(value_or_series).__name!r}")