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