24#include "absl/strings/str_format.h"
34class BaseAllDifferent :
public Constraint {
36 BaseAllDifferent(Solver*
const s,
const std::vector<IntVar*>& vars)
37 : Constraint(s),
vars_(vars) {}
38 ~BaseAllDifferent()
override {}
39 std::string DebugStringInternal(
const std::string&
name)
const {
44 const std::vector<IntVar*>
vars_;
45 int64_t size()
const {
return vars_.size(); }
51class ValueAllDifferent :
public BaseAllDifferent {
53 ValueAllDifferent(Solver*
const s,
const std::vector<IntVar*>& vars)
54 : BaseAllDifferent(s, vars) {}
55 ~ValueAllDifferent()
override {}
58 void InitialPropagate()
override;
59 void OneMove(
int index);
62 std::string DebugString()
const override {
63 return DebugStringInternal(
"ValueAllDifferent");
65 void Accept(ModelVisitor*
const visitor)
const override {
74 RevSwitch all_instantiated_;
77void ValueAllDifferent::Post() {
78 for (
int i = 0; i < size(); ++i) {
86void ValueAllDifferent::InitialPropagate() {
87 for (
int i = 0; i < size(); ++i) {
88 if (
vars_[i]->Bound()) {
94void ValueAllDifferent::OneMove(
int index) {
97 for (
int j = 0; j < size(); ++j) {
99 if (
vars_[j]->Size() < 0xFFFFFF) {
100 vars_[j]->RemoveValue(val);
102 solver()->AddConstraint(solver()->MakeNonEquality(
vars_[j], val));
109bool ValueAllDifferent::AllMoves() {
110 if (all_instantiated_.
Switched() || size() == 0) {
113 for (
int i = 0; i < size(); ++i) {
114 if (!
vars_[i]->Bound()) {
118 std::unique_ptr<int64_t[]> values(
new int64_t[size()]);
119 for (
int i = 0; i < size(); ++i) {
120 values[i] =
vars_[i]->Value();
122 std::sort(values.get(), values.get() + size());
123 for (
int i = 0; i < size() - 1; ++i) {
124 if (values[i] == values[i + 1]) {
129 all_instantiated_.
Switch(solver());
136class RangeBipartiteMatching {
145 RangeBipartiteMatching(Solver*
const solver,
int size)
148 intervals_(new Interval[size + 1]),
149 min_sorted_(new Interval*[size]),
150 max_sorted_(new Interval*[size]),
151 bounds_(new int64_t[2 * size + 2]),
152 tree_(new int[2 * size + 2]),
153 diff_(new int64_t[2 * size + 2]),
154 hall_(new int[2 * size + 2]),
156 for (
int i = 0; i < size; ++i) {
157 max_sorted_[i] = &intervals_[i];
158 min_sorted_[i] = max_sorted_[i];
162 void SetRange(
int index, int64_t imin, int64_t imax) {
163 intervals_[
index].min = imin;
164 intervals_[
index].max = imax;
170 const bool modified1 = PropagateMin();
171 const bool modified2 = PropagateMax();
172 return modified1 || modified2;
175 int64_t Min(
int index)
const {
return intervals_[
index].min; }
177 int64_t Max(
int index)
const {
return intervals_[
index].max; }
183 std::sort(min_sorted_.get(), min_sorted_.get() + size_,
184 CompareIntervalMin());
185 std::sort(max_sorted_.get(), max_sorted_.get() + size_,
186 CompareIntervalMax());
188 int64_t
min = min_sorted_[0]->min;
189 int64_t
max = max_sorted_[0]->max + 1;
190 int64_t last =
min - 2;
197 if (i < size_ &&
min <=
max) {
200 bounds_[++nb] = last;
202 min_sorted_[i]->min_rank = nb;
204 min = min_sorted_[i]->min;
209 bounds_[++nb] = last;
211 max_sorted_[j]->max_rank = nb;
215 max = max_sorted_[j]->max + 1;
219 bounds_[nb + 1] = bounds_[nb] + 2;
223 bool PropagateMin() {
224 bool modified =
false;
226 for (
int i = 1; i <= active_size_ + 1; ++i) {
229 diff_[i] = bounds_[i] - bounds_[i - 1];
232 for (
int i = 0; i < size_; ++i) {
233 const int x = max_sorted_[i]->min_rank;
234 const int y = max_sorted_[i]->max_rank;
235 int z = PathMax(tree_.get(), x + 1);
237 if (--diff_[z] == 0) {
239 z = PathMax(tree_.get(), z + 1);
242 PathSet(x + 1, z, z, tree_.get());
243 if (diff_[z] < bounds_[z] - bounds_[y]) {
247 int w = PathMax(hall_.get(), hall_[x]);
248 max_sorted_[i]->min = bounds_[w];
249 PathSet(x, w, w, hall_.get());
252 if (diff_[z] == bounds_[z] - bounds_[y]) {
253 PathSet(hall_[y], j - 1, y, hall_.get());
260 bool PropagateMax() {
261 bool modified =
false;
263 for (
int i = 0; i <= active_size_; i++) {
266 diff_[i] = bounds_[i + 1] - bounds_[i];
269 for (
int i = size_ - 1; i >= 0; --i) {
270 const int x = min_sorted_[i]->max_rank;
271 const int y = min_sorted_[i]->min_rank;
272 int z = PathMin(tree_.get(), x - 1);
274 if (--diff_[z] == 0) {
276 z = PathMin(tree_.get(), z - 1);
279 PathSet(x - 1, z, z, tree_.get());
280 if (diff_[z] < bounds_[y] - bounds_[z]) {
285 int w = PathMin(hall_.get(), hall_[x]);
286 min_sorted_[i]->max = bounds_[w] - 1;
287 PathSet(x, w, w, hall_.get());
290 if (diff_[z] == bounds_[y] - bounds_[z]) {
291 PathSet(hall_[y], j + 1, y, hall_.get());
302 struct CompareIntervalMin {
303 bool operator()(
const Interval* i1,
const Interval* i2)
const {
304 return (i1->min < i2->min);
309 struct CompareIntervalMax {
310 bool operator()(
const Interval* i1,
const Interval* i2)
const {
311 return (i1->max < i2->max);
315 void PathSet(
int start,
int end,
int to,
int*
const tree) {
324 int PathMin(
const int*
const tree,
int index) {
326 while (tree[i] < i) {
332 int PathMax(
const int*
const tree,
int index) {
334 while (tree[i] > i) {
340 Solver*
const solver_;
342 std::unique_ptr<Interval[]> intervals_;
343 std::unique_ptr<Interval*[]> min_sorted_;
344 std::unique_ptr<Interval*[]> max_sorted_;
347 std::unique_ptr<int64_t[]> bounds_;
348 std::unique_ptr<int[]> tree_;
349 std::unique_ptr<int64_t[]> diff_;
350 std::unique_ptr<int[]> hall_;
354class BoundsAllDifferent :
public BaseAllDifferent {
356 BoundsAllDifferent(Solver*
const s,
const std::vector<IntVar*>& vars)
357 : BaseAllDifferent(s, vars), matching_(s, vars.size()) {}
359 ~BoundsAllDifferent()
override {}
361 void Post()
override {
363 solver(),
this, &BoundsAllDifferent::IncrementalPropagate,
364 "IncrementalPropagate");
366 for (
int i = 0; i < size(); ++i) {
367 vars_[i]->WhenRange(range);
369 &BoundsAllDifferent::PropagateValue,
370 "PropagateValue", i);
375 void InitialPropagate()
override {
376 IncrementalPropagate();
377 for (
int i = 0; i < size(); ++i) {
378 if (
vars_[i]->Bound()) {
384 virtual void IncrementalPropagate() {
385 for (
int i = 0; i < size(); ++i) {
386 matching_.SetRange(i,
vars_[i]->Min(),
vars_[i]->Max());
389 if (matching_.Propagate()) {
390 for (
int i = 0; i < size(); ++i) {
391 vars_[i]->SetRange(matching_.Min(i), matching_.Max(i));
396 void PropagateValue(
int index) {
397 const int64_t to_remove =
vars_[
index]->Value();
398 for (
int j = 0; j <
index; j++) {
399 if (
vars_[j]->Size() < 0xFFFFFF) {
400 vars_[j]->RemoveValue(to_remove);
402 solver()->AddConstraint(solver()->MakeNonEquality(
vars_[j], to_remove));
405 for (
int j =
index + 1; j < size(); j++) {
406 if (
vars_[j]->Size() < 0xFFFFFF) {
407 vars_[j]->RemoveValue(to_remove);
409 solver()->AddConstraint(solver()->MakeNonEquality(
vars_[j], to_remove));
414 std::string DebugString()
const override {
415 return DebugStringInternal(
"BoundsAllDifferent");
418 void Accept(ModelVisitor*
const visitor)
const override {
427 RangeBipartiteMatching matching_;
430class SortConstraint :
public Constraint {
432 SortConstraint(Solver*
const solver,
433 const std::vector<IntVar*>& original_vars,
434 const std::vector<IntVar*>& sorted_vars)
435 : Constraint(solver),
436 ovars_(original_vars),
438 mins_(original_vars.size(), 0),
439 maxs_(original_vars.size(), 0),
440 matching_(solver, original_vars.size()) {}
442 ~SortConstraint()
override {}
444 void Post()
override {
446 solver()->MakeDelayedConstraintInitialPropagateCallback(
this);
447 for (
int i = 0; i < size(); ++i) {
448 ovars_[i]->WhenRange(demon);
449 svars_[i]->WhenRange(demon);
453 void InitialPropagate()
override {
454 for (
int i = 0; i < size(); ++i) {
457 ovars_[i]->Range(&vmin, &vmax);
462 std::sort(mins_.begin(), mins_.end());
463 std::sort(maxs_.begin(), maxs_.end());
464 for (
int i = 0; i < size(); ++i) {
465 svars_[i]->SetRange(mins_[i], maxs_[i]);
468 for (
int i = 0; i < size() - 1; ++i) {
469 svars_[i + 1]->SetMin(svars_[i]->Min());
471 for (
int i = size() - 1; i > 0; --i) {
472 svars_[i - 1]->SetMax(svars_[i]->Max());
475 for (
int i = 0; i < size(); ++i) {
478 FindIntersectionRange(i, &imin, &imax);
479 matching_.SetRange(i, imin, imax);
481 matching_.Propagate();
482 for (
int i = 0; i < size(); ++i) {
483 const int64_t vmin = svars_[matching_.Min(i)]->Min();
484 const int64_t vmax = svars_[matching_.Max(i)]->Max();
485 ovars_[i]->SetRange(vmin, vmax);
489 void Accept(ModelVisitor*
const visitor)
const override {
498 std::string DebugString()
const override {
504 int64_t size()
const {
return ovars_.size(); }
506 void FindIntersectionRange(
int index, int64_t*
const range_min,
507 int64_t*
const range_max)
const {
511 while (imin < size() && NotIntersect(
index, imin)) {
514 if (imin == size()) {
517 int64_t imax = size() - 1;
518 while (imax > imin && NotIntersect(
index, imax)) {
525 bool NotIntersect(
int oindex,
int sindex)
const {
526 return ovars_[oindex]->Min() > svars_[sindex]->Max() ||
527 ovars_[oindex]->Max() < svars_[sindex]->Min();
530 const std::vector<IntVar*> ovars_;
531 const std::vector<IntVar*> svars_;
532 std::vector<int64_t> mins_;
533 std::vector<int64_t> maxs_;
534 RangeBipartiteMatching matching_;
539class AllDifferentExcept :
public Constraint {
541 AllDifferentExcept(Solver*
const s, std::vector<IntVar*> vars,
542 int64_t escape_value)
543 : Constraint(s),
vars_(
std::move(vars)), escape_value_(escape_value) {}
545 ~AllDifferentExcept()
override {}
547 void Post()
override {
548 for (
int i = 0; i <
vars_.size(); ++i) {
551 solver(),
this, &AllDifferentExcept::Propagate,
"Propagate", i);
556 void InitialPropagate()
override {
557 for (
int i = 0; i <
vars_.size(); ++i) {
558 if (
vars_[i]->Bound()) {
564 void Propagate(
int index) {
566 if (val != escape_value_) {
567 for (
int j = 0; j <
vars_.size(); ++j) {
569 vars_[j]->RemoveValue(val);
575 std::string DebugString()
const override {
576 return absl::StrFormat(
"AllDifferentExcept([%s], %d",
580 void Accept(ModelVisitor*
const visitor)
const override {
589 std::vector<IntVar*>
vars_;
590 const int64_t escape_value_;
598class NullIntersectArrayExcept :
public Constraint {
600 NullIntersectArrayExcept(Solver*
const s, std::vector<IntVar*> first_vars,
601 std::vector<IntVar*> second_vars,
602 int64_t escape_value)
604 first_vars_(
std::move(first_vars)),
605 second_vars_(
std::move(second_vars)),
606 escape_value_(escape_value),
607 has_escape_value_(true) {}
609 NullIntersectArrayExcept(Solver*
const s, std::vector<IntVar*> first_vars,
610 std::vector<IntVar*> second_vars)
612 first_vars_(
std::move(first_vars)),
613 second_vars_(
std::move(second_vars)),
615 has_escape_value_(false) {}
617 ~NullIntersectArrayExcept()
override {}
619 void Post()
override {
620 for (
int i = 0; i < first_vars_.size(); ++i) {
621 IntVar*
const var = first_vars_[i];
623 solver(),
this, &NullIntersectArrayExcept::PropagateFirst,
624 "PropagateFirst", i);
627 for (
int i = 0; i < second_vars_.size(); ++i) {
628 IntVar*
const var = second_vars_[i];
630 solver(),
this, &NullIntersectArrayExcept::PropagateSecond,
631 "PropagateSecond", i);
636 void InitialPropagate()
override {
637 for (
int i = 0; i < first_vars_.size(); ++i) {
638 if (first_vars_[i]->Bound()) {
642 for (
int i = 0; i < second_vars_.size(); ++i) {
643 if (second_vars_[i]->Bound()) {
649 void PropagateFirst(
int index) {
650 const int64_t val = first_vars_[
index]->Value();
651 if (!has_escape_value_ || val != escape_value_) {
652 for (
int j = 0; j < second_vars_.size(); ++j) {
653 second_vars_[j]->RemoveValue(val);
658 void PropagateSecond(
int index) {
659 const int64_t val = second_vars_[
index]->Value();
660 if (!has_escape_value_ || val != escape_value_) {
661 for (
int j = 0; j < first_vars_.size(); ++j) {
662 first_vars_[j]->RemoveValue(val);
667 std::string DebugString()
const override {
668 return absl::StrFormat(
"NullIntersectArray([%s], [%s], escape = %d",
674 void Accept(ModelVisitor*
const visitor)
const override {
685 std::vector<IntVar*> first_vars_;
686 std::vector<IntVar*> second_vars_;
687 const int64_t escape_value_;
688 const bool has_escape_value_;
697 bool stronger_propagation) {
698 const int size = vars.size();
699 for (
int i = 0; i < size; ++i) {
704 }
else if (size == 2) {
706 const_cast<IntVar* const
>(vars[1]));
708 if (stronger_propagation) {
709 return RevAlloc(
new BoundsAllDifferent(
this, vars));
711 return RevAlloc(
new ValueAllDifferent(
this, vars));
717 const std::vector<IntVar*>& sorted) {
718 CHECK_EQ(vars.size(), sorted.size());
719 return RevAlloc(
new SortConstraint(
this, vars, sorted));
723 int64_t escape_value) {
724 int escape_candidates = 0;
725 for (
int i = 0; i < vars.size(); ++i) {
726 escape_candidates += (vars[i]->Contains(escape_value));
728 if (escape_candidates <= 1) {
731 return RevAlloc(
new AllDifferentExcept(
this, vars, escape_value));
736 const std::vector<IntVar*>& second_vars) {
737 return RevAlloc(
new NullIntersectArrayExcept(
this, first_vars, second_vars));
741 const std::vector<IntVar*>& first_vars,
742 const std::vector<IntVar*>& second_vars, int64_t escape_value) {
743 int first_escape_candidates = 0;
744 for (
int i = 0; i < first_vars.size(); ++i) {
745 first_escape_candidates += (first_vars[i]->Contains(escape_value));
747 int second_escape_candidates = 0;
748 for (
int i = 0; i < second_vars.size(); ++i) {
749 second_escape_candidates += (second_vars[i]->Contains(escape_value));
751 if (first_escape_candidates == 0 || second_escape_candidates == 0) {
753 new NullIntersectArrayExcept(
this, first_vars, second_vars));
755 return RevAlloc(
new NullIntersectArrayExcept(
this, first_vars, second_vars,
const std::vector< IntVar * > vars_
#define CHECK_EQ(val1, val2)
A constraint is the main modeling object.
The class IntVar is a subset of IntExpr.
virtual void WhenBound(Demon *d)=0
This method attaches a demon that will be awakened when the variable is bound.
static const char kSortingConstraint[]
static const char kRangeArgument[]
static const char kTargetArgument[]
static const char kNullIntersect[]
static const char kValueArgument[]
static const char kLeftArgument[]
static const char kVarsArgument[]
static const char kRightArgument[]
static const char kAllDifferent[]
void Switch(Solver *const solver)
Constraint * MakeNullIntersectExcept(const std::vector< IntVar * > &first_vars, const std::vector< IntVar * > &second_vars, int64_t escape_value)
Creates a constraint that states that all variables in the first vector are different from all variab...
Constraint * MakeNullIntersect(const std::vector< IntVar * > &first_vars, const std::vector< IntVar * > &second_vars)
Creates a constraint that states that all variables in the first vector are different from all variab...
Constraint * MakeTrueConstraint()
This constraint always succeeds.
Constraint * MakeAllDifferentExcept(const std::vector< IntVar * > &vars, int64_t escape_value)
All variables are pairwise different, unless they are assigned to the escape value.
Constraint * MakeNonEquality(IntExpr *const left, IntExpr *const right)
left != right
Constraint * MakeAllDifferent(const std::vector< IntVar * > &vars)
All variables are pairwise different.
Constraint * MakeSortingConstraint(const std::vector< IntVar * > &vars, const std::vector< IntVar * > &sorted)
Creates a constraint binding the arrays of variables "vars" and "sorted_vars": sorted_vars[0] must be...
T * RevAlloc(T *object)
Registers the given object as being reversible.
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)
Demon * MakeConstraintDemon1(Solver *const s, T *const ct, void(T::*method)(P), const std::string &name, P param1)
std::optional< int64_t > end