Google OR-Tools v9.12
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
integer_base.h
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#ifndef OR_TOOLS_SAT_INTEGER_BASE_H_
15#define OR_TOOLS_SAT_INTEGER_BASE_H_
16
17#include <stdlib.h>
18
19#include <algorithm>
20#include <cstdint>
21#include <limits>
22#include <ostream>
23#include <string>
24#include <utility>
25#include <vector>
26
27#include "absl/log/check.h"
28#include "absl/strings/str_cat.h"
29#include "absl/types/span.h"
36
37namespace operations_research {
38namespace sat {
39
40// Value type of an integer variable. An integer variable is always bounded
41// on both sides, and this type is also used to store the bounds [lb, ub] of the
42// range of each integer variable.
43//
44// Note that both bounds are inclusive, which allows to write many propagation
45// algorithms for just one of the bound and apply it to the negated variables to
46// get the symmetric algorithm for the other bound.
48
49// The max range of an integer variable is [kMinIntegerValue, kMaxIntegerValue].
50//
51// It is symmetric so the set of possible ranges stays the same when we take the
52// negation of a variable. Moreover, we need some IntegerValue that fall outside
53// this range on both side so that we can usually take care of integer overflow
54// by simply doing "saturated arithmetic" and if one of the bound overflow, the
55// two bounds will "cross" each others and we will get an empty range.
56constexpr IntegerValue kMaxIntegerValue(
57 std::numeric_limits<IntegerValue::ValueType>::max() - 1);
58constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue.value());
59
60inline double ToDouble(IntegerValue value) {
61 const double kInfinity = std::numeric_limits<double>::infinity();
62 if (value >= kMaxIntegerValue) return kInfinity;
63 if (value <= kMinIntegerValue) return -kInfinity;
64 return static_cast<double>(value.value());
65}
66
67template <class IntType>
68inline IntType IntTypeAbs(IntType t) {
69 return IntType(std::abs(t.value()));
70}
71
72inline IntegerValue CeilRatio(IntegerValue dividend,
73 IntegerValue positive_divisor) {
74 DCHECK_GT(positive_divisor, 0);
75 const IntegerValue result = dividend / positive_divisor;
76 const IntegerValue adjust =
77 static_cast<IntegerValue>(result * positive_divisor < dividend);
78 return result + adjust;
79}
80
81inline IntegerValue FloorRatio(IntegerValue dividend,
82 IntegerValue positive_divisor) {
83 DCHECK_GT(positive_divisor, 0);
84 const IntegerValue result = dividend / positive_divisor;
85 const IntegerValue adjust =
86 static_cast<IntegerValue>(result * positive_divisor > dividend);
87 return result - adjust;
88}
89
90// Overflows and saturated arithmetic.
91
92inline IntegerValue CapProdI(IntegerValue a, IntegerValue b) {
93 return IntegerValue(CapProd(a.value(), b.value()));
94}
95
96inline IntegerValue CapSubI(IntegerValue a, IntegerValue b) {
97 return IntegerValue(CapSub(a.value(), b.value()));
98}
99
100inline IntegerValue CapAddI(IntegerValue a, IntegerValue b) {
101 return IntegerValue(CapAdd(a.value(), b.value()));
102}
103
104inline bool ProdOverflow(IntegerValue t, IntegerValue value) {
105 return AtMinOrMaxInt64(CapProd(t.value(), value.value()));
106}
107
108inline bool AtMinOrMaxInt64I(IntegerValue t) {
109 return AtMinOrMaxInt64(t.value());
110}
111
112// Returns dividend - FloorRatio(dividend, divisor) * divisor;
113//
114// This function is around the same speed than the computation above, but it
115// never causes integer overflow. Note also that when calling FloorRatio() then
116// PositiveRemainder(), the compiler should optimize the modulo away and just
117// reuse the one from the first integer division.
118inline IntegerValue PositiveRemainder(IntegerValue dividend,
119 IntegerValue positive_divisor) {
120 DCHECK_GT(positive_divisor, 0);
121 const IntegerValue m = dividend % positive_divisor;
122 return m < 0 ? m + positive_divisor : m;
123}
124
125inline bool AddTo(IntegerValue a, IntegerValue* result) {
126 if (AtMinOrMaxInt64I(a)) return false;
127 const IntegerValue add = CapAddI(a, *result);
128 if (AtMinOrMaxInt64I(add)) return false;
129 *result = add;
130 return true;
131}
132
133// Computes result += a * b, and return false iff there is an overflow.
134inline bool AddProductTo(IntegerValue a, IntegerValue b, IntegerValue* result) {
135 const IntegerValue prod = CapProdI(a, b);
136 if (AtMinOrMaxInt64I(prod)) return false;
137 const IntegerValue add = CapAddI(prod, *result);
138 if (AtMinOrMaxInt64I(add)) return false;
139 *result = add;
140 return true;
141}
142
143// Computes result += a * a, and return false iff there is an overflow.
144inline bool AddSquareTo(IntegerValue a, IntegerValue* result) {
145 return AddProductTo(a, a, result);
146}
147
148// Index of an IntegerVariable.
149//
150// Each time we create an IntegerVariable we also create its negation. This is
151// done like that so internally we only stores and deal with lower bound. The
152// upper bound being the lower bound of the negated variable.
154const IntegerVariable kNoIntegerVariable(-1);
155inline IntegerVariable NegationOf(IntegerVariable i) {
156 return IntegerVariable(i.value() ^ 1);
157}
158
159inline bool VariableIsPositive(IntegerVariable i) {
160 return (i.value() & 1) == 0;
161}
162
163inline IntegerVariable PositiveVariable(IntegerVariable i) {
164 return IntegerVariable(i.value() & (~1));
165}
166
167// Special type for storing only one thing for var and NegationOf(var).
168DEFINE_STRONG_INDEX_TYPE(PositiveOnlyIndex);
169inline PositiveOnlyIndex GetPositiveOnlyIndex(IntegerVariable var) {
170 return PositiveOnlyIndex(var.value() / 2);
171}
172
173inline std::string IntegerTermDebugString(IntegerVariable var,
174 IntegerValue coeff) {
175 coeff = VariableIsPositive(var) ? coeff : -coeff;
176 return absl::StrCat(coeff.value(), "*X", var.value() / 2);
177}
178
179// Returns the vector of the negated variables.
180std::vector<IntegerVariable> NegationOf(absl::Span<const IntegerVariable> vars);
181
182// The integer equivalent of a literal.
183// It represents an IntegerVariable and an upper/lower bound on it.
184//
185// Overflow: all the bounds below kMinIntegerValue and kMaxIntegerValue are
186// treated as kMinIntegerValue - 1 and kMaxIntegerValue + 1.
188 // Because IntegerLiteral should never be created at a bound less constrained
189 // than an existing IntegerVariable bound, we don't allow GreaterOrEqual() to
190 // have a bound lower than kMinIntegerValue, and LowerOrEqual() to have a
191 // bound greater than kMaxIntegerValue. The other side is not constrained
192 // to allow for a computed bound to overflow. Note that both the full initial
193 // domain and the empty domain can always be represented.
194 static IntegerLiteral GreaterOrEqual(IntegerVariable i, IntegerValue bound);
195 static IntegerLiteral LowerOrEqual(IntegerVariable i, IntegerValue bound);
196
197 // These two static integer literals represent an always true and an always
198 // false condition.
201
202 // Clients should prefer the static construction methods above.
204 IntegerLiteral(IntegerVariable v, IntegerValue b) : var(v), bound(b) {
205 DCHECK_GE(bound, kMinIntegerValue);
206 DCHECK_LE(bound, kMaxIntegerValue + 1);
207 }
208
209 bool IsValid() const { return var != kNoIntegerVariable; }
210 bool IsAlwaysTrue() const { return var == kNoIntegerVariable && bound <= 0; }
211 bool IsAlwaysFalse() const { return var == kNoIntegerVariable && bound > 0; }
212
213 // The negation of x >= bound is x <= bound - 1.
214 IntegerLiteral Negated() const;
215
217 return var == o.var && bound == o.bound;
218 }
220 return var != o.var || bound != o.bound;
221 }
222
223 std::string DebugString() const {
224 return VariableIsPositive(var)
225 ? absl::StrCat("I", var.value() / 2, ">=", bound.value())
226 : absl::StrCat("I", var.value() / 2, "<=", -bound.value());
227 }
228
229 // Note that bound should be in [kMinIntegerValue, kMaxIntegerValue + 1].
230 IntegerVariable var = kNoIntegerVariable;
231 IntegerValue bound = IntegerValue(0);
232};
233
234inline std::ostream& operator<<(std::ostream& os, IntegerLiteral i_lit) {
235 os << i_lit.DebugString();
236 return os;
237}
238
239inline std::ostream& operator<<(std::ostream& os,
240 absl::Span<const IntegerLiteral> literals) {
241 os << "[";
242 bool first = true;
243 for (const IntegerLiteral literal : literals) {
244 if (first) {
245 first = false;
246 } else {
247 os << ",";
248 }
249 os << literal.DebugString();
250 }
251 os << "]";
252 return os;
253}
254
255// Represents [coeff * variable + constant] or just a [constant].
256//
257// In some places it is useful to manipulate such expression instead of having
258// to create an extra integer variable. This is mainly used for scheduling
259// related constraints.
261 // Helper to construct an AffineExpression.
262 AffineExpression() = default;
263 AffineExpression(IntegerValue cst) // NOLINT(runtime/explicit)
264 : constant(cst) {}
265 AffineExpression(IntegerVariable v) // NOLINT(runtime/explicit)
266 : var(v), coeff(1) {}
267 AffineExpression(IntegerVariable v, IntegerValue c)
268 : var(c >= 0 ? v : NegationOf(v)), coeff(IntTypeAbs(c)) {}
269 AffineExpression(IntegerVariable v, IntegerValue c, IntegerValue cst)
270 : var(c >= 0 ? v : NegationOf(v)), coeff(IntTypeAbs(c)), constant(cst) {}
271
272 // Returns the integer literal corresponding to expression >= value or
273 // expression <= value.
274 //
275 // On constant expressions, they will return IntegerLiteral::TrueLiteral()
276 // or IntegerLiteral::FalseLiteral().
277 IntegerLiteral GreaterOrEqual(IntegerValue bound) const;
278 IntegerLiteral LowerOrEqual(IntegerValue bound) const;
279
284
285 AffineExpression MultipliedBy(IntegerValue multiplier) const {
286 // Note that this also works if multiplier is negative.
287 return AffineExpression(var, coeff * multiplier, constant * multiplier);
288 }
289
291 return var == o.var && coeff == o.coeff && constant == o.constant;
292 }
293
294 // Returns the value of this affine expression given its variable value.
295 IntegerValue ValueAt(IntegerValue var_value) const {
296 return coeff * var_value + constant;
297 }
298
299 // Returns the affine expression value under a given LP solution.
301 lp_values) const {
302 if (var == kNoIntegerVariable) return ToDouble(constant);
303 return ToDouble(coeff) * lp_values[var] + ToDouble(constant);
304 }
305
306 bool IsConstant() const { return var == kNoIntegerVariable; }
307
308 std::string DebugString() const {
309 if (var == kNoIntegerVariable) return absl::StrCat(constant.value());
310 if (constant == 0) {
311 return absl::StrCat("(", coeff.value(), " * X", var.value(), ")");
312 } else {
313 return absl::StrCat("(", coeff.value(), " * X", var.value(), " + ",
314 constant.value(), ")");
315 }
316 }
317
318 // The coefficient MUST be positive. Use NegationOf(var) if needed.
319 //
320 // TODO(user): Make this private to enforce the invariant that coeff cannot be
321 // negative.
322 IntegerVariable var = kNoIntegerVariable; // kNoIntegerVariable for constant.
323 IntegerValue coeff = IntegerValue(0); // Zero for constant.
324 IntegerValue constant = IntegerValue(0);
325};
326
327template <typename H>
329 if (e.var != kNoIntegerVariable) {
330 h = H::combine(std::move(h), e.var);
331 h = H::combine(std::move(h), e.coeff);
332 }
333 h = H::combine(std::move(h), e.constant);
334
335 return h;
336}
337
338// A model singleton that holds the root level integer variable domains.
339// we just store a single domain for both var and its negation.
341 : public util_intops::StrongVector<PositiveOnlyIndex, Domain> {};
342
343// A model singleton used for debugging. If this is set in the model, then we
344// can check that various derived constraint do not exclude this solution (if it
345// is a known optimal solution for instance).
347 // This is the value of all proto variables.
348 // It should be of the same size of the PRESOLVED model and should correspond
349 // to a solution to the presolved model.
350 std::vector<int64_t> proto_values;
351
352 // This is filled from proto_values at load-time, and using the
353 // cp_model_mapping, we cache the solution of the integer variables that are
354 // mapped. Note that it is possible that not all integer variable are mapped.
355 //
356 // TODO(user): When this happen we should be able to infer the value of these
357 // derived variable in the solution. For now, we only do that for the
358 // objective variable.
361};
362
363// A value and a literal.
367 const ValueLiteralPair& b) const {
368 return a.literal < b.literal;
369 }
370 };
373 const ValueLiteralPair& b) const {
374 return (a.value < b.value) ||
375 (a.value == b.value && a.literal < b.literal);
376 }
377 };
378
379 bool operator==(const ValueLiteralPair& o) const {
380 return value == o.value && literal == o.literal;
381 }
382
383 std::string DebugString() const;
384
385 IntegerValue value = IntegerValue(0);
387};
388
389std::ostream& operator<<(std::ostream& os, const ValueLiteralPair& p);
390
391DEFINE_STRONG_INDEX_TYPE(IntervalVariable);
392const IntervalVariable kNoIntervalVariable(-1);
393
394// ============================================================================
395// Implementation.
396// ============================================================================
397
398inline IntegerLiteral IntegerLiteral::GreaterOrEqual(IntegerVariable i,
399 IntegerValue bound) {
402}
403
404inline IntegerLiteral IntegerLiteral::LowerOrEqual(IntegerVariable i,
405 IntegerValue bound) {
411 return IntegerLiteral(kNoIntegerVariable, IntegerValue(-1));
415 return IntegerLiteral(kNoIntegerVariable, IntegerValue(1));
417
419 // Note that bound >= kMinIntegerValue, so -bound + 1 will have the correct
420 // capped value.
421 return IntegerLiteral(
422 NegationOf(IntegerVariable(var)),
424}
425
426// var * coeff + constant >= bound.
428 IntegerValue bound) const {
430 return constant >= bound ? IntegerLiteral::TrueLiteral()
432 }
433 DCHECK_GT(coeff, 0);
435 CeilRatio(bound - constant, coeff));
436}
437
438// var * coeff + constant <= bound.
439inline IntegerLiteral AffineExpression::LowerOrEqual(IntegerValue bound) const {
440 if (var == kNoIntegerVariable) {
442 : IntegerLiteral::FalseLiteral();
443 }
444 DCHECK_GT(coeff, 0);
446}
447
448} // namespace sat
449} // namespace operations_research
450
451#endif // OR_TOOLS_SAT_INTEGER_BASE_H_
bool AddSquareTo(IntegerValue a, IntegerValue *result)
Computes result += a * a, and return false iff there is an overflow.
constexpr double kInfinity
Infinity for type Fractional.
Definition lp_types.h:87
IntegerValue FloorRatio(IntegerValue dividend, IntegerValue positive_divisor)
bool AddProductTo(IntegerValue a, IntegerValue b, IntegerValue *result)
Computes result += a * b, and return false iff there is an overflow.
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
bool AddTo(IntegerValue a, IntegerValue *result)
IntType IntTypeAbs(IntType t)
IntegerValue CeilRatio(IntegerValue dividend, IntegerValue positive_divisor)
bool ProdOverflow(IntegerValue t, IntegerValue value)
const LiteralIndex kNoLiteralIndex(-1)
std::string IntegerTermDebugString(IntegerVariable var, IntegerValue coeff)
std::vector< IntegerVariable > NegationOf(absl::Span< const IntegerVariable > vars)
Returns the vector of the negated variables.
Definition integer.cc:52
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue.value())
const IntegerVariable kNoIntegerVariable(-1)
const IntervalVariable kNoIntervalVariable(-1)
IntegerVariable PositiveVariable(IntegerVariable i)
std::ostream & operator<<(std::ostream &os, const BoolVar &var)
Definition cp_model.cc:89
IntegerValue PositiveRemainder(IntegerValue dividend, IntegerValue positive_divisor)
IntegerValue CapAddI(IntegerValue a, IntegerValue b)
H AbslHashValue(H h, const IntVar &i)
– ABSL HASHING SUPPORT --------------------------------------------------—
Definition cp_model.h:515
PositiveOnlyIndex GetPositiveOnlyIndex(IntegerVariable var)
bool VariableIsPositive(IntegerVariable i)
IntegerValue CapSubI(IntegerValue a, IntegerValue b)
bool AtMinOrMaxInt64I(IntegerValue t)
IntegerValue CapProdI(IntegerValue a, IntegerValue b)
Overflows and saturated arithmetic.
double ToDouble(IntegerValue value)
In SWIG mode, we don't want anything besides these top-level includes.
bool AtMinOrMaxInt64(int64_t x)
Checks if x is equal to the min or the max value of an int64_t.
int64_t CapAdd(int64_t x, int64_t y)
int64_t CapSub(int64_t x, int64_t y)
int64_t CapProd(int64_t x, int64_t y)
#define DEFINE_STRONG_INT64_TYPE(integer_type_name)
#define DEFINE_STRONG_INDEX_TYPE(index_type_name)
IntegerLiteral GreaterOrEqual(IntegerValue bound) const
var * coeff + constant >= bound.
bool operator==(AffineExpression o) const
AffineExpression MultipliedBy(IntegerValue multiplier) const
AffineExpression(IntegerVariable v, IntegerValue c, IntegerValue cst)
AffineExpression()=default
Helper to construct an AffineExpression.
IntegerValue ValueAt(IntegerValue var_value) const
Returns the value of this affine expression given its variable value.
AffineExpression(IntegerVariable v, IntegerValue c)
double LpValue(const util_intops::StrongVector< IntegerVariable, double > &lp_values) const
Returns the affine expression value under a given LP solution.
IntegerLiteral LowerOrEqual(IntegerValue bound) const
var * coeff + constant <= bound.
util_intops::StrongVector< IntegerVariable, bool > ivar_has_value
util_intops::StrongVector< IntegerVariable, IntegerValue > ivar_values
bool operator==(IntegerLiteral o) const
static IntegerLiteral GreaterOrEqual(IntegerVariable i, IntegerValue bound)
IntegerLiteral Negated() const
The negation of x >= bound is x <= bound - 1.
static IntegerLiteral LowerOrEqual(IntegerVariable i, IntegerValue bound)
IntegerLiteral(IntegerVariable v, IntegerValue b)
bool operator!=(IntegerLiteral o) const
IntegerLiteral()
Clients should prefer the static construction methods above.
bool operator()(const ValueLiteralPair &a, const ValueLiteralPair &b) const
bool operator()(const ValueLiteralPair &a, const ValueLiteralPair &b) const
bool operator==(const ValueLiteralPair &o) const