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