Google OR-Tools: ortools/constraint_solver/alldiff_cst.cc Source File
23#include "absl/strings/str_format.h"
24#include "absl/strings/string_view.h"
33class BaseAllDifferent : public Constraint {
35 BaseAllDifferent(Solver* const s, const std::vector<IntVar*>& vars)
36 : Constraint(s), vars_(vars) {}
37 ~BaseAllDifferent() override {}
38 std::string DebugStringInternal(absl::string_view name) const {
39 return absl::StrFormat("%s(%s)", name, JoinDebugStringPtr(vars_, ", "));
43 const std::vector<IntVar*> vars_;
44 int64_t size() const { return vars_.size(); }
50class ValueAllDifferent : public BaseAllDifferent {
52 ValueAllDifferent(Solver* const s, const std::vector<IntVar*>& vars)
53 : BaseAllDifferent(s, vars) {}
54 ~ValueAllDifferent() override {}
57 void InitialPropagate() override;
61 std::string DebugString() const override {
62 return DebugStringInternal("ValueAllDifferent");
64 void Accept(ModelVisitor* const visitor) const override {
73 RevSwitch all_instantiated_;
76void ValueAllDifferent::Post() {
77 for (int i = 0; i < size(); ++i) {
78 IntVar* var = vars_[i];
85void ValueAllDifferent::InitialPropagate() {
86 for (int i = 0; i < size(); ++i) {
93void ValueAllDifferent::OneMove(int index) {
95 const int64_t val = vars_[index]->Value();
96 for (int j = 0; j < size(); ++j) {
98 if (vars_[j]->Size() < 0xFFFFFF) {
99 vars_[j]->RemoveValue(val);
101 solver()->AddConstraint(solver()->MakeNonEquality(vars_[j], val));
108bool ValueAllDifferent::AllMoves() {
109 if (all_instantiated_.Switched() || size() == 0) {
112 for (int i = 0; i < size(); ++i) {
117 std::unique_ptr<int64_t[]> values(new int64_t[size()]);
118 for (int i = 0; i < size(); ++i) {
119 values[i] = vars_[i]->Value();
121 std::sort(values.get(), values.get() + size());
122 for (int i = 0; i < size() - 1; ++i) {
123 if (values[i] == values[i + 1]) {
128 all_instantiated_.Switch(solver());
135class RangeBipartiteMatching {
144 RangeBipartiteMatching(Solver* const solver, int size)
147 intervals_(new Interval[size + 1]),
148 min_sorted_(new Interval*[size]),
149 max_sorted_(new Interval*[size]),
150 bounds_(new int64_t[2 * size + 2]),
151 tree_(new int[2 * size + 2]),
152 diff_(new int64_t[2 * size + 2]),
153 hall_(new int[2 * size + 2]),
155 for (int i = 0; i < size; ++i) {
156 max_sorted_[i] = &intervals_[i];
157 min_sorted_[i] = max_sorted_[i];
161 void SetRange(int index, int64_t imin, int64_t imax) {
162 intervals_[index].min = imin;
163 intervals_[index].max = imax;
169 const bool modified1 = PropagateMin();
170 const bool modified2 = PropagateMax();
171 return modified1 || modified2;
174 int64_t Min(int index) const { return intervals_[index].min; }
176 int64_t Max(int index) const { return intervals_[index].max; }
182 std::sort(min_sorted_.get(), min_sorted_.get() + size_,
184 std::sort(max_sorted_.get(), max_sorted_.get() + size_,
187 int64_t min = min_sorted_[0]->min;
188 int64_t max = max_sorted_[0]->max + 1;
192 int i = 0;
196 if (i < size_ && min <= max) {
201 min_sorted_[i]->min_rank = nb;
203 min = min_sorted_[i]->min;
210 max_sorted_[j]->max_rank = nb;
214 max = max_sorted_[j]->max + 1;
218 bounds_[nb + 1] = bounds_[nb] + 2;
225 for (int i = 1; i <= active_size_ + 1; ++i) {
228 diff_[i] = bounds_[i] - bounds_[i - 1];
231 for (int i = 0; i < size_; ++i) {
232 const int x = max_sorted_[i]->min_rank;
233 const int y = max_sorted_[i]->max_rank;
234 int z = PathMax(tree_.get(), x + 1);
238 z = PathMax(tree_.get(), z + 1);
241 PathSet(x + 1, z, z, tree_.get());
242 if (diff_[z] < bounds_[z] - bounds_[y]) {
243 solver_->Fail();
246 int w = PathMax(hall_.get(), hall_[x]);
247 max_sorted_[i]->min = bounds_[w];
248 PathSet(x, w, w, hall_.get());
251 if (diff_[z] == bounds_[z] - bounds_[y]) {
252 PathSet(hall_[y], j - 1, y, hall_.get());
262 for (int i = 0; i <= active_size_; i++) {
265 diff_[i] = bounds_[i + 1] - bounds_[i];
268 for (int i = size_ - 1; i >= 0; --i) {
269 const int x = min_sorted_[i]->max_rank;
270 const int y = min_sorted_[i]->min_rank;
271 int z = PathMin(tree_.get(), x - 1);
275 z = PathMin(tree_.get(), z - 1);
278 PathSet(x - 1, z, z, tree_.get());
279 if (diff_[z] < bounds_[y] - bounds_[z]) {
280 solver_->Fail();
284 int w = PathMin(hall_.get(), hall_[x]);
285 min_sorted_[i]->max = bounds_[w] - 1;
286 PathSet(x, w, w, hall_.get());
289 if (diff_[z] == bounds_[y] - bounds_[z]) {
290 PathSet(hall_[y], j + 1, y, hall_.get());
301 struct CompareIntervalMin {
302 bool operator()(const Interval* i1, const Interval* i2) const {
303 return (i1->min < i2->min);
308 struct CompareIntervalMax {
309 bool operator()(const Interval* i1, const Interval* i2) const {
310 return (i1->max < i2->max);
314 void PathSet(int start, int end, int to, int* const tree) {
319 tree[k] = to;
323 int PathMin(const int* const tree, int index) {
324 int i = index;
328 return i;
331 int PathMax(const int* const tree, int index) {
332 int i = index;
336 return i;
341 std::unique_ptr<Interval[]> intervals_;
342 std::unique_ptr<Interval*[]> min_sorted_;
343 std::unique_ptr<Interval*[]> max_sorted_;
346 std::unique_ptr<int64_t[]> bounds_;
347 std::unique_ptr<int[]> tree_;
348 std::unique_ptr<int64_t[]> diff_;
349 std::unique_ptr<int[]> hall_;
353class BoundsAllDifferent : public BaseAllDifferent {
355 BoundsAllDifferent(Solver* const s, const std::vector<IntVar*>& vars)
356 : BaseAllDifferent(s, vars), matching_(s, vars.size()) {}
358 ~BoundsAllDifferent() override {}
362 solver(), this, &BoundsAllDifferent::IncrementalPropagate,
365 for (int i = 0; i < size(); ++i) {
366 vars_[i]->WhenRange(range);
368 &BoundsAllDifferent::PropagateValue,
370 vars_[i]->WhenBound(bound);
374 void InitialPropagate() override {
376 for (int i = 0; i < size(); ++i) {
383 virtual void IncrementalPropagate() {
384 for (int i = 0; i < size(); ++i) {
385 matching_.SetRange(i, vars_[i]->Min(), vars_[i]->Max());
388 if (matching_.Propagate()) {
389 for (int i = 0; i < size(); ++i) {
390 vars_[i]->SetRange(matching_.Min(i), matching_.Max(i));
395 void PropagateValue(int index) {
396 const int64_t to_remove = vars_[index]->Value();
397 for (int j = 0; j < index; j++) {
398 if (vars_[j]->Size() < 0xFFFFFF) {
399 vars_[j]->RemoveValue(to_remove);
401 solver()->AddConstraint(solver()->MakeNonEquality(vars_[j], to_remove));
404 for (int j = index + 1; j < size(); j++) {
405 if (vars_[j]->Size() < 0xFFFFFF) {
406 vars_[j]->RemoveValue(to_remove);
408 solver()->AddConstraint(solver()->MakeNonEquality(vars_[j], to_remove));
413 std::string DebugString() const override {
414 return DebugStringInternal("BoundsAllDifferent");
417 void Accept(ModelVisitor* const visitor) const override {
418 visitor->BeginVisitConstraint(ModelVisitor::kAllDifferent, this);
419 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
421 visitor->VisitIntegerArgument(ModelVisitor::kRangeArgument, 1);
422 visitor->EndVisitConstraint(ModelVisitor::kAllDifferent, this);
426 RangeBipartiteMatching matching_;
429class SortConstraint : public Constraint {
431 SortConstraint(Solver* const solver,
432 const std::vector<IntVar*>& original_vars,
433 const std::vector<IntVar*>& sorted_vars)
437 mins_(original_vars.size(), 0),
438 maxs_(original_vars.size(), 0),
439 matching_(solver, original_vars.size()) {}
441 ~SortConstraint() override {}
445 solver()->MakeDelayedConstraintInitialPropagateCallback(this);
446 for (int i = 0; i < size(); ++i) {
447 ovars_[i]->WhenRange(demon);
448 svars_[i]->WhenRange(demon);
452 void InitialPropagate() override {
453 for (int i = 0; i < size(); ++i) {
456 ovars_[i]->Range(&vmin, &vmax);
457 mins_[i] = vmin;
458 maxs_[i] = vmax;
461 std::sort(mins_.begin(), mins_.end());
462 std::sort(maxs_.begin(), maxs_.end());
463 for (int i = 0; i < size(); ++i) {
464 svars_[i]->SetRange(mins_[i], maxs_[i]);
467 for (int i = 0; i < size() - 1; ++i) {
468 svars_[i + 1]->SetMin(svars_[i]->Min());
470 for (int i = size() - 1; i > 0; --i) {
471 svars_[i - 1]->SetMax(svars_[i]->Max());
474 for (int i = 0; i < size(); ++i) {
477 FindIntersectionRange(i, &imin, &imax);
478 matching_.SetRange(i, imin, imax);
481 for (int i = 0; i < size(); ++i) {
482 const int64_t vmin = svars_[matching_.Min(i)]->Min();
483 const int64_t vmax = svars_[matching_.Max(i)]->Max();
484 ovars_[i]->SetRange(vmin, vmax);
488 void Accept(ModelVisitor* const visitor) const override {
489 visitor->BeginVisitConstraint(ModelVisitor::kSortingConstraint, this);
490 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
492 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kTargetArgument,
494 visitor->EndVisitConstraint(ModelVisitor::kSortingConstraint, this);
497 std::string DebugString() const override {
498 return absl::StrFormat("Sort(%s, %s)", JoinDebugStringPtr(ovars_, ", "),
503 int64_t size() const { return ovars_.size(); }
505 void FindIntersectionRange(int index, int64_t* const range_min,
506 int64_t* const range_max) const {
510 while (imin < size() && NotIntersect(index, imin)) {
516 int64_t imax = size() - 1;
517 while (imax > imin && NotIntersect(index, imax)) {
524 bool NotIntersect(int oindex, int sindex) const {
525 return ovars_[oindex]->Min() > svars_[sindex]->Max() ||
526 ovars_[oindex]->Max() < svars_[sindex]->Min();
529 const std::vector<IntVar*> ovars_;
530 const std::vector<IntVar*> svars_;
531 std::vector<int64_t> mins_;
532 std::vector<int64_t> maxs_;
533 RangeBipartiteMatching matching_;
538class AllDifferentExcept : public Constraint {
540 AllDifferentExcept(Solver* const s, std::vector<IntVar*> vars,
542 : Constraint(s), vars_(std::move(vars)), escape_value_(escape_value) {}
544 ~AllDifferentExcept() override {}
547 for (int i = 0; i < vars_.size(); ++i) {
548 IntVar* const var = vars_[i];
550 solver(), this, &AllDifferentExcept::Propagate, "Propagate", i);
555 void InitialPropagate() override {
556 for (int i = 0; i < vars_.size(); ++i) {
563 void Propagate(int index) {
564 const int64_t val = vars_[index]->Value();
565 if (val != escape_value_) {
566 for (int j = 0; j < vars_.size(); ++j) {
568 vars_[j]->RemoveValue(val);
574 std::string DebugString() const override {
575 return absl::StrFormat("AllDifferentExcept([%s], %d",
579 void Accept(ModelVisitor* const visitor) const override {
580 visitor->BeginVisitConstraint(ModelVisitor::kAllDifferent, this);
581 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
583 visitor->VisitIntegerArgument(ModelVisitor::kValueArgument, escape_value_);
584 visitor->EndVisitConstraint(ModelVisitor::kAllDifferent, this);
588 std::vector<IntVar*> vars_;
589 const int64_t escape_value_;
597class NullIntersectArrayExcept : public Constraint {
599 NullIntersectArrayExcept(Solver* const s, std::vector<IntVar*> first_vars,
600 std::vector<IntVar*> second_vars,
603 first_vars_(std::move(first_vars)),
604 second_vars_(std::move(second_vars)),
605 escape_value_(escape_value),
606 has_escape_value_(true) {}
608 NullIntersectArrayExcept(Solver* const s, std::vector<IntVar*> first_vars,
609 std::vector<IntVar*> second_vars)
611 first_vars_(std::move(first_vars)),
612 second_vars_(std::move(second_vars)),
614 has_escape_value_(false) {}
616 ~NullIntersectArrayExcept() override {}
619 for (int i = 0; i < first_vars_.size(); ++i) {
620 IntVar* const var = first_vars_[i];
622 solver(), this, &NullIntersectArrayExcept::PropagateFirst,
626 for (int i = 0; i < second_vars_.size(); ++i) {
627 IntVar* const var = second_vars_[i];
629 solver(), this, &NullIntersectArrayExcept::PropagateSecond,
635 void InitialPropagate() override {
636 for (int i = 0; i < first_vars_.size(); ++i) {
637 if (first_vars_[i]->Bound()) {
641 for (int i = 0; i < second_vars_.size(); ++i) {
642 if (second_vars_[i]->Bound()) {
648 void PropagateFirst(int index) {
649 const int64_t val = first_vars_[index]->Value();
650 if (!has_escape_value_ || val != escape_value_) {
651 for (int j = 0; j < second_vars_.size(); ++j) {
652 second_vars_[j]->RemoveValue(val);
657 void PropagateSecond(int index) {
658 const int64_t val = second_vars_[index]->Value();
659 if (!has_escape_value_ || val != escape_value_) {
660 for (int j = 0; j < first_vars_.size(); ++j) {
661 first_vars_[j]->RemoveValue(val);
666 std::string DebugString() const override {
667 return absl::StrFormat("NullIntersectArray([%s], [%s], escape = %d",
673 void Accept(ModelVisitor* const visitor) const override {
674 visitor->BeginVisitConstraint(ModelVisitor::kNullIntersect, this);
675 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kLeftArgument,
677 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kRightArgument,
679 visitor->VisitIntegerArgument(ModelVisitor::kValueArgument, escape_value_);
680 visitor->EndVisitConstraint(ModelVisitor::kNullIntersect, this);
684 std::vector<IntVar*> first_vars_;
685 std::vector<IntVar*> second_vars_;
686 const int64_t escape_value_;
687 const bool has_escape_value_;
696 bool stronger_propagation) {
697 const int size = vars.size();
698 for (int i = 0; i < size; ++i) {
699 CHECK_EQ(this, vars[i]->solver());
705 const_cast<IntVar* const>(vars[1]));
707 if (stronger_propagation) {
708 return RevAlloc(new BoundsAllDifferent(this, vars));
710 return RevAlloc(new ValueAllDifferent(this, vars));
716 const std::vector<IntVar*>& sorted) {
717 CHECK_EQ(vars.size(), sorted.size());
718 return RevAlloc(new SortConstraint(this, vars, sorted));
722 int64_t escape_value) {
723 int escape_candidates = 0;
724 for (int i = 0; i < vars.size(); ++i) {
725 escape_candidates += (vars[i]->Contains(escape_value));
727 if (escape_candidates <= 1) {
730 return RevAlloc(new AllDifferentExcept(this, vars, escape_value));
735 const std::vector<IntVar*>& second_vars) {
736 return RevAlloc(new NullIntersectArrayExcept(this, first_vars, second_vars));
740 const std::vector<IntVar*>& first_vars,
741 const std::vector<IntVar*>& second_vars, int64_t escape_value) {
742 int first_escape_candidates = 0;
743 for (int i = 0; i < first_vars.size(); ++i) {
744 first_escape_candidates += (first_vars[i]->Contains(escape_value));
746 int second_escape_candidates = 0;
747 for (int i = 0; i < second_vars.size(); ++i) {
748 second_escape_candidates += (second_vars[i]->Contains(escape_value));
750 if (first_escape_candidates == 0 || second_escape_candidates == 0) {
752 new NullIntersectArrayExcept(this, first_vars, second_vars));
754 return RevAlloc(new NullIntersectArrayExcept(this, first_vars, second_vars,
static const char kRangeArgument[]
static const char kAllDifferent[]
static const char kVarsArgument[]
void Switch(Solver *const solver)
Constraint * MakeSortingConstraint(const std::vector< IntVar * > &vars, const std::vector< IntVar * > &sorted)
Definition alldiff_cst.cc:716
Constraint * MakeNonEquality(IntExpr *left, IntExpr *right)
left != right
void Fail()
Abandon the current branch in the search tree. A backtrack will follow.
Constraint * MakeAllDifferentExcept(const std::vector< IntVar * > &vars, int64_t escape_value)
Definition alldiff_cst.cc:722
Constraint * MakeNullIntersectExcept(const std::vector< IntVar * > &first_vars, const std::vector< IntVar * > &second_vars, int64_t escape_value)
Definition alldiff_cst.cc:740
Constraint * MakeTrueConstraint()
This constraint always succeeds.
Constraint * MakeAllDifferent(const std::vector< IntVar * > &vars)
Definition alldiff_cst.cc:692
Constraint * MakeNullIntersect(const std::vector< IntVar * > &first_vars, const std::vector< IntVar * > &second_vars)
Definition alldiff_cst.cc:735
For infeasible and unbounded see Not checked if options check_solutions_if_inf_or_unbounded and the If options first_solution_only is false
std::string JoinDebugStringPtr(const std::vector< T > &v, absl::string_view separator)
Demon * MakeDelayedConstraintDemon0(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)
trees with all degrees equal w the current value of w
trees with all degrees equal to