15"""Methods for building and solving model_builder models.
17The following two sections describe the main
18methods for building and solving those models.
20* [`Model`](#model_builder.Model): Methods for creating
21models, including variables and constraints.
22* [`Solver`](#model_builder.Solver): Methods for solving
23a model and evaluating solutions.
25Additional methods for solving Model models:
27* [`Constraint`](#model_builder.Constraint): A few utility methods for modifying
28 constraints created by `Model`.
29* [`LinearExpr`](#model_builder.LinearExpr): Methods for creating constraints
30 and the objective from large arrays of coefficients.
32Other methods and functions listed are primarily used for developing OR-Tools,
33rather than for solving specific optimization problems.
36from collections.abc
import Callable
40from typing
import Optional, Union
50NumberT = Union[int, float, numbers.Real, np.number]
51IntegerT = Union[int, numbers.Integral, np.integer]
52LinearExprT = Union[mbh.LinearExpr, NumberT]
53ConstraintT = Union[mbh.BoundedLinearExpression, bool]
54_IndexOrSeries = Union[pd.Index, pd.Series]
55_VariableOrConstraint = Union[
"LinearConstraint", mbh.Variable]
58AffineExpr = mbh.AffineExpr
59BoundedLinearExpression = mbh.BoundedLinearExpression
60FlatExpr = mbh.FlatExpr
61LinearExpr = mbh.LinearExpr
62SolveStatus = mbh.SolveStatus
63Variable = mbh.Variable
67 bounded_expr: Union[bool, mbh.BoundedLinearExpression],
68 helper: mbh.ModelBuilderHelper,
71 """Creates a new linear constraint in the helper.
73 It handles boolean values (which might arise in the construction of
74 BoundedLinearExpressions).
76 If bounded_expr is a Boolean value, the created constraint is different.
77 In that case, the constraint will be immutable and marked as under-specified.
78 It will be always feasible or infeasible whether the value is True or False.
81 bounded_expr: The bounded expression used to create the constraint.
82 helper: The helper to create the constraint.
83 name: The name of the constraint to be created.
86 LinearConstraint: a constraint in the helper corresponding to the input.
89 TypeError: If constraint is an invalid type.
91 if isinstance(bounded_expr, bool):
94 helper.set_constraint_name(c.index, name)
97 helper.set_constraint_lower_bound(c.index, 0.0)
98 helper.set_constraint_upper_bound(c.index, 0.0)
101 helper.set_constraint_lower_bound(c.index, 1)
102 helper.set_constraint_upper_bound(c.index, -1)
104 if isinstance(bounded_expr, mbh.BoundedLinearExpression):
107 helper.add_terms_to_constraint(c.index, bounded_expr.vars, bounded_expr.coeffs)
108 helper.set_constraint_lower_bound(c.index, bounded_expr.lower_bound)
109 helper.set_constraint_upper_bound(c.index, bounded_expr.upper_bound)
112 helper.set_constraint_name(c.index, name)
114 raise TypeError(f
"invalid type={type(bounded_expr).__name__!r}")
118 bounded_expr: Union[bool, mbh.BoundedLinearExpression],
119 helper: mbh.ModelBuilderHelper,
124 """Creates a new enforced linear constraint in the helper.
126 It handles boolean values (which might arise in the construction of
127 BoundedLinearExpressions).
129 If bounded_expr is a Boolean value, the linear part of the constraint is
131 In that case, the constraint will be immutable and marked as under-specified.
132 Its linear part will be always feasible or infeasible whether the value is
136 bounded_expr: The bounded expression used to create the constraint.
137 helper: The helper to create the constraint.
138 var: the variable used in the indicator
139 value: the value used in the indicator
140 name: The name of the constraint to be created.
143 EnforcedLinearConstraint: a constraint in the helper corresponding to the
147 TypeError: If constraint is an invalid type.
149 if isinstance(bounded_expr, bool):
152 c.indicator_variable = var
153 c.indicator_value = value
155 helper.set_enforced_constraint_name(c.index, name)
158 helper.set_enforced_constraint_lower_bound(c.index, 0.0)
159 helper.set_enforced_constraint_upper_bound(c.index, 0.0)
162 helper.set_enforced_constraint_lower_bound(c.index, 1)
163 helper.set_enforced_constraint_upper_bound(c.index, -1)
165 if isinstance(bounded_expr, mbh.BoundedLinearExpression):
167 c.indicator_variable = var
168 c.indicator_value = value
169 helper.add_terms_to_enforced_constraint(
170 c.index, bounded_expr.vars, bounded_expr.coeffs
172 helper.set_enforced_constraint_lower_bound(c.index, bounded_expr.lower_bound)
173 helper.set_enforced_constraint_upper_bound(c.index, bounded_expr.upper_bound)
175 helper.set_constraint_name(c.index, name)
178 raise TypeError(f
"invalid type={type(bounded_expr).__name__!r}")
182 """Stores a linear equation.
185 x = model.new_num_var(0, 10, 'x')
186 y = model.new_num_var(0, 10, 'y')
188 linear_constraint = model.add(x + 2 * y == 5)
193 helper: mbh.ModelBuilderHelper,
195 index: Optional[IntegerT] =
None,
196 is_under_specified: bool =
False,
198 """LinearConstraint constructor.
201 helper: The pybind11 ModelBuilderHelper.
202 index: If specified, recreates a wrapper to an existing linear constraint.
203 is_under_specified: indicates if the constraint was created by
207 self.
__index = helper.add_linear_constraint()
210 self.
__helper: mbh.ModelBuilderHelper = helper
218 """Returns the index of the constraint in the helper."""
222 def helper(self) -> mbh.ModelBuilderHelper:
223 """Returns the ModelBuilderHelper instance."""
248 return constraint_name
249 return f
"linear_constraint#{self.__index}"
252 def name(self, name: str) ->
None:
257 """Returns True if the constraint is under specified.
259 Usually, it means that it was created by model.add(False) or model.add(True)
260 The effect is that modifying the constraint will raise an exception.
265 """Raises an exception if the constraint is under specified."""
268 f
"Constraint {self.index} is under specified and cannot be modified"
276 f
"LinearConstraint({self.name}, lb={self.lower_bound},"
277 f
" ub={self.upper_bound},"
278 f
" var_indices={self.helper.constraint_var_indices(self.index)},"
279 f
" coefficients={self.helper.constraint_coefficients(self.index)})"
283 """Sets the coefficient of the variable in the constraint."""
285 self.
__helper.set_constraint_coefficient(self.
__index, var.index, coeff)
287 def add_term(self, var: Variable, coeff: NumberT) ->
None:
288 """Adds var * coeff to the constraint."""
290 self.
__helper.safe_add_term_to_constraint(self.
__index, var.index, coeff)
293 """Clear all terms of the constraint."""
299 """Stores an enforced linear equation, also name indicator constraint.
302 x = model.new_num_var(0, 10, 'x')
303 y = model.new_num_var(0, 10, 'y')
304 z = model.new_bool_var('z')
306 enforced_linear_constraint = model.add_enforced(x + 2 * y == 5, z, False)
311 helper: mbh.ModelBuilderHelper,
313 index: Optional[IntegerT] =
None,
314 is_under_specified: bool =
False,
316 """EnforcedLinearConstraint constructor.
319 helper: The pybind11 ModelBuilderHelper.
320 index: If specified, recreates a wrapper to an existing linear constraint.
321 is_under_specified: indicates if the constraint was created by
325 self.
__index = helper.add_enforced_linear_constraint()
327 if not helper.is_enforced_linear_constraint(index):
329 f
"the given index {index} does not refer to an enforced linear"
334 self.
__helper: mbh.ModelBuilderHelper = helper
339 """Returns the index of the constraint in the helper."""
343 def helper(self) -> mbh.ModelBuilderHelper:
344 """Returns the ModelBuilderHelper instance."""
367 enforcement_var_index = (
368 self.
__helper.enforced_constraint_indicator_variable_index(self.
__index)
372 @indicator_variable.setter
374 self.
__helper.set_enforced_constraint_indicator_variable_index(
382 @indicator_value.setter
384 self.
__helper.set_enforced_constraint_indicator_value(self.
__index, value)
390 return constraint_name
391 return f
"enforced_linear_constraint#{self.__index}"
394 def name(self, name: str) ->
None:
399 """Returns True if the constraint is under specified.
401 Usually, it means that it was created by model.add(False) or model.add(True)
402 The effect is that modifying the constraint will raise an exception.
407 """Raises an exception if the constraint is under specified."""
410 f
"Constraint {self.index} is under specified and cannot be modified"
418 f
"EnforcedLinearConstraint({self.name}, lb={self.lower_bound},"
419 f
" ub={self.upper_bound},"
420 f
" var_indices={self.helper.enforced_constraint_var_indices(self.index)},"
421 f
" coefficients={self.helper.enforced_constraint_coefficients(self.index)},"
422 f
" indicator_variable={self.indicator_variable}"
423 f
" indicator_value={self.indicator_value})"
427 """Sets the coefficient of the variable in the constraint."""
429 self.
__helper.set_enforced_constraint_coefficient(
433 def add_term(self, var: Variable, coeff: NumberT) ->
None:
434 """Adds var * coeff to the constraint."""
436 self.
__helper.safe_add_term_to_enforced_constraint(
441 """Clear all terms of the constraint."""
447 """Methods for building a linear model.
449 Methods beginning with:
451 * ```new_``` create integer, boolean, or interval variables.
452 * ```add_``` create new constraints and add them to the model.
456 self.
__helper: mbh.ModelBuilderHelper = mbh.ModelBuilderHelper()
459 """Returns a clone of the current model."""
461 clone.helper.overwrite_model(self.
helper)
471 self, constraints: Optional[_IndexOrSeries] =
None
473 if constraints
is None:
484 self, variables: Optional[_IndexOrSeries] =
None
486 if variables
is None:
491 """Gets all linear constraints in the model."""
494 name=
"linear_constraint",
498 self, constraints: Optional[_IndexOrSeries] =
None
500 """Gets the expressions of all linear constraints in the set.
502 If `constraints` is a `pd.Index`, then the output will be indexed by the
503 constraints. If `constraints` is a `pd.Series` indexed by the underlying
504 dimensions, then the output will be indexed by the same underlying
508 constraints (Union[pd.Index, pd.Series]): Optional. The set of linear
509 constraints from which to get the expressions. If unspecified, all
510 linear constraints will be in scope.
513 pd.Series: The expressions of all linear constraints in the set.
517 func=
lambda c: mbh.FlatExpr(
521 for var_id
in c.helper.constraint_var_indices(c.index)
523 c.helper.constraint_coefficients(c.index),
530 self, constraints: Optional[_IndexOrSeries] =
None
532 """Gets the lower bounds of all linear constraints in the set.
534 If `constraints` is a `pd.Index`, then the output will be indexed by the
535 constraints. If `constraints` is a `pd.Series` indexed by the underlying
536 dimensions, then the output will be indexed by the same underlying
540 constraints (Union[pd.Index, pd.Series]): Optional. The set of linear
541 constraints from which to get the lower bounds. If unspecified, all
542 linear constraints will be in scope.
545 pd.Series: The lower bounds of all linear constraints in the set.
548 func=
lambda c: c.lower_bound,
553 self, constraints: Optional[_IndexOrSeries] =
None
555 """Gets the upper bounds of all linear constraints in the set.
557 If `constraints` is a `pd.Index`, then the output will be indexed by the
558 constraints. If `constraints` is a `pd.Series` indexed by the underlying
559 dimensions, then the output will be indexed by the same underlying
563 constraints (Union[pd.Index, pd.Series]): Optional. The set of linear
564 constraints. If unspecified, all linear constraints will be in scope.
567 pd.Series: The upper bounds of all linear constraints in the set.
570 func=
lambda c: c.upper_bound,
575 """Gets all variables in the model."""
582 self, variables: Optional[_IndexOrSeries] =
None
584 """Gets the lower bounds of all variables in the set.
586 If `variables` is a `pd.Index`, then the output will be indexed by the
587 variables. If `variables` is a `pd.Series` indexed by the underlying
588 dimensions, then the output will be indexed by the same underlying
592 variables (Union[pd.Index, pd.Series]): Optional. The set of variables
593 from which to get the lower bounds. If unspecified, all variables will
597 pd.Series: The lower bounds of all variables in the set.
600 func=
lambda v: v.lower_bound,
605 self, variables: Optional[_IndexOrSeries] =
None
607 """Gets the upper bounds of all variables in the set.
610 variables (Union[pd.Index, pd.Series]): Optional. The set of variables
611 from which to get the upper bounds. If unspecified, all variables will
615 pd.Series: The upper bounds of all variables in the set.
618 func=
lambda v: v.upper_bound,
625 self, lb: NumberT, ub: NumberT, is_integer: bool, name: Optional[str]
627 """Create an integer variable with domain [lb, ub].
630 lb: Lower bound of the variable.
631 ub: Upper bound of the variable.
632 is_integer: Indicates if the variable must take integral values.
633 name: The name of the variable.
636 a variable whose domain is [lb, ub].
644 self, lb: NumberT, ub: NumberT, name: Optional[str] =
None
646 """Create an integer variable with domain [lb, ub].
649 lb: Lower bound of the variable.
650 ub: Upper bound of the variable.
651 name: The name of the variable.
654 a variable whose domain is [lb, ub].
657 return self.
new_var(lb, ub,
True, name)
660 self, lb: NumberT, ub: NumberT, name: Optional[str] =
None
662 """Create an integer variable with domain [lb, ub].
665 lb: Lower bound of the variable.
666 ub: Upper bound of the variable.
667 name: The name of the variable.
670 a variable whose domain is [lb, ub].
673 return self.
new_var(lb, ub,
False, name)
676 """Creates a 0-1 variable with the given name."""
677 return self.
new_var(0, 1,
True, 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}")