Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
integer_expr.h
Go to the documentation of this file.
1// Copyright 2010-2024 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_EXPR_H_
15#define OR_TOOLS_SAT_INTEGER_EXPR_H_
16
17#include <algorithm>
18#include <cmath>
19#include <cstdint>
20#include <cstdlib>
21#include <functional>
22#include <memory>
23#include <utility>
24#include <vector>
25
26#include "absl/log/check.h"
27#include "absl/types/span.h"
28#include "ortools/sat/integer.h"
31#include "ortools/sat/model.h"
34#include "ortools/sat/sat_parameters.pb.h"
38
39namespace operations_research {
40namespace sat {
41
42// A really basic implementation of an upper-bounded sum of integer variables.
43// The complexity is in O(num_variables) at each propagation.
44//
45// Note that we assume that there can be NO integer overflow. This must be
46// checked at model validation time before this is even created. If
47// use_int128 is true, then we actually do the computations that could overflow
48// in 128 bits, so that we can deal with constraints that might overflow (like
49// the one scaled from the LP relaxation). Note that we still use some
50// preconditions, such that for each variable the difference between their
51// bounds fit on an int64_t.
52//
53// TODO(user): Technically we could still have an int128 overflow since we
54// sum n terms that cannot overflow but can still be pretty close to the limit.
55// Make sure this never happens! For most problem though, because the variable
56// bounds will be smaller than 10^9, we are pretty safe.
57//
58// TODO(user): If one has many such constraint, it will be more efficient to
59// propagate all of them at once rather than doing it one at the time.
60//
61// TODO(user): Explore tree structure to get a log(n) complexity.
62//
63// TODO(user): When the variables are Boolean, use directly the pseudo-Boolean
64// constraint implementation. But we do need support for enforcement literals
65// there.
66template <bool use_int128 = false>
69 public:
70 // If refied_literal is kNoLiteralIndex then this is a normal constraint,
71 // otherwise we enforce the implication refied_literal => constraint is true.
72 // Note that we don't do the reverse implication here, it is usually done by
73 // another LinearConstraintPropagator constraint on the negated variables.
74 LinearConstraintPropagator(absl::Span<const Literal> enforcement_literals,
75 absl::Span<const IntegerVariable> vars,
76 absl::Span<const IntegerValue> coeffs,
77 IntegerValue upper_bound, Model* model);
78
79 // This version allow to std::move the memory from the LinearConstraint
80 // directly. It Only uses the upper bound. Id does not support
81 // enforcement_literals.
83
84 // We propagate:
85 // - If the sum of the individual lower-bound is > upper_bound, we fail.
86 // - For all i, upper-bound of i
87 // <= upper_bound - Sum {individual lower-bound excluding i).
88 bool Propagate() final;
90
91 // Same as Propagate() but only consider current root level bounds. This is
92 // mainly useful for the LP propagator since it can find relevant optimal
93 // really late in the search tree.
95
96 // This is a pretty usage specific function. Returns the implied lower bound
97 // on target_var if the given integer literal is false (resp. true). If the
98 // variables do not appear both in the linear inequality, this returns two
99 // kMinIntegerValue.
100 std::pair<IntegerValue, IntegerValue> ConditionalLb(
101 IntegerLiteral integer_literal, IntegerVariable target_var) const;
102
103 // For LazyReasonInterface.
104 void Explain(int id, IntegerValue propagation_slack,
105 IntegerVariable var_to_explain, int trail_index,
106 std::vector<Literal>* literals_reason,
107 std::vector<int>* trail_indices_reason) final;
108
109 private:
110 // Fills integer_reason_ with all the current lower_bounds. The real
111 // explanation may require removing one of them, but as an optimization, we
112 // always keep all the IntegerLiteral in integer_reason_, and swap them as
113 // needed just before pushing something.
114 void FillIntegerReason();
115
116 const IntegerValue upper_bound_;
117
118 // To gain a bit on memory (since we might have many linear constraint),
119 // we share this amongst all of them. Note that this is not accessed by
120 // two different thread though. Also the vector are only used as "temporary"
121 // so they are okay to be shared.
122 struct Shared {
123 explicit Shared(Model* model)
124 : assignment(model->GetOrCreate<Trail>()->Assignment()),
125 integer_trail(model->GetOrCreate<IntegerTrail>()),
126 time_limit(model->GetOrCreate<TimeLimit>()),
127 rev_int_repository(model->GetOrCreate<RevIntRepository>()),
128 rev_integer_value_repository(
129 model->GetOrCreate<RevIntegerValueRepository>()) {}
130
131 const VariablesAssignment& assignment;
132 IntegerTrail* integer_trail;
133 TimeLimit* time_limit;
134 RevIntRepository* rev_int_repository;
135 RevIntegerValueRepository* rev_integer_value_repository;
136
137 // Parallel vectors.
138 std::vector<IntegerLiteral> integer_reason;
139 std::vector<IntegerValue> reason_coeffs;
140 };
141 Shared* shared_;
142
143 // Reversible sum of the lower bound of the fixed variables.
144 bool is_registered_ = false;
145 IntegerValue rev_lb_fixed_vars_;
146
147 // Reversible number of fixed variables.
148 int rev_num_fixed_vars_;
149
150 // Those vectors are shuffled during search to ensure that the variables
151 // (resp. coefficients) contained in the range [0, rev_num_fixed_vars_) of
152 // vars_ (resp. coeffs_) are fixed (resp. belong to fixed variables).
153 const int size_;
154 const std::unique_ptr<IntegerVariable[]> vars_;
155 const std::unique_ptr<IntegerValue[]> coeffs_;
156 const std::unique_ptr<IntegerValue[]> max_variations_;
157
158 // This is just the negation of the enforcement literal and it never changes.
159 std::vector<Literal> literal_reason_;
160};
161
164
165// Explicit instantiations in integer_expr.cc.
166extern template class LinearConstraintPropagator<true>;
167extern template class LinearConstraintPropagator<false>;
168
169// This assumes target = SUM_i coeffs[i] * vars[i], and detects that the target
170// must be of the form (a*X + b).
171//
172// This propagator is quite specific and runs only at level zero. For now, this
173// is mainly used for the objective variable. As we fix terms with high
174// objective coefficient, it is possible the only terms left have a common
175// divisor. This close app2-2.mps in less than a second instead of running
176// forever to prove the optimal (in single thread).
178 public:
179 LevelZeroEquality(IntegerVariable target,
180 const std::vector<IntegerVariable>& vars,
181 const std::vector<IntegerValue>& coeffs, Model* model);
182
183 bool Propagate() final;
184
185 private:
186 const IntegerVariable target_;
187 const std::vector<IntegerVariable> vars_;
188 const std::vector<IntegerValue> coeffs_;
189
190 IntegerValue gcd_ = IntegerValue(1);
191
192 Trail* trail_;
193 IntegerTrail* integer_trail_;
194};
195
196// A min (resp max) constraint of the form min == MIN(vars) can be decomposed
197// into two inequalities:
198// 1/ min <= MIN(vars), which is the same as for all v in vars, "min <= v".
199// This can be taken care of by the LowerOrEqual(min, v) constraint.
200// 2/ min >= MIN(vars).
201//
202// And in turn, 2/ can be decomposed in:
203// a) lb(min) >= lb(MIN(vars)) = MIN(lb(var));
204// b) ub(min) >= ub(MIN(vars)) and we can't propagate anything here unless
205// there is just one possible variable 'v' that can be the min:
206// for all u != v, lb(u) > ub(min);
207// In this case, ub(min) >= ub(v).
208//
209// This constraint take care of a) and b). That is:
210// - If the min of the lower bound of the vars increase, then the lower bound of
211// the min_var will be >= to it.
212// - If there is only one candidate for the min, then if the ub(min) decrease,
213// the ub of the only candidate will be <= to it.
214//
215// Complexity: This is a basic implementation in O(num_vars) on each call to
216// Propagate(), which will happen each time one or more variables in vars_
217// changed.
218//
219// TODO(user): Implement a more efficient algorithm when the need arise.
221 public:
222 MinPropagator(const std::vector<IntegerVariable>& vars,
223 IntegerVariable min_var, IntegerTrail* integer_trail);
224
225 // This type is neither copyable nor movable.
226 MinPropagator(const MinPropagator&) = delete;
228
229 bool Propagate() final;
230 void RegisterWith(GenericLiteralWatcher* watcher);
231
232 private:
233 const std::vector<IntegerVariable> vars_;
234 const IntegerVariable min_var_;
235 IntegerTrail* integer_trail_;
236
237 std::vector<IntegerLiteral> integer_reason_;
238};
239
240// Same as MinPropagator except this works on min = MIN(exprs) where exprs are
241// linear expressions. It uses IntegerSumLE to propagate bounds on the exprs.
242// Assumes Canonical expressions (all positive coefficients).
244 public:
245 LinMinPropagator(const std::vector<LinearExpression>& exprs,
246 IntegerVariable min_var, Model* model);
249
250 bool Propagate() final;
251 void RegisterWith(GenericLiteralWatcher* watcher);
252
253 // For LazyReasonInterface.
254 void Explain(int id, IntegerValue propagation_slack,
255 IntegerVariable var_to_explain, int trail_index,
256 std::vector<Literal>* literals_reason,
257 std::vector<int>* trail_indices_reason) final;
258
259 private:
260 // Lighter version of IntegerSumLE. This uses the current value of
261 // integer_reason_ in addition to the reason for propagating the linear
262 // constraint. The coeffs are assumed to be positive here.
263 bool PropagateLinearUpperBound(int id, absl::Span<const IntegerVariable> vars,
264 absl::Span<const IntegerValue> coeffs,
265 IntegerValue upper_bound);
266
267 const std::vector<LinearExpression> exprs_;
268 const IntegerVariable min_var_;
269 std::vector<IntegerValue> expr_lbs_;
270 Model* model_;
271 IntegerTrail* integer_trail_;
272 std::vector<IntegerValue> max_variations_;
273 std::vector<IntegerValue> reason_coeffs_;
274 std::vector<IntegerLiteral> local_reason_;
275 std::vector<IntegerLiteral> integer_reason_for_unique_candidate_;
276 int rev_unique_candidate_ = 0;
277};
278
279// Propagates a * b = p.
280//
281// The bounds [min, max] of a and b will be propagated perfectly, but not
282// the bounds on p as this require more complex arithmetics.
284 public:
286 IntegerTrail* integer_trail);
287
288 // This type is neither copyable nor movable.
291
292 bool Propagate() final;
293 void RegisterWith(GenericLiteralWatcher* watcher);
294
295 private:
296 // Maybe replace a_, b_ or c_ by their negation to simplify the cases.
297 bool CanonicalizeCases();
298
299 // Special case when all are >= 0.
300 // We use faster code and better reasons than the generic code.
301 bool PropagateWhenAllNonNegative();
302
303 // Internal helper, see code for more details.
304 bool PropagateMaxOnPositiveProduct(AffineExpression a, AffineExpression b,
305 IntegerValue min_p, IntegerValue max_p);
306
307 // Note that we might negate any two terms in CanonicalizeCases() during
308 // each propagation. This is fine.
312
313 IntegerTrail* integer_trail_;
314};
315
316// Propagates num / denom = div. Basic version, we don't extract any special
317// cases, and we only propagates the bounds. It expects denom to be > 0.
318//
319// TODO(user): Deal with overflow.
321 public:
323 AffineExpression div, IntegerTrail* integer_trail);
324
325 // This type is neither copyable nor movable.
328
329 bool Propagate() final;
330 void RegisterWith(GenericLiteralWatcher* watcher);
331
332 private:
333 // Propagates the fact that the signs of each domain, if fixed, are
334 // compatible.
335 bool PropagateSigns(AffineExpression num, AffineExpression denom,
336 AffineExpression div);
337
338 // If both num and div >= 0, we can propagate their upper bounds.
339 bool PropagateUpperBounds(AffineExpression num, AffineExpression denom,
340 AffineExpression div);
341
342 // When the sign of all 3 expressions are fixed, we can do morel propagation.
343 //
344 // By using negated expressions, we can make sure the domains of num, denom,
345 // and div are positive.
346 bool PropagatePositiveDomains(AffineExpression num, AffineExpression denom,
347 AffineExpression div);
348
349 const AffineExpression num_;
350 const AffineExpression denom_;
351 const AffineExpression div_;
352 const AffineExpression negated_denom_;
353 const AffineExpression negated_num_;
354 const AffineExpression negated_div_;
355 IntegerTrail* integer_trail_;
356};
357
358// Propagates var_a / cst_b = var_c. Basic version, we don't extract any special
359// cases, and we only propagates the bounds. cst_b must be > 0.
361 public:
363 AffineExpression c, IntegerTrail* integer_trail);
364
365 // This type is neither copyable nor movable.
368
369 bool Propagate() final;
370 void RegisterWith(GenericLiteralWatcher* watcher);
371
372 private:
373 const AffineExpression a_;
374 const IntegerValue b_;
375 const AffineExpression c_;
376
377 IntegerTrail* integer_trail_;
378};
379
380// Propagates target == expr % mod. Basic version, we don't extract any special
381// cases, and we only propagates the bounds. mod must be > 0.
383 public:
384 FixedModuloPropagator(AffineExpression expr, IntegerValue mod,
385 AffineExpression target, IntegerTrail* integer_trail);
386
387 // This type is neither copyable nor movable.
390
391 bool Propagate() final;
392 void RegisterWith(GenericLiteralWatcher* watcher);
393
394 private:
395 bool PropagateSignsAndTargetRange();
396 bool PropagateBoundsWhenExprIsPositive(AffineExpression expr,
397 AffineExpression target);
398 bool PropagateOuterBounds();
399
401 const IntegerValue mod_;
402 const AffineExpression target_;
403 const AffineExpression negated_expr_;
404 const AffineExpression negated_target_;
405 IntegerTrail* integer_trail_;
406};
407
408// Propagates x * x = s.
409// TODO(user): Only works for x nonnegative.
411 public:
413 IntegerTrail* integer_trail);
414
415 // This type is neither copyable nor movable.
418
419 bool Propagate() final;
420 void RegisterWith(GenericLiteralWatcher* watcher);
421
422 private:
423 const AffineExpression x_;
424 const AffineExpression s_;
425 IntegerTrail* integer_trail_;
426};
427
428// =============================================================================
429// Model based functions.
430// =============================================================================
431
432// Weighted sum <= constant.
433template <typename VectorInt>
434inline std::function<void(Model*)> WeightedSumLowerOrEqual(
435 const std::vector<IntegerVariable>& vars, const VectorInt& coefficients,
436 int64_t upper_bound) {
437 return [=](Model* model) {
439 model);
440 };
441}
442
443// Weighted sum >= constant.
444template <typename VectorInt>
445inline std::function<void(Model*)> WeightedSumGreaterOrEqual(
446 const std::vector<IntegerVariable>& vars, const VectorInt& coefficients,
447 int64_t lower_bound) {
448 // We just negate everything and use an <= constraints.
449 std::vector<int64_t> negated_coeffs(coefficients.begin(), coefficients.end());
450 for (int64_t& ref : negated_coeffs) ref = -ref;
451 return WeightedSumLowerOrEqual(vars, negated_coeffs, -lower_bound);
452}
453
454// Weighted sum == constant.
455template <typename VectorInt>
456inline std::function<void(Model*)> FixedWeightedSum(
457 const std::vector<IntegerVariable>& vars, const VectorInt& coefficients,
458 int64_t value) {
459 return [=](Model* model) {
462 };
463}
464
465// enforcement_literals => sum <= upper_bound
467 absl::Span<const Literal> enforcement_literals,
468 absl::Span<const IntegerVariable> vars,
469 absl::Span<const int64_t> coefficients, int64_t upper_bound, Model* model) {
470 // Linear1.
471 DCHECK_GE(vars.size(), 1);
472 if (vars.size() == 1) {
473 DCHECK_NE(coefficients[0], 0);
474 IntegerVariable var = vars[0];
475 IntegerValue coeff(coefficients[0]);
476 if (coeff < 0) {
477 var = NegationOf(var);
478 coeff = -coeff;
479 }
480 const IntegerValue rhs = FloorRatio(IntegerValue(upper_bound), coeff);
481 if (enforcement_literals.empty()) {
482 model->Add(LowerOrEqual(var, rhs.value()));
483 } else {
484 model->Add(Implication(enforcement_literals,
486 }
487 return;
488 }
489
490 // Detect precedences with 2 and 3 terms.
491 const SatParameters& params = *model->GetOrCreate<SatParameters>();
492 if (!params.new_linear_propagation()) {
493 if (vars.size() == 2 && (coefficients[0] == 1 || coefficients[0] == -1) &&
494 (coefficients[1] == 1 || coefficients[1] == -1)) {
496 enforcement_literals,
497 coefficients[0] == 1 ? vars[0] : NegationOf(vars[0]),
498 coefficients[1] == 1 ? vars[1] : NegationOf(vars[1]), upper_bound,
499 model);
500 return;
501 }
502 if (vars.size() == 3 && (coefficients[0] == 1 || coefficients[0] == -1) &&
503 (coefficients[1] == 1 || coefficients[1] == -1) &&
504 (coefficients[2] == 1 || coefficients[2] == -1)) {
506 enforcement_literals,
507 coefficients[0] == 1 ? vars[0] : NegationOf(vars[0]),
508 coefficients[1] == 1 ? vars[1] : NegationOf(vars[1]),
509 coefficients[2] == 1 ? vars[2] : NegationOf(vars[2]), upper_bound,
510 model);
511 return;
512 }
513 }
514
515 // If value == min(expression), then we can avoid creating the sum.
516 //
517 // TODO(user): Deal with the case with no enforcement literal, in case the
518 // presolve was turned off?
519 if (!enforcement_literals.empty()) {
520 IntegerValue expression_min(0);
521 auto* integer_trail = model->GetOrCreate<IntegerTrail>();
522 for (int i = 0; i < vars.size(); ++i) {
523 expression_min +=
524 coefficients[i] * (coefficients[i] >= 0
525 ? integer_trail->LevelZeroLowerBound(vars[i])
526 : integer_trail->LevelZeroUpperBound(vars[i]));
527 }
528 if (expression_min == upper_bound) {
529 // Tricky: as we create integer literal, we might propagate stuff and
530 // the bounds might change, so if the expression_min increase with the
531 // bound we use, then the literal must be false.
532 IntegerValue non_cached_min;
533 for (int i = 0; i < vars.size(); ++i) {
534 if (coefficients[i] > 0) {
535 const IntegerValue lb = integer_trail->LevelZeroLowerBound(vars[i]);
536 non_cached_min += coefficients[i] * lb;
537 model->Add(Implication(enforcement_literals,
538 IntegerLiteral::LowerOrEqual(vars[i], lb)));
539 } else if (coefficients[i] < 0) {
540 const IntegerValue ub = integer_trail->LevelZeroUpperBound(vars[i]);
541 non_cached_min += coefficients[i] * ub;
542 model->Add(Implication(enforcement_literals,
544 }
545 }
546 if (non_cached_min > expression_min) {
547 std::vector<Literal> clause;
548 for (const Literal l : enforcement_literals) {
549 clause.push_back(l.Negated());
550 }
551 model->Add(ClauseConstraint(clause));
552 }
553 return;
554 }
555 }
556
557 if (params.new_linear_propagation()) {
558 const bool ok = model->GetOrCreate<LinearPropagator>()->AddConstraint(
559 enforcement_literals, vars,
560 std::vector<IntegerValue>(coefficients.begin(), coefficients.end()),
561 IntegerValue(upper_bound));
562 if (!ok) {
563 auto* sat_solver = model->GetOrCreate<SatSolver>();
564 if (sat_solver->CurrentDecisionLevel() == 0) {
565 sat_solver->NotifyThatModelIsUnsat();
566 } else {
567 LOG(FATAL) << "We currently do not support adding conflicting "
568 "constraint at positive level.";
569 }
570 }
571 } else {
572 IntegerSumLE* constraint = new IntegerSumLE(
573 enforcement_literals, vars,
574 std::vector<IntegerValue>(coefficients.begin(), coefficients.end()),
575 IntegerValue(upper_bound), model);
576 constraint->RegisterWith(model->GetOrCreate<GenericLiteralWatcher>());
577 model->TakeOwnership(constraint);
578 }
579}
580
581// enforcement_literals => sum >= lower_bound
583 absl::Span<const Literal> enforcement_literals,
584 absl::Span<const IntegerVariable> vars,
585 absl::Span<const int64_t> coefficients, int64_t lower_bound, Model* model) {
586 // We just negate everything and use an <= constraint.
587 std::vector<int64_t> negated_coeffs(coefficients.begin(), coefficients.end());
588 for (int64_t& ref : negated_coeffs) ref = -ref;
589 AddWeightedSumLowerOrEqual(enforcement_literals, vars, negated_coeffs,
591}
592
593// TODO(user): Delete once Telamon use new function.
594inline std::function<void(Model*)> ConditionalWeightedSumLowerOrEqual(
595 const std::vector<Literal>& enforcement_literals,
596 const std::vector<IntegerVariable>& vars,
597 const std::vector<int64_t>& coefficients, int64_t upper_bound) {
598 return [=](Model* model) {
599 AddWeightedSumLowerOrEqual(enforcement_literals, vars, coefficients,
601 };
602}
603inline std::function<void(Model*)> ConditionalWeightedSumGreaterOrEqual(
604 const std::vector<Literal>& enforcement_literals,
605 const std::vector<IntegerVariable>& vars,
606 const std::vector<int64_t>& coefficients, int64_t upper_bound) {
607 return [=](Model* model) {
608 AddWeightedSumGreaterOrEqual(enforcement_literals, vars, coefficients,
610 };
611}
612
613// LinearConstraint version.
615 const absl::Span<const Literal> enforcement_literals,
617 if (cst.num_terms == 0) {
618 if (cst.lb <= 0 && cst.ub >= 0) return;
619
620 // The enforcement literals cannot be all at true.
621 std::vector<Literal> clause;
622 for (const Literal lit : enforcement_literals) {
623 clause.push_back(lit.Negated());
624 }
625 return model->Add(ClauseConstraint(clause));
626 }
627
628 // TODO(user): Remove the conversion!
629 std::vector<IntegerVariable> vars(cst.num_terms);
630 std::vector<int64_t> coeffs(cst.num_terms);
631 for (int i = 0; i < cst.num_terms; ++i) {
632 vars[i] = cst.vars[i];
633 coeffs[i] = cst.coeffs[i].value();
634 }
635
636 if (cst.ub < kMaxIntegerValue) {
637 AddWeightedSumLowerOrEqual(enforcement_literals, vars, coeffs,
638 cst.ub.value(), model);
639 }
640 if (cst.lb > kMinIntegerValue) {
641 AddWeightedSumGreaterOrEqual(enforcement_literals, vars, coeffs,
642 cst.lb.value(), model);
643 }
644}
645
646inline void LoadLinearConstraint(const LinearConstraint& cst, Model* model) {
649
651 const absl::Span<const Literal> enforcement_literals, AffineExpression left,
654 builder.AddTerm(left, 1);
655 builder.AddTerm(right, -1);
656 LoadConditionalLinearConstraint(enforcement_literals, builder.Build(), model);
657}
658
659// Model-based function to create an IntegerVariable that corresponds to the
660// given weighted sum of other IntegerVariables.
661//
662// Note that this is templated so that it can seamlessly accept vector<int> or
663// vector<int64_t>.
664//
665// TODO(user): invert the coefficients/vars arguments.
666template <typename VectorInt>
667inline std::function<IntegerVariable(Model*)> NewWeightedSum(
668 const VectorInt& coefficients, const std::vector<IntegerVariable>& vars) {
669 return [=](Model* model) {
670 std::vector<IntegerVariable> new_vars = vars;
671 // To avoid overflow in the FixedWeightedSum() constraint, we need to
672 // compute the basic bounds on the sum.
673 //
674 // TODO(user): deal with overflow here too!
675 int64_t sum_lb(0);
676 int64_t sum_ub(0);
677 for (int i = 0; i < new_vars.size(); ++i) {
678 if (coefficients[i] > 0) {
679 sum_lb += coefficients[i] * model->Get(LowerBound(new_vars[i]));
680 sum_ub += coefficients[i] * model->Get(UpperBound(new_vars[i]));
681 } else {
682 sum_lb += coefficients[i] * model->Get(UpperBound(new_vars[i]));
683 sum_ub += coefficients[i] * model->Get(LowerBound(new_vars[i]));
684 }
685 }
686
687 const IntegerVariable sum = model->Add(NewIntegerVariable(sum_lb, sum_ub));
688 new_vars.push_back(sum);
689 std::vector<int64_t> new_coeffs(coefficients.begin(), coefficients.end());
690 new_coeffs.push_back(-1);
691 model->Add(FixedWeightedSum(new_vars, new_coeffs, 0));
692 return sum;
693 };
694}
695
696// Expresses the fact that an existing integer variable is equal to the minimum
697// of other integer variables.
698inline std::function<void(Model*)> IsEqualToMinOf(
699 IntegerVariable min_var, const std::vector<IntegerVariable>& vars) {
700 return [=](Model* model) {
701 for (const IntegerVariable& var : vars) {
702 model->Add(LowerOrEqual(min_var, var));
703 }
704
705 MinPropagator* constraint =
706 new MinPropagator(vars, min_var, model->GetOrCreate<IntegerTrail>());
707 constraint->RegisterWith(model->GetOrCreate<GenericLiteralWatcher>());
708 model->TakeOwnership(constraint);
709 };
710}
711
712// Expresses the fact that an existing integer variable is equal to the minimum
713// of linear expressions. Assumes Canonical expressions (all positive
714// coefficients).
715inline std::function<void(Model*)> IsEqualToMinOf(
716 const LinearExpression& min_expr,
717 const std::vector<LinearExpression>& exprs) {
718 return [=](Model* model) {
719 IntegerTrail* integer_trail = model->GetOrCreate<IntegerTrail>();
720
721 IntegerVariable min_var;
722 if (min_expr.vars.size() == 1 &&
723 std::abs(min_expr.coeffs[0].value()) == 1 && min_expr.offset == 0) {
724 if (min_expr.coeffs[0].value() == 1) {
725 min_var = min_expr.vars[0];
726 } else {
727 min_var = NegationOf(min_expr.vars[0]);
728 }
729 } else {
730 // Create a new variable if the expression is not just a single variable.
731 IntegerValue min_lb = min_expr.Min(*integer_trail);
732 IntegerValue min_ub = min_expr.Max(*integer_trail);
733 min_var = integer_trail->AddIntegerVariable(min_lb, min_ub);
734
735 // min_var = min_expr
736 LinearConstraintBuilder builder(0, 0);
737 builder.AddLinearExpression(min_expr, 1);
738 builder.AddTerm(min_var, -1);
739 LoadLinearConstraint(builder.Build(), model);
740 }
741 for (const LinearExpression& expr : exprs) {
743 builder.AddLinearExpression(expr, 1);
744 builder.AddTerm(min_var, -1);
745 LoadLinearConstraint(builder.Build(), model);
746 }
747
748 LinMinPropagator* constraint = new LinMinPropagator(exprs, min_var, model);
749 constraint->RegisterWith(model->GetOrCreate<GenericLiteralWatcher>());
750 model->TakeOwnership(constraint);
751 };
752}
753
754// Expresses the fact that an existing integer variable is equal to the maximum
755// of other integer variables.
756inline std::function<void(Model*)> IsEqualToMaxOf(
757 IntegerVariable max_var, const std::vector<IntegerVariable>& vars) {
758 return [=](Model* model) {
759 std::vector<IntegerVariable> negated_vars;
760 for (const IntegerVariable& var : vars) {
761 negated_vars.push_back(NegationOf(var));
762 model->Add(GreaterOrEqual(max_var, var));
763 }
764
765 MinPropagator* constraint = new MinPropagator(
766 negated_vars, NegationOf(max_var), model->GetOrCreate<IntegerTrail>());
767 constraint->RegisterWith(model->GetOrCreate<GenericLiteralWatcher>());
768 model->TakeOwnership(constraint);
769 };
770}
771
772// Expresses the fact that an existing integer variable is equal to one of
773// the given values, each selected by a given literal.
774std::function<void(Model*)> IsOneOf(IntegerVariable var,
775 const std::vector<Literal>& selectors,
776 const std::vector<IntegerValue>& values);
777
778template <class T>
779void RegisterAndTransferOwnership(Model* model, T* ct) {
780 ct->RegisterWith(model->GetOrCreate<GenericLiteralWatcher>());
781 model->TakeOwnership(ct);
782}
783// Adds the constraint: a * b = p.
784inline std::function<void(Model*)> ProductConstraint(AffineExpression a,
785 AffineExpression b,
787 return [=](Model* model) {
788 IntegerTrail* integer_trail = model->GetOrCreate<IntegerTrail>();
789 if (a == b) {
790 if (integer_trail->LowerBound(a) >= 0) {
792 new SquarePropagator(a, p, integer_trail));
793 return;
794 }
795 if (integer_trail->UpperBound(a) <= 0) {
797 model, new SquarePropagator(a.Negated(), p, integer_trail));
798 return;
799 }
800 }
802 new ProductPropagator(a, b, p, integer_trail));
803 };
804}
805
806// Adds the constraint: num / denom = div. (denom > 0).
807inline std::function<void(Model*)> DivisionConstraint(AffineExpression num,
808 AffineExpression denom,
810 return [=](Model* model) {
811 IntegerTrail* integer_trail = model->GetOrCreate<IntegerTrail>();
812 DivisionPropagator* constraint;
813 if (integer_trail->UpperBound(denom) < 0) {
814 constraint = new DivisionPropagator(num.Negated(), denom.Negated(), div,
815 integer_trail);
816
817 } else {
818 constraint = new DivisionPropagator(num, denom, div, integer_trail);
819 }
820 constraint->RegisterWith(model->GetOrCreate<GenericLiteralWatcher>());
821 model->TakeOwnership(constraint);
822 };
823}
824
825// Adds the constraint: a / b = c where b is a constant.
826inline std::function<void(Model*)> FixedDivisionConstraint(AffineExpression a,
827 IntegerValue b,
829 return [=](Model* model) {
830 IntegerTrail* integer_trail = model->GetOrCreate<IntegerTrail>();
831 FixedDivisionPropagator* constraint =
832 b > 0 ? new FixedDivisionPropagator(a, b, c, integer_trail)
833 : new FixedDivisionPropagator(a.Negated(), -b, c, integer_trail);
834 constraint->RegisterWith(model->GetOrCreate<GenericLiteralWatcher>());
835 model->TakeOwnership(constraint);
836 };
837}
838
839// Adds the constraint: a % b = c where b is a constant.
840inline std::function<void(Model*)> FixedModuloConstraint(AffineExpression a,
841 IntegerValue b,
843 return [=](Model* model) {
844 IntegerTrail* integer_trail = model->GetOrCreate<IntegerTrail>();
845 FixedModuloPropagator* constraint =
846 new FixedModuloPropagator(a, b, c, integer_trail);
847 constraint->RegisterWith(model->GetOrCreate<GenericLiteralWatcher>());
848 model->TakeOwnership(constraint);
849 };
850}
851
852} // namespace sat
853} // namespace operations_research
854
855#endif // OR_TOOLS_SAT_INTEGER_EXPR_H_
const std::vector< IntVar * > vars_
void RegisterWith(GenericLiteralWatcher *watcher)
DivisionPropagator(const DivisionPropagator &)=delete
This type is neither copyable nor movable.
DivisionPropagator & operator=(const DivisionPropagator &)=delete
FixedDivisionPropagator(const FixedDivisionPropagator &)=delete
This type is neither copyable nor movable.
FixedDivisionPropagator & operator=(const FixedDivisionPropagator &)=delete
FixedModuloPropagator & operator=(const FixedModuloPropagator &)=delete
FixedModuloPropagator(const FixedModuloPropagator &)=delete
This type is neither copyable nor movable.
IntegerValue LowerBound(IntegerVariable i) const
Returns the current lower/upper bound of the given integer variable.
Definition integer.h:1717
IntegerValue UpperBound(IntegerVariable i) const
Definition integer.h:1721
IntegerValue LevelZeroUpperBound(IntegerVariable var) const
Definition integer.h:1817
IntegerValue LevelZeroLowerBound(IntegerVariable var) const
Returns globally valid lower/upper bound on the given integer variable.
Definition integer.h:1812
IntegerVariable AddIntegerVariable(IntegerValue lower_bound, IntegerValue upper_bound)
Definition integer.cc:837
LinMinPropagator & operator=(const LinMinPropagator &)=delete
void RegisterWith(GenericLiteralWatcher *watcher)
LinMinPropagator(const LinMinPropagator &)=delete
void AddTerm(IntegerVariable var, IntegerValue coeff)
void AddLinearExpression(const LinearExpression &expr)
std::pair< IntegerValue, IntegerValue > ConditionalLb(IntegerLiteral integer_literal, IntegerVariable target_var) const
NOTE(user): This is only used with int128, so we code only a single version.
void RegisterWith(GenericLiteralWatcher *watcher)
LinearConstraintPropagator(absl::Span< const Literal > enforcement_literals, absl::Span< const IntegerVariable > vars, absl::Span< const IntegerValue > coeffs, IntegerValue upper_bound, Model *model)
void Explain(int id, IntegerValue propagation_slack, IntegerVariable var_to_explain, int trail_index, std::vector< Literal > *literals_reason, std::vector< int > *trail_indices_reason) final
For LazyReasonInterface.
MinPropagator(const MinPropagator &)=delete
This type is neither copyable nor movable.
void RegisterWith(GenericLiteralWatcher *watcher)
MinPropagator & operator=(const MinPropagator &)=delete
ProductPropagator(const ProductPropagator &)=delete
This type is neither copyable nor movable.
ProductPropagator & operator=(const ProductPropagator &)=delete
Base class for CP like propagators.
Definition integer.h:1414
SquarePropagator(const SquarePropagator &)=delete
This type is neither copyable nor movable.
SquarePropagator & operator=(const SquarePropagator &)=delete
const VariablesAssignment & Assignment() const
Definition sat_base.h:462
int64_t a
Definition table.cc:44
const Constraint * ct
int64_t value
IntVar *const expr_
Definition element.cc:88
IntVar * var
double upper_bound
double lower_bound
absl::Span< const double > coefficients
GRBmodel * model
int lit
IntegerValue FloorRatio(IntegerValue dividend, IntegerValue positive_divisor)
Definition integer.h:94
std::function< void(Model *)> WeightedSumGreaterOrEqual(const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64_t lower_bound)
Weighted sum >= constant.
std::function< void(Model *)> IsOneOf(IntegerVariable var, const std::vector< Literal > &selectors, const std::vector< IntegerValue > &values)
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
std::function< void(Model *)> WeightedSumLowerOrEqual(const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64_t upper_bound)
Weighted sum <= constant.
std::function< void(Model *)> ProductConstraint(AffineExpression a, AffineExpression b, AffineExpression p)
Adds the constraint: a * b = p.
std::function< void(Model *)> ClauseConstraint(absl::Span< const Literal > literals)
Definition sat_solver.h:933
std::function< int64_t(const Model &)> LowerBound(IntegerVariable v)
Definition integer.h:1955
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
Returns the vector of the negated variables.
Definition integer.cc:51
std::function< void(Model *)> LowerOrEqual(IntegerVariable v, int64_t ub)
Definition integer.h:1998
std::function< void(Model *)> FixedDivisionConstraint(AffineExpression a, IntegerValue b, AffineExpression c)
Adds the constraint: a / b = c where b is a constant.
void LoadConditionalLinearConstraint(const absl::Span< const Literal > enforcement_literals, const LinearConstraint &cst, Model *model)
LinearConstraint version.
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue.value())
std::function< void(Model *)> Implication(absl::Span< const Literal > enforcement_literals, IntegerLiteral i)
Definition integer.h:2025
std::function< void(Model *)> IsEqualToMaxOf(IntegerVariable max_var, const std::vector< IntegerVariable > &vars)
std::function< void(Model *)> DivisionConstraint(AffineExpression num, AffineExpression denom, AffineExpression div)
Adds the constraint: num / denom = div. (denom > 0).
void AddConditionalAffinePrecedence(const absl::Span< const Literal > enforcement_literals, AffineExpression left, AffineExpression right, Model *model)
void RegisterAndTransferOwnership(Model *model, T *ct)
void AddWeightedSumLowerOrEqual(absl::Span< const Literal > enforcement_literals, absl::Span< const IntegerVariable > vars, absl::Span< const int64_t > coefficients, int64_t upper_bound, Model *model)
enforcement_literals => sum <= upper_bound
std::function< void(Model *)> ConditionalWeightedSumGreaterOrEqual(const std::vector< Literal > &enforcement_literals, const std::vector< IntegerVariable > &vars, const std::vector< int64_t > &coefficients, int64_t upper_bound)
std::function< int64_t(const Model &)> UpperBound(IntegerVariable v)
Definition integer.h:1961
std::function< void(Model *)> ConditionalWeightedSumLowerOrEqual(const std::vector< Literal > &enforcement_literals, const std::vector< IntegerVariable > &vars, const std::vector< int64_t > &coefficients, int64_t upper_bound)
std::function< void(Model *)> IsEqualToMinOf(IntegerVariable min_var, const std::vector< IntegerVariable > &vars)
std::function< IntegerVariable(Model *)> NewIntegerVariable(int64_t lb, int64_t ub)
Definition integer.h:1907
std::function< void(Model *)> GreaterOrEqual(IntegerVariable v, int64_t lb)
Definition integer.h:1983
void AddConditionalSum3LowerOrEqual(absl::Span< const Literal > enforcement_literals, IntegerVariable a, IntegerVariable b, IntegerVariable c, int64_t ub, Model *model)
std::function< IntegerVariable(Model *)> NewWeightedSum(const VectorInt &coefficients, const std::vector< IntegerVariable > &vars)
std::function< void(Model *)> FixedModuloConstraint(AffineExpression a, IntegerValue b, AffineExpression c)
Adds the constraint: a % b = c where b is a constant.
void LoadLinearConstraint(const ConstraintProto &ct, Model *m)
void AddWeightedSumGreaterOrEqual(absl::Span< const Literal > enforcement_literals, absl::Span< const IntegerVariable > vars, absl::Span< const int64_t > coefficients, int64_t lower_bound, Model *model)
enforcement_literals => sum >= lower_bound
LinearConstraintPropagator< false > IntegerSumLE
void AddConditionalSum2LowerOrEqual(absl::Span< const Literal > enforcement_literals, IntegerVariable a, IntegerVariable b, int64_t ub, Model *model)
l => (a + b <= ub).
std::function< void(Model *)> FixedWeightedSum(const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64_t value)
Weighted sum == constant.
In SWIG mode, we don't want anything besides these top-level includes.
STL namespace.
const Variable x
Definition qp_tests.cc:127
static IntegerLiteral GreaterOrEqual(IntegerVariable i, IntegerValue bound)
Definition integer.h:1667
static IntegerLiteral LowerOrEqual(IntegerVariable i, IntegerValue bound)
Definition integer.h:1673
std::unique_ptr< IntegerValue[]> coeffs
std::unique_ptr< IntegerVariable[]> vars