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