OR-Tools  9.6
element.cc
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 #include <algorithm>
15 #include <cstdint>
16 #include <functional>
17 #include <limits>
18 #include <memory>
19 #include <numeric>
20 #include <string>
21 #include <utility>
22 #include <vector>
23 
24 #include "absl/strings/str_format.h"
25 #include "absl/strings/str_join.h"
27 #include "ortools/base/logging.h"
32 
33 ABSL_FLAG(bool, cp_disable_element_cache, true,
34  "If true, caching for IntElement is disabled.");
35 
36 namespace operations_research {
37 
38 // ----- IntExprElement -----
39 void LinkVarExpr(Solver* const s, IntExpr* const expr, IntVar* const var);
40 
41 namespace {
42 
43 template <class T>
44 class VectorLess {
45  public:
46  explicit VectorLess(const std::vector<T>* values) : values_(values) {}
47  bool operator()(const T& x, const T& y) const {
48  return (*values_)[x] < (*values_)[y];
49  }
50 
51  private:
52  const std::vector<T>* values_;
53 };
54 
55 template <class T>
56 class VectorGreater {
57  public:
58  explicit VectorGreater(const std::vector<T>* values) : values_(values) {}
59  bool operator()(const T& x, const T& y) const {
60  return (*values_)[x] > (*values_)[y];
61  }
62 
63  private:
64  const std::vector<T>* values_;
65 };
66 
67 // ----- BaseIntExprElement -----
68 
69 class BaseIntExprElement : public BaseIntExpr {
70  public:
71  BaseIntExprElement(Solver* const s, IntVar* const e);
72  ~BaseIntExprElement() override {}
73  int64_t Min() const override;
74  int64_t Max() const override;
75  void Range(int64_t* mi, int64_t* ma) override;
76  void SetMin(int64_t m) override;
77  void SetMax(int64_t m) override;
78  void SetRange(int64_t mi, int64_t ma) override;
79  bool Bound() const override { return (expr_->Bound()); }
80  // TODO(user) : improve me, the previous test is not always true
81  void WhenRange(Demon* d) override { expr_->WhenRange(d); }
82 
83  protected:
84  virtual int64_t ElementValue(int index) const = 0;
85  virtual int64_t ExprMin() const = 0;
86  virtual int64_t ExprMax() const = 0;
87 
88  IntVar* const expr_;
89 
90  private:
91  void UpdateSupports() const;
92  template <typename T>
93  void UpdateElementIndexBounds(T check_value) {
94  const int64_t emin = ExprMin();
95  const int64_t emax = ExprMax();
96  int64_t nmin = emin;
97  int64_t value = ElementValue(nmin);
98  while (nmin < emax && check_value(value)) {
99  nmin++;
100  value = ElementValue(nmin);
101  }
102  if (nmin == emax && check_value(value)) {
103  solver()->Fail();
104  }
105  int64_t nmax = emax;
106  value = ElementValue(nmax);
107  while (nmax >= nmin && check_value(value)) {
108  nmax--;
109  value = ElementValue(nmax);
110  }
111  expr_->SetRange(nmin, nmax);
112  }
113 
114  mutable int64_t min_;
115  mutable int min_support_;
116  mutable int64_t max_;
117  mutable int max_support_;
118  mutable bool initial_update_;
119  IntVarIterator* const expr_iterator_;
120 };
121 
122 BaseIntExprElement::BaseIntExprElement(Solver* const s, IntVar* const e)
123  : BaseIntExpr(s),
124  expr_(e),
125  min_(0),
126  min_support_(-1),
127  max_(0),
128  max_support_(-1),
129  initial_update_(true),
130  expr_iterator_(expr_->MakeDomainIterator(true)) {
131  CHECK(s != nullptr);
132  CHECK(e != nullptr);
133 }
134 
135 int64_t BaseIntExprElement::Min() const {
136  UpdateSupports();
137  return min_;
138 }
139 
140 int64_t BaseIntExprElement::Max() const {
141  UpdateSupports();
142  return max_;
143 }
144 
145 void BaseIntExprElement::Range(int64_t* mi, int64_t* ma) {
146  UpdateSupports();
147  *mi = min_;
148  *ma = max_;
149 }
150 
151 void BaseIntExprElement::SetMin(int64_t m) {
152  UpdateElementIndexBounds([m](int64_t value) { return value < m; });
153 }
154 
155 void BaseIntExprElement::SetMax(int64_t m) {
156  UpdateElementIndexBounds([m](int64_t value) { return value > m; });
157 }
158 
159 void BaseIntExprElement::SetRange(int64_t mi, int64_t ma) {
160  if (mi > ma) {
161  solver()->Fail();
162  }
163  UpdateElementIndexBounds(
164  [mi, ma](int64_t value) { return value < mi || value > ma; });
165 }
166 
167 void BaseIntExprElement::UpdateSupports() const {
168  if (initial_update_ || !expr_->Contains(min_support_) ||
169  !expr_->Contains(max_support_)) {
170  const int64_t emin = ExprMin();
171  const int64_t emax = ExprMax();
172  int64_t min_value = ElementValue(emax);
173  int64_t max_value = min_value;
174  int min_support = emax;
175  int max_support = emax;
176  const uint64_t expr_size = expr_->Size();
177  if (expr_size > 1) {
178  if (expr_size == emax - emin + 1) {
179  // Value(emax) already stored in min_value, max_value.
180  for (int64_t index = emin; index < emax; ++index) {
181  const int64_t value = ElementValue(index);
182  if (value > max_value) {
183  max_value = value;
184  max_support = index;
185  } else if (value < min_value) {
186  min_value = value;
187  min_support = index;
188  }
189  }
190  } else {
191  for (const int64_t index : InitAndGetValues(expr_iterator_)) {
192  if (index >= emin && index <= emax) {
193  const int64_t value = ElementValue(index);
194  if (value > max_value) {
195  max_value = value;
196  max_support = index;
197  } else if (value < min_value) {
198  min_value = value;
199  min_support = index;
200  }
201  }
202  }
203  }
204  }
205  Solver* s = solver();
206  s->SaveAndSetValue(&min_, min_value);
207  s->SaveAndSetValue(&min_support_, min_support);
208  s->SaveAndSetValue(&max_, max_value);
209  s->SaveAndSetValue(&max_support_, max_support);
210  s->SaveAndSetValue(&initial_update_, false);
211  }
212 }
213 
214 // ----- IntElementConstraint -----
215 
216 // This constraint implements 'elem' == 'values'['index'].
217 // It scans the bounds of 'elem' to propagate on the domain of 'index'.
218 // It scans the domain of 'index' to compute the new bounds of 'elem'.
219 class IntElementConstraint : public CastConstraint {
220  public:
221  IntElementConstraint(Solver* const s, const std::vector<int64_t>& values,
222  IntVar* const index, IntVar* const elem)
223  : CastConstraint(s, elem),
224  values_(values),
225  index_(index),
226  index_iterator_(index_->MakeDomainIterator(true)) {
227  CHECK(index != nullptr);
228  }
229 
230  void Post() override {
231  Demon* const d =
232  solver()->MakeDelayedConstraintInitialPropagateCallback(this);
233  index_->WhenDomain(d);
234  target_var_->WhenRange(d);
235  }
236 
237  void InitialPropagate() override {
238  index_->SetRange(0, values_.size() - 1);
239  const int64_t target_var_min = target_var_->Min();
240  const int64_t target_var_max = target_var_->Max();
241  int64_t new_min = target_var_max;
242  int64_t new_max = target_var_min;
243  to_remove_.clear();
244  for (const int64_t index : InitAndGetValues(index_iterator_)) {
245  const int64_t value = values_[index];
246  if (value < target_var_min || value > target_var_max) {
247  to_remove_.push_back(index);
248  } else {
249  if (value < new_min) {
250  new_min = value;
251  }
252  if (value > new_max) {
253  new_max = value;
254  }
255  }
256  }
257  target_var_->SetRange(new_min, new_max);
258  if (!to_remove_.empty()) {
259  index_->RemoveValues(to_remove_);
260  }
261  }
262 
263  std::string DebugString() const override {
264  return absl::StrFormat("IntElementConstraint(%s, %s, %s)",
265  absl::StrJoin(values_, ", "), index_->DebugString(),
266  target_var_->DebugString());
267  }
268 
269  void Accept(ModelVisitor* const visitor) const override {
270  visitor->BeginVisitConstraint(ModelVisitor::kElementEqual, this);
271  visitor->VisitIntegerArrayArgument(ModelVisitor::kValuesArgument, values_);
272  visitor->VisitIntegerExpressionArgument(ModelVisitor::kIndexArgument,
273  index_);
274  visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
275  target_var_);
276  visitor->EndVisitConstraint(ModelVisitor::kElementEqual, this);
277  }
278 
279  private:
280  const std::vector<int64_t> values_;
281  IntVar* const index_;
282  IntVarIterator* const index_iterator_;
283  std::vector<int64_t> to_remove_;
284 };
285 
286 // ----- IntExprElement
287 
288 IntVar* BuildDomainIntVar(Solver* const solver, std::vector<int64_t>* values);
289 
290 class IntExprElement : public BaseIntExprElement {
291  public:
292  IntExprElement(Solver* const s, const std::vector<int64_t>& vals,
293  IntVar* const expr)
294  : BaseIntExprElement(s, expr), values_(vals) {}
295 
296  ~IntExprElement() override {}
297 
298  std::string name() const override {
299  const int size = values_.size();
300  if (size > 10) {
301  return absl::StrFormat("IntElement(array of size %d, %s)", size,
302  expr_->name());
303  } else {
304  return absl::StrFormat("IntElement(%s, %s)", absl::StrJoin(values_, ", "),
305  expr_->name());
306  }
307  }
308 
309  std::string DebugString() const override {
310  const int size = values_.size();
311  if (size > 10) {
312  return absl::StrFormat("IntElement(array of size %d, %s)", size,
313  expr_->DebugString());
314  } else {
315  return absl::StrFormat("IntElement(%s, %s)", absl::StrJoin(values_, ", "),
316  expr_->DebugString());
317  }
318  }
319 
320  IntVar* CastToVar() override {
321  Solver* const s = solver();
322  IntVar* const var = s->MakeIntVar(values_);
323  s->AddCastConstraint(
324  s->RevAlloc(new IntElementConstraint(s, values_, expr_, var)), var,
325  this);
326  return var;
327  }
328 
329  void Accept(ModelVisitor* const visitor) const override {
330  visitor->BeginVisitIntegerExpression(ModelVisitor::kElement, this);
331  visitor->VisitIntegerArrayArgument(ModelVisitor::kValuesArgument, values_);
332  visitor->VisitIntegerExpressionArgument(ModelVisitor::kIndexArgument,
333  expr_);
334  visitor->EndVisitIntegerExpression(ModelVisitor::kElement, this);
335  }
336 
337  protected:
338  int64_t ElementValue(int index) const override {
339  DCHECK_LT(index, values_.size());
340  return values_[index];
341  }
342  int64_t ExprMin() const override {
343  return std::max<int64_t>(0, expr_->Min());
344  }
345  int64_t ExprMax() const override {
346  return values_.empty()
347  ? 0
348  : std::min<int64_t>(values_.size() - 1, expr_->Max());
349  }
350 
351  private:
352  const std::vector<int64_t> values_;
353 };
354 
355 // ----- Range Minimum Query-based Element -----
356 
357 class RangeMinimumQueryExprElement : public BaseIntExpr {
358  public:
359  RangeMinimumQueryExprElement(Solver* solver,
360  const std::vector<int64_t>& values,
361  IntVar* index);
362  ~RangeMinimumQueryExprElement() override {}
363  int64_t Min() const override;
364  int64_t Max() const override;
365  void Range(int64_t* mi, int64_t* ma) override;
366  void SetMin(int64_t m) override;
367  void SetMax(int64_t m) override;
368  void SetRange(int64_t mi, int64_t ma) override;
369  bool Bound() const override { return (index_->Bound()); }
370  // TODO(user) : improve me, the previous test is not always true
371  void WhenRange(Demon* d) override { index_->WhenRange(d); }
372  IntVar* CastToVar() override {
373  // TODO(user): Should we try to make holes in the domain of index_, as we
374  // do here, or should we only propagate bounds as we do in
375  // IncreasingIntExprElement ?
376  IntVar* const var = solver()->MakeIntVar(min_rmq_.array());
377  solver()->AddCastConstraint(solver()->RevAlloc(new IntElementConstraint(
378  solver(), min_rmq_.array(), index_, var)),
379  var, this);
380  return var;
381  }
382  void Accept(ModelVisitor* const visitor) const override {
383  visitor->BeginVisitIntegerExpression(ModelVisitor::kElement, this);
384  visitor->VisitIntegerArrayArgument(ModelVisitor::kValuesArgument,
385  min_rmq_.array());
386  visitor->VisitIntegerExpressionArgument(ModelVisitor::kIndexArgument,
387  index_);
388  visitor->EndVisitIntegerExpression(ModelVisitor::kElement, this);
389  }
390 
391  private:
392  int64_t IndexMin() const { return std::max<int64_t>(0, index_->Min()); }
393  int64_t IndexMax() const {
394  return std::min<int64_t>(min_rmq_.array().size() - 1, index_->Max());
395  }
396 
397  IntVar* const index_;
398  const RangeMinimumQuery<int64_t, std::less<int64_t>> min_rmq_;
399  const RangeMinimumQuery<int64_t, std::greater<int64_t>> max_rmq_;
400 };
401 
402 RangeMinimumQueryExprElement::RangeMinimumQueryExprElement(
403  Solver* solver, const std::vector<int64_t>& values, IntVar* index)
404  : BaseIntExpr(solver), index_(index), min_rmq_(values), max_rmq_(values) {
405  CHECK(solver != nullptr);
406  CHECK(index != nullptr);
407 }
408 
409 int64_t RangeMinimumQueryExprElement::Min() const {
410  return min_rmq_.GetMinimumFromRange(IndexMin(), IndexMax() + 1);
411 }
412 
413 int64_t RangeMinimumQueryExprElement::Max() const {
414  return max_rmq_.GetMinimumFromRange(IndexMin(), IndexMax() + 1);
415 }
416 
417 void RangeMinimumQueryExprElement::Range(int64_t* mi, int64_t* ma) {
418  const int64_t range_min = IndexMin();
419  const int64_t range_max = IndexMax() + 1;
420  *mi = min_rmq_.GetMinimumFromRange(range_min, range_max);
421  *ma = max_rmq_.GetMinimumFromRange(range_min, range_max);
422 }
423 
424 #define UPDATE_RMQ_BASE_ELEMENT_INDEX_BOUNDS(test) \
425  const std::vector<int64_t>& values = min_rmq_.array(); \
426  int64_t index_min = IndexMin(); \
427  int64_t index_max = IndexMax(); \
428  int64_t value = values[index_min]; \
429  while (index_min < index_max && (test)) { \
430  index_min++; \
431  value = values[index_min]; \
432  } \
433  if (index_min == index_max && (test)) { \
434  solver()->Fail(); \
435  } \
436  value = values[index_max]; \
437  while (index_max >= index_min && (test)) { \
438  index_max--; \
439  value = values[index_max]; \
440  } \
441  index_->SetRange(index_min, index_max);
442 
443 void RangeMinimumQueryExprElement::SetMin(int64_t m) {
445 }
446 
447 void RangeMinimumQueryExprElement::SetMax(int64_t m) {
449 }
450 
451 void RangeMinimumQueryExprElement::SetRange(int64_t mi, int64_t ma) {
452  if (mi > ma) {
453  solver()->Fail();
454  }
455  UPDATE_RMQ_BASE_ELEMENT_INDEX_BOUNDS(value < mi || value > ma);
456 }
457 
458 #undef UPDATE_RMQ_BASE_ELEMENT_INDEX_BOUNDS
459 
460 // ----- Increasing Element -----
461 
462 class IncreasingIntExprElement : public BaseIntExpr {
463  public:
464  IncreasingIntExprElement(Solver* const s, const std::vector<int64_t>& values,
465  IntVar* const index);
466  ~IncreasingIntExprElement() override {}
467 
468  int64_t Min() const override;
469  void SetMin(int64_t m) override;
470  int64_t Max() const override;
471  void SetMax(int64_t m) override;
472  void SetRange(int64_t mi, int64_t ma) override;
473  bool Bound() const override { return (index_->Bound()); }
474  // TODO(user) : improve me, the previous test is not always true
475  std::string name() const override {
476  return absl::StrFormat("IntElement(%s, %s)", absl::StrJoin(values_, ", "),
477  index_->name());
478  }
479  std::string DebugString() const override {
480  return absl::StrFormat("IntElement(%s, %s)", absl::StrJoin(values_, ", "),
481  index_->DebugString());
482  }
483 
484  void Accept(ModelVisitor* const visitor) const override {
485  visitor->BeginVisitIntegerExpression(ModelVisitor::kElement, this);
486  visitor->VisitIntegerArrayArgument(ModelVisitor::kValuesArgument, values_);
487  visitor->VisitIntegerExpressionArgument(ModelVisitor::kIndexArgument,
488  index_);
489  visitor->EndVisitIntegerExpression(ModelVisitor::kElement, this);
490  }
491 
492  void WhenRange(Demon* d) override { index_->WhenRange(d); }
493 
494  IntVar* CastToVar() override {
495  Solver* const s = solver();
496  IntVar* const var = s->MakeIntVar(values_);
497  LinkVarExpr(s, this, var);
498  return var;
499  }
500 
501  private:
502  const std::vector<int64_t> values_;
503  IntVar* const index_;
504 };
505 
506 IncreasingIntExprElement::IncreasingIntExprElement(
507  Solver* const s, const std::vector<int64_t>& values, IntVar* const index)
508  : BaseIntExpr(s), values_(values), index_(index) {
509  DCHECK(index);
510  DCHECK(s);
511 }
512 
513 int64_t IncreasingIntExprElement::Min() const {
514  const int64_t expression_min = std::max<int64_t>(0, index_->Min());
515  return (expression_min < values_.size()
516  ? values_[expression_min]
518 }
519 
520 void IncreasingIntExprElement::SetMin(int64_t m) {
521  const int64_t index_min = std::max<int64_t>(0, index_->Min());
522  const int64_t index_max =
523  std::min<int64_t>(values_.size() - 1, index_->Max());
524 
525  if (index_min > index_max || m > values_[index_max]) {
526  solver()->Fail();
527  }
528 
529  const std::vector<int64_t>::const_iterator first =
530  std::lower_bound(values_.begin(), values_.end(), m);
531  const int64_t new_index_min = first - values_.begin();
532  index_->SetMin(new_index_min);
533 }
534 
535 int64_t IncreasingIntExprElement::Max() const {
536  const int64_t expression_max =
537  std::min<int64_t>(values_.size() - 1, index_->Max());
538  return (expression_max >= 0 ? values_[expression_max]
540 }
541 
542 void IncreasingIntExprElement::SetMax(int64_t m) {
543  int64_t index_min = std::max<int64_t>(0, index_->Min());
544  if (m < values_[index_min]) {
545  solver()->Fail();
546  }
547 
548  const std::vector<int64_t>::const_iterator last_after =
549  std::upper_bound(values_.begin(), values_.end(), m);
550  const int64_t new_index_max = (last_after - values_.begin()) - 1;
551  index_->SetRange(0, new_index_max);
552 }
553 
554 void IncreasingIntExprElement::SetRange(int64_t mi, int64_t ma) {
555  if (mi > ma) {
556  solver()->Fail();
557  }
558  const int64_t index_min = std::max<int64_t>(0, index_->Min());
559  const int64_t index_max =
560  std::min<int64_t>(values_.size() - 1, index_->Max());
561 
562  if (mi > ma || ma < values_[index_min] || mi > values_[index_max]) {
563  solver()->Fail();
564  }
565 
566  const std::vector<int64_t>::const_iterator first =
567  std::lower_bound(values_.begin(), values_.end(), mi);
568  const int64_t new_index_min = first - values_.begin();
569 
570  const std::vector<int64_t>::const_iterator last_after =
571  std::upper_bound(first, values_.end(), ma);
572  const int64_t new_index_max = (last_after - values_.begin()) - 1;
573 
574  // Assign.
575  index_->SetRange(new_index_min, new_index_max);
576 }
577 
578 // ----- Solver::MakeElement(int array, int var) -----
579 IntExpr* BuildElement(Solver* const solver, const std::vector<int64_t>& values,
580  IntVar* const index) {
581  // Various checks.
582  // Is array constant?
583  if (IsArrayConstant(values, values[0])) {
584  solver->AddConstraint(solver->MakeBetweenCt(index, 0, values.size() - 1));
585  return solver->MakeIntConst(values[0]);
586  }
587  // Is array built with booleans only?
588  // TODO(user): We could maintain the index of the first one.
589  if (IsArrayBoolean(values)) {
590  std::vector<int64_t> ones;
591  int first_zero = -1;
592  for (int i = 0; i < values.size(); ++i) {
593  if (values[i] == 1) {
594  ones.push_back(i);
595  } else {
596  first_zero = i;
597  }
598  }
599  if (ones.size() == 1) {
600  DCHECK_EQ(int64_t{1}, values[ones.back()]);
601  solver->AddConstraint(solver->MakeBetweenCt(index, 0, values.size() - 1));
602  return solver->MakeIsEqualCstVar(index, ones.back());
603  } else if (ones.size() == values.size() - 1) {
604  solver->AddConstraint(solver->MakeBetweenCt(index, 0, values.size() - 1));
605  return solver->MakeIsDifferentCstVar(index, first_zero);
606  } else if (ones.size() == ones.back() - ones.front() + 1) { // contiguous.
607  solver->AddConstraint(solver->MakeBetweenCt(index, 0, values.size() - 1));
608  IntVar* const b = solver->MakeBoolVar("ContiguousBooleanElementVar");
609  solver->AddConstraint(
610  solver->MakeIsBetweenCt(index, ones.front(), ones.back(), b));
611  return b;
612  } else {
613  IntVar* const b = solver->MakeBoolVar("NonContiguousBooleanElementVar");
614  solver->AddConstraint(solver->MakeBetweenCt(index, 0, values.size() - 1));
615  solver->AddConstraint(solver->MakeIsMemberCt(index, ones, b));
616  return b;
617  }
618  }
619  IntExpr* cache = nullptr;
620  if (!absl::GetFlag(FLAGS_cp_disable_element_cache)) {
621  cache = solver->Cache()->FindVarConstantArrayExpression(
622  index, values, ModelCache::VAR_CONSTANT_ARRAY_ELEMENT);
623  }
624  if (cache != nullptr) {
625  return cache;
626  } else {
627  IntExpr* result = nullptr;
628  if (values.size() >= 2 && index->Min() == 0 && index->Max() == 1) {
629  result = solver->MakeSum(solver->MakeProd(index, values[1] - values[0]),
630  values[0]);
631  } else if (values.size() == 2 && index->Contains(0) && index->Contains(1)) {
632  solver->AddConstraint(solver->MakeBetweenCt(index, 0, 1));
633  result = solver->MakeSum(solver->MakeProd(index, values[1] - values[0]),
634  values[0]);
635  } else if (IsIncreasingContiguous(values)) {
636  result = solver->MakeSum(index, values[0]);
637  } else if (IsIncreasing(values)) {
638  result = solver->RegisterIntExpr(solver->RevAlloc(
639  new IncreasingIntExprElement(solver, values, index)));
640  } else {
641  if (solver->parameters().use_element_rmq()) {
642  result = solver->RegisterIntExpr(solver->RevAlloc(
643  new RangeMinimumQueryExprElement(solver, values, index)));
644  } else {
645  result = solver->RegisterIntExpr(
646  solver->RevAlloc(new IntExprElement(solver, values, index)));
647  }
648  }
649  if (!absl::GetFlag(FLAGS_cp_disable_element_cache)) {
650  solver->Cache()->InsertVarConstantArrayExpression(
651  result, index, values, ModelCache::VAR_CONSTANT_ARRAY_ELEMENT);
652  }
653  return result;
654  }
655 }
656 } // namespace
657 
658 IntExpr* Solver::MakeElement(const std::vector<int64_t>& values,
659  IntVar* const index) {
660  DCHECK(index);
661  DCHECK_EQ(this, index->solver());
662  if (index->Bound()) {
663  return MakeIntConst(values[index->Min()]);
664  }
665  return BuildElement(this, values, index);
666 }
667 
668 IntExpr* Solver::MakeElement(const std::vector<int>& values,
669  IntVar* const index) {
670  DCHECK(index);
671  DCHECK_EQ(this, index->solver());
672  if (index->Bound()) {
673  return MakeIntConst(values[index->Min()]);
674  }
675  return BuildElement(this, ToInt64Vector(values), index);
676 }
677 
678 // ----- IntExprFunctionElement -----
679 
680 namespace {
681 class IntExprFunctionElement : public BaseIntExprElement {
682  public:
683  IntExprFunctionElement(Solver* const s, Solver::IndexEvaluator1 values,
684  IntVar* const e);
685  ~IntExprFunctionElement() override;
686 
687  std::string name() const override {
688  return absl::StrFormat("IntFunctionElement(%s)", expr_->name());
689  }
690 
691  std::string DebugString() const override {
692  return absl::StrFormat("IntFunctionElement(%s)", expr_->DebugString());
693  }
694 
695  void Accept(ModelVisitor* const visitor) const override {
696  // Warning: This will expand all values into a vector.
697  visitor->BeginVisitIntegerExpression(ModelVisitor::kElement, this);
698  visitor->VisitIntegerExpressionArgument(ModelVisitor::kIndexArgument,
699  expr_);
700  visitor->VisitInt64ToInt64Extension(values_, expr_->Min(), expr_->Max());
701  visitor->EndVisitIntegerExpression(ModelVisitor::kElement, this);
702  }
703 
704  protected:
705  int64_t ElementValue(int index) const override { return values_(index); }
706  int64_t ExprMin() const override { return expr_->Min(); }
707  int64_t ExprMax() const override { return expr_->Max(); }
708 
709  private:
710  Solver::IndexEvaluator1 values_;
711 };
712 
713 IntExprFunctionElement::IntExprFunctionElement(Solver* const s,
714  Solver::IndexEvaluator1 values,
715  IntVar* const e)
716  : BaseIntExprElement(s, e), values_(std::move(values)) {
717  CHECK(values_ != nullptr);
718 }
719 
720 IntExprFunctionElement::~IntExprFunctionElement() {}
721 
722 // ----- Increasing Element -----
723 
724 class IncreasingIntExprFunctionElement : public BaseIntExpr {
725  public:
726  IncreasingIntExprFunctionElement(Solver* const s,
728  IntVar* const index)
729  : BaseIntExpr(s), values_(std::move(values)), index_(index) {
730  DCHECK(values_ != nullptr);
731  DCHECK(index);
732  DCHECK(s);
733  }
734 
735  ~IncreasingIntExprFunctionElement() override {}
736 
737  int64_t Min() const override { return values_(index_->Min()); }
738 
739  void SetMin(int64_t m) override {
740  const int64_t index_min = index_->Min();
741  const int64_t index_max = index_->Max();
742  if (m > values_(index_max)) {
743  solver()->Fail();
744  }
745  const int64_t new_index_min = FindNewIndexMin(index_min, index_max, m);
746  index_->SetMin(new_index_min);
747  }
748 
749  int64_t Max() const override { return values_(index_->Max()); }
750 
751  void SetMax(int64_t m) override {
752  int64_t index_min = index_->Min();
753  int64_t index_max = index_->Max();
754  if (m < values_(index_min)) {
755  solver()->Fail();
756  }
757  const int64_t new_index_max = FindNewIndexMax(index_min, index_max, m);
758  index_->SetMax(new_index_max);
759  }
760 
761  void SetRange(int64_t mi, int64_t ma) override {
762  const int64_t index_min = index_->Min();
763  const int64_t index_max = index_->Max();
764  const int64_t value_min = values_(index_min);
765  const int64_t value_max = values_(index_max);
766  if (mi > ma || ma < value_min || mi > value_max) {
767  solver()->Fail();
768  }
769  if (mi <= value_min && ma >= value_max) {
770  // Nothing to do.
771  return;
772  }
773 
774  const int64_t new_index_min = FindNewIndexMin(index_min, index_max, mi);
775  const int64_t new_index_max = FindNewIndexMax(new_index_min, index_max, ma);
776  // Assign.
777  index_->SetRange(new_index_min, new_index_max);
778  }
779 
780  std::string name() const override {
781  return absl::StrFormat("IncreasingIntExprFunctionElement(values, %s)",
782  index_->name());
783  }
784 
785  std::string DebugString() const override {
786  return absl::StrFormat("IncreasingIntExprFunctionElement(values, %s)",
787  index_->DebugString());
788  }
789 
790  void WhenRange(Demon* d) override { index_->WhenRange(d); }
791 
792  void Accept(ModelVisitor* const visitor) const override {
793  // Warning: This will expand all values into a vector.
794  visitor->BeginVisitIntegerExpression(ModelVisitor::kElement, this);
795  visitor->VisitIntegerExpressionArgument(ModelVisitor::kIndexArgument,
796  index_);
797  if (index_->Min() == 0) {
798  visitor->VisitInt64ToInt64AsArray(values_, ModelVisitor::kValuesArgument,
799  index_->Max());
800  } else {
801  visitor->VisitInt64ToInt64Extension(values_, index_->Min(),
802  index_->Max());
803  }
804  visitor->EndVisitIntegerExpression(ModelVisitor::kElement, this);
805  }
806 
807  private:
808  int64_t FindNewIndexMin(int64_t index_min, int64_t index_max, int64_t m) {
809  if (m <= values_(index_min)) {
810  return index_min;
811  }
812 
813  DCHECK_LT(values_(index_min), m);
814  DCHECK_GE(values_(index_max), m);
815 
816  int64_t index_lower_bound = index_min;
817  int64_t index_upper_bound = index_max;
818  while (index_upper_bound - index_lower_bound > 1) {
819  DCHECK_LT(values_(index_lower_bound), m);
820  DCHECK_GE(values_(index_upper_bound), m);
821  const int64_t pivot = (index_lower_bound + index_upper_bound) / 2;
822  const int64_t pivot_value = values_(pivot);
823  if (pivot_value < m) {
824  index_lower_bound = pivot;
825  } else {
826  index_upper_bound = pivot;
827  }
828  }
829  DCHECK(values_(index_upper_bound) >= m);
830  return index_upper_bound;
831  }
832 
833  int64_t FindNewIndexMax(int64_t index_min, int64_t index_max, int64_t m) {
834  if (m >= values_(index_max)) {
835  return index_max;
836  }
837 
838  DCHECK_LE(values_(index_min), m);
839  DCHECK_GT(values_(index_max), m);
840 
841  int64_t index_lower_bound = index_min;
842  int64_t index_upper_bound = index_max;
843  while (index_upper_bound - index_lower_bound > 1) {
844  DCHECK_LE(values_(index_lower_bound), m);
845  DCHECK_GT(values_(index_upper_bound), m);
846  const int64_t pivot = (index_lower_bound + index_upper_bound) / 2;
847  const int64_t pivot_value = values_(pivot);
848  if (pivot_value > m) {
849  index_upper_bound = pivot;
850  } else {
851  index_lower_bound = pivot;
852  }
853  }
854  DCHECK(values_(index_lower_bound) <= m);
855  return index_lower_bound;
856  }
857 
858  Solver::IndexEvaluator1 values_;
859  IntVar* const index_;
860 };
861 } // namespace
862 
864  IntVar* const index) {
865  CHECK_EQ(this, index->solver());
866  return RegisterIntExpr(
867  RevAlloc(new IntExprFunctionElement(this, std::move(values), index)));
868 }
869 
871  bool increasing, IntVar* const index) {
872  CHECK_EQ(this, index->solver());
873  if (increasing) {
874  return RegisterIntExpr(
875  RevAlloc(new IncreasingIntExprFunctionElement(this, values, index)));
876  } else {
877  // You need to pass by copy such that opposite_value does not include a
878  // dandling reference when leaving this scope.
879  Solver::IndexEvaluator1 opposite_values = [values](int64_t i) {
880  return -values(i);
881  };
883  new IncreasingIntExprFunctionElement(this, opposite_values, index))));
884  }
885 }
886 
887 // ----- IntIntExprFunctionElement -----
888 
889 namespace {
890 class IntIntExprFunctionElement : public BaseIntExpr {
891  public:
892  IntIntExprFunctionElement(Solver* const s, Solver::IndexEvaluator2 values,
893  IntVar* const expr1, IntVar* const expr2);
894  ~IntIntExprFunctionElement() override;
895  std::string DebugString() const override {
896  return absl::StrFormat("IntIntFunctionElement(%s,%s)",
897  expr1_->DebugString(), expr2_->DebugString());
898  }
899  int64_t Min() const override;
900  int64_t Max() const override;
901  void Range(int64_t* lower_bound, int64_t* upper_bound) override;
902  void SetMin(int64_t lower_bound) override;
903  void SetMax(int64_t upper_bound) override;
904  void SetRange(int64_t lower_bound, int64_t upper_bound) override;
905  bool Bound() const override { return expr1_->Bound() && expr2_->Bound(); }
906  // TODO(user) : improve me, the previous test is not always true
907  void WhenRange(Demon* d) override {
908  expr1_->WhenRange(d);
909  expr2_->WhenRange(d);
910  }
911 
912  void Accept(ModelVisitor* const visitor) const override {
913  visitor->BeginVisitIntegerExpression(ModelVisitor::kElement, this);
914  visitor->VisitIntegerExpressionArgument(ModelVisitor::kIndexArgument,
915  expr1_);
916  visitor->VisitIntegerExpressionArgument(ModelVisitor::kIndex2Argument,
917  expr2_);
918  // Warning: This will expand all values into a vector.
919  const int64_t expr1_min = expr1_->Min();
920  const int64_t expr1_max = expr1_->Max();
921  visitor->VisitIntegerArgument(ModelVisitor::kMinArgument, expr1_min);
922  visitor->VisitIntegerArgument(ModelVisitor::kMaxArgument, expr1_max);
923  for (int i = expr1_min; i <= expr1_max; ++i) {
924  visitor->VisitInt64ToInt64Extension(
925  [this, i](int64_t j) { return values_(i, j); }, expr2_->Min(),
926  expr2_->Max());
927  }
928  visitor->EndVisitIntegerExpression(ModelVisitor::kElement, this);
929  }
930 
931  private:
932  int64_t ElementValue(int index1, int index2) const {
933  return values_(index1, index2);
934  }
935  void UpdateSupports() const;
936 
937  IntVar* const expr1_;
938  IntVar* const expr2_;
939  mutable int64_t min_;
940  mutable int min_support1_;
941  mutable int min_support2_;
942  mutable int64_t max_;
943  mutable int max_support1_;
944  mutable int max_support2_;
945  mutable bool initial_update_;
946  Solver::IndexEvaluator2 values_;
947  IntVarIterator* const expr1_iterator_;
948  IntVarIterator* const expr2_iterator_;
949 };
950 
951 IntIntExprFunctionElement::IntIntExprFunctionElement(
952  Solver* const s, Solver::IndexEvaluator2 values, IntVar* const expr1,
953  IntVar* const expr2)
954  : BaseIntExpr(s),
955  expr1_(expr1),
956  expr2_(expr2),
957  min_(0),
958  min_support1_(-1),
959  min_support2_(-1),
960  max_(0),
961  max_support1_(-1),
962  max_support2_(-1),
963  initial_update_(true),
964  values_(std::move(values)),
965  expr1_iterator_(expr1_->MakeDomainIterator(true)),
966  expr2_iterator_(expr2_->MakeDomainIterator(true)) {
967  CHECK(values_ != nullptr);
968 }
969 
970 IntIntExprFunctionElement::~IntIntExprFunctionElement() {}
971 
972 int64_t IntIntExprFunctionElement::Min() const {
973  UpdateSupports();
974  return min_;
975 }
976 
977 int64_t IntIntExprFunctionElement::Max() const {
978  UpdateSupports();
979  return max_;
980 }
981 
983  int64_t* upper_bound) {
984  UpdateSupports();
985  *lower_bound = min_;
986  *upper_bound = max_;
987 }
988 
989 #define UPDATE_ELEMENT_INDEX_BOUNDS(test) \
990  const int64_t emin1 = expr1_->Min(); \
991  const int64_t emax1 = expr1_->Max(); \
992  const int64_t emin2 = expr2_->Min(); \
993  const int64_t emax2 = expr2_->Max(); \
994  int64_t nmin1 = emin1; \
995  bool found = false; \
996  while (nmin1 <= emax1 && !found) { \
997  for (int i = emin2; i <= emax2; ++i) { \
998  int64_t value = ElementValue(nmin1, i); \
999  if (test) { \
1000  found = true; \
1001  break; \
1002  } \
1003  } \
1004  if (!found) { \
1005  nmin1++; \
1006  } \
1007  } \
1008  if (nmin1 > emax1) { \
1009  solver()->Fail(); \
1010  } \
1011  int64_t nmin2 = emin2; \
1012  found = false; \
1013  while (nmin2 <= emax2 && !found) { \
1014  for (int i = emin1; i <= emax1; ++i) { \
1015  int64_t value = ElementValue(i, nmin2); \
1016  if (test) { \
1017  found = true; \
1018  break; \
1019  } \
1020  } \
1021  if (!found) { \
1022  nmin2++; \
1023  } \
1024  } \
1025  if (nmin2 > emax2) { \
1026  solver()->Fail(); \
1027  } \
1028  int64_t nmax1 = emax1; \
1029  found = false; \
1030  while (nmax1 >= nmin1 && !found) { \
1031  for (int i = emin2; i <= emax2; ++i) { \
1032  int64_t value = ElementValue(nmax1, i); \
1033  if (test) { \
1034  found = true; \
1035  break; \
1036  } \
1037  } \
1038  if (!found) { \
1039  nmax1--; \
1040  } \
1041  } \
1042  int64_t nmax2 = emax2; \
1043  found = false; \
1044  while (nmax2 >= nmin2 && !found) { \
1045  for (int i = emin1; i <= emax1; ++i) { \
1046  int64_t value = ElementValue(i, nmax2); \
1047  if (test) { \
1048  found = true; \
1049  break; \
1050  } \
1051  } \
1052  if (!found) { \
1053  nmax2--; \
1054  } \
1055  } \
1056  expr1_->SetRange(nmin1, nmax1); \
1057  expr2_->SetRange(nmin2, nmax2);
1058 
1059 void IntIntExprFunctionElement::SetMin(int64_t lower_bound) {
1061 }
1062 
1063 void IntIntExprFunctionElement::SetMax(int64_t upper_bound) {
1065 }
1066 
1067 void IntIntExprFunctionElement::SetRange(int64_t lower_bound,
1068  int64_t upper_bound) {
1069  if (lower_bound > upper_bound) {
1070  solver()->Fail();
1071  }
1073 }
1074 
1075 #undef UPDATE_ELEMENT_INDEX_BOUNDS
1076 
1077 void IntIntExprFunctionElement::UpdateSupports() const {
1078  if (initial_update_ || !expr1_->Contains(min_support1_) ||
1079  !expr1_->Contains(max_support1_) || !expr2_->Contains(min_support2_) ||
1080  !expr2_->Contains(max_support2_)) {
1081  const int64_t emax1 = expr1_->Max();
1082  const int64_t emax2 = expr2_->Max();
1083  int64_t min_value = ElementValue(emax1, emax2);
1084  int64_t max_value = min_value;
1085  int min_support1 = emax1;
1086  int max_support1 = emax1;
1087  int min_support2 = emax2;
1088  int max_support2 = emax2;
1089  for (const int64_t index1 : InitAndGetValues(expr1_iterator_)) {
1090  for (const int64_t index2 : InitAndGetValues(expr2_iterator_)) {
1091  const int64_t value = ElementValue(index1, index2);
1092  if (value > max_value) {
1093  max_value = value;
1094  max_support1 = index1;
1095  max_support2 = index2;
1096  } else if (value < min_value) {
1097  min_value = value;
1098  min_support1 = index1;
1099  min_support2 = index2;
1100  }
1101  }
1102  }
1103  Solver* s = solver();
1104  s->SaveAndSetValue(&min_, min_value);
1105  s->SaveAndSetValue(&min_support1_, min_support1);
1106  s->SaveAndSetValue(&min_support2_, min_support2);
1107  s->SaveAndSetValue(&max_, max_value);
1108  s->SaveAndSetValue(&max_support1_, max_support1);
1109  s->SaveAndSetValue(&max_support2_, max_support2);
1110  s->SaveAndSetValue(&initial_update_, false);
1111  }
1112 }
1113 } // namespace
1114 
1116  IntVar* const index1, IntVar* const index2) {
1117  CHECK_EQ(this, index1->solver());
1118  CHECK_EQ(this, index2->solver());
1119  return RegisterIntExpr(RevAlloc(
1120  new IntIntExprFunctionElement(this, std::move(values), index1, index2)));
1121 }
1122 
1123 // ---------- Generalized element ----------
1124 
1125 // ----- IfThenElseCt -----
1126 
1128  public:
1129  IfThenElseCt(Solver* const solver, IntVar* const condition,
1130  IntExpr* const one, IntExpr* const zero, IntVar* const target)
1131  : CastConstraint(solver, target),
1132  condition_(condition),
1133  zero_(zero),
1134  one_(one) {}
1135 
1136  ~IfThenElseCt() override {}
1137 
1138  void Post() override {
1139  Demon* const demon = solver()->MakeConstraintInitialPropagateCallback(this);
1140  condition_->WhenBound(demon);
1141  one_->WhenRange(demon);
1142  zero_->WhenRange(demon);
1143  target_var_->WhenRange(demon);
1144  }
1145 
1146  void InitialPropagate() override {
1147  condition_->SetRange(0, 1);
1148  const int64_t target_var_min = target_var_->Min();
1149  const int64_t target_var_max = target_var_->Max();
1150  int64_t new_min = std::numeric_limits<int64_t>::min();
1151  int64_t new_max = std::numeric_limits<int64_t>::max();
1152  if (condition_->Max() == 0) {
1153  zero_->SetRange(target_var_min, target_var_max);
1154  zero_->Range(&new_min, &new_max);
1155  } else if (condition_->Min() == 1) {
1156  one_->SetRange(target_var_min, target_var_max);
1157  one_->Range(&new_min, &new_max);
1158  } else {
1159  if (target_var_max < zero_->Min() || target_var_min > zero_->Max()) {
1160  condition_->SetValue(1);
1161  one_->SetRange(target_var_min, target_var_max);
1162  one_->Range(&new_min, &new_max);
1163  } else if (target_var_max < one_->Min() || target_var_min > one_->Max()) {
1164  condition_->SetValue(0);
1165  zero_->SetRange(target_var_min, target_var_max);
1166  zero_->Range(&new_min, &new_max);
1167  } else {
1168  int64_t zl = 0;
1169  int64_t zu = 0;
1170  int64_t ol = 0;
1171  int64_t ou = 0;
1172  zero_->Range(&zl, &zu);
1173  one_->Range(&ol, &ou);
1174  new_min = std::min(zl, ol);
1175  new_max = std::max(zu, ou);
1176  }
1177  }
1178  target_var_->SetRange(new_min, new_max);
1179  }
1180 
1181  std::string DebugString() const override {
1182  return absl::StrFormat("(%s ? %s : %s) == %s", condition_->DebugString(),
1183  one_->DebugString(), zero_->DebugString(),
1185  }
1186 
1187  void Accept(ModelVisitor* const visitor) const override {}
1188 
1189  private:
1190  IntVar* const condition_;
1191  IntExpr* const zero_;
1192  IntExpr* const one_;
1193 };
1194 
1195 // ----- IntExprEvaluatorElementCt -----
1196 
1197 // This constraint implements evaluator(index) == var. It is delayed such
1198 // that propagation only occurs when all variables have been touched.
1199 // The range of the evaluator is [range_start, range_end).
1200 
1201 namespace {
1202 class IntExprEvaluatorElementCt : public CastConstraint {
1203  public:
1204  IntExprEvaluatorElementCt(Solver* const s, Solver::Int64ToIntVar evaluator,
1205  int64_t range_start, int64_t range_end,
1206  IntVar* const index, IntVar* const target_var);
1207  ~IntExprEvaluatorElementCt() override {}
1208 
1209  void Post() override;
1210  void InitialPropagate() override;
1211 
1212  void Propagate();
1213  void Update(int index);
1214  void UpdateExpr();
1215 
1216  std::string DebugString() const override;
1217  void Accept(ModelVisitor* const visitor) const override;
1218 
1219  protected:
1220  IntVar* const index_;
1221 
1222  private:
1224  const int64_t range_start_;
1225  const int64_t range_end_;
1226  int min_support_;
1227  int max_support_;
1228 };
1229 
1230 IntExprEvaluatorElementCt::IntExprEvaluatorElementCt(
1231  Solver* const s, Solver::Int64ToIntVar evaluator, int64_t range_start,
1232  int64_t range_end, IntVar* const index, IntVar* const target_var)
1233  : CastConstraint(s, target_var),
1234  index_(index),
1235  evaluator_(std::move(evaluator)),
1236  range_start_(range_start),
1237  range_end_(range_end),
1238  min_support_(-1),
1239  max_support_(-1) {}
1240 
1241 void IntExprEvaluatorElementCt::Post() {
1242  Demon* const delayed_propagate_demon = MakeDelayedConstraintDemon0(
1243  solver(), this, &IntExprEvaluatorElementCt::Propagate, "Propagate");
1244  for (int i = range_start_; i < range_end_; ++i) {
1245  IntVar* const current_var = evaluator_(i);
1246  current_var->WhenRange(delayed_propagate_demon);
1247  Demon* const update_demon = MakeConstraintDemon1(
1248  solver(), this, &IntExprEvaluatorElementCt::Update, "Update", i);
1249  current_var->WhenRange(update_demon);
1250  }
1251  index_->WhenRange(delayed_propagate_demon);
1252  Demon* const update_expr_demon = MakeConstraintDemon0(
1253  solver(), this, &IntExprEvaluatorElementCt::UpdateExpr, "UpdateExpr");
1254  index_->WhenRange(update_expr_demon);
1255  Demon* const update_var_demon = MakeConstraintDemon0(
1256  solver(), this, &IntExprEvaluatorElementCt::Propagate, "UpdateVar");
1257 
1258  target_var_->WhenRange(update_var_demon);
1259 }
1260 
1261 void IntExprEvaluatorElementCt::InitialPropagate() { Propagate(); }
1262 
1263 void IntExprEvaluatorElementCt::Propagate() {
1264  const int64_t emin = std::max(range_start_, index_->Min());
1265  const int64_t emax = std::min<int64_t>(range_end_ - 1, index_->Max());
1266  const int64_t vmin = target_var_->Min();
1267  const int64_t vmax = target_var_->Max();
1268  if (emin == emax) {
1269  index_->SetValue(emin); // in case it was reduced by the above min/max.
1270  evaluator_(emin)->SetRange(vmin, vmax);
1271  } else {
1272  int64_t nmin = emin;
1273  for (; nmin <= emax; nmin++) {
1274  // break if the intersection of
1275  // [evaluator_(nmin)->Min(), evaluator_(nmin)->Max()] and [vmin, vmax]
1276  // is non-empty.
1277  IntVar* const nmin_var = evaluator_(nmin);
1278  if (nmin_var->Min() <= vmax && nmin_var->Max() >= vmin) break;
1279  }
1280  int64_t nmax = emax;
1281  for (; nmin <= nmax; nmax--) {
1282  // break if the intersection of
1283  // [evaluator_(nmin)->Min(), evaluator_(nmin)->Max()] and [vmin, vmax]
1284  // is non-empty.
1285  IntExpr* const nmax_var = evaluator_(nmax);
1286  if (nmax_var->Min() <= vmax && nmax_var->Max() >= vmin) break;
1287  }
1288  index_->SetRange(nmin, nmax);
1289  if (nmin == nmax) {
1290  evaluator_(nmin)->SetRange(vmin, vmax);
1291  }
1292  }
1293  if (min_support_ == -1 || max_support_ == -1) {
1294  int min_support = -1;
1295  int max_support = -1;
1296  int64_t gmin = std::numeric_limits<int64_t>::max();
1297  int64_t gmax = std::numeric_limits<int64_t>::min();
1298  for (int i = index_->Min(); i <= index_->Max(); ++i) {
1299  IntExpr* const var_i = evaluator_(i);
1300  const int64_t vmin = var_i->Min();
1301  if (vmin < gmin) {
1302  gmin = vmin;
1303  }
1304  const int64_t vmax = var_i->Max();
1305  if (vmax > gmax) {
1306  gmax = vmax;
1307  }
1308  }
1309  solver()->SaveAndSetValue(&min_support_, min_support);
1310  solver()->SaveAndSetValue(&max_support_, max_support);
1311  target_var_->SetRange(gmin, gmax);
1312  }
1313 }
1314 
1315 void IntExprEvaluatorElementCt::Update(int index) {
1316  if (index == min_support_ || index == max_support_) {
1317  solver()->SaveAndSetValue(&min_support_, -1);
1318  solver()->SaveAndSetValue(&max_support_, -1);
1319  }
1320 }
1321 
1322 void IntExprEvaluatorElementCt::UpdateExpr() {
1323  if (!index_->Contains(min_support_) || !index_->Contains(max_support_)) {
1324  solver()->SaveAndSetValue(&min_support_, -1);
1325  solver()->SaveAndSetValue(&max_support_, -1);
1326  }
1327 }
1328 
1329 namespace {
1330 std::string StringifyEvaluatorBare(const Solver::Int64ToIntVar& evaluator,
1331  int64_t range_start, int64_t range_end) {
1332  std::string out;
1333  for (int64_t i = range_start; i < range_end; ++i) {
1334  if (i != range_start) {
1335  out += ", ";
1336  }
1337  out += absl::StrFormat("%d -> %s", i, evaluator(i)->DebugString());
1338  }
1339  return out;
1340 }
1341 
1342 std::string StringifyInt64ToIntVar(const Solver::Int64ToIntVar& evaluator,
1343  int64_t range_begin, int64_t range_end) {
1344  std::string out;
1345  if (range_end - range_begin > 10) {
1346  out = absl::StrFormat(
1347  "IntToIntVar(%s, ...%s)",
1348  StringifyEvaluatorBare(evaluator, range_begin, range_begin + 5),
1349  StringifyEvaluatorBare(evaluator, range_end - 5, range_end));
1350  } else {
1351  out = absl::StrFormat(
1352  "IntToIntVar(%s)",
1353  StringifyEvaluatorBare(evaluator, range_begin, range_end));
1354  }
1355  return out;
1356 }
1357 } // namespace
1358 
1359 std::string IntExprEvaluatorElementCt::DebugString() const {
1360  return StringifyInt64ToIntVar(evaluator_, range_start_, range_end_);
1361 }
1362 
1363 void IntExprEvaluatorElementCt::Accept(ModelVisitor* const visitor) const {
1364  visitor->BeginVisitConstraint(ModelVisitor::kElementEqual, this);
1365  visitor->VisitIntegerVariableEvaluatorArgument(
1367  visitor->VisitIntegerExpressionArgument(ModelVisitor::kIndexArgument, index_);
1368  visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
1369  target_var_);
1370  visitor->EndVisitConstraint(ModelVisitor::kElementEqual, this);
1371 }
1372 
1373 // ----- IntExprArrayElementCt -----
1374 
1375 // This constraint implements vars[index] == var. It is delayed such
1376 // that propagation only occurs when all variables have been touched.
1377 
1378 class IntExprArrayElementCt : public IntExprEvaluatorElementCt {
1379  public:
1380  IntExprArrayElementCt(Solver* const s, std::vector<IntVar*> vars,
1381  IntVar* const index, IntVar* const target_var);
1382 
1383  std::string DebugString() const override;
1384  void Accept(ModelVisitor* const visitor) const override;
1385 
1386  private:
1387  const std::vector<IntVar*> vars_;
1388 };
1389 
1390 IntExprArrayElementCt::IntExprArrayElementCt(Solver* const s,
1391  std::vector<IntVar*> vars,
1392  IntVar* const index,
1393  IntVar* const target_var)
1394  : IntExprEvaluatorElementCt(
1395  s, [this](int64_t idx) { return vars_[idx]; }, 0, vars.size(), index,
1396  target_var),
1397  vars_(std::move(vars)) {}
1398 
1399 std::string IntExprArrayElementCt::DebugString() const {
1400  int64_t size = vars_.size();
1401  if (size > 10) {
1402  return absl::StrFormat(
1403  "IntExprArrayElement(var array of size %d, %s) == %s", size,
1404  index_->DebugString(), target_var_->DebugString());
1405  } else {
1406  return absl::StrFormat("IntExprArrayElement([%s], %s) == %s",
1407  JoinDebugStringPtr(vars_, ", "),
1408  index_->DebugString(), target_var_->DebugString());
1409  }
1410 }
1411 
1412 void IntExprArrayElementCt::Accept(ModelVisitor* const visitor) const {
1413  visitor->BeginVisitConstraint(ModelVisitor::kElementEqual, this);
1414  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
1415  vars_);
1416  visitor->VisitIntegerExpressionArgument(ModelVisitor::kIndexArgument, index_);
1417  visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
1418  target_var_);
1419  visitor->EndVisitConstraint(ModelVisitor::kElementEqual, this);
1420 }
1421 
1422 // ----- IntExprArrayElementCstCt -----
1423 
1424 // This constraint implements vars[index] == constant.
1425 
1426 class IntExprArrayElementCstCt : public Constraint {
1427  public:
1428  IntExprArrayElementCstCt(Solver* const s, const std::vector<IntVar*>& vars,
1429  IntVar* const index, int64_t target)
1430  : Constraint(s),
1431  vars_(vars),
1432  index_(index),
1433  target_(target),
1434  demons_(vars.size()) {}
1435 
1436  ~IntExprArrayElementCstCt() override {}
1437 
1438  void Post() override {
1439  for (int i = 0; i < vars_.size(); ++i) {
1440  demons_[i] = MakeConstraintDemon1(
1441  solver(), this, &IntExprArrayElementCstCt::Propagate, "Propagate", i);
1442  vars_[i]->WhenDomain(demons_[i]);
1443  }
1444  Demon* const index_demon = MakeConstraintDemon0(
1445  solver(), this, &IntExprArrayElementCstCt::PropagateIndex,
1446  "PropagateIndex");
1447  index_->WhenBound(index_demon);
1448  }
1449 
1450  void InitialPropagate() override {
1451  for (int i = 0; i < vars_.size(); ++i) {
1452  Propagate(i);
1453  }
1454  PropagateIndex();
1455  }
1456 
1457  void Propagate(int index) {
1458  if (!vars_[index]->Contains(target_)) {
1459  index_->RemoveValue(index);
1460  demons_[index]->inhibit(solver());
1461  }
1462  }
1463 
1464  void PropagateIndex() {
1465  if (index_->Bound()) {
1466  vars_[index_->Min()]->SetValue(target_);
1467  }
1468  }
1469 
1470  std::string DebugString() const override {
1471  return absl::StrFormat("IntExprArrayElement([%s], %s) == %d",
1472  JoinDebugStringPtr(vars_, ", "),
1473  index_->DebugString(), target_);
1474  }
1475 
1476  void Accept(ModelVisitor* const visitor) const override {
1477  visitor->BeginVisitConstraint(ModelVisitor::kElementEqual, this);
1478  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
1479  vars_);
1480  visitor->VisitIntegerExpressionArgument(ModelVisitor::kIndexArgument,
1481  index_);
1482  visitor->VisitIntegerArgument(ModelVisitor::kTargetArgument, target_);
1483  visitor->EndVisitConstraint(ModelVisitor::kElementEqual, this);
1484  }
1485 
1486  private:
1487  const std::vector<IntVar*> vars_;
1488  IntVar* const index_;
1489  const int64_t target_;
1490  std::vector<Demon*> demons_;
1491 };
1492 
1493 // This constraint implements index == position(constant in vars).
1494 
1495 class IntExprIndexOfCt : public Constraint {
1496  public:
1497  IntExprIndexOfCt(Solver* const s, const std::vector<IntVar*>& vars,
1498  IntVar* const index, int64_t target)
1499  : Constraint(s),
1500  vars_(vars),
1501  index_(index),
1502  target_(target),
1503  demons_(vars_.size()),
1504  index_iterator_(index->MakeHoleIterator(true)) {}
1505 
1506  ~IntExprIndexOfCt() override {}
1507 
1508  void Post() override {
1509  for (int i = 0; i < vars_.size(); ++i) {
1510  demons_[i] = MakeConstraintDemon1(
1511  solver(), this, &IntExprIndexOfCt::Propagate, "Propagate", i);
1512  vars_[i]->WhenDomain(demons_[i]);
1513  }
1514  Demon* const index_demon = MakeConstraintDemon0(
1515  solver(), this, &IntExprIndexOfCt::PropagateIndex, "PropagateIndex");
1516  index_->WhenDomain(index_demon);
1517  }
1518 
1519  void InitialPropagate() override {
1520  for (int i = 0; i < vars_.size(); ++i) {
1521  if (!index_->Contains(i)) {
1522  vars_[i]->RemoveValue(target_);
1523  } else if (!vars_[i]->Contains(target_)) {
1524  index_->RemoveValue(i);
1525  demons_[i]->inhibit(solver());
1526  } else if (vars_[i]->Bound()) {
1527  index_->SetValue(i);
1528  demons_[i]->inhibit(solver());
1529  }
1530  }
1531  }
1532 
1533  void Propagate(int index) {
1534  if (!vars_[index]->Contains(target_)) {
1535  index_->RemoveValue(index);
1536  demons_[index]->inhibit(solver());
1537  } else if (vars_[index]->Bound()) {
1538  index_->SetValue(index);
1539  }
1540  }
1541 
1542  void PropagateIndex() {
1543  const int64_t oldmax = index_->OldMax();
1544  const int64_t vmin = index_->Min();
1545  const int64_t vmax = index_->Max();
1546  for (int64_t value = index_->OldMin(); value < vmin; ++value) {
1547  vars_[value]->RemoveValue(target_);
1548  demons_[value]->inhibit(solver());
1549  }
1550  for (const int64_t value : InitAndGetValues(index_iterator_)) {
1551  vars_[value]->RemoveValue(target_);
1552  demons_[value]->inhibit(solver());
1553  }
1554  for (int64_t value = vmax + 1; value <= oldmax; ++value) {
1555  vars_[value]->RemoveValue(target_);
1556  demons_[value]->inhibit(solver());
1557  }
1558  if (index_->Bound()) {
1559  vars_[index_->Min()]->SetValue(target_);
1560  }
1561  }
1562 
1563  std::string DebugString() const override {
1564  return absl::StrFormat("IntExprIndexOf([%s], %s) == %d",
1565  JoinDebugStringPtr(vars_, ", "),
1566  index_->DebugString(), target_);
1567  }
1568 
1569  void Accept(ModelVisitor* const visitor) const override {
1570  visitor->BeginVisitConstraint(ModelVisitor::kIndexOf, this);
1571  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
1572  vars_);
1573  visitor->VisitIntegerExpressionArgument(ModelVisitor::kIndexArgument,
1574  index_);
1575  visitor->VisitIntegerArgument(ModelVisitor::kTargetArgument, target_);
1576  visitor->EndVisitConstraint(ModelVisitor::kIndexOf, this);
1577  }
1578 
1579  private:
1580  const std::vector<IntVar*> vars_;
1581  IntVar* const index_;
1582  const int64_t target_;
1583  std::vector<Demon*> demons_;
1584  IntVarIterator* const index_iterator_;
1585 };
1586 
1587 // Factory helper.
1588 
1589 Constraint* MakeElementEqualityFunc(Solver* const solver,
1590  const std::vector<int64_t>& vals,
1591  IntVar* const index, IntVar* const target) {
1592  if (index->Bound()) {
1593  const int64_t val = index->Min();
1594  if (val < 0 || val >= vals.size()) {
1595  return solver->MakeFalseConstraint();
1596  } else {
1597  return solver->MakeEquality(target, vals[val]);
1598  }
1599  } else {
1600  if (IsIncreasingContiguous(vals)) {
1601  return solver->MakeEquality(target, solver->MakeSum(index, vals[0]));
1602  } else {
1603  return solver->RevAlloc(
1604  new IntElementConstraint(solver, vals, index, target));
1605  }
1606  }
1607 }
1608 } // namespace
1609 
1611  IntExpr* const then_expr,
1612  IntExpr* const else_expr,
1613  IntVar* const target_var) {
1614  return RevAlloc(
1615  new IfThenElseCt(this, condition, then_expr, else_expr, target_var));
1616 }
1617 
1618 IntExpr* Solver::MakeElement(const std::vector<IntVar*>& vars,
1619  IntVar* const index) {
1620  if (index->Bound()) {
1621  return vars[index->Min()];
1622  }
1623  const int size = vars.size();
1624  if (AreAllBound(vars)) {
1625  std::vector<int64_t> values(size);
1626  for (int i = 0; i < size; ++i) {
1627  values[i] = vars[i]->Value();
1628  }
1629  return MakeElement(values, index);
1630  }
1631  if (index->Size() == 2 && index->Min() + 1 == index->Max() &&
1632  index->Min() >= 0 && index->Max() < vars.size()) {
1633  // Let's get the index between 0 and 1.
1634  IntVar* const scaled_index = MakeSum(index, -index->Min())->Var();
1635  IntVar* const zero = vars[index->Min()];
1636  IntVar* const one = vars[index->Max()];
1637  const std::string name = absl::StrFormat(
1638  "ElementVar([%s], %s)", JoinNamePtr(vars, ", "), index->name());
1639  IntVar* const target = MakeIntVar(std::min(zero->Min(), one->Min()),
1640  std::max(zero->Max(), one->Max()), name);
1641  AddConstraint(
1642  RevAlloc(new IfThenElseCt(this, scaled_index, one, zero, target)));
1643  return target;
1644  }
1645  int64_t emin = std::numeric_limits<int64_t>::max();
1646  int64_t emax = std::numeric_limits<int64_t>::min();
1647  std::unique_ptr<IntVarIterator> iterator(index->MakeDomainIterator(false));
1648  for (const int64_t index_value : InitAndGetValues(iterator.get())) {
1649  if (index_value >= 0 && index_value < size) {
1650  emin = std::min(emin, vars[index_value]->Min());
1651  emax = std::max(emax, vars[index_value]->Max());
1652  }
1653  }
1654  const std::string vname =
1655  size > 10 ? absl::StrFormat("ElementVar(var array of size %d, %s)", size,
1656  index->DebugString())
1657  : absl::StrFormat("ElementVar([%s], %s)",
1658  JoinNamePtr(vars, ", "), index->name());
1659  IntVar* const element_var = MakeIntVar(emin, emax, vname);
1660  AddConstraint(
1661  RevAlloc(new IntExprArrayElementCt(this, vars, index, element_var)));
1662  return element_var;
1663 }
1664 
1665 IntExpr* Solver::MakeElement(Int64ToIntVar vars, int64_t range_start,
1666  int64_t range_end, IntVar* argument) {
1667  const std::string index_name =
1668  !argument->name().empty() ? argument->name() : argument->DebugString();
1669  const std::string vname = absl::StrFormat(
1670  "ElementVar(%s, %s)",
1671  StringifyInt64ToIntVar(vars, range_start, range_end), index_name);
1672  IntVar* const element_var =
1675  IntExprEvaluatorElementCt* evaluation_ct = new IntExprEvaluatorElementCt(
1676  this, std::move(vars), range_start, range_end, argument, element_var);
1677  AddConstraint(RevAlloc(evaluation_ct));
1678  evaluation_ct->Propagate();
1679  return element_var;
1680 }
1681 
1682 Constraint* Solver::MakeElementEquality(const std::vector<int64_t>& vals,
1683  IntVar* const index,
1684  IntVar* const target) {
1685  return MakeElementEqualityFunc(this, vals, index, target);
1686 }
1687 
1688 Constraint* Solver::MakeElementEquality(const std::vector<int>& vals,
1689  IntVar* const index,
1690  IntVar* const target) {
1691  return MakeElementEqualityFunc(this, ToInt64Vector(vals), index, target);
1692 }
1693 
1694 Constraint* Solver::MakeElementEquality(const std::vector<IntVar*>& vars,
1695  IntVar* const index,
1696  IntVar* const target) {
1697  if (AreAllBound(vars)) {
1698  std::vector<int64_t> values(vars.size());
1699  for (int i = 0; i < vars.size(); ++i) {
1700  values[i] = vars[i]->Value();
1701  }
1702  return MakeElementEquality(values, index, target);
1703  }
1704  if (index->Bound()) {
1705  const int64_t val = index->Min();
1706  if (val < 0 || val >= vars.size()) {
1707  return MakeFalseConstraint();
1708  } else {
1709  return MakeEquality(target, vars[val]);
1710  }
1711  } else {
1712  if (target->Bound()) {
1713  return RevAlloc(
1714  new IntExprArrayElementCstCt(this, vars, index, target->Min()));
1715  } else {
1716  return RevAlloc(new IntExprArrayElementCt(this, vars, index, target));
1717  }
1718  }
1719 }
1720 
1721 Constraint* Solver::MakeElementEquality(const std::vector<IntVar*>& vars,
1722  IntVar* const index, int64_t target) {
1723  if (AreAllBound(vars)) {
1724  std::vector<int> valid_indices;
1725  for (int i = 0; i < vars.size(); ++i) {
1726  if (vars[i]->Value() == target) {
1727  valid_indices.push_back(i);
1728  }
1729  }
1730  return MakeMemberCt(index, valid_indices);
1731  }
1732  if (index->Bound()) {
1733  const int64_t pos = index->Min();
1734  if (pos >= 0 && pos < vars.size()) {
1735  IntVar* const var = vars[pos];
1736  return MakeEquality(var, target);
1737  } else {
1738  return MakeFalseConstraint();
1739  }
1740  } else {
1741  return RevAlloc(new IntExprArrayElementCstCt(this, vars, index, target));
1742  }
1743 }
1744 
1745 Constraint* Solver::MakeIndexOfConstraint(const std::vector<IntVar*>& vars,
1746  IntVar* const index, int64_t target) {
1747  if (index->Bound()) {
1748  const int64_t pos = index->Min();
1749  if (pos >= 0 && pos < vars.size()) {
1750  IntVar* const var = vars[pos];
1751  return MakeEquality(var, target);
1752  } else {
1753  return MakeFalseConstraint();
1754  }
1755  } else {
1756  return RevAlloc(new IntExprIndexOfCt(this, vars, index, target));
1757  }
1758 }
1759 
1760 IntExpr* Solver::MakeIndexExpression(const std::vector<IntVar*>& vars,
1761  int64_t value) {
1762  IntExpr* const cache = model_cache_->FindVarArrayConstantExpression(
1764  if (cache != nullptr) {
1765  return cache->Var();
1766  } else {
1767  const std::string name =
1768  absl::StrFormat("Index(%s, %d)", JoinNamePtr(vars, ", "), value);
1769  IntVar* const index = MakeIntVar(0, vars.size() - 1, name);
1771  model_cache_->InsertVarArrayConstantExpression(
1773  return index;
1774  }
1775 }
1776 } // namespace operations_research
const std::vector< IntVar * > vars_
Definition: alldiff_cst.cc:44
int64_t max
Definition: alldiff_cst.cc:140
int64_t min
Definition: alldiff_cst.cc:139
Cast constraints are special channeling constraints designed to keep a variable in sync with an expre...
A constraint is the main modeling object.
A Demon is the base element of a propagation queue.
void Post() override
This method is called when the constraint is processed by the solver.
Definition: element.cc:1138
void InitialPropagate() override
This method performs the initial propagation of the constraint.
Definition: element.cc:1146
IfThenElseCt(Solver *const solver, IntVar *const condition, IntExpr *const one, IntExpr *const zero, IntVar *const target)
Definition: element.cc:1129
void Accept(ModelVisitor *const visitor) const override
Accepts the given visitor.
Definition: element.cc:1187
std::string DebugString() const override
Definition: element.cc:1181
Utility class to encapsulate an IntVarIterator and use it in a range-based loop.
The class IntExpr is the base of all integer expressions in constraint programming.
virtual IntVar * Var()=0
Creates a variable from the expression.
virtual void SetRange(int64_t l, int64_t u)
This method sets both the min and the max of the expression.
virtual bool Bound() const
Returns true if the min and the max of the expression are equal.
virtual void SetValue(int64_t v)
This method sets the value of the expression.
virtual int64_t Min() const =0
virtual int64_t Max() const =0
virtual void Range(int64_t *l, int64_t *u)
By default calls Min() and Max(), but can be redefined when Min and Max code can be factorized.
virtual void WhenRange(Demon *d)=0
Attach a demon that will watch the min or the max of the expression.
The class IntVar is a subset of IntExpr.
virtual bool Contains(int64_t v) const =0
This method returns whether the value 'v' is in the domain of the variable.
virtual void WhenBound(Demon *d)=0
This method attaches a demon that will be awakened when the variable is bound.
virtual std::string name() const
Object naming.
IntExpr * MakeIndexExpression(const std::vector< IntVar * > &vars, int64_t value)
Returns the expression expr such that vars[expr] == value.
Definition: element.cc:1760
IntExpr * RegisterIntExpr(IntExpr *const expr)
Registers a new IntExpr and wraps it inside a TraceIntExpr if necessary.
Definition: trace.cc:850
Constraint * MakeFalseConstraint()
This constraint always fails.
Definition: constraints.cc:523
Constraint * MakeEquality(IntExpr *const left, IntExpr *const right)
left == right
Definition: range_cst.cc:514
Constraint * MakeElementEquality(const std::vector< int64_t > &vals, IntVar *const index, IntVar *const target)
Definition: element.cc:1682
IntVar * MakeIntVar(int64_t min, int64_t max, const std::string &name)
MakeIntVar will create the best range based int var for the bounds given.
Constraint * MakeMemberCt(IntExpr *const expr, const std::vector< int64_t > &values)
expr in set.
Definition: expr_cst.cc:1165
std::function< int64_t(int64_t, int64_t)> IndexEvaluator2
void AddConstraint(Constraint *const c)
Adds the constraint 'c' to the model.
IntExpr * MakeOpposite(IntExpr *const expr)
-expr
Constraint * MakeIfThenElseCt(IntVar *const condition, IntExpr *const then_expr, IntExpr *const else_expr, IntVar *const target_var)
Special cases with arrays of size two.
Definition: element.cc:1610
Demon * MakeConstraintInitialPropagateCallback(Constraint *const ct)
This method is a specialized case of the MakeConstraintDemon method to call the InitiatePropagate of ...
Definition: constraints.cc:35
Constraint * MakeIndexOfConstraint(const std::vector< IntVar * > &vars, IntVar *const index, int64_t target)
This constraint is a special case of the element constraint with an array of integer variables,...
Definition: element.cc:1745
IntExpr * MakeElement(const std::vector< int64_t > &values, IntVar *const index)
values[index]
Definition: element.cc:658
T * RevAlloc(T *object)
Registers the given object as being reversible.
IntExpr * MakeSum(IntExpr *const left, IntExpr *const right)
left + right.
std::function< int64_t(int64_t)> IndexEvaluator1
Callback typedefs.
std::function< IntVar *(int64_t)> Int64ToIntVar
IntExpr * MakeMonotonicElement(IndexEvaluator1 values, bool increasing, IntVar *const index)
Function based element.
Definition: element.cc:870
int64_t b
std::vector< int64_t > to_remove_
const std::string name
int64_t value
#define UPDATE_ELEMENT_INDEX_BOUNDS(test)
Definition: element.cc:989
IntVar *const expr_
Definition: element.cc:88
ABSL_FLAG(bool, cp_disable_element_cache, true, "If true, caching for IntElement is disabled.")
#define UPDATE_RMQ_BASE_ELEMENT_INDEX_BOUNDS(test)
Definition: element.cc:424
IntVar * var
Definition: expr_array.cc:1874
int index
std::pair< double, double > Range
Definition: statistics.h:27
std::function< int64_t(const Model &)> Value(IntegerVariable v)
Definition: integer.h:1795
Collection of objects used to extend the Constraint Solver library.
bool IsArrayConstant(const std::vector< T > &values, const T &value)
bool IsIncreasing(const std::vector< T > &values)
Demon * MakeConstraintDemon0(Solver *const s, T *const ct, void(T::*method)(), const std::string &name)
bool IsArrayBoolean(const std::vector< T > &values)
Demon * MakeConstraintDemon1(Solver *const s, T *const ct, void(T::*method)(P), const std::string &name, P param1)
Demon * MakeDelayedConstraintDemon0(Solver *const s, T *const ct, void(T::*method)(), const std::string &name)
std::string JoinDebugStringPtr(const std::vector< T > &v, const std::string &separator)
Definition: string_array.h:45
bool IsIncreasingContiguous(const std::vector< T > &values)
std::vector< int64_t > ToInt64Vector(const std::vector< int > &input)
Definition: utilities.cc:829
void LinkVarExpr(Solver *const s, IntExpr *const expr, IntVar *const var)
bool AreAllBound(const std::vector< IntVar * > &vars)
std::string JoinNamePtr(const std::vector< T > &v, const std::string &separator)
Definition: string_array.h:52
IntVar * upper_bound
Definition: routing.cc:1087
IntVar * lower_bound
Definition: routing.cc:1086
IntervalVar *const target_var_
std::function< int64_t(int64_t, int64_t)> evaluator_
Definition: search.cc:1384