24#include "absl/strings/str_format.h"
25#include "absl/strings/string_view.h"
35class BaseAllDifferent :
public Constraint {
37 BaseAllDifferent(Solver*
const s,
const std::vector<IntVar*>& vars)
38 : Constraint(s),
vars_(vars) {}
39 ~BaseAllDifferent()
override {}
40 std::string DebugStringInternal(absl::string_view
name)
const {
45 const std::vector<IntVar*>
vars_;
46 int64_t
size()
const {
return vars_.size(); }
52class ValueAllDifferent :
public BaseAllDifferent {
54 ValueAllDifferent(Solver*
const s,
const std::vector<IntVar*>& vars)
55 : BaseAllDifferent(s, vars) {}
56 ~ValueAllDifferent()
override {}
59 void InitialPropagate()
override;
60 void OneMove(
int index);
63 std::string DebugString()
const override {
64 return DebugStringInternal(
"ValueAllDifferent");
66 void Accept(ModelVisitor*
const visitor)
const override {
75 RevSwitch all_instantiated_;
78void ValueAllDifferent::Post() {
79 for (
int i = 0;
i <
size(); ++
i) {
87void ValueAllDifferent::InitialPropagate() {
88 for (
int i = 0;
i <
size(); ++
i) {
89 if (
vars_[i]->Bound()) {
95void ValueAllDifferent::OneMove(
int index) {
98 for (
int j = 0; j <
size(); ++j) {
100 if (
vars_[j]->Size() < 0xFFFFFF) {
101 vars_[j]->RemoveValue(val);
103 solver()->AddConstraint(solver()->MakeNonEquality(
vars_[j], val));
110bool ValueAllDifferent::AllMoves() {
114 for (
int i = 0;
i <
size(); ++
i) {
115 if (!
vars_[i]->Bound()) {
119 std::unique_ptr<int64_t[]> values(
new int64_t[
size()]);
120 for (
int i = 0;
i <
size(); ++
i) {
123 std::sort(values.get(), values.get() +
size());
124 for (
int i = 0;
i <
size() - 1; ++
i) {
125 if (values[i] == values[i + 1]) {
130 all_instantiated_.
Switch(solver());
137class RangeBipartiteMatching {
146 RangeBipartiteMatching(Solver*
const solver,
int size)
149 intervals_(new Interval[
size + 1]),
150 min_sorted_(new Interval*[
size]),
151 max_sorted_(new Interval*[
size]),
152 bounds_(new int64_t[2 *
size + 2]),
153 tree_(new int[2 *
size + 2]),
154 diff_(new int64_t[2 *
size + 2]),
155 hall_(new int[2 *
size + 2]),
157 for (
int i = 0;
i <
size; ++
i) {
158 max_sorted_[
i] = &intervals_[
i];
159 min_sorted_[
i] = max_sorted_[
i];
163 void SetRange(
int index, int64_t imin, int64_t imax) {
164 intervals_[
index].min = imin;
165 intervals_[
index].max = imax;
171 const bool modified1 = PropagateMin();
172 const bool modified2 = PropagateMax();
173 return modified1 || modified2;
176 int64_t Min(
int index)
const {
return intervals_[
index].min; }
178 int64_t Max(
int index)
const {
return intervals_[
index].max; }
184 std::sort(min_sorted_.get(), min_sorted_.get() + size_,
185 CompareIntervalMin());
186 std::sort(max_sorted_.get(), max_sorted_.get() + size_,
187 CompareIntervalMax());
189 int64_t
min = min_sorted_[0]->min;
190 int64_t
max = max_sorted_[0]->max + 1;
191 int64_t last =
min - 2;
198 if (i < size_ &&
min <=
max) {
201 bounds_[++nb] = last;
203 min_sorted_[
i]->min_rank = nb;
205 min = min_sorted_[
i]->min;
210 bounds_[++nb] = last;
212 max_sorted_[j]->max_rank = nb;
216 max = max_sorted_[j]->max + 1;
220 bounds_[nb + 1] = bounds_[nb] + 2;
224 bool PropagateMin() {
225 bool modified =
false;
227 for (
int i = 1;
i <= active_size_ + 1; ++
i) {
230 diff_[
i] = bounds_[
i] - bounds_[
i - 1];
233 for (
int i = 0;
i < size_; ++
i) {
234 const int x = max_sorted_[
i]->min_rank;
235 const int y = max_sorted_[
i]->max_rank;
236 int z = PathMax(tree_.get(),
x + 1);
238 if (--diff_[z] == 0) {
240 z = PathMax(tree_.get(), z + 1);
243 PathSet(
x + 1, z, z, tree_.get());
244 if (diff_[z] < bounds_[z] - bounds_[
y]) {
248 int w = PathMax(hall_.get(), hall_[
x]);
249 max_sorted_[
i]->min = bounds_[
w];
250 PathSet(
x,
w,
w, hall_.get());
253 if (diff_[z] == bounds_[z] - bounds_[
y]) {
254 PathSet(hall_[
y], j - 1,
y, hall_.get());
261 bool PropagateMax() {
262 bool modified =
false;
264 for (
int i = 0;
i <= active_size_;
i++) {
267 diff_[
i] = bounds_[
i + 1] - bounds_[
i];
270 for (
int i = size_ - 1;
i >= 0; --
i) {
271 const int x = min_sorted_[
i]->max_rank;
272 const int y = min_sorted_[
i]->min_rank;
273 int z = PathMin(tree_.get(),
x - 1);
275 if (--diff_[z] == 0) {
277 z = PathMin(tree_.get(), z - 1);
280 PathSet(
x - 1, z, z, tree_.get());
281 if (diff_[z] < bounds_[
y] - bounds_[z]) {
286 int w = PathMin(hall_.get(), hall_[
x]);
287 min_sorted_[
i]->max = bounds_[
w] - 1;
288 PathSet(
x,
w,
w, hall_.get());
291 if (diff_[z] == bounds_[
y] - bounds_[z]) {
292 PathSet(hall_[
y], j + 1,
y, hall_.get());
303 struct CompareIntervalMin {
304 bool operator()(
const Interval* i1,
const Interval* i2)
const {
305 return (i1->min < i2->min);
310 struct CompareIntervalMax {
311 bool operator()(
const Interval* i1,
const Interval* i2)
const {
312 return (i1->max < i2->max);
316 void PathSet(
int start,
int end,
int to,
int*
const tree) {
325 int PathMin(
const int*
const tree,
int index) {
327 while (tree[i] < i) {
333 int PathMax(
const int*
const tree,
int index) {
335 while (tree[i] > i) {
341 Solver*
const solver_;
343 std::unique_ptr<Interval[]> intervals_;
344 std::unique_ptr<Interval*[]> min_sorted_;
345 std::unique_ptr<Interval*[]> max_sorted_;
348 std::unique_ptr<int64_t[]> bounds_;
349 std::unique_ptr<int[]> tree_;
350 std::unique_ptr<int64_t[]> diff_;
351 std::unique_ptr<int[]> hall_;
355class BoundsAllDifferent :
public BaseAllDifferent {
357 BoundsAllDifferent(Solver*
const s,
const std::vector<IntVar*>& vars)
358 : BaseAllDifferent(s, vars), matching_(s, vars.
size()) {}
360 ~BoundsAllDifferent()
override {}
362 void Post()
override {
364 solver(),
this, &BoundsAllDifferent::IncrementalPropagate,
365 "IncrementalPropagate");
367 for (
int i = 0;
i <
size(); ++
i) {
370 &BoundsAllDifferent::PropagateValue,
371 "PropagateValue", i);
376 void InitialPropagate()
override {
377 IncrementalPropagate();
378 for (
int i = 0;
i <
size(); ++
i) {
379 if (
vars_[i]->Bound()) {
385 virtual void IncrementalPropagate() {
386 for (
int i = 0;
i <
size(); ++
i) {
387 matching_.SetRange(i,
vars_[i]->Min(),
vars_[i]->Max());
390 if (matching_.Propagate()) {
391 for (
int i = 0;
i <
size(); ++
i) {
392 vars_[
i]->SetRange(matching_.Min(i), matching_.Max(i));
397 void PropagateValue(
int index) {
398 const int64_t to_remove =
vars_[
index]->Value();
399 for (
int j = 0; j <
index; j++) {
400 if (
vars_[j]->Size() < 0xFFFFFF) {
401 vars_[j]->RemoveValue(to_remove);
403 solver()->AddConstraint(solver()->MakeNonEquality(
vars_[j], to_remove));
406 for (
int j =
index + 1; j <
size(); j++) {
407 if (
vars_[j]->Size() < 0xFFFFFF) {
408 vars_[j]->RemoveValue(to_remove);
410 solver()->AddConstraint(solver()->MakeNonEquality(
vars_[j], to_remove));
415 std::string DebugString()
const override {
416 return DebugStringInternal(
"BoundsAllDifferent");
419 void Accept(ModelVisitor*
const visitor)
const override {
420 visitor->BeginVisitConstraint(ModelVisitor::kAllDifferent,
this);
421 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
423 visitor->VisitIntegerArgument(ModelVisitor::kRangeArgument, 1);
424 visitor->EndVisitConstraint(ModelVisitor::kAllDifferent,
this);
428 RangeBipartiteMatching matching_;
431class SortConstraint :
public Constraint {
433 SortConstraint(Solver*
const solver,
434 const std::vector<IntVar*>& original_vars,
435 const std::vector<IntVar*>& sorted_vars)
436 : Constraint(solver),
437 ovars_(original_vars),
439 mins_(original_vars.
size(), 0),
440 maxs_(original_vars.
size(), 0),
441 matching_(solver, original_vars.
size()) {}
443 ~SortConstraint()
override {}
445 void Post()
override {
447 solver()->MakeDelayedConstraintInitialPropagateCallback(
this);
448 for (
int i = 0;
i <
size(); ++
i) {
449 ovars_[
i]->WhenRange(demon);
450 svars_[
i]->WhenRange(demon);
454 void InitialPropagate()
override {
455 for (
int i = 0;
i <
size(); ++
i) {
458 ovars_[
i]->Range(&vmin, &vmax);
463 std::sort(mins_.begin(), mins_.end());
464 std::sort(maxs_.begin(), maxs_.end());
465 for (
int i = 0;
i <
size(); ++
i) {
466 svars_[
i]->SetRange(mins_[i], maxs_[i]);
469 for (
int i = 0;
i <
size() - 1; ++
i) {
470 svars_[
i + 1]->SetMin(svars_[i]->Min());
472 for (
int i =
size() - 1;
i > 0; --
i) {
473 svars_[
i - 1]->SetMax(svars_[i]->Max());
476 for (
int i = 0;
i <
size(); ++
i) {
479 FindIntersectionRange(i, &imin, &imax);
480 matching_.SetRange(i, imin, imax);
482 matching_.Propagate();
483 for (
int i = 0;
i <
size(); ++
i) {
484 const int64_t vmin = svars_[matching_.Min(i)]->Min();
485 const int64_t vmax = svars_[matching_.Max(i)]->Max();
486 ovars_[
i]->SetRange(vmin, vmax);
490 void Accept(ModelVisitor*
const visitor)
const override {
491 visitor->BeginVisitConstraint(ModelVisitor::kSortingConstraint,
this);
492 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
494 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kTargetArgument,
496 visitor->EndVisitConstraint(ModelVisitor::kSortingConstraint,
this);
499 std::string DebugString()
const override {
505 int64_t
size()
const {
return ovars_.size(); }
507 void FindIntersectionRange(
int index, int64_t*
const range_min,
508 int64_t*
const range_max)
const {
512 while (imin <
size() && NotIntersect(
index, imin)) {
515 if (imin ==
size()) {
518 int64_t imax =
size() - 1;
519 while (imax > imin && NotIntersect(
index, imax)) {
526 bool NotIntersect(
int oindex,
int sindex)
const {
527 return ovars_[oindex]->Min() > svars_[sindex]->Max() ||
528 ovars_[oindex]->Max() < svars_[sindex]->Min();
531 const std::vector<IntVar*> ovars_;
532 const std::vector<IntVar*> svars_;
533 std::vector<int64_t> mins_;
534 std::vector<int64_t> maxs_;
535 RangeBipartiteMatching matching_;
540class AllDifferentExcept :
public Constraint {
542 AllDifferentExcept(Solver*
const s, std::vector<IntVar*> vars,
543 int64_t escape_value)
544 : Constraint(s),
vars_(
std::move(vars)), escape_value_(escape_value) {}
546 ~AllDifferentExcept()
override {}
548 void Post()
override {
549 for (
int i = 0;
i <
vars_.size(); ++
i) {
552 solver(),
this, &AllDifferentExcept::Propagate,
"Propagate", i);
557 void InitialPropagate()
override {
558 for (
int i = 0;
i <
vars_.size(); ++
i) {
559 if (
vars_[i]->Bound()) {
565 void Propagate(
int index) {
567 if (val != escape_value_) {
568 for (
int j = 0; j <
vars_.size(); ++j) {
570 vars_[j]->RemoveValue(val);
576 std::string DebugString()
const override {
577 return absl::StrFormat(
"AllDifferentExcept([%s], %d",
581 void Accept(ModelVisitor*
const visitor)
const override {
582 visitor->BeginVisitConstraint(ModelVisitor::kAllDifferent,
this);
583 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
585 visitor->VisitIntegerArgument(ModelVisitor::kValueArgument, escape_value_);
586 visitor->EndVisitConstraint(ModelVisitor::kAllDifferent,
this);
590 std::vector<IntVar*>
vars_;
591 const int64_t escape_value_;
599class NullIntersectArrayExcept :
public Constraint {
601 NullIntersectArrayExcept(Solver*
const s, std::vector<IntVar*> first_vars,
602 std::vector<IntVar*> second_vars,
603 int64_t escape_value)
605 first_vars_(
std::move(first_vars)),
606 second_vars_(
std::move(second_vars)),
607 escape_value_(escape_value),
608 has_escape_value_(
true) {}
610 NullIntersectArrayExcept(Solver*
const s, std::vector<IntVar*> first_vars,
611 std::vector<IntVar*> second_vars)
613 first_vars_(
std::move(first_vars)),
614 second_vars_(
std::move(second_vars)),
616 has_escape_value_(
false) {}
618 ~NullIntersectArrayExcept()
override {}
620 void Post()
override {
621 for (
int i = 0;
i < first_vars_.size(); ++
i) {
622 IntVar*
const var = first_vars_[
i];
624 solver(),
this, &NullIntersectArrayExcept::PropagateFirst,
625 "PropagateFirst", i);
628 for (
int i = 0;
i < second_vars_.size(); ++
i) {
629 IntVar*
const var = second_vars_[
i];
631 solver(),
this, &NullIntersectArrayExcept::PropagateSecond,
632 "PropagateSecond", i);
637 void InitialPropagate()
override {
638 for (
int i = 0;
i < first_vars_.size(); ++
i) {
639 if (first_vars_[i]->Bound()) {
643 for (
int i = 0;
i < second_vars_.size(); ++
i) {
644 if (second_vars_[i]->Bound()) {
650 void PropagateFirst(
int index) {
651 const int64_t val = first_vars_[
index]->Value();
652 if (!has_escape_value_ || val != escape_value_) {
653 for (
int j = 0; j < second_vars_.size(); ++j) {
654 second_vars_[j]->RemoveValue(val);
659 void PropagateSecond(
int index) {
660 const int64_t val = second_vars_[
index]->Value();
661 if (!has_escape_value_ || val != escape_value_) {
662 for (
int j = 0; j < first_vars_.size(); ++j) {
663 first_vars_[j]->RemoveValue(val);
668 std::string DebugString()
const override {
669 return absl::StrFormat(
"NullIntersectArray([%s], [%s], escape = %d",
675 void Accept(ModelVisitor*
const visitor)
const override {
676 visitor->BeginVisitConstraint(ModelVisitor::kNullIntersect,
this);
677 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kLeftArgument,
679 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kRightArgument,
681 visitor->VisitIntegerArgument(ModelVisitor::kValueArgument, escape_value_);
682 visitor->EndVisitConstraint(ModelVisitor::kNullIntersect,
this);
686 std::vector<IntVar*> first_vars_;
687 std::vector<IntVar*> second_vars_;
688 const int64_t escape_value_;
689 const bool has_escape_value_;
694 return MakeAllDifferent(vars,
true);
698 bool stronger_propagation) {
699 const int size = vars.size();
700 for (
int i = 0; i <
size; ++i) {
701 CHECK_EQ(
this, vars[i]->solver());
704 return MakeTrueConstraint();
705 }
else if (
size == 2) {
706 return MakeNonEquality(
const_cast<IntVar* const
>(vars[0]),
707 const_cast<IntVar* const
>(vars[1]));
709 if (stronger_propagation) {
710 return RevAlloc(
new BoundsAllDifferent(
this, vars));
712 return RevAlloc(
new ValueAllDifferent(
this, vars));
718 const std::vector<IntVar*>& sorted) {
719 CHECK_EQ(vars.size(), sorted.size());
720 return RevAlloc(
new SortConstraint(
this, vars, sorted));
724 int64_t escape_value) {
725 int escape_candidates = 0;
726 for (
int i = 0; i < vars.size(); ++i) {
727 escape_candidates += (vars[i]->Contains(escape_value));
729 if (escape_candidates <= 1) {
730 return MakeAllDifferent(vars);
732 return RevAlloc(
new AllDifferentExcept(
this, vars, escape_value));
737 const std::vector<IntVar*>& second_vars) {
738 return RevAlloc(
new NullIntersectArrayExcept(
this, first_vars, second_vars));
742 const std::vector<IntVar*>& first_vars,
743 const std::vector<IntVar*>& second_vars, int64_t escape_value) {
744 int first_escape_candidates = 0;
745 for (
int i = 0; i < first_vars.size(); ++i) {
746 first_escape_candidates += (first_vars[i]->Contains(escape_value));
748 int second_escape_candidates = 0;
749 for (
int i = 0; i < second_vars.size(); ++i) {
750 second_escape_candidates += (second_vars[i]->Contains(escape_value));
752 if (first_escape_candidates == 0 || second_escape_candidates == 0) {
754 new NullIntersectArrayExcept(
this, first_vars, second_vars));
756 return RevAlloc(
new NullIntersectArrayExcept(
this, first_vars, second_vars,
const std::vector< IntVar * > 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)
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)
Constraint * MakeNullIntersectExcept(const std::vector< IntVar * > &first_vars, const std::vector< IntVar * > &second_vars, int64_t escape_value)
Constraint * MakeAllDifferent(const std::vector< IntVar * > &vars)
Constraint * MakeNullIntersect(const std::vector< IntVar * > &first_vars, const std::vector< IntVar * > &second_vars)
const std::string name
A name for logging purposes.
For infeasible and unbounded see Not checked if options check_solutions_if_inf_or_unbounded and the If options first_solution_only is false
problem is infeasible or unbounded (default).
In SWIG mode, we don't want anything besides these top-level includes.
std::string JoinDebugStringPtr(const std::vector< T > &v, absl::string_view separator)
Join v[i]->DebugString().
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
std::optional< int64_t > end
const std::optional< Range > & range