OR-Tools  9.0
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 
21 #include "ortools/base/int_type.h"
23 #include "ortools/base/logging.h"
24 #include "ortools/base/macros.h"
25 #include "ortools/base/mathutil.h"
26 #include "ortools/sat/integer.h"
28 #include "ortools/sat/model.h"
30 #include "ortools/sat/sat_base.h"
31 #include "ortools/sat/sat_solver.h"
32 #include "ortools/util/rev.h"
33 
34 namespace operations_research {
35 namespace 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;
67  void RegisterWith(GenericLiteralWatcher* watcher);
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.
72  bool PropagateAtLevelZero();
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) contraint 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 //
236 // TODO(user): For now this only works on variables that are non-negative.
237 // TODO(user): This only propagate the direction => c, do the reverse.
238 // TODO(user): Deal with overflow.
239 // TODO(user): Unit-test this like the ProductPropagator.
241  public:
242  DivisionPropagator(IntegerVariable a, IntegerVariable b, IntegerVariable c,
243  IntegerTrail* integer_trail);
244 
245  bool Propagate() final;
246  void RegisterWith(GenericLiteralWatcher* watcher);
247 
248  private:
249  const IntegerVariable a_;
250  const IntegerVariable b_;
251  const IntegerVariable c_;
252  IntegerTrail* integer_trail_;
253 
255 };
256 
257 // Propagates var_a / cst_b = var_c. Basic version, we don't extract any special
258 // cases, and we only propagates the bounds. cst_b must be > 0.
260  public:
261  FixedDivisionPropagator(IntegerVariable a, IntegerValue b, IntegerVariable c,
262  IntegerTrail* integer_trail);
263 
264  bool Propagate() final;
265  void RegisterWith(GenericLiteralWatcher* watcher);
266 
267  private:
268  const IntegerVariable a_;
269  const IntegerValue b_;
270  const IntegerVariable c_;
271  IntegerTrail* integer_trail_;
272 
274 };
275 
276 // Propagates x * x = s.
277 // TODO(user): Only works for x nonnegative.
279  public:
280  SquarePropagator(IntegerVariable x, IntegerVariable s,
281  IntegerTrail* integer_trail);
282 
283  bool Propagate() final;
284  void RegisterWith(GenericLiteralWatcher* watcher);
285 
286  private:
287  const IntegerVariable x_;
288  const IntegerVariable s_;
289  IntegerTrail* integer_trail_;
290 
292 };
293 
294 // =============================================================================
295 // Model based functions.
296 // =============================================================================
297 
298 // Weighted sum <= constant.
299 template <typename VectorInt>
300 inline std::function<void(Model*)> WeightedSumLowerOrEqual(
301  const std::vector<IntegerVariable>& vars, const VectorInt& coefficients,
302  int64_t upper_bound) {
303  // Special cases.
304  CHECK_GE(vars.size(), 1);
305  if (vars.size() == 1) {
306  const int64_t c = coefficients[0];
307  CHECK_NE(c, 0);
308  if (c > 0) {
309  return LowerOrEqual(
310  vars[0],
311  FloorRatio(IntegerValue(upper_bound), IntegerValue(c)).value());
312  } else {
313  return GreaterOrEqual(
314  vars[0],
315  CeilRatio(IntegerValue(-upper_bound), IntegerValue(-c)).value());
316  }
317  }
318  if (vars.size() == 2 && (coefficients[0] == 1 || coefficients[0] == -1) &&
319  (coefficients[1] == 1 || coefficients[1] == -1)) {
320  return Sum2LowerOrEqual(
321  coefficients[0] == 1 ? vars[0] : NegationOf(vars[0]),
322  coefficients[1] == 1 ? vars[1] : NegationOf(vars[1]), upper_bound);
323  }
324  if (vars.size() == 3 && (coefficients[0] == 1 || coefficients[0] == -1) &&
325  (coefficients[1] == 1 || coefficients[1] == -1) &&
326  (coefficients[2] == 1 || coefficients[2] == -1)) {
327  return Sum3LowerOrEqual(
328  coefficients[0] == 1 ? vars[0] : NegationOf(vars[0]),
329  coefficients[1] == 1 ? vars[1] : NegationOf(vars[1]),
330  coefficients[2] == 1 ? vars[2] : NegationOf(vars[2]), upper_bound);
331  }
332 
333  return [=](Model* model) {
334  // We split large constraints into a square root number of parts.
335  // This is to avoid a bad complexity while propagating them since our
336  // algorithm is not in O(num_changes).
337  //
338  // TODO(user): Alternatively, we could use a O(num_changes) propagation (a
339  // bit tricky to implement), or a decomposition into a tree with more than
340  // one level. Both requires experimentations.
341  //
342  // TODO(user): If the initial constraint was an equalilty we will create
343  // the "intermediate" variable twice where we could have use the same for
344  // both direction. Improve?
345  const int num_vars = vars.size();
346  if (num_vars > 100) {
347  std::vector<IntegerVariable> bucket_sum_vars;
348 
349  std::vector<IntegerVariable> local_vars;
350  std::vector<IntegerValue> local_coeffs;
351 
352  int i = 0;
353  const int num_buckets = static_cast<int>(std::round(std::sqrt(num_vars)));
354  for (int b = 0; b < num_buckets; ++b) {
355  local_vars.clear();
356  local_coeffs.clear();
357  int64_t bucket_lb = 0;
358  int64_t bucket_ub = 0;
359  const int limit = num_vars * (b + 1);
360  for (; i * num_buckets < limit; ++i) {
361  local_vars.push_back(vars[i]);
362  local_coeffs.push_back(IntegerValue(coefficients[i]));
363  const int64_t term1 =
364  model->Get(LowerBound(vars[i])) * coefficients[i];
365  const int64_t term2 =
366  model->Get(UpperBound(vars[i])) * coefficients[i];
367  bucket_lb += std::min(term1, term2);
368  bucket_ub += std::max(term1, term2);
369  }
370 
371  const IntegerVariable bucket_sum =
372  model->Add(NewIntegerVariable(bucket_lb, bucket_ub));
373  bucket_sum_vars.push_back(bucket_sum);
374  local_vars.push_back(bucket_sum);
375  local_coeffs.push_back(IntegerValue(-1));
376  IntegerSumLE* constraint = new IntegerSumLE(
377  {}, local_vars, local_coeffs, IntegerValue(0), model);
378  constraint->RegisterWith(model->GetOrCreate<GenericLiteralWatcher>());
379  model->TakeOwnership(constraint);
380  }
381 
382  // Create the root-level sum.
383  local_vars.clear();
384  local_coeffs.clear();
385  for (const IntegerVariable var : bucket_sum_vars) {
386  local_vars.push_back(var);
387  local_coeffs.push_back(IntegerValue(1));
388  }
389  IntegerSumLE* constraint = new IntegerSumLE(
390  {}, local_vars, local_coeffs, IntegerValue(upper_bound), model);
391  constraint->RegisterWith(model->GetOrCreate<GenericLiteralWatcher>());
392  model->TakeOwnership(constraint);
393  return;
394  }
395 
396  IntegerSumLE* constraint = new IntegerSumLE(
397  {}, vars,
398  std::vector<IntegerValue>(coefficients.begin(), coefficients.end()),
399  IntegerValue(upper_bound), model);
400  constraint->RegisterWith(model->GetOrCreate<GenericLiteralWatcher>());
401  model->TakeOwnership(constraint);
402  };
403 }
404 
405 // Weighted sum >= constant.
406 template <typename VectorInt>
407 inline std::function<void(Model*)> WeightedSumGreaterOrEqual(
408  const std::vector<IntegerVariable>& vars, const VectorInt& coefficients,
409  int64_t lower_bound) {
410  // We just negate everything and use an <= constraints.
411  std::vector<int64_t> negated_coeffs(coefficients.begin(), coefficients.end());
412  for (int64_t& ref : negated_coeffs) ref = -ref;
413  return WeightedSumLowerOrEqual(vars, negated_coeffs, -lower_bound);
414 }
415 
416 // Weighted sum == constant.
417 template <typename VectorInt>
418 inline std::function<void(Model*)> FixedWeightedSum(
419  const std::vector<IntegerVariable>& vars, const VectorInt& coefficients,
420  int64_t value) {
421  return [=](Model* model) {
424  };
425 }
426 
427 // enforcement_literals => sum <= upper_bound
428 template <typename VectorInt>
429 inline std::function<void(Model*)> ConditionalWeightedSumLowerOrEqual(
430  const std::vector<Literal>& enforcement_literals,
431  const std::vector<IntegerVariable>& vars, const VectorInt& coefficients,
432  int64_t upper_bound) {
433  // Special cases.
434  CHECK_GE(vars.size(), 1);
435  if (vars.size() == 1) {
436  CHECK_NE(coefficients[0], 0);
437  if (coefficients[0] > 0) {
438  return Implication(
439  enforcement_literals,
441  vars[0], FloorRatio(IntegerValue(upper_bound),
442  IntegerValue(coefficients[0]))));
443  } else {
444  return Implication(
445  enforcement_literals,
447  vars[0], CeilRatio(IntegerValue(-upper_bound),
448  IntegerValue(-coefficients[0]))));
449  }
450  }
451 
452  if (vars.size() == 2 && (coefficients[0] == 1 || coefficients[0] == -1) &&
453  (coefficients[1] == 1 || coefficients[1] == -1)) {
455  coefficients[0] == 1 ? vars[0] : NegationOf(vars[0]),
456  coefficients[1] == 1 ? vars[1] : NegationOf(vars[1]), upper_bound,
457  enforcement_literals);
458  }
459  if (vars.size() == 3 && (coefficients[0] == 1 || coefficients[0] == -1) &&
460  (coefficients[1] == 1 || coefficients[1] == -1) &&
461  (coefficients[2] == 1 || coefficients[2] == -1)) {
463  coefficients[0] == 1 ? vars[0] : NegationOf(vars[0]),
464  coefficients[1] == 1 ? vars[1] : NegationOf(vars[1]),
465  coefficients[2] == 1 ? vars[2] : NegationOf(vars[2]), upper_bound,
466  enforcement_literals);
467  }
468 
469  return [=](Model* model) {
470  // If value == min(expression), then we can avoid creating the sum.
471  IntegerValue expression_min(0);
472  auto* integer_trail = model->GetOrCreate<IntegerTrail>();
473  for (int i = 0; i < vars.size(); ++i) {
474  expression_min +=
475  coefficients[i] * (coefficients[i] >= 0
476  ? integer_trail->LowerBound(vars[i])
477  : integer_trail->UpperBound(vars[i]));
478  }
479  if (expression_min == upper_bound) {
480  // Tricky: as we create integer literal, we might propagate stuff and
481  // the bounds might change, so if the expression_min increase with the
482  // bound we use, then the literal must be false.
483  IntegerValue non_cached_min;
484  for (int i = 0; i < vars.size(); ++i) {
485  if (coefficients[i] > 0) {
486  const IntegerValue lb = integer_trail->LowerBound(vars[i]);
487  non_cached_min += coefficients[i] * lb;
488  model->Add(Implication(enforcement_literals,
489  IntegerLiteral::LowerOrEqual(vars[i], lb)));
490  } else if (coefficients[i] < 0) {
491  const IntegerValue ub = integer_trail->UpperBound(vars[i]);
492  non_cached_min += coefficients[i] * ub;
493  model->Add(Implication(enforcement_literals,
494  IntegerLiteral::GreaterOrEqual(vars[i], ub)));
495  }
496  }
497  if (non_cached_min > expression_min) {
498  std::vector<Literal> clause;
499  for (const Literal l : enforcement_literals) {
500  clause.push_back(l.Negated());
501  }
502  model->Add(ClauseConstraint(clause));
503  }
504  } else {
505  IntegerSumLE* constraint = new IntegerSumLE(
506  enforcement_literals, vars,
507  std::vector<IntegerValue>(coefficients.begin(), coefficients.end()),
508  IntegerValue(upper_bound), model);
509  constraint->RegisterWith(model->GetOrCreate<GenericLiteralWatcher>());
510  model->TakeOwnership(constraint);
511  }
512  };
513 }
514 
515 // enforcement_literals => sum >= lower_bound
516 template <typename VectorInt>
517 inline std::function<void(Model*)> ConditionalWeightedSumGreaterOrEqual(
518  const std::vector<Literal>& enforcement_literals,
519  const std::vector<IntegerVariable>& vars, const VectorInt& coefficients,
520  int64_t lower_bound) {
521  // We just negate everything and use an <= constraint.
522  std::vector<int64_t> negated_coeffs(coefficients.begin(), coefficients.end());
523  for (int64_t& ref : negated_coeffs) ref = -ref;
524  return ConditionalWeightedSumLowerOrEqual(enforcement_literals, vars,
525  negated_coeffs, -lower_bound);
526 }
527 
528 // Weighted sum <= constant reified.
529 template <typename VectorInt>
530 inline std::function<void(Model*)> WeightedSumLowerOrEqualReif(
531  Literal is_le, const std::vector<IntegerVariable>& vars,
532  const VectorInt& coefficients, int64_t upper_bound) {
533  return [=](Model* model) {
535  upper_bound));
537  {is_le.Negated()}, vars, coefficients, upper_bound + 1));
538  };
539 }
540 
541 // Weighted sum >= constant reified.
542 template <typename VectorInt>
543 inline std::function<void(Model*)> WeightedSumGreaterOrEqualReif(
544  Literal is_ge, const std::vector<IntegerVariable>& vars,
545  const VectorInt& coefficients, int64_t lower_bound) {
546  return [=](Model* model) {
548  lower_bound));
550  {is_ge.Negated()}, vars, coefficients, lower_bound - 1));
551  };
552 }
553 
554 // LinearConstraint version.
556  if (cst.vars.empty()) {
557  if (cst.lb <= 0 && cst.ub >= 0) return;
558  model->GetOrCreate<SatSolver>()->NotifyThatModelIsUnsat();
559  return;
560  }
561 
562  // TODO(user): Remove the conversion!
563  std::vector<int64_t> converted_coeffs;
564  for (const IntegerValue v : cst.coeffs) converted_coeffs.push_back(v.value());
565  if (cst.ub < kMaxIntegerValue) {
566  model->Add(
567  WeightedSumLowerOrEqual(cst.vars, converted_coeffs, cst.ub.value()));
568  }
569  if (cst.lb > kMinIntegerValue) {
570  model->Add(
571  WeightedSumGreaterOrEqual(cst.vars, converted_coeffs, cst.lb.value()));
572  }
573 }
574 
576  const absl::Span<const Literal> enforcement_literals,
577  const LinearConstraint& cst, Model* model) {
578  if (enforcement_literals.empty()) {
579  return LoadLinearConstraint(cst, model);
580  }
581  if (cst.vars.empty()) {
582  if (cst.lb <= 0 && cst.ub >= 0) return;
583  return model->Add(ClauseConstraint(enforcement_literals));
584  }
585 
586  // TODO(user): Remove the conversion!
587  std::vector<Literal> converted_literals(enforcement_literals.begin(),
588  enforcement_literals.end());
589  std::vector<int64_t> converted_coeffs;
590  for (const IntegerValue v : cst.coeffs) converted_coeffs.push_back(v.value());
591 
592  if (cst.ub < kMaxIntegerValue) {
594  converted_literals, cst.vars, converted_coeffs, cst.ub.value()));
595  }
596  if (cst.lb > kMinIntegerValue) {
598  converted_literals, cst.vars, converted_coeffs, cst.lb.value()));
599  }
600 }
601 
602 // Weighted sum == constant reified.
603 // TODO(user): Simplify if the constant is at the edge of the possible values.
604 template <typename VectorInt>
605 inline std::function<void(Model*)> FixedWeightedSumReif(
606  Literal is_eq, const std::vector<IntegerVariable>& vars,
607  const VectorInt& coefficients, int64_t value) {
608  return [=](Model* model) {
609  // We creates two extra Boolean variables in this case. The alternative is
610  // to code a custom propagator for the direction equality => reified.
611  const Literal is_le = Literal(model->Add(NewBooleanVariable()), true);
612  const Literal is_ge = Literal(model->Add(NewBooleanVariable()), true);
613  model->Add(ReifiedBoolAnd({is_le, is_ge}, is_eq));
616  };
617 }
618 
619 // Weighted sum != constant.
620 // TODO(user): Simplify if the constant is at the edge of the possible values.
621 template <typename VectorInt>
622 inline std::function<void(Model*)> WeightedSumNotEqual(
623  const std::vector<IntegerVariable>& vars, const VectorInt& coefficients,
624  int64_t value) {
625  return [=](Model* model) {
626  // Exactly one of these alternative must be true.
627  const Literal is_lt = Literal(model->Add(NewBooleanVariable()), true);
628  const Literal is_gt = is_lt.Negated();
630  value - 1));
632  value + 1));
633  };
634 }
635 
636 // Model-based function to create an IntegerVariable that corresponds to the
637 // given weighted sum of other IntegerVariables.
638 //
639 // Note that this is templated so that it can seamlessly accept vector<int> or
640 // vector<int64_t>.
641 //
642 // TODO(user): invert the coefficients/vars arguments.
643 template <typename VectorInt>
644 inline std::function<IntegerVariable(Model*)> NewWeightedSum(
645  const VectorInt& coefficients, const std::vector<IntegerVariable>& vars) {
646  return [=](Model* model) {
647  std::vector<IntegerVariable> new_vars = vars;
648  // To avoid overflow in the FixedWeightedSum() constraint, we need to
649  // compute the basic bounds on the sum.
650  //
651  // TODO(user): deal with overflow here too!
652  int64_t sum_lb(0);
653  int64_t sum_ub(0);
654  for (int i = 0; i < new_vars.size(); ++i) {
655  if (coefficients[i] > 0) {
656  sum_lb += coefficients[i] * model->Get(LowerBound(new_vars[i]));
657  sum_ub += coefficients[i] * model->Get(UpperBound(new_vars[i]));
658  } else {
659  sum_lb += coefficients[i] * model->Get(UpperBound(new_vars[i]));
660  sum_ub += coefficients[i] * model->Get(LowerBound(new_vars[i]));
661  }
662  }
663 
664  const IntegerVariable sum = model->Add(NewIntegerVariable(sum_lb, sum_ub));
665  new_vars.push_back(sum);
666  std::vector<int64_t> new_coeffs(coefficients.begin(), coefficients.end());
667  new_coeffs.push_back(-1);
668  model->Add(FixedWeightedSum(new_vars, new_coeffs, 0));
669  return sum;
670  };
671 }
672 
673 // Expresses the fact that an existing integer variable is equal to the minimum
674 // of other integer variables.
675 inline std::function<void(Model*)> IsEqualToMinOf(
676  IntegerVariable min_var, const std::vector<IntegerVariable>& vars) {
677  return [=](Model* model) {
678  for (const IntegerVariable& var : vars) {
679  model->Add(LowerOrEqual(min_var, var));
680  }
681 
682  MinPropagator* constraint =
683  new MinPropagator(vars, min_var, model->GetOrCreate<IntegerTrail>());
684  constraint->RegisterWith(model->GetOrCreate<GenericLiteralWatcher>());
685  model->TakeOwnership(constraint);
686  };
687 }
688 
689 // Expresses the fact that an existing integer variable is equal to the minimum
690 // of linear expressions. Assumes Canonical expressions (all positive
691 // coefficients).
692 inline std::function<void(Model*)> IsEqualToMinOf(
693  const LinearExpression& min_expr,
694  const std::vector<LinearExpression>& exprs) {
695  return [=](Model* model) {
696  IntegerTrail* integer_trail = model->GetOrCreate<IntegerTrail>();
697 
698  IntegerVariable min_var;
699  if (min_expr.vars.size() == 1 &&
700  std::abs(min_expr.coeffs[0].value()) == 1) {
701  if (min_expr.coeffs[0].value() == 1) {
702  min_var = min_expr.vars[0];
703  } else {
704  min_var = NegationOf(min_expr.vars[0]);
705  }
706  } else {
707  // Create a new variable if the expression is not just a single variable.
708  IntegerValue min_lb = LinExprLowerBound(min_expr, *integer_trail);
709  IntegerValue min_ub = LinExprUpperBound(min_expr, *integer_trail);
710  min_var = integer_trail->AddIntegerVariable(min_lb, min_ub);
711 
712  // min_var = min_expr
713  std::vector<IntegerVariable> min_sum_vars = min_expr.vars;
714  std::vector<int64_t> min_sum_coeffs;
715  for (IntegerValue coeff : min_expr.coeffs) {
716  min_sum_coeffs.push_back(coeff.value());
717  }
718  min_sum_vars.push_back(min_var);
719  min_sum_coeffs.push_back(-1);
720 
721  model->Add(FixedWeightedSum(min_sum_vars, min_sum_coeffs,
722  -min_expr.offset.value()));
723  }
724  for (const LinearExpression& expr : exprs) {
725  // min_var <= expr
726  std::vector<IntegerVariable> vars = expr.vars;
727  std::vector<int64_t> coeffs;
728  for (IntegerValue coeff : expr.coeffs) {
729  coeffs.push_back(coeff.value());
730  }
731  vars.push_back(min_var);
732  coeffs.push_back(-1);
733  model->Add(WeightedSumGreaterOrEqual(vars, coeffs, -expr.offset.value()));
734  }
735 
736  LinMinPropagator* constraint = new LinMinPropagator(exprs, min_var, model);
737  constraint->RegisterWith(model->GetOrCreate<GenericLiteralWatcher>());
738  model->TakeOwnership(constraint);
739  };
740 }
741 
742 // Expresses the fact that an existing integer variable is equal to the maximum
743 // of other integer variables.
744 inline std::function<void(Model*)> IsEqualToMaxOf(
745  IntegerVariable max_var, const std::vector<IntegerVariable>& vars) {
746  return [=](Model* model) {
747  std::vector<IntegerVariable> negated_vars;
748  for (const IntegerVariable& var : vars) {
749  negated_vars.push_back(NegationOf(var));
750  model->Add(GreaterOrEqual(max_var, var));
751  }
752 
753  MinPropagator* constraint = new MinPropagator(
754  negated_vars, NegationOf(max_var), model->GetOrCreate<IntegerTrail>());
755  constraint->RegisterWith(model->GetOrCreate<GenericLiteralWatcher>());
756  model->TakeOwnership(constraint);
757  };
758 }
759 
760 // Expresses the fact that an existing integer variable is equal to one of
761 // the given values, each selected by a given literal.
762 std::function<void(Model*)> IsOneOf(IntegerVariable var,
763  const std::vector<Literal>& selectors,
764  const std::vector<IntegerValue>& values);
765 
766 template <class T>
768  ct->RegisterWith(model->GetOrCreate<GenericLiteralWatcher>());
769  model->TakeOwnership(ct);
770 }
771 // Adds the constraint: a * b = p.
772 inline std::function<void(Model*)> ProductConstraint(IntegerVariable a,
773  IntegerVariable b,
774  IntegerVariable p) {
775  return [=](Model* model) {
776  IntegerTrail* integer_trail = model->GetOrCreate<IntegerTrail>();
777  if (a == b) {
778  if (model->Get(LowerBound(a)) >= 0) {
780  new SquarePropagator(a, p, integer_trail));
781  } else if (model->Get(UpperBound(a)) <= 0) {
783  model, new SquarePropagator(NegationOf(a), p, integer_trail));
784  } else {
785  LOG(FATAL) << "Not supported";
786  }
787  } else if (model->Get(LowerBound(a)) >= 0 &&
788  model->Get(LowerBound(b)) >= 0) {
790  model, new PositiveProductPropagator(a, b, p, integer_trail));
791  } else if (model->Get(LowerBound(a)) >= 0 &&
792  model->Get(UpperBound(b)) <= 0) {
795  integer_trail));
796  } else if (model->Get(UpperBound(a)) <= 0 &&
797  model->Get(LowerBound(b)) >= 0) {
800  integer_trail));
801  } else if (model->Get(UpperBound(a)) <= 0 &&
802  model->Get(UpperBound(b)) <= 0) {
805  integer_trail));
806  } else {
807  LOG(FATAL) << "Not supported";
808  }
809  };
810 }
811 
812 // Adds the constraint: a / b = c.
813 inline std::function<void(Model*)> DivisionConstraint(IntegerVariable a,
814  IntegerVariable b,
815  IntegerVariable c) {
816  return [=](Model* model) {
817  IntegerTrail* integer_trail = model->GetOrCreate<IntegerTrail>();
818  DivisionPropagator* constraint =
819  new DivisionPropagator(a, b, c, integer_trail);
820  constraint->RegisterWith(model->GetOrCreate<GenericLiteralWatcher>());
821  model->TakeOwnership(constraint);
822  };
823 }
824 
825 // Adds the constraint: a / b = c where b is a constant.
826 inline std::function<void(Model*)> FixedDivisionConstraint(IntegerVariable a,
827  IntegerValue b,
828  IntegerVariable c) {
829  return [=](Model* model) {
830  IntegerTrail* integer_trail = model->GetOrCreate<IntegerTrail>();
831  FixedDivisionPropagator* constraint =
832  b > 0
833  ? new FixedDivisionPropagator(a, b, c, integer_trail)
834  : new FixedDivisionPropagator(NegationOf(a), -b, c, integer_trail);
835  constraint->RegisterWith(model->GetOrCreate<GenericLiteralWatcher>());
836  model->TakeOwnership(constraint);
837  };
838 }
839 
840 } // namespace sat
841 } // namespace operations_research
842 
843 #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:709
#define CHECK_NE(val1, val2)
Definition: base/logging.h:706
#define LOG(severity)
Definition: base/logging.h:423
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:605
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 *)> GreaterOrEqual(IntegerVariable v, int64_t lb)
Definition: integer.h:1500
std::function< int64_t(const Model &)> UpperBound(IntegerVariable v)
Definition: integer.h:1478
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:744
IntegerValue LinExprLowerBound(const LinearExpression &expr, const IntegerTrail &integer_trail)
std::function< void(Model *)> ClauseConstraint(absl::Span< const Literal > literals)
Definition: sat_solver.h:906
std::function< void(Model *)> DivisionConstraint(IntegerVariable a, IntegerVariable b, IntegerVariable c)
Definition: integer_expr.h:813
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:429
IntegerValue CeilRatio(IntegerValue dividend, IntegerValue positive_divisor)
Definition: integer.h:82
std::function< void(Model *)> FixedWeightedSumReif(Literal is_eq, const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64_t value)
Definition: integer_expr.h:605
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue)
std::function< BooleanVariable(Model *)> NewBooleanVariable()
Definition: integer.h:1417
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:575
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 *)> WeightedSumNotEqual(const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64_t value)
Definition: integer_expr.h:622
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:517
std::function< void(Model *)> Sum2LowerOrEqual(IntegerVariable a, IntegerVariable b, int64_t ub)
Definition: precedences.h:353
void RegisterAndTransferOwnership(Model *model, T *ct)
Definition: integer_expr.h:767
std::function< IntegerVariable(Model *)> NewWeightedSum(const VectorInt &coefficients, const std::vector< IntegerVariable > &vars)
Definition: integer_expr.h:644
void LoadLinearConstraint(const ConstraintProto &ct, Model *m)
std::function< void(Model *)> Implication(const std::vector< Literal > &enforcement_literals, IntegerLiteral i)
Definition: integer.h:1543
std::function< void(Model *)> FixedDivisionConstraint(IntegerVariable a, IntegerValue b, IntegerVariable c)
Definition: integer_expr.h:826
std::function< void(Model *)> Sum3LowerOrEqual(IntegerVariable a, IntegerVariable b, IntegerVariable c, int64_t ub)
Definition: precedences.h:371
std::function< void(Model *)> WeightedSumLowerOrEqual(const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64_t upper_bound)
Definition: integer_expr.h:300
std::function< void(Model *)> FixedWeightedSum(const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64_t value)
Definition: integer_expr.h:418
std::function< void(Model *)> LowerOrEqual(IntegerVariable v, int64_t ub)
Definition: integer.h:1515
std::function< IntegerVariable(Model *)> NewIntegerVariable(int64_t lb, int64_t ub)
Definition: integer.h:1431
std::function< void(Model *)> ReifiedBoolAnd(const std::vector< Literal > &literals, Literal r)
Definition: sat_solver.h:970
std::function< void(Model *)> WeightedSumLowerOrEqualReif(Literal is_le, const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64_t upper_bound)
Definition: integer_expr.h:530
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:675
std::function< void(Model *)> WeightedSumGreaterOrEqualReif(Literal is_ge, const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64_t lower_bound)
Definition: integer_expr.h:543
IntegerValue LinExprUpperBound(const LinearExpression &expr, const IntegerTrail &integer_trail)
std::function< int64_t(const Model &)> LowerBound(IntegerVariable v)
Definition: integer.h:1472
std::function< void(Model *)> ProductConstraint(IntegerVariable a, IntegerVariable b, IntegerVariable p)
Definition: integer_expr.h:772
std::function< void(Model *)> WeightedSumGreaterOrEqual(const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64_t lower_bound)
Definition: integer_expr.h:407
std::function< void(Model *)> ConditionalSum3LowerOrEqual(IntegerVariable a, IntegerVariable b, IntegerVariable c, int64_t ub, const std::vector< Literal > &enforcement_literals)
Definition: precedences.h:382
Collection of objects used to extend the Constraint Solver library.
static IntegerLiteral LowerOrEqual(IntegerVariable i, IntegerValue bound)
Definition: integer.h:1275
static IntegerLiteral GreaterOrEqual(IntegerVariable i, IntegerValue bound)
Definition: integer.h:1269