Google OR-Tools v9.14
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
linear_constraints.py
Go to the documentation of this file.
1# Copyright 2010-2025 Google LLC
2# Licensed under the Apache License, Version 2.0 (the "License");
3# you may not use this file except in compliance with the License.
4# You may obtain a copy of the License at
5#
6# http://www.apache.org/licenses/LICENSE-2.0
7#
8# Unless required by applicable law or agreed to in writing, software
9# distributed under the License is distributed on an "AS IS" BASIS,
10# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11# See the License for the specific language governing permissions and
12# limitations under the License.
13
14"""Linear constraint in a model."""
15
16from typing import Any, Iterator, NamedTuple
17
19from ortools.math_opt.python import from_model
20from ortools.math_opt.python import variables
21from ortools.math_opt.python.elemental import elemental
22
23
25 """A linear constraint for an optimization model.
26
27 A LinearConstraint adds the following restriction on feasible solutions to an
28 optimization model:
29 lb <= sum_{i in I} a_i * x_i <= ub
30 where x_i are the decision variables of the problem. lb == ub is allowed, this
31 models the equality constraint:
32 sum_{i in I} a_i * x_i == b
33 Setting lb > ub will result in an InvalidArgument error at solve time (the
34 values are allowed to cross temporarily between solves).
35
36 A LinearConstraint can be configured as follows:
37 * lower_bound: a float property, lb above. Should not be NaN nor +inf.
38 * upper_bound: a float property, ub above. Should not be NaN nor -inf.
39 * set_coefficient() and get_coefficient(): get and set the a_i * x_i
40 terms. The variable must be from the same model as this constraint, and
41 the a_i must be finite and not NaN. The coefficient for any variable not
42 set is 0.0, and setting a coefficient to 0.0 removes it from I above.
43
44 The name is optional, read only, and used only for debugging. Non-empty names
45 should be distinct.
46
47 Do not create a LinearConstraint directly, use Model.add_linear_constraint()
48 instead. Two LinearConstraint objects can represent the same constraint (for
49 the same model). They will have the same underlying LinearConstraint.elemental
50 for storing the data. The LinearConstraint class is simply a reference to an
51 Elemental.
52 """
53
54 __slots__ = "_elemental", "_id"
55
56 def __init__(self, elem: elemental.Elemental, cid: int) -> None:
57 """Internal only, prefer Model functions (add_linear_constraint() and get_linear_constraint())."""
58 if not isinstance(cid, int):
59 raise TypeError(f"cid type should be int, was:{type(cid).__name__!r}")
61 self._id: int = cid
62
63 @property
64 def lower_bound(self) -> float:
65 return self._elemental.get_attr(
66 enums.DoubleAttr1.LINEAR_CONSTRAINT_LOWER_BOUND, (self._id,)
67 )
68
69 @lower_bound.setter
70 def lower_bound(self, value: float) -> None:
71 self._elemental.set_attr(
72 enums.DoubleAttr1.LINEAR_CONSTRAINT_LOWER_BOUND, (self._id,), value
73 )
74
75 @property
76 def upper_bound(self) -> float:
77 return self._elemental.get_attr(
78 enums.DoubleAttr1.LINEAR_CONSTRAINT_UPPER_BOUND, (self._id,)
79 )
80
81 @upper_bound.setter
82 def upper_bound(self, value: float) -> None:
83 self._elemental.set_attr(
84 enums.DoubleAttr1.LINEAR_CONSTRAINT_UPPER_BOUND, (self._id,), value
85 )
86
87 @property
88 def name(self) -> str:
89 return self._elemental.get_element_name(
90 enums.ElementType.LINEAR_CONSTRAINT, self._id
91 )
92
93 @property
94 def id(self) -> int:
95 return self._id
96
97 @property
98 def elemental(self) -> elemental.Elemental:
99 """Internal use only."""
100 return self._elemental
101
102 def set_coefficient(self, var: variables.Variable, coefficient: float) -> None:
103 from_model.model_is_same(var, self)
104 self._elemental.set_attr(
105 enums.DoubleAttr2.LINEAR_CONSTRAINT_COEFFICIENT,
106 (self._id, var.id),
107 coefficient,
108 )
109
110 def get_coefficient(self, var: variables.Variable) -> float:
111 from_model.model_is_same(var, self)
112 return self._elemental.get_attr(
113 enums.DoubleAttr2.LINEAR_CONSTRAINT_COEFFICIENT, (self._id, var.id)
114 )
115
116 def terms(self) -> Iterator[variables.LinearTerm]:
117 """Yields the variable/coefficient pairs with nonzero coefficient for this linear constraint."""
118 keys = self._elemental.slice_attr(
119 enums.DoubleAttr2.LINEAR_CONSTRAINT_COEFFICIENT, 0, self._id
120 )
121 coefs = self._elemental.get_attrs(
122 enums.DoubleAttr2.LINEAR_CONSTRAINT_COEFFICIENT, keys
123 )
124 for i in range(len(keys)):
126 variable=variables.Variable(self._elemental, int(keys[i, 1])),
127 coefficient=float(coefs[i]),
128 )
129
130 def as_bounded_linear_expression(self) -> variables.BoundedLinearExpression:
131 """Returns the bounded expression from lower_bound, upper_bound and terms."""
132 return variables.BoundedLinearExpression(
134 )
135
136 def __str__(self):
137 """Returns the name, or a string containing the id if the name is empty."""
138 return self.name if self.name else f"linear_constraint_{self.id}"
139
140 def __repr__(self):
141 return f"<LinearConstraint id: {self.id}, name: {self.name!r}>"
142
143 def __eq__(self, other: Any) -> bool:
144 if isinstance(other, LinearConstraint):
145 return self._id == other._id and self._elemental is other._elemental
146 return False
147
148 def __hash__(self) -> int:
149 return hash(self._id)
150
151
153 linear_constraint: LinearConstraint
155 coefficient: float
variables.BoundedLinearExpression as_bounded_linear_expression(self)
None __init__(self, elemental.Elemental elem, int cid)
None set_coefficient(self, variables.Variable var, float coefficient)