OR-Tools  9.3
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"
32
33namespace operations_research {
34
37 "InitialPropagate");
38}
39
41 Constraint* const ct) {
43 "InitialPropagate");
44}
45
46namespace {
47class 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
61class 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
77class 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
93class 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
122class 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
225class 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
313class 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
442class 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}
527Constraint* Solver::MakeFalseConstraint(const std::string& explanation) {
528 return RevAlloc(new FalseConstraint(this, explanation));
529}
530
531void 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
543Constraint* Solver::MakeLexicalLess(const std::vector<IntVar*>& left,
544 const std::vector<IntVar*>& right) {
545 return RevAlloc(new LexicalLess(this, left, right, true));
546}
547
548Constraint* 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
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
#define CHECK(condition)
Definition: base/logging.h:495
#define CHECK_EQ(val1, val2)
Definition: base/logging.h:703
#define DCHECK(condition)
Definition: base/logging.h:890
A constraint is the main modeling object.
virtual void InitialPropagate()=0
This method performs the initial propagation of the constraint.
A Demon is the base element of a propagation queue.
virtual IntVar * Var()=0
Creates a variable from the expression.
The class IntVar is a subset of IntExpr.
void SetValue(Solver *const s, const T &val)
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
Constraint * MakeFalseConstraint()
This constraint always fails.
Definition: constraints.cc:523
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
Demon * MakeActionDemon(Action action)
Creates a demon from a callback.
Definition: constraints.cc:510
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
Demon * MakeClosureDemon(Closure closure)
!defined(SWIG)
Definition: constraints.cc:514
IntExpr * MakeOpposite(IntExpr *const expr)
-expr
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 * MakeTrueConstraint()
This constraint always succeeds.
Definition: constraints.cc:518
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 * 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
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::function< void()> Closure
std::function< void(Solver *)> Action
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
T * RevAlloc(T *object)
Registers the given object as being reversible.
std::vector< IntVarIterator * > holes_
const Constraint * ct
int64_t value
IntVar * var
Definition: expr_array.cc:1874
int index
Collection of objects used to extend the Constraint Solver library.
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
Demon * MakeConstraintDemon0(Solver *const s, T *const ct, void(T::*method)(), const std::string &name)
Demon * MakeConstraintDemon1(Solver *const s, T *const ct, void(T::*method)(P), const std::string &name, P param1)