OR-Tools  9.3
integer_expr.h
Go to the documentation of this file.
1// Copyright 2010-2021 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 <utility>
23#include <vector>
24
25#include "absl/types/span.h"
28#include "ortools/base/macros.h"
30#include "ortools/sat/integer.h"
32#include "ortools/sat/model.h"
36#include "ortools/util/rev.h"
39
40namespace operations_research {
41namespace sat {
42
43// A really basic implementation of an upper-bounded sum of integer variables.
44// The complexity is in O(num_variables) at each propagation.
45//
46// Note that we assume that there can be NO integer overflow. This must be
47// checked at model validation time before this is even created.
48//
49// TODO(user): If one has many such constraint, it will be more efficient to
50// propagate all of them at once rather than doing it one at the time.
51//
52// TODO(user): Explore tree structure to get a log(n) complexity.
53//
54// TODO(user): When the variables are Boolean, use directly the pseudo-Boolean
55// constraint implementation. But we do need support for enforcement literals
56// there.
58 public:
59 // If refied_literal is kNoLiteralIndex then this is a normal constraint,
60 // otherwise we enforce the implication refied_literal => constraint is true.
61 // Note that we don't do the reverse implication here, it is usually done by
62 // another IntegerSumLE constraint on the negated variables.
63 IntegerSumLE(const std::vector<Literal>& enforcement_literals,
64 const std::vector<IntegerVariable>& vars,
65 const std::vector<IntegerValue>& coeffs,
66 IntegerValue upper_bound, Model* model);
67
68 // We propagate:
69 // - If the sum of the individual lower-bound is > upper_bound, we fail.
70 // - For all i, upper-bound of i
71 // <= upper_bound - Sum {individual lower-bound excluding i).
72 bool Propagate() final;
74
75 // Same as Propagate() but only consider current root level bounds. This is
76 // mainly useful for the LP propagator since it can find relevant optimal
77 // really late in the search tree.
79
80 // This is a pretty usage specific function. Returns the implied lower bound
81 // on target_var if the given integer literal is false (resp. true). If the
82 // variables do not appear both in the linear inequality, this returns two
83 // kMinIntegerValue.
84 std::pair<IntegerValue, IntegerValue> ConditionalLb(
85 IntegerLiteral integer_literal, IntegerVariable target_var) const;
86
87 private:
88 // Fills integer_reason_ with all the current lower_bounds. The real
89 // explanation may require removing one of them, but as an optimization, we
90 // always keep all the IntegerLiteral in integer_reason_, and swap them as
91 // needed just before pushing something.
92 void FillIntegerReason();
93
94 const std::vector<Literal> enforcement_literals_;
95 const IntegerValue upper_bound_;
96
97 Trail* trail_;
98 IntegerTrail* integer_trail_;
99 TimeLimit* time_limit_;
100 RevIntegerValueRepository* rev_integer_value_repository_;
101
102 // Reversible sum of the lower bound of the fixed variables.
103 bool is_registered_ = false;
104 IntegerValue rev_lb_fixed_vars_;
105
106 // Reversible number of fixed variables.
107 int rev_num_fixed_vars_;
108
109 // Those vectors are shuffled during search to ensure that the variables
110 // (resp. coefficients) contained in the range [0, rev_num_fixed_vars_) of
111 // vars_ (resp. coeffs_) are fixed (resp. belong to fixed variables).
112 std::vector<IntegerVariable> vars_;
113 std::vector<IntegerValue> coeffs_;
114 std::vector<IntegerValue> max_variations_;
115
116 std::vector<Literal> literal_reason_;
117
118 // Parallel vectors.
119 std::vector<IntegerLiteral> integer_reason_;
120 std::vector<IntegerValue> reason_coeffs_;
121
122 DISALLOW_COPY_AND_ASSIGN(IntegerSumLE);
123};
124
125// This assumes target = SUM_i coeffs[i] * vars[i], and detects that the target
126// must be of the form (a*X + b).
127//
128// This propagator is quite specific and runs only at level zero. For now, this
129// is mainly used for the objective variable. As we fix terms with high
130// objective coefficient, it is possible the only terms left have a common
131// divisor. This close app2-2.mps in less than a second instead of running
132// forever to prove the optimal (in single thread).
134 public:
135 LevelZeroEquality(IntegerVariable target,
136 const std::vector<IntegerVariable>& vars,
137 const std::vector<IntegerValue>& coeffs, Model* model);
138
139 bool Propagate() final;
140
141 private:
142 const IntegerVariable target_;
143 const std::vector<IntegerVariable> vars_;
144 const std::vector<IntegerValue> coeffs_;
145
146 IntegerValue gcd_ = IntegerValue(1);
147
148 Trail* trail_;
149 IntegerTrail* integer_trail_;
150};
151
152// A min (resp max) constraint of the form min == MIN(vars) can be decomposed
153// into two inequalities:
154// 1/ min <= MIN(vars), which is the same as for all v in vars, "min <= v".
155// This can be taken care of by the LowerOrEqual(min, v) constraint.
156// 2/ min >= MIN(vars).
157//
158// And in turn, 2/ can be decomposed in:
159// a) lb(min) >= lb(MIN(vars)) = MIN(lb(var));
160// b) ub(min) >= ub(MIN(vars)) and we can't propagate anything here unless
161// there is just one possible variable 'v' that can be the min:
162// for all u != v, lb(u) > ub(min);
163// In this case, ub(min) >= ub(v).
164//
165// This constraint take care of a) and b). That is:
166// - If the min of the lower bound of the vars increase, then the lower bound of
167// the min_var will be >= to it.
168// - If there is only one candidate for the min, then if the ub(min) decrease,
169// the ub of the only candidate will be <= to it.
170//
171// Complexity: This is a basic implementation in O(num_vars) on each call to
172// Propagate(), which will happen each time one or more variables in vars_
173// changed.
174//
175// TODO(user): Implement a more efficient algorithm when the need arise.
177 public:
178 MinPropagator(const std::vector<IntegerVariable>& vars,
179 IntegerVariable min_var, IntegerTrail* integer_trail);
180
181 bool Propagate() final;
182 void RegisterWith(GenericLiteralWatcher* watcher);
183
184 private:
185 const std::vector<IntegerVariable> vars_;
186 const IntegerVariable min_var_;
187 IntegerTrail* integer_trail_;
188
189 std::vector<IntegerLiteral> integer_reason_;
190
191 DISALLOW_COPY_AND_ASSIGN(MinPropagator);
192};
193
194// Same as MinPropagator except this works on min = MIN(exprs) where exprs are
195// linear expressions. It uses IntegerSumLE to propagate bounds on the exprs.
196// Assumes Canonical expressions (all positive coefficients).
198 public:
199 LinMinPropagator(const std::vector<LinearExpression>& exprs,
200 IntegerVariable min_var, Model* model);
203
204 bool Propagate() final;
205 void RegisterWith(GenericLiteralWatcher* watcher);
206
207 private:
208 // Lighter version of IntegerSumLE. This uses the current value of
209 // integer_reason_ in addition to the reason for propagating the linear
210 // constraint. The coeffs are assumed to be positive here.
211 bool PropagateLinearUpperBound(const std::vector<IntegerVariable>& vars,
212 const std::vector<IntegerValue>& coeffs,
213 IntegerValue upper_bound);
214
215 const std::vector<LinearExpression> exprs_;
216 const IntegerVariable min_var_;
217 std::vector<IntegerValue> expr_lbs_;
218 Model* model_;
219 IntegerTrail* integer_trail_;
220 std::vector<IntegerLiteral> integer_reason_for_unique_candidate_;
221 int rev_unique_candidate_ = 0;
222};
223
224// Propagates a * b = p.
225//
226// The bounds [min, max] of a and b will be propagated perfectly, but not
227// the bounds on p as this require more complex arithmetics.
229 public:
231 IntegerTrail* integer_trail);
232
233 bool Propagate() final;
234 void RegisterWith(GenericLiteralWatcher* watcher);
235
236 private:
237 // Maybe replace a_, b_ or c_ by their negation to simplify the cases.
238 bool CanonicalizeCases();
239
240 // Special case when all are >= 0.
241 // We use faster code and better reasons than the generic code.
242 bool PropagateWhenAllNonNegative();
243
244 // Internal helper, see code for more details.
245 bool PropagateMaxOnPositiveProduct(AffineExpression a, AffineExpression b,
246 IntegerValue min_p, IntegerValue max_p);
247
248 // Note that we might negate any two terms in CanonicalizeCases() during
249 // each propagation. This is fine.
253
254 IntegerTrail* integer_trail_;
255
257};
258
259// Propagates num / denom = div. Basic version, we don't extract any special
260// cases, and we only propagates the bounds. It expects denom to be > 0.
261//
262// TODO(user): Deal with overflow.
264 public:
266 AffineExpression div, IntegerTrail* integer_trail);
267
268 bool Propagate() final;
269 void RegisterWith(GenericLiteralWatcher* watcher);
270
271 private:
272 // Propagates the fact that the signs of each domain, if fixed, are
273 // compatible.
274 bool PropagateSigns();
275
276 // If both num and div >= 0, we can propagate their upper bounds.
277 bool PropagateUpperBounds(AffineExpression num, AffineExpression denom,
278 AffineExpression div);
279
280 // When the sign of all 3 expressions are fixed, we can do morel propagation.
281 //
282 // By using negated expressions, we can make sure the domains of num, denom,
283 // and div are positive.
284 bool PropagatePositiveDomains(AffineExpression num, AffineExpression denom,
285 AffineExpression div);
286
287 const AffineExpression num_;
288 const AffineExpression denom_;
289 const AffineExpression div_;
290 const AffineExpression negated_num_;
291 const AffineExpression negated_div_;
292 IntegerTrail* integer_trail_;
293
295};
296
297// Propagates var_a / cst_b = var_c. Basic version, we don't extract any special
298// cases, and we only propagates the bounds. cst_b must be > 0.
300 public:
302 AffineExpression c, IntegerTrail* integer_trail);
303
304 bool Propagate() final;
305 void RegisterWith(GenericLiteralWatcher* watcher);
306
307 private:
308 const AffineExpression a_;
309 const IntegerValue b_;
310 const AffineExpression c_;
311
312 IntegerTrail* integer_trail_;
313
315};
316
317// Propagates target == expr % mod. Basic version, we don't extract any special
318// cases, and we only propagates the bounds. mod must be > 0.
320 public:
321 FixedModuloPropagator(AffineExpression expr, IntegerValue mod,
322 AffineExpression target, IntegerTrail* integer_trail);
323
324 bool Propagate() final;
325 void RegisterWith(GenericLiteralWatcher* watcher);
326
327 private:
328 bool PropagateSignsAndTargetRange();
329 bool PropagateBoundsWhenExprIsPositive(AffineExpression expr,
330 AffineExpression target);
331 bool PropagateOuterBounds();
332
334 const IntegerValue mod_;
335 const AffineExpression target_;
336 const AffineExpression negated_expr_;
337 const AffineExpression negated_target_;
338 IntegerTrail* integer_trail_;
339
341};
342
343// Propagates x * x = s.
344// TODO(user): Only works for x nonnegative.
346 public:
348 IntegerTrail* integer_trail);
349
350 bool Propagate() final;
351 void RegisterWith(GenericLiteralWatcher* watcher);
352
353 private:
354 const AffineExpression x_;
355 const AffineExpression s_;
356 IntegerTrail* integer_trail_;
357
359};
360
361// =============================================================================
362// Model based functions.
363// =============================================================================
364
365// Weighted sum <= constant.
366template <typename VectorInt>
367inline std::function<void(Model*)> WeightedSumLowerOrEqual(
368 const std::vector<IntegerVariable>& vars, const VectorInt& coefficients,
369 int64_t upper_bound) {
370 // Special cases.
371 CHECK_GE(vars.size(), 1);
372 if (vars.size() == 1) {
373 const int64_t c = coefficients[0];
374 CHECK_NE(c, 0);
375 if (c > 0) {
376 return LowerOrEqual(
377 vars[0],
378 FloorRatio(IntegerValue(upper_bound), IntegerValue(c)).value());
379 } else {
380 return GreaterOrEqual(
381 vars[0],
382 CeilRatio(IntegerValue(-upper_bound), IntegerValue(-c)).value());
383 }
384 }
385 if (vars.size() == 2 && (coefficients[0] == 1 || coefficients[0] == -1) &&
386 (coefficients[1] == 1 || coefficients[1] == -1)) {
387 return Sum2LowerOrEqual(
388 coefficients[0] == 1 ? vars[0] : NegationOf(vars[0]),
389 coefficients[1] == 1 ? vars[1] : NegationOf(vars[1]), upper_bound);
390 }
391 if (vars.size() == 3 && (coefficients[0] == 1 || coefficients[0] == -1) &&
392 (coefficients[1] == 1 || coefficients[1] == -1) &&
393 (coefficients[2] == 1 || coefficients[2] == -1)) {
394 return Sum3LowerOrEqual(
395 coefficients[0] == 1 ? vars[0] : NegationOf(vars[0]),
396 coefficients[1] == 1 ? vars[1] : NegationOf(vars[1]),
397 coefficients[2] == 1 ? vars[2] : NegationOf(vars[2]), upper_bound);
398 }
399
400 return [=](Model* model) {
401 // We split large constraints into a square root number of parts.
402 // This is to avoid a bad complexity while propagating them since our
403 // algorithm is not in O(num_changes).
404 //
405 // TODO(user): Alternatively, we could use a O(num_changes) propagation (a
406 // bit tricky to implement), or a decomposition into a tree with more than
407 // one level. Both requires experimentations.
408 //
409 // TODO(user): If the initial constraint was an equalilty we will create
410 // the "intermediate" variable twice where we could have use the same for
411 // both direction. Improve?
412 const int num_vars = vars.size();
413 if (num_vars > 100) {
414 std::vector<IntegerVariable> bucket_sum_vars;
415
416 std::vector<IntegerVariable> local_vars;
417 std::vector<IntegerValue> local_coeffs;
418
419 int i = 0;
420 const int num_buckets = static_cast<int>(std::round(std::sqrt(num_vars)));
421 for (int b = 0; b < num_buckets; ++b) {
422 local_vars.clear();
423 local_coeffs.clear();
424 int64_t bucket_lb = 0;
425 int64_t bucket_ub = 0;
426 const int limit = num_vars * (b + 1);
427 for (; i * num_buckets < limit; ++i) {
428 local_vars.push_back(vars[i]);
429 local_coeffs.push_back(IntegerValue(coefficients[i]));
430 const int64_t term1 =
431 model->Get(LowerBound(vars[i])) * coefficients[i];
432 const int64_t term2 =
433 model->Get(UpperBound(vars[i])) * coefficients[i];
434 bucket_lb += std::min(term1, term2);
435 bucket_ub += std::max(term1, term2);
436 }
437
438 const IntegerVariable bucket_sum =
439 model->Add(NewIntegerVariable(bucket_lb, bucket_ub));
440 bucket_sum_vars.push_back(bucket_sum);
441 local_vars.push_back(bucket_sum);
442 local_coeffs.push_back(IntegerValue(-1));
443 IntegerSumLE* constraint = new IntegerSumLE(
444 {}, local_vars, local_coeffs, IntegerValue(0), model);
445 constraint->RegisterWith(model->GetOrCreate<GenericLiteralWatcher>());
446 model->TakeOwnership(constraint);
447 }
448
449 // Create the root-level sum.
450 local_vars.clear();
451 local_coeffs.clear();
452 for (const IntegerVariable var : bucket_sum_vars) {
453 local_vars.push_back(var);
454 local_coeffs.push_back(IntegerValue(1));
455 }
456 IntegerSumLE* constraint = new IntegerSumLE(
457 {}, local_vars, local_coeffs, IntegerValue(upper_bound), model);
458 constraint->RegisterWith(model->GetOrCreate<GenericLiteralWatcher>());
459 model->TakeOwnership(constraint);
460 return;
461 }
462
463 IntegerSumLE* constraint = new IntegerSumLE(
464 {}, vars,
465 std::vector<IntegerValue>(coefficients.begin(), coefficients.end()),
466 IntegerValue(upper_bound), model);
467 constraint->RegisterWith(model->GetOrCreate<GenericLiteralWatcher>());
468 model->TakeOwnership(constraint);
469 };
470}
471
472// Weighted sum >= constant.
473template <typename VectorInt>
474inline std::function<void(Model*)> WeightedSumGreaterOrEqual(
475 const std::vector<IntegerVariable>& vars, const VectorInt& coefficients,
476 int64_t lower_bound) {
477 // We just negate everything and use an <= constraints.
478 std::vector<int64_t> negated_coeffs(coefficients.begin(), coefficients.end());
479 for (int64_t& ref : negated_coeffs) ref = -ref;
480 return WeightedSumLowerOrEqual(vars, negated_coeffs, -lower_bound);
481}
482
483// Weighted sum == constant.
484template <typename VectorInt>
485inline std::function<void(Model*)> FixedWeightedSum(
486 const std::vector<IntegerVariable>& vars, const VectorInt& coefficients,
487 int64_t value) {
488 return [=](Model* model) {
491 };
492}
493
494// enforcement_literals => sum <= upper_bound
495template <typename VectorInt>
496inline std::function<void(Model*)> ConditionalWeightedSumLowerOrEqual(
497 const std::vector<Literal>& enforcement_literals,
498 const std::vector<IntegerVariable>& vars, const VectorInt& coefficients,
499 int64_t upper_bound) {
500 // Special cases.
501 CHECK_GE(vars.size(), 1);
502 if (vars.size() == 1) {
503 CHECK_NE(coefficients[0], 0);
504 if (coefficients[0] > 0) {
505 return Implication(
506 enforcement_literals,
508 vars[0], FloorRatio(IntegerValue(upper_bound),
509 IntegerValue(coefficients[0]))));
510 } else {
511 return Implication(
512 enforcement_literals,
514 vars[0], CeilRatio(IntegerValue(-upper_bound),
515 IntegerValue(-coefficients[0]))));
516 }
517 }
518
519 if (vars.size() == 2 && (coefficients[0] == 1 || coefficients[0] == -1) &&
520 (coefficients[1] == 1 || coefficients[1] == -1)) {
522 coefficients[0] == 1 ? vars[0] : NegationOf(vars[0]),
523 coefficients[1] == 1 ? vars[1] : NegationOf(vars[1]), upper_bound,
524 enforcement_literals);
525 }
526 if (vars.size() == 3 && (coefficients[0] == 1 || coefficients[0] == -1) &&
527 (coefficients[1] == 1 || coefficients[1] == -1) &&
528 (coefficients[2] == 1 || coefficients[2] == -1)) {
530 coefficients[0] == 1 ? vars[0] : NegationOf(vars[0]),
531 coefficients[1] == 1 ? vars[1] : NegationOf(vars[1]),
532 coefficients[2] == 1 ? vars[2] : NegationOf(vars[2]), upper_bound,
533 enforcement_literals);
534 }
535
536 return [=](Model* model) {
537 // If value == min(expression), then we can avoid creating the sum.
538 IntegerValue expression_min(0);
539 auto* integer_trail = model->GetOrCreate<IntegerTrail>();
540 for (int i = 0; i < vars.size(); ++i) {
541 expression_min +=
542 coefficients[i] * (coefficients[i] >= 0
543 ? integer_trail->LowerBound(vars[i])
544 : integer_trail->UpperBound(vars[i]));
545 }
546 if (expression_min == upper_bound) {
547 // Tricky: as we create integer literal, we might propagate stuff and
548 // the bounds might change, so if the expression_min increase with the
549 // bound we use, then the literal must be false.
550 IntegerValue non_cached_min;
551 for (int i = 0; i < vars.size(); ++i) {
552 if (coefficients[i] > 0) {
553 const IntegerValue lb = integer_trail->LowerBound(vars[i]);
554 non_cached_min += coefficients[i] * lb;
555 model->Add(Implication(enforcement_literals,
556 IntegerLiteral::LowerOrEqual(vars[i], lb)));
557 } else if (coefficients[i] < 0) {
558 const IntegerValue ub = integer_trail->UpperBound(vars[i]);
559 non_cached_min += coefficients[i] * ub;
560 model->Add(Implication(enforcement_literals,
561 IntegerLiteral::GreaterOrEqual(vars[i], ub)));
562 }
563 }
564 if (non_cached_min > expression_min) {
565 std::vector<Literal> clause;
566 for (const Literal l : enforcement_literals) {
567 clause.push_back(l.Negated());
568 }
569 model->Add(ClauseConstraint(clause));
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
582// enforcement_literals => sum >= lower_bound
583template <typename VectorInt>
584inline std::function<void(Model*)> ConditionalWeightedSumGreaterOrEqual(
585 const std::vector<Literal>& enforcement_literals,
586 const std::vector<IntegerVariable>& vars, const VectorInt& coefficients,
587 int64_t lower_bound) {
588 // We just negate everything and use an <= constraint.
589 std::vector<int64_t> negated_coeffs(coefficients.begin(), coefficients.end());
590 for (int64_t& ref : negated_coeffs) ref = -ref;
591 return ConditionalWeightedSumLowerOrEqual(enforcement_literals, vars,
592 negated_coeffs, -lower_bound);
593}
594
595// Weighted sum <= constant reified.
596template <typename VectorInt>
597inline std::function<void(Model*)> WeightedSumLowerOrEqualReif(
598 Literal is_le, const std::vector<IntegerVariable>& vars,
599 const VectorInt& coefficients, int64_t upper_bound) {
600 return [=](Model* model) {
602 upper_bound));
604 {is_le.Negated()}, vars, coefficients, upper_bound + 1));
605 };
606}
607
608// Weighted sum >= constant reified.
609template <typename VectorInt>
610inline std::function<void(Model*)> WeightedSumGreaterOrEqualReif(
611 Literal is_ge, const std::vector<IntegerVariable>& vars,
612 const VectorInt& coefficients, int64_t lower_bound) {
613 return [=](Model* model) {
615 lower_bound));
617 {is_ge.Negated()}, vars, coefficients, lower_bound - 1));
618 };
619}
620
621// LinearConstraint version.
623 if (cst.vars.empty()) {
624 if (cst.lb <= 0 && cst.ub >= 0) return;
625 model->GetOrCreate<SatSolver>()->NotifyThatModelIsUnsat();
626 return;
627 }
628
629 // TODO(user): Remove the conversion!
630 std::vector<int64_t> converted_coeffs;
631
632 for (const IntegerValue v : cst.coeffs) converted_coeffs.push_back(v.value());
633 if (cst.ub < kMaxIntegerValue) {
634 model->Add(
635 WeightedSumLowerOrEqual(cst.vars, converted_coeffs, cst.ub.value()));
636 }
637 if (cst.lb > kMinIntegerValue) {
638 model->Add(
639 WeightedSumGreaterOrEqual(cst.vars, converted_coeffs, cst.lb.value()));
640 }
641}
642
644 const absl::Span<const Literal> enforcement_literals,
645 const LinearConstraint& cst, Model* model) {
646 if (enforcement_literals.empty()) {
647 return LoadLinearConstraint(cst, model);
648 }
649 if (cst.vars.empty()) {
650 if (cst.lb <= 0 && cst.ub >= 0) return;
651 return model->Add(ClauseConstraint(enforcement_literals));
652 }
653
654 // TODO(user): Remove the conversion!
655 std::vector<Literal> converted_literals(enforcement_literals.begin(),
656 enforcement_literals.end());
657 std::vector<int64_t> converted_coeffs;
658 for (const IntegerValue v : cst.coeffs) converted_coeffs.push_back(v.value());
659
660 if (cst.ub < kMaxIntegerValue) {
662 converted_literals, cst.vars, converted_coeffs, cst.ub.value()));
663 }
664 if (cst.lb > kMinIntegerValue) {
666 converted_literals, cst.vars, converted_coeffs, cst.lb.value()));
667 }
668}
669
670// Weighted sum == constant reified.
671// TODO(user): Simplify if the constant is at the edge of the possible values.
672template <typename VectorInt>
673inline std::function<void(Model*)> FixedWeightedSumReif(
674 Literal is_eq, const std::vector<IntegerVariable>& vars,
675 const VectorInt& coefficients, int64_t value) {
676 return [=](Model* model) {
677 // We creates two extra Boolean variables in this case. The alternative is
678 // to code a custom propagator for the direction equality => reified.
679 const Literal is_le = Literal(model->Add(NewBooleanVariable()), true);
680 const Literal is_ge = Literal(model->Add(NewBooleanVariable()), true);
681 model->Add(ReifiedBoolAnd({is_le, is_ge}, is_eq));
684 };
685}
686
687// Weighted sum != constant.
688// TODO(user): Simplify if the constant is at the edge of the possible values.
689template <typename VectorInt>
690inline std::function<void(Model*)> WeightedSumNotEqual(
691 const std::vector<IntegerVariable>& vars, const VectorInt& coefficients,
692 int64_t value) {
693 return [=](Model* model) {
694 // Exactly one of these alternative must be true.
695 const Literal is_lt = Literal(model->Add(NewBooleanVariable()), true);
696 const Literal is_gt = is_lt.Negated();
698 value - 1));
700 value + 1));
701 };
702}
703
704// Model-based function to create an IntegerVariable that corresponds to the
705// given weighted sum of other IntegerVariables.
706//
707// Note that this is templated so that it can seamlessly accept vector<int> or
708// vector<int64_t>.
709//
710// TODO(user): invert the coefficients/vars arguments.
711template <typename VectorInt>
712inline std::function<IntegerVariable(Model*)> NewWeightedSum(
713 const VectorInt& coefficients, const std::vector<IntegerVariable>& vars) {
714 return [=](Model* model) {
715 std::vector<IntegerVariable> new_vars = vars;
716 // To avoid overflow in the FixedWeightedSum() constraint, we need to
717 // compute the basic bounds on the sum.
718 //
719 // TODO(user): deal with overflow here too!
720 int64_t sum_lb(0);
721 int64_t sum_ub(0);
722 for (int i = 0; i < new_vars.size(); ++i) {
723 if (coefficients[i] > 0) {
724 sum_lb += coefficients[i] * model->Get(LowerBound(new_vars[i]));
725 sum_ub += coefficients[i] * model->Get(UpperBound(new_vars[i]));
726 } else {
727 sum_lb += coefficients[i] * model->Get(UpperBound(new_vars[i]));
728 sum_ub += coefficients[i] * model->Get(LowerBound(new_vars[i]));
729 }
730 }
731
732 const IntegerVariable sum = model->Add(NewIntegerVariable(sum_lb, sum_ub));
733 new_vars.push_back(sum);
734 std::vector<int64_t> new_coeffs(coefficients.begin(), coefficients.end());
735 new_coeffs.push_back(-1);
736 model->Add(FixedWeightedSum(new_vars, new_coeffs, 0));
737 return sum;
738 };
739}
740
741// Expresses the fact that an existing integer variable is equal to the minimum
742// of other integer variables.
743inline std::function<void(Model*)> IsEqualToMinOf(
744 IntegerVariable min_var, const std::vector<IntegerVariable>& vars) {
745 return [=](Model* model) {
746 for (const IntegerVariable& var : vars) {
747 model->Add(LowerOrEqual(min_var, var));
748 }
749
750 MinPropagator* constraint =
751 new MinPropagator(vars, min_var, model->GetOrCreate<IntegerTrail>());
752 constraint->RegisterWith(model->GetOrCreate<GenericLiteralWatcher>());
753 model->TakeOwnership(constraint);
754 };
755}
756
757// Expresses the fact that an existing integer variable is equal to the minimum
758// of linear expressions. Assumes Canonical expressions (all positive
759// coefficients).
760inline std::function<void(Model*)> IsEqualToMinOf(
761 const LinearExpression& min_expr,
762 const std::vector<LinearExpression>& exprs) {
763 return [=](Model* model) {
764 IntegerTrail* integer_trail = model->GetOrCreate<IntegerTrail>();
765
766 IntegerVariable min_var;
767 if (min_expr.vars.size() == 1 &&
768 std::abs(min_expr.coeffs[0].value()) == 1 && min_expr.offset == 0) {
769 if (min_expr.coeffs[0].value() == 1) {
770 min_var = min_expr.vars[0];
771 } else {
772 min_var = NegationOf(min_expr.vars[0]);
773 }
774 } else {
775 // Create a new variable if the expression is not just a single variable.
776 IntegerValue min_lb = LinExprLowerBound(min_expr, *integer_trail);
777 IntegerValue min_ub = LinExprUpperBound(min_expr, *integer_trail);
778 min_var = integer_trail->AddIntegerVariable(min_lb, min_ub);
779
780 // min_var = min_expr
781 std::vector<IntegerVariable> min_sum_vars = min_expr.vars;
782 std::vector<int64_t> min_sum_coeffs;
783 for (IntegerValue coeff : min_expr.coeffs) {
784 min_sum_coeffs.push_back(coeff.value());
785 }
786 min_sum_vars.push_back(min_var);
787 min_sum_coeffs.push_back(-1);
788
789 model->Add(FixedWeightedSum(min_sum_vars, min_sum_coeffs,
790 -min_expr.offset.value()));
791 }
792 for (const LinearExpression& expr : exprs) {
793 // min_var <= expr
794 std::vector<IntegerVariable> vars = expr.vars;
795 std::vector<int64_t> coeffs;
796 for (IntegerValue coeff : expr.coeffs) {
797 coeffs.push_back(coeff.value());
798 }
799 vars.push_back(min_var);
800 coeffs.push_back(-1);
801 model->Add(WeightedSumGreaterOrEqual(vars, coeffs, -expr.offset.value()));
802 }
803
804 LinMinPropagator* constraint = new LinMinPropagator(exprs, min_var, model);
805 constraint->RegisterWith(model->GetOrCreate<GenericLiteralWatcher>());
806 model->TakeOwnership(constraint);
807 };
808}
809
810// Expresses the fact that an existing integer variable is equal to the maximum
811// of other integer variables.
812inline std::function<void(Model*)> IsEqualToMaxOf(
813 IntegerVariable max_var, const std::vector<IntegerVariable>& vars) {
814 return [=](Model* model) {
815 std::vector<IntegerVariable> negated_vars;
816 for (const IntegerVariable& var : vars) {
817 negated_vars.push_back(NegationOf(var));
818 model->Add(GreaterOrEqual(max_var, var));
819 }
820
821 MinPropagator* constraint = new MinPropagator(
822 negated_vars, NegationOf(max_var), model->GetOrCreate<IntegerTrail>());
823 constraint->RegisterWith(model->GetOrCreate<GenericLiteralWatcher>());
824 model->TakeOwnership(constraint);
825 };
826}
827
828// Expresses the fact that an existing integer variable is equal to one of
829// the given values, each selected by a given literal.
830std::function<void(Model*)> IsOneOf(IntegerVariable var,
831 const std::vector<Literal>& selectors,
832 const std::vector<IntegerValue>& values);
833
834template <class T>
836 ct->RegisterWith(model->GetOrCreate<GenericLiteralWatcher>());
837 model->TakeOwnership(ct);
838}
839// Adds the constraint: a * b = p.
840inline std::function<void(Model*)> ProductConstraint(AffineExpression a,
843 return [=](Model* model) {
844 IntegerTrail* integer_trail = model->GetOrCreate<IntegerTrail>();
845 if (a == b) {
846 if (integer_trail->LowerBound(a) >= 0) {
848 new SquarePropagator(a, p, integer_trail));
849 return;
850 }
851 if (integer_trail->UpperBound(a) <= 0) {
853 model, new SquarePropagator(a.Negated(), p, integer_trail));
854 return;
855 }
856 }
858 new ProductPropagator(a, b, p, integer_trail));
859 };
860}
861
862// Adds the constraint: num / denom = div. (denom > 0).
863inline std::function<void(Model*)> DivisionConstraint(AffineExpression num,
864 AffineExpression denom,
865 AffineExpression div) {
866 return [=](Model* model) {
867 IntegerTrail* integer_trail = model->GetOrCreate<IntegerTrail>();
868 DivisionPropagator* constraint;
869 if (integer_trail->UpperBound(denom) < 0) {
870 constraint = new DivisionPropagator(num.Negated(), denom.Negated(), div,
871 integer_trail);
872
873 } else {
874 constraint = new DivisionPropagator(num, denom, div, integer_trail);
875 }
876 constraint->RegisterWith(model->GetOrCreate<GenericLiteralWatcher>());
877 model->TakeOwnership(constraint);
878 };
879}
880
881// Adds the constraint: a / b = c where b is a constant.
882inline std::function<void(Model*)> FixedDivisionConstraint(AffineExpression a,
883 IntegerValue b,
885 return [=](Model* model) {
886 IntegerTrail* integer_trail = model->GetOrCreate<IntegerTrail>();
887 FixedDivisionPropagator* constraint =
888 b > 0 ? new FixedDivisionPropagator(a, b, c, integer_trail)
889 : new FixedDivisionPropagator(a.Negated(), -b, c, integer_trail);
890 constraint->RegisterWith(model->GetOrCreate<GenericLiteralWatcher>());
891 model->TakeOwnership(constraint);
892 };
893}
894
895// Adds the constraint: a % b = c where b is a constant.
896inline std::function<void(Model*)> FixedModuloConstraint(AffineExpression a,
897 IntegerValue b,
899 return [=](Model* model) {
900 IntegerTrail* integer_trail = model->GetOrCreate<IntegerTrail>();
901 FixedModuloPropagator* constraint =
902 new FixedModuloPropagator(a, b, c, integer_trail);
903 constraint->RegisterWith(model->GetOrCreate<GenericLiteralWatcher>());
904 model->TakeOwnership(constraint);
905 };
906}
907
908} // namespace sat
909} // namespace operations_research
910
911#endif // OR_TOOLS_SAT_INTEGER_EXPR_H_
int64_t max
Definition: alldiff_cst.cc:140
int64_t min
Definition: alldiff_cst.cc:139
#define CHECK_GE(val1, val2)
Definition: base/logging.h:707
#define CHECK_NE(val1, val2)
Definition: base/logging.h:704
A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...
Definition: time_limit.h:106
void RegisterWith(GenericLiteralWatcher *watcher)
std::pair< IntegerValue, IntegerValue > ConditionalLb(IntegerLiteral integer_literal, IntegerVariable target_var) const
Definition: integer_expr.cc:92
IntegerSumLE(const std::vector< Literal > &enforcement_literals, const std::vector< IntegerVariable > &vars, const std::vector< IntegerValue > &coeffs, IntegerValue upper_bound, Model *model)
Definition: integer_expr.cc:44
IntegerValue UpperBound(IntegerVariable i) const
Definition: integer.h:1449
IntegerVariable AddIntegerVariable(IntegerValue lower_bound, IntegerValue upper_bound)
Definition: integer.cc:643
IntegerValue LowerBound(IntegerVariable i) const
Definition: integer.h:1445
LevelZeroEquality(IntegerVariable target, const std::vector< IntegerVariable > &vars, const std::vector< IntegerValue > &coeffs, Model *model)
LinMinPropagator & operator=(const LinMinPropagator &)=delete
LinMinPropagator(const std::vector< LinearExpression > &exprs, IntegerVariable min_var, Model *model)
LinMinPropagator(const LinMinPropagator &)=delete
void RegisterWith(GenericLiteralWatcher *watcher)
void RegisterWith(GenericLiteralWatcher *watcher)
MinPropagator(const std::vector< IntegerVariable > &vars, IntegerVariable min_var, IntegerTrail *integer_trail)
Class that owns everything related to a particular optimization model.
Definition: sat/model.h:42
int64_t b
int64_t a
const Constraint * ct
int64_t value
IntVar *const expr_
Definition: element.cc:87
IntVar * var
Definition: expr_array.cc:1874
double upper_bound
double lower_bound
absl::Span< const double > coefficients
GRBmodel * model
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition: macros.h:29
IntegerValue FloorRatio(IntegerValue dividend, IntegerValue positive_divisor)
Definition: integer.h:98
std::function< void(Model *)> WeightedSumGreaterOrEqual(const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64_t lower_bound)
Definition: integer_expr.h:474
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
IntegerValue LinExprLowerBound(const LinearExpression &expr, const IntegerTrail &integer_trail)
IntegerValue CeilRatio(IntegerValue dividend, IntegerValue positive_divisor)
Definition: integer.h:89
std::function< void(Model *)> WeightedSumLowerOrEqual(const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64_t upper_bound)
Definition: integer_expr.h:367
std::function< void(Model *)> ProductConstraint(AffineExpression a, AffineExpression b, AffineExpression p)
Definition: integer_expr.h:840
std::function< void(Model *)> ClauseConstraint(absl::Span< const Literal > literals)
Definition: sat_solver.h:935
std::function< int64_t(const Model &)> LowerBound(IntegerVariable v)
Definition: integer.h:1663
std::function< void(Model *)> IsOneOf(IntegerVariable var, const std::vector< Literal > &selectors, const std::vector< IntegerValue > &values)
std::function< BooleanVariable(Model *)> NewBooleanVariable()
Definition: integer.h:1608
std::function< void(Model *)> LowerOrEqual(IntegerVariable v, int64_t ub)
Definition: integer.h:1706
std::function< void(Model *)> FixedDivisionConstraint(AffineExpression a, IntegerValue b, AffineExpression c)
Definition: integer_expr.h:882
void LoadConditionalLinearConstraint(const absl::Span< const Literal > enforcement_literals, const LinearConstraint &cst, Model *model)
Definition: integer_expr.h:643
std::function< void(Model *)> ConditionalWeightedSumGreaterOrEqual(const std::vector< Literal > &enforcement_literals, const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64_t lower_bound)
Definition: integer_expr.h:584
std::function< void(Model *)> WeightedSumGreaterOrEqualReif(Literal is_ge, const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64_t lower_bound)
Definition: integer_expr.h:610
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue.value())
std::function< void(Model *)> Sum2LowerOrEqual(IntegerVariable a, IntegerVariable b, int64_t ub)
Definition: precedences.h:355
std::function< void(Model *)> ConditionalWeightedSumLowerOrEqual(const std::vector< Literal > &enforcement_literals, const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64_t upper_bound)
Definition: integer_expr.h:496
std::function< void(Model *)> WeightedSumNotEqual(const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64_t value)
Definition: integer_expr.h:690
std::function< void(Model *)> IsEqualToMaxOf(IntegerVariable max_var, const std::vector< IntegerVariable > &vars)
Definition: integer_expr.h:812
std::function< void(Model *)> DivisionConstraint(AffineExpression num, AffineExpression denom, AffineExpression div)
Definition: integer_expr.h:863
std::function< void(Model *)> Implication(const std::vector< Literal > &enforcement_literals, IntegerLiteral i)
Definition: integer.h:1734
std::function< void(Model *)> WeightedSumLowerOrEqualReif(Literal is_le, const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64_t upper_bound)
Definition: integer_expr.h:597
void RegisterAndTransferOwnership(Model *model, T *ct)
Definition: integer_expr.h:835
void LoadLinearConstraint(const ConstraintProto &ct, Model *m)
std::function< int64_t(const Model &)> UpperBound(IntegerVariable v)
Definition: integer.h:1669
std::function< void(Model *)> ReifiedBoolAnd(const std::vector< Literal > &literals, Literal r)
Definition: sat_solver.h:999
std::function< void(Model *)> FixedWeightedSumReif(Literal is_eq, const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64_t value)
Definition: integer_expr.h:673
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
Definition: integer.cc:47
std::function< void(Model *)> IsEqualToMinOf(IntegerVariable min_var, const std::vector< IntegerVariable > &vars)
Definition: integer_expr.h:743
std::function< IntegerVariable(Model *)> NewIntegerVariable(int64_t lb, int64_t ub)
Definition: integer.h:1622
std::function< void(Model *)> GreaterOrEqual(IntegerVariable v, int64_t lb)
Definition: integer.h:1691
std::function< void(Model *)> ConditionalSum2LowerOrEqual(IntegerVariable a, IntegerVariable b, int64_t ub, const std::vector< Literal > &enforcement_literals)
Definition: precedences.h:362
std::function< void(Model *)> Sum3LowerOrEqual(IntegerVariable a, IntegerVariable b, IntegerVariable c, int64_t ub)
Definition: precedences.h:373
IntegerValue LinExprUpperBound(const LinearExpression &expr, const IntegerTrail &integer_trail)
std::function< IntegerVariable(Model *)> NewWeightedSum(const VectorInt &coefficients, const std::vector< IntegerVariable > &vars)
Definition: integer_expr.h:712
std::function< void(Model *)> FixedModuloConstraint(AffineExpression a, IntegerValue b, AffineExpression c)
Definition: integer_expr.h:896
std::function< void(Model *)> ConditionalSum3LowerOrEqual(IntegerVariable a, IntegerVariable b, IntegerVariable c, int64_t ub, const std::vector< Literal > &enforcement_literals)
Definition: precedences.h:384
std::function< void(Model *)> FixedWeightedSum(const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64_t value)
Definition: integer_expr.h:485
Collection of objects used to extend the Constraint Solver library.
STL namespace.
AffineExpression Negated() const
Definition: integer.h:258
static IntegerLiteral LowerOrEqual(IntegerVariable i, IntegerValue bound)
Definition: integer.h:1393
static IntegerLiteral GreaterOrEqual(IntegerVariable i, IntegerValue bound)
Definition: integer.h:1387
const double coeff