OR-Tools  9.1
constraints.cc
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 #include <string.h>
15 
16 #include <algorithm>
17 #include <cstdint>
18 #include <limits>
19 #include <memory>
20 #include <string>
21 #include <utility>
22 #include <vector>
23 
24 #include "absl/strings/str_cat.h"
25 #include "absl/strings/str_format.h"
27 #include "ortools/base/logging.h"
32 
33 namespace operations_research {
34 
37  "InitialPropagate");
38 }
39 
41  Constraint* const ct) {
43  "InitialPropagate");
44 }
45 
46 namespace {
47 class ActionDemon : public Demon {
48  public:
49  explicit ActionDemon(const Solver::Action& action) : action_(action) {
50  CHECK(action != nullptr);
51  }
52 
53  ~ActionDemon() override {}
54 
55  void Run(Solver* const solver) override { action_(solver); }
56 
57  private:
58  Solver::Action action_;
59 };
60 
61 class ClosureDemon : public Demon {
62  public:
63  explicit ClosureDemon(const Solver::Closure& closure) : closure_(closure) {
64  CHECK(closure != nullptr);
65  }
66 
67  ~ClosureDemon() override {}
68 
69  void Run(Solver* const solver) override { closure_(); }
70 
71  private:
72  Solver::Closure closure_;
73 };
74 
75 // ----- True and False Constraint -----
76 
77 class TrueConstraint : public Constraint {
78  public:
79  explicit TrueConstraint(Solver* const s) : Constraint(s) {}
80  ~TrueConstraint() override {}
81 
82  void Post() override {}
83  void InitialPropagate() override {}
84  std::string DebugString() const override { return "TrueConstraint()"; }
85 
86  void Accept(ModelVisitor* const visitor) const override {
87  visitor->BeginVisitConstraint(ModelVisitor::kTrueConstraint, this);
88  visitor->EndVisitConstraint(ModelVisitor::kTrueConstraint, this);
89  }
90  IntVar* Var() override { return solver()->MakeIntConst(1); }
91 };
92 
93 class FalseConstraint : public Constraint {
94  public:
95  explicit FalseConstraint(Solver* const s) : Constraint(s) {}
96  FalseConstraint(Solver* const s, const std::string& explanation)
97  : Constraint(s), explanation_(explanation) {}
98  ~FalseConstraint() override {}
99 
100  void Post() override {}
101  void InitialPropagate() override { solver()->Fail(); }
102  std::string DebugString() const override {
103  return absl::StrCat("FalseConstraint(", explanation_, ")");
104  }
105 
106  void Accept(ModelVisitor* const visitor) const override {
107  visitor->BeginVisitConstraint(ModelVisitor::kFalseConstraint, this);
108  visitor->EndVisitConstraint(ModelVisitor::kFalseConstraint, this);
109  }
110  IntVar* Var() override { return solver()->MakeIntConst(0); }
111 
112  private:
113  const std::string explanation_;
114 };
115 
116 // ----- Map Variable Domain to Boolean Var Array -----
117 // TODO(user) : optimize constraint to avoid ping pong.
118 // After a boolvar is set to 0, we remove the value from the var.
119 // There is no need to rescan the var to find the hole if the size at the end of
120 // UpdateActive() is the same as the size at the beginning of VarDomain().
121 
122 class MapDomain : public Constraint {
123  public:
124  MapDomain(Solver* const s, IntVar* const var,
125  const std::vector<IntVar*>& actives)
126  : Constraint(s), var_(var), actives_(actives) {
127  holes_ = var->MakeHoleIterator(true);
128  }
129 
130  ~MapDomain() override {}
131 
132  void Post() override {
133  Demon* vd = MakeConstraintDemon0(solver(), this, &MapDomain::VarDomain,
134  "VarDomain");
135  var_->WhenDomain(vd);
136  Demon* vb =
137  MakeConstraintDemon0(solver(), this, &MapDomain::VarBound, "VarBound");
138  var_->WhenBound(vb);
139  std::unique_ptr<IntVarIterator> domain_it(
140  var_->MakeDomainIterator(/*reversible=*/false));
141  for (const int64_t index : InitAndGetValues(domain_it.get())) {
142  if (index >= 0 && index < actives_.size() && !actives_[index]->Bound()) {
143  Demon* d = MakeConstraintDemon1(
144  solver(), this, &MapDomain::UpdateActive, "UpdateActive", index);
145  actives_[index]->WhenDomain(d);
146  }
147  }
148  }
149 
150  void InitialPropagate() override {
151  for (int i = 0; i < actives_.size(); ++i) {
152  actives_[i]->SetRange(int64_t{0}, int64_t{1});
153  if (!var_->Contains(i)) {
154  actives_[i]->SetValue(0);
155  } else if (actives_[i]->Max() == 0LL) {
156  var_->RemoveValue(i);
157  }
158  if (actives_[i]->Min() == 1LL) {
159  var_->SetValue(i);
160  }
161  }
162  if (var_->Bound()) {
163  VarBound();
164  }
165  }
166 
167  void UpdateActive(int64_t index) {
168  IntVar* const act = actives_[index];
169  if (act->Max() == 0) {
170  var_->RemoveValue(index);
171  } else if (act->Min() == 1) {
172  var_->SetValue(index);
173  }
174  }
175 
176  void VarDomain() {
177  const int64_t oldmin = var_->OldMin();
178  const int64_t oldmax = var_->OldMax();
179  const int64_t vmin = var_->Min();
180  const int64_t vmax = var_->Max();
181  const int64_t size = actives_.size();
182  for (int64_t j = std::max(oldmin, int64_t{0}); j < std::min(vmin, size);
183  ++j) {
184  actives_[j]->SetValue(0);
185  }
186  for (const int64_t j : InitAndGetValues(holes_)) {
187  if (j >= 0 && j < size) {
188  actives_[j]->SetValue(0);
189  }
190  }
191  for (int64_t j = std::max(vmax + int64_t{1}, int64_t{0});
192  j <= std::min(oldmax, size - int64_t{1}); ++j) {
193  actives_[j]->SetValue(int64_t{0});
194  }
195  }
196 
197  void VarBound() {
198  const int64_t val = var_->Min();
199  if (val >= 0 && val < actives_.size()) {
200  actives_[val]->SetValue(1);
201  }
202  }
203  std::string DebugString() const override {
204  return absl::StrFormat("MapDomain(%s, [%s])", var_->DebugString(),
205  JoinDebugStringPtr(actives_, ", "));
206  }
207 
208  void Accept(ModelVisitor* const visitor) const override {
209  visitor->BeginVisitConstraint(ModelVisitor::kMapDomain, this);
210  visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
211  var_);
212  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
213  actives_);
214  visitor->EndVisitConstraint(ModelVisitor::kMapDomain, this);
215  }
216 
217  private:
218  IntVar* const var_;
219  std::vector<IntVar*> actives_;
220  IntVarIterator* holes_;
221 };
222 
223 // ----- Lex constraint -----
224 
225 class LexicalLess : public Constraint {
226  public:
227  LexicalLess(Solver* const s, const std::vector<IntVar*>& left,
228  const std::vector<IntVar*>& right, bool strict)
229  : Constraint(s),
230  left_(left),
231  right_(right),
232  active_var_(0),
233  strict_(strict),
234  demon_(nullptr) {
235  CHECK_EQ(left.size(), right.size());
236  }
237 
238  ~LexicalLess() override {}
239 
240  void Post() override {
241  const int position = JumpEqualVariables(0);
242  active_var_.SetValue(solver(), position);
243  if (position < left_.size()) {
244  demon_ = solver()->MakeConstraintInitialPropagateCallback(this);
245  left_[position]->WhenRange(demon_);
246  right_[position]->WhenRange(demon_);
247  }
248  }
249 
250  void InitialPropagate() override {
251  const int position = JumpEqualVariables(active_var_.Value());
252  if (position >= left_.size()) {
253  if (strict_) {
254  solver()->Fail();
255  }
256  return;
257  }
258  if (position != active_var_.Value()) {
259  left_[position]->WhenRange(demon_);
260  right_[position]->WhenRange(demon_);
261  active_var_.SetValue(solver(), position);
262  }
263  const int next_non_equal = JumpEqualVariables(position + 1);
264  if ((strict_ && next_non_equal == left_.size()) ||
265  (next_non_equal < left_.size() &&
266  left_[next_non_equal]->Min() > right_[next_non_equal]->Max())) {
267  // We need to be strict if we are the last in the array, or if
268  // the next one is impossible.
269  left_[position]->SetMax(right_[position]->Max() - 1);
270  right_[position]->SetMin(left_[position]->Min() + 1);
271  } else {
272  left_[position]->SetMax(right_[position]->Max());
273  right_[position]->SetMin(left_[position]->Min());
274  }
275  }
276 
277  std::string DebugString() const override {
278  return absl::StrFormat(
279  "%s([%s], [%s])", strict_ ? "LexicalLess" : "LexicalLessOrEqual",
280  JoinDebugStringPtr(left_, ", "), JoinDebugStringPtr(right_, ", "));
281  }
282 
283  void Accept(ModelVisitor* const visitor) const override {
284  visitor->BeginVisitConstraint(ModelVisitor::kLexLess, this);
285  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kLeftArgument,
286  left_);
287  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kRightArgument,
288  right_);
289  visitor->VisitIntegerArgument(ModelVisitor::kValueArgument, strict_);
290  visitor->EndVisitConstraint(ModelVisitor::kLexLess, this);
291  }
292 
293  private:
294  int JumpEqualVariables(int start_position) const {
295  int position = start_position;
296  while (position < left_.size() && left_[position]->Bound() &&
297  right_[position]->Bound() &&
298  left_[position]->Min() == right_[position]->Min()) {
299  position++;
300  }
301  return position;
302  }
303 
304  std::vector<IntVar*> left_;
305  std::vector<IntVar*> right_;
306  NumericalRev<int> active_var_;
307  const bool strict_;
308  Demon* demon_;
309 };
310 
311 // ----- Inverse permutation constraint -----
312 
313 class InversePermutationConstraint : public Constraint {
314  public:
315  InversePermutationConstraint(Solver* const s,
316  const std::vector<IntVar*>& left,
317  const std::vector<IntVar*>& right)
318  : Constraint(s),
319  left_(left),
320  right_(right),
321  left_hole_iterators_(left.size()),
322  left_domain_iterators_(left_.size()),
323  right_hole_iterators_(right_.size()),
324  right_domain_iterators_(right_.size()) {
325  CHECK_EQ(left_.size(), right_.size());
326  for (int i = 0; i < left_.size(); ++i) {
327  left_hole_iterators_[i] = left_[i]->MakeHoleIterator(true);
328  left_domain_iterators_[i] = left_[i]->MakeDomainIterator(true);
329  right_hole_iterators_[i] = right_[i]->MakeHoleIterator(true);
330  right_domain_iterators_[i] = right_[i]->MakeDomainIterator(true);
331  }
332  }
333 
334  ~InversePermutationConstraint() override {}
335 
336  void Post() override {
337  for (int i = 0; i < left_.size(); ++i) {
338  Demon* const left_demon = MakeConstraintDemon1(
339  solver(), this,
340  &InversePermutationConstraint::PropagateHolesOfLeftVarToRight,
341  "PropagateHolesOfLeftVarToRight", i);
342  left_[i]->WhenDomain(left_demon);
343  Demon* const right_demon = MakeConstraintDemon1(
344  solver(), this,
345  &InversePermutationConstraint::PropagateHolesOfRightVarToLeft,
346  "PropagateHolesOfRightVarToLeft", i);
347  right_[i]->WhenDomain(right_demon);
348  }
349  solver()->AddConstraint(
350  solver()->MakeAllDifferent(left_, /*stronger_propagation=*/false));
351  solver()->AddConstraint(
352  solver()->MakeAllDifferent(right_, /*stronger_propagation=*/false));
353  }
354 
355  void InitialPropagate() override {
356  const int size = left_.size();
357  for (int i = 0; i < size; ++i) {
358  left_[i]->SetRange(0, size - 1);
359  right_[i]->SetRange(0, size - 1);
360  }
361  for (int i = 0; i < size; ++i) {
362  PropagateDomain(i, left_[i], left_domain_iterators_[i], right_);
363  PropagateDomain(i, right_[i], right_domain_iterators_[i], left_);
364  }
365  }
366 
367  void PropagateHolesOfLeftVarToRight(int index) {
368  PropagateHoles(index, left_[index], left_hole_iterators_[index], right_);
369  }
370 
371  void PropagateHolesOfRightVarToLeft(int index) {
372  PropagateHoles(index, right_[index], right_hole_iterators_[index], left_);
373  }
374 
375  std::string DebugString() const override {
376  return absl::StrFormat("InversePermutationConstraint([%s], [%s])",
377  JoinDebugStringPtr(left_, ", "),
378  JoinDebugStringPtr(right_, ", "));
379  }
380 
381  void Accept(ModelVisitor* const visitor) const override {
382  visitor->BeginVisitConstraint(ModelVisitor::kInversePermutation, this);
383  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kLeftArgument,
384  left_);
385  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kRightArgument,
386  right_);
387  visitor->EndVisitConstraint(ModelVisitor::kInversePermutation, this);
388  }
389 
390  private:
391  // See PropagateHolesOfLeftVarToRight() and PropagateHolesOfRightVarToLeft().
392  void PropagateHoles(int index, IntVar* const var, IntVarIterator* const holes,
393  const std::vector<IntVar*>& inverse) {
394  const int64_t oldmin = std::max(var->OldMin(), int64_t{0});
395  const int64_t oldmax =
396  std::min(var->OldMax(), static_cast<int64_t>(left_.size() - 1));
397  const int64_t vmin = var->Min();
398  const int64_t vmax = var->Max();
399  for (int64_t value = oldmin; value < vmin; ++value) {
400  inverse[value]->RemoveValue(index);
401  }
402  for (const int64_t hole : InitAndGetValues(holes)) {
403  if (hole >= 0 && hole < left_.size()) {
404  inverse[hole]->RemoveValue(index);
405  }
406  }
407  for (int64_t value = vmax + 1; value <= oldmax; ++value) {
408  inverse[value]->RemoveValue(index);
409  }
410  }
411 
412  void PropagateDomain(int index, IntVar* const var,
413  IntVarIterator* const domain,
414  const std::vector<IntVar*>& inverse) {
415  // Iterators are not safe w.r.t. removal. Postponing deletions.
416  tmp_removed_values_.clear();
417  for (const int64_t value : InitAndGetValues(domain)) {
418  if (!inverse[value]->Contains(index)) {
419  tmp_removed_values_.push_back(value);
420  }
421  }
422  // Once we've finished iterating over the domain, we may call
423  // RemoveValues().
424  if (!tmp_removed_values_.empty()) {
425  var->RemoveValues(tmp_removed_values_);
426  }
427  }
428 
429  std::vector<IntVar*> left_;
430  std::vector<IntVar*> right_;
431  std::vector<IntVarIterator*> left_hole_iterators_;
432  std::vector<IntVarIterator*> left_domain_iterators_;
433  std::vector<IntVarIterator*> right_hole_iterators_;
434  std::vector<IntVarIterator*> right_domain_iterators_;
435 
436  // used only in PropagateDomain().
437  std::vector<int64_t> tmp_removed_values_;
438 };
439 
440 // Index of first Max Value
441 
442 class IndexOfFirstMaxValue : public Constraint {
443  public:
444  IndexOfFirstMaxValue(Solver* solver, IntVar* index,
445  const std::vector<IntVar*>& vars)
446  : Constraint(solver), index_(index), vars_(vars) {}
447 
448  ~IndexOfFirstMaxValue() override {}
449 
450  void Post() override {
451  Demon* const demon =
452  solver()->MakeDelayedConstraintInitialPropagateCallback(this);
453  index_->WhenRange(demon);
454  for (IntVar* const var : vars_) {
455  var->WhenRange(demon);
456  }
457  }
458 
459  void InitialPropagate() override {
460  const int64_t vsize = vars_.size();
461  const int64_t imin = std::max(int64_t{0}, index_->Min());
462  const int64_t imax = std::min(vsize - 1, index_->Max());
463  int64_t max_max = std::numeric_limits<int64_t>::min();
464  int64_t max_min = std::numeric_limits<int64_t>::min();
465 
466  // Compute min and max value in the current interval covered by index_.
467  for (int i = imin; i <= imax; ++i) {
468  max_max = std::max(max_max, vars_[i]->Max());
469  max_min = std::max(max_min, vars_[i]->Min());
470  }
471 
472  // Propagate the fact that the first maximum value belongs to the
473  // [imin..imax].
474  for (int i = 0; i < imin; ++i) {
475  vars_[i]->SetMax(max_max - 1);
476  }
477  for (int i = imax + 1; i < vsize; ++i) {
478  vars_[i]->SetMax(max_max);
479  }
480 
481  // Shave bounds for index_.
482  int64_t min_index = imin;
483  while (vars_[min_index]->Max() < max_min) {
484  min_index++;
485  }
486  int64_t max_index = imax;
487  while (vars_[max_index]->Max() < max_min) {
488  max_index--;
489  }
490  index_->SetRange(min_index, max_index);
491  }
492 
493  std::string DebugString() const override {
494  return absl::StrFormat("IndexMax(%s, [%s])", index_->DebugString(),
495  JoinDebugStringPtr(vars_, ", "));
496  }
497 
498  void Accept(ModelVisitor* const visitor) const override {
499  // TODO(user): Implement me.
500  }
501 
502  private:
503  IntVar* const index_;
504  const std::vector<IntVar*> vars_;
505 };
506 } // namespace
507 
508 // ----- API -----
509 
511  return RevAlloc(new ActionDemon(action));
512 }
513 
515  return RevAlloc(new ClosureDemon(closure));
516 }
517 
519  DCHECK(true_constraint_ != nullptr);
520  return true_constraint_;
521 }
522 
524  DCHECK(false_constraint_ != nullptr);
525  return false_constraint_;
526 }
527 Constraint* Solver::MakeFalseConstraint(const std::string& explanation) {
528  return RevAlloc(new FalseConstraint(this, explanation));
529 }
530 
531 void Solver::InitCachedConstraint() {
532  DCHECK(true_constraint_ == nullptr);
533  true_constraint_ = RevAlloc(new TrueConstraint(this));
534  DCHECK(false_constraint_ == nullptr);
535  false_constraint_ = RevAlloc(new FalseConstraint(this));
536 }
537 
539  const std::vector<IntVar*>& actives) {
540  return RevAlloc(new MapDomain(this, var, actives));
541 }
542 
543 Constraint* Solver::MakeLexicalLess(const std::vector<IntVar*>& left,
544  const std::vector<IntVar*>& right) {
545  return RevAlloc(new LexicalLess(this, left, right, true));
546 }
547 
548 Constraint* Solver::MakeLexicalLessOrEqual(const std::vector<IntVar*>& left,
549  const std::vector<IntVar*>& right) {
550  return RevAlloc(new LexicalLess(this, left, right, false));
551 }
552 
554  const std::vector<IntVar*>& left, const std::vector<IntVar*>& right) {
555  return RevAlloc(new InversePermutationConstraint(this, left, right));
556 }
557 
559  IntVar* index, const std::vector<IntVar*>& vars) {
560  return RevAlloc(new IndexOfFirstMaxValue(this, index, vars));
561 }
562 
564  IntVar* index, const std::vector<IntVar*>& vars) {
565  std::vector<IntVar*> opp_vars(vars.size());
566  for (int i = 0; i < vars.size(); ++i) {
567  opp_vars[i] = MakeOpposite(vars[i])->Var();
568  }
569  return RevAlloc(new IndexOfFirstMaxValue(this, index, opp_vars));
570 }
571 } // namespace operations_research
Constraint * MakeFalseConstraint()
This constraint always fails.
Definition: constraints.cc:523
Constraint * MakeMapDomain(IntVar *const var, const std::vector< IntVar * > &actives)
This constraint maps the domain of 'var' onto the array of variables 'actives'.
Definition: constraints.cc:538
#define CHECK(condition)
Definition: base/logging.h:491
int64_t min
Definition: alldiff_cst.cc:139
Demon * MakeDelayedConstraintInitialPropagateCallback(Constraint *const ct)
This method is a specialized case of the MakeConstraintDemon method to call the InitiatePropagate of ...
Definition: constraints.cc:40
std::vector< IntVarIterator * > holes_
virtual void InitialPropagate()=0
This method performs the initial propagation of the constraint.
Constraint * MakeInversePermutationConstraint(const std::vector< IntVar * > &left, const std::vector< IntVar * > &right)
Creates a constraint that enforces that 'left' and 'right' both represent permutations of [0....
Definition: constraints.cc:553
A Demon is the base element of a propagation queue.
A constraint is the main modeling object.
virtual IntVar * Var()=0
Creates a variable from the expression.
Demon * MakeConstraintInitialPropagateCallback(Constraint *const ct)
This method is a specialized case of the MakeConstraintDemon method to call the InitiatePropagate of ...
Definition: constraints.cc:35
Demon * MakeConstraintDemon0(Solver *const s, T *const ct, void(T::*method)(), const std::string &name)
int64_t max
Definition: alldiff_cst.cc:140
std::function< void(Solver *)> Action
int index
Definition: pack.cc:509
Demon * MakeClosureDemon(Closure closure)
!defined(SWIG)
Definition: constraints.cc:514
Constraint * MakeLexicalLessOrEqual(const std::vector< IntVar * > &left, const std::vector< IntVar * > &right)
Creates a constraint that enforces that left is lexicographically less than or equal to right.
Definition: constraints.cc:548
Constraint * MakeIndexOfFirstMaxValueConstraint(IntVar *index, const std::vector< IntVar * > &vars)
Creates a constraint that binds the index variable to the index of the first variable with the maximu...
Definition: constraints.cc:558
The class IntVar is a subset of IntExpr.
#define CHECK_EQ(val1, val2)
Definition: base/logging.h:698
const std::vector< IntVar * > vars_
Definition: alldiff_cst.cc:44
Constraint * MakeIndexOfFirstMinValueConstraint(IntVar *index, const std::vector< IntVar * > &vars)
Creates a constraint that binds the index variable to the index of the first variable with the minimu...
Definition: constraints.cc:563
T * RevAlloc(T *object)
Registers the given object as being reversible.
Constraint * MakeLexicalLess(const std::vector< IntVar * > &left, const std::vector< IntVar * > &right)
Creates a constraint that enforces that left is lexicographically less than right.
Definition: constraints.cc:543
#define DCHECK(condition)
Definition: base/logging.h:885
void SetValue(Solver *const s, const T &val)
Constraint * MakeTrueConstraint()
This constraint always succeeds.
Definition: constraints.cc:518
Collection of objects used to extend the Constraint Solver library.
std::string JoinDebugStringPtr(const std::vector< T > &v, const std::string &separator)
Definition: string_array.h:45
Demon * MakeDelayedConstraintDemon0(Solver *const s, T *const ct, void(T::*method)(), const std::string &name)
IntVar * var
Definition: expr_array.cc:1874
IntExpr * MakeOpposite(IntExpr *const expr)
-expr
Demon * MakeActionDemon(Action action)
Creates a demon from a callback.
Definition: constraints.cc:510
int64_t value
Demon * MakeConstraintDemon1(Solver *const s, T *const ct, void(T::*method)(P), const std::string &name, P param1)
const Constraint * ct
std::function< void()> Closure