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