23#include "absl/container/flat_hash_map.h"
24#include "absl/log/check.h"
25#include "absl/strings/str_format.h"
26#include "absl/strings/str_join.h"
27#include "absl/types/span.h"
38struct AffineTransformation {
39 AffineTransformation() : a(1), b(0) {}
40 AffineTransformation(int64_t aa, int64_t bb) : a(aa), b(bb) {
46 bool Reverse(int64_t value, int64_t*
const reverse)
const {
47 const int64_t temp = value - b;
50 DCHECK_EQ(Forward(*reverse), value);
57 int64_t Forward(int64_t value)
const {
return value * a + b; }
59 int64_t UnsafeReverse(int64_t value)
const {
return (value - b) / a; }
66 std::string DebugString()
const {
67 return absl::StrFormat(
"(%d * x + %d)", a, b);
74 VarLinearizer() : target_var_(nullptr), transformation_(nullptr) {}
75 ~VarLinearizer()
override {}
77 void VisitIntegerVariable(
const IntVar*
const variable,
78 const std::string& operation, int64_t value,
79 IntVar*
const delegate)
override {
82 delegate->Accept(
this);
86 delegate->Accept(
this);
89 PushMultiplier(value);
90 delegate->Accept(
this);
93 *target_var_ =
const_cast<IntVar*
>(variable);
94 transformation_->a = multipliers_.back();
98 void VisitIntegerVariable(
const IntVar*
const variable,
99 IntExpr*
const delegate)
override {
100 *target_var_ =
const_cast<IntVar*
>(variable);
101 transformation_->a = multipliers_.back();
104 void Visit(
const IntVar*
const var, IntVar**
const target_var,
105 AffineTransformation*
const transformation) {
106 target_var_ = target_var;
107 transformation_ = transformation;
108 transformation->Clear();
112 CHECK(multipliers_.empty());
115 std::string DebugString()
const override {
return "VarLinearizer"; }
118 void AddConstant(int64_t constant) {
119 transformation_->b += constant * multipliers_.back();
122 void PushMultiplier(int64_t multiplier) {
123 if (multipliers_.empty()) {
124 multipliers_.push_back(multiplier);
126 multipliers_.push_back(multiplier * multipliers_.back());
130 void PopMultiplier() { multipliers_.pop_back(); }
132 std::vector<int64_t> multipliers_;
133 IntVar** target_var_;
134 AffineTransformation* transformation_;
137static const int kBitsInUint64 = 64;
153class BasePositiveTableConstraint :
public Constraint {
155 BasePositiveTableConstraint(Solver*
const s,
const std::vector<IntVar*>& vars,
156 const IntTupleSet& tuples)
158 tuple_count_(tuples.NumTuples()),
164 transformations_(arity_) {
174 VarLinearizer linearizer;
175 for (
int i = 0;
i < arity_; ++
i) {
176 linearizer.Visit(vars[i], &vars_[i], &transformations_[i]);
179 for (
int i = 0;
i < arity_; ++
i) {
180 holes_[
i] = vars_[
i]->MakeHoleIterator(
true);
181 iterators_[
i] = vars_[
i]->MakeDomainIterator(
true);
185 ~BasePositiveTableConstraint()
override {}
187 std::string DebugString()
const override {
188 return absl::StrFormat(
"AllowedAssignments(arity = %d, tuple_count = %d)",
189 arity_, tuple_count_);
192 void Accept(ModelVisitor*
const visitor)
const override {
201 bool TupleValue(
int tuple_index,
int var_index, int64_t*
const value)
const {
202 return transformations_[var_index].Reverse(
203 tuples_.Value(tuple_index, var_index), value);
206 int64_t UnsafeTupleValue(
int tuple_index,
int var_index)
const {
207 return transformations_[var_index].UnsafeReverse(
208 tuples_.Value(tuple_index, var_index));
211 bool IsTupleSupported(
int tuple_index) {
212 for (
int var_index = 0; var_index < arity_; ++var_index) {
214 if (!TupleValue(tuple_index, var_index, &value) ||
215 !vars_[var_index]->Contains(value)) {
222 const int tuple_count_;
224 std::vector<IntVar*> vars_;
225 std::vector<IntVarIterator*> holes_;
226 std::vector<IntVarIterator*> iterators_;
227 std::vector<int64_t> to_remove_;
231 const IntTupleSet tuples_;
234 std::vector<AffineTransformation> transformations_;
237class PositiveTableConstraint :
public BasePositiveTableConstraint {
239 typedef absl::flat_hash_map<int, std::vector<uint64_t>> ValueBitset;
241 PositiveTableConstraint(Solver*
const s,
const std::vector<IntVar*>& vars,
242 const IntTupleSet& tuples)
243 : BasePositiveTableConstraint(s, vars, tuples),
245 active_tuples_(tuples.NumTuples()) {}
247 ~PositiveTableConstraint()
override {}
249 void Post()
override {
251 solver(),
this, &PositiveTableConstraint::Propagate,
"Propagate");
252 for (
int i = 0;
i < arity_; ++
i) {
253 vars_[
i]->WhenDomain(d);
255 solver(),
this, &PositiveTableConstraint::Update,
"Update", i);
256 vars_[
i]->WhenDomain(u);
260 masks_.resize(arity_);
261 for (
int i = 0;
i < tuple_count_; ++
i) {
265 std::vector<uint64_t> actives(word_length_, 0);
266 for (
int tuple_index = 0; tuple_index < tuple_count_; ++tuple_index) {
267 if (IsTupleSupported(tuple_index)) {
268 SetBit64(actives.data(), tuple_index);
271 active_tuples_.Init(solver(), actives);
274 void InitialPropagate()
override {
276 for (
int var_index = 0; var_index < arity_; ++var_index) {
277 for (
const auto& it : masks_[var_index]) {
278 if (!vars_[var_index]->Contains(it.first)) {
279 active_tuples_.RevSubtract(solver(), it.second);
283 if (active_tuples_.Empty()) {
287 for (
int var_index = 0; var_index < arity_; ++var_index) {
288 const ValueBitset& mask = masks_[var_index];
289 IntVar*
const var = vars_[var_index];
291 for (
const int64_t value : InitAndGetValues(iterators_[var_index])) {
292 if (!mask.contains(value)) {
293 to_remove_.push_back(value);
296 if (!to_remove_.empty()) {
297 var->RemoveValues(to_remove_);
303 for (
int var_index = 0; var_index < arity_; ++var_index) {
304 IntVar*
const var = vars_[var_index];
306 for (
const int64_t value : InitAndGetValues(iterators_[var_index])) {
307 if (!Supported(var_index, value)) {
308 to_remove_.push_back(value);
311 if (!to_remove_.empty()) {
312 var->RemoveValues(to_remove_);
317 void Update(
int index) {
318 const ValueBitset& var_masks = masks_[index];
319 IntVar*
const var = vars_[index];
320 const int64_t old_max = var->OldMax();
321 const int64_t vmin = var->Min();
322 const int64_t vmax = var->Max();
323 for (int64_t value = var->OldMin(); value < vmin; ++value) {
324 const auto& it = var_masks.find(value);
325 if (it != var_masks.end()) {
326 BlankActives(it->second);
329 for (
const int64_t value : InitAndGetValues(holes_[index])) {
330 const auto& it = var_masks.find(value);
331 if (it != var_masks.end()) {
332 BlankActives(it->second);
335 for (int64_t value = vmax + 1; value <= old_max; ++value) {
336 const auto& it = var_masks.find(value);
337 if (it != var_masks.end()) {
338 BlankActives(it->second);
343 void BlankActives(
const std::vector<uint64_t>& mask) {
345 active_tuples_.RevSubtract(solver(), mask);
346 if (active_tuples_.Empty()) {
352 bool Supported(
int var_index, int64_t value) {
353 DCHECK_GE(var_index, 0);
354 DCHECK_LT(var_index, arity_);
355 DCHECK(masks_[var_index].contains(value));
356 const std::vector<uint64_t>& mask = masks_[var_index][value];
358 return active_tuples_.Intersects(mask, &tmp);
361 std::string DebugString()
const override {
362 return absl::StrFormat(
"PositiveTableConstraint([%s], %d tuples)",
367 void InitializeMask(
int tuple_index) {
368 std::vector<int64_t> cache(arity_);
369 for (
int var_index = 0; var_index < arity_; ++var_index) {
370 if (!TupleValue(tuple_index, var_index, &cache[var_index])) {
374 for (
int var_index = 0; var_index < arity_; ++var_index) {
375 const int64_t value = cache[var_index];
376 std::vector<uint64_t>& mask = masks_[var_index][value];
378 mask.assign(word_length_, 0);
384 const int word_length_;
385 UnsortedNullableRevBitset active_tuples_;
386 std::vector<ValueBitset> masks_;
387 std::vector<uint64_t> temp_mask_;
392class CompactPositiveTableConstraint :
public BasePositiveTableConstraint {
394 CompactPositiveTableConstraint(Solver*
const s,
395 const std::vector<IntVar*>& vars,
396 const IntTupleSet& tuples)
397 : BasePositiveTableConstraint(s, vars, tuples),
399 active_tuples_(tuples.NumTuples()),
401 mask_starts_(arity_),
403 original_min_(arity_, 0),
404 temp_mask_(word_length_, 0),
408 var_sizes_(arity_, 0) {}
410 ~CompactPositiveTableConstraint()
override {}
412 void Post()
override {
414 solver(),
this, &CompactPositiveTableConstraint::Propagate,
416 for (
int i = 0;
i < arity_; ++
i) {
418 solver(),
this, &CompactPositiveTableConstraint::Update,
"Update", i);
419 vars_[
i]->WhenDomain(u);
421 for (
int i = 0;
i < arity_; ++
i) {
422 var_sizes_.SetValue(solver(), i, vars_[i]->Size());
426 void InitialPropagate()
override {
428 FillMasksAndActiveTuples();
429 ComputeMasksBoundaries();
431 RemoveUnsupportedValues();
438 if (touched_var_ == -2) {
445 for (
int var_index = 0; var_index < arity_; ++var_index) {
450 if (var_index == touched_var_) {
454 IntVar*
const var = vars_[var_index];
455 const int64_t original_min = original_min_[var_index];
456 const int64_t var_size = var->Size();
461 if (!Supported(var_index, var->Min() - original_min)) {
467 const int64_t var_min = var->Min();
468 const int64_t var_max = var->Max();
469 const bool min_support = Supported(var_index, var_min - original_min);
470 const bool max_support = Supported(var_index, var_max - original_min);
475 var->SetValue(var_max);
476 var_sizes_.SetValue(solver(), var_index, 1);
478 }
else if (!max_support) {
479 var->SetValue(var_min);
480 var_sizes_.SetValue(solver(), var_index, 1);
486 const int64_t var_min = var->Min();
487 const int64_t var_max = var->Max();
488 int64_t new_min = var_min;
489 int64_t new_max = var_max;
493 if (var_max - var_min + 1 == var_size) {
494 for (; new_min <= var_max; ++new_min) {
495 if (Supported(var_index, new_min - original_min)) {
499 for (; new_max >= new_min; --new_max) {
500 if (Supported(var_index, new_max - original_min)) {
504 var->SetRange(new_min, new_max);
505 for (int64_t value = new_min + 1; value < new_max; ++value) {
506 if (!Supported(var_index, value - original_min)) {
507 to_remove_.push_back(value);
514 new_min = std::numeric_limits<int64_t>::max();
515 for (
const int64_t value :
516 InitAndGetValues(iterators_[var_index])) {
517 if (!Supported(var_index, value - original_min)) {
518 to_remove_.push_back(value);
520 if (new_min == std::numeric_limits<int64_t>::max()) {
528 var->SetRange(new_min, new_max);
530 int index = to_remove_.size() - 1;
531 while (index >= 0 && to_remove_[index] > new_max) {
534 to_remove_.resize(index + 1);
536 var->RemoveValues(to_remove_);
537 var_sizes_.SetValue(solver(), var_index, var->Size());
543 void Update(
int var_index) {
544 if (vars_[var_index]->Size() == var_sizes_.Value(var_index)) {
551 IntVar*
const var = vars_[var_index];
552 bool changed =
false;
553 const int64_t omin = original_min_[var_index];
554 const int64_t var_size = var->Size();
555 const int64_t var_min = var->Min();
556 const int64_t var_max = var->Max();
560 changed = AndMaskWithActive(masks_[var_index][var_min - omin]);
564 SetTempMask(var_index, var_min - omin);
565 OrTempMask(var_index, var_max - omin);
566 changed = AndMaskWithActive(temp_mask_);
570 const int64_t estimated_hole_size =
571 var_sizes_.Value(var_index) - var_size;
572 const int64_t old_min = var->OldMin();
573 const int64_t old_max = var->OldMax();
576 const int64_t number_of_operations =
577 estimated_hole_size + var_min - old_min + old_max - var_max;
578 if (number_of_operations < var_size) {
580 for (int64_t value = old_min; value < var_min; ++value) {
581 changed |= SubtractMaskFromActive(masks_[var_index][value - omin]);
583 for (
const int64_t value : InitAndGetValues(holes_[var_index])) {
584 changed |= SubtractMaskFromActive(masks_[var_index][value - omin]);
586 for (int64_t value = var_max + 1; value <= old_max; ++value) {
587 changed |= SubtractMaskFromActive(masks_[var_index][value - omin]);
593 if (var_max - var_min + 1 == var_size) {
594 for (int64_t value = var_min; value <= var_max; ++value) {
595 OrTempMask(var_index, value - omin);
598 for (
const int64_t value :
599 InitAndGetValues(iterators_[var_index])) {
600 OrTempMask(var_index, value - omin);
604 changed = AndMaskWithActive(temp_mask_);
608 var_sizes_.SetValue(solver(), var_index, var_size);
613 if (touched_var_ == -1 || touched_var_ == var_index) {
614 touched_var_ = var_index;
618 EnqueueDelayedDemon(demon_);
622 std::string DebugString()
const override {
623 return absl::StrFormat(
"CompactPositiveTableConstraint([%s], %d tuples)",
632 for (
int i = 0;
i < arity_; ++
i) {
633 original_min_[
i] = vars_[
i]->Min();
634 const int64_t span = vars_[
i]->Max() - original_min_[
i] + 1;
635 masks_[
i].resize(span);
639 void FillMasksAndActiveTuples() {
640 std::vector<uint64_t> actives(word_length_, 0);
641 for (
int tuple_index = 0; tuple_index < tuple_count_; ++tuple_index) {
642 if (IsTupleSupported(tuple_index)) {
643 SetBit64(actives.data(), tuple_index);
645 for (
int var_index = 0; var_index < arity_; ++var_index) {
646 const int64_t value = UnsafeTupleValue(tuple_index, var_index);
647 const int64_t value_index = value - original_min_[var_index];
648 DCHECK_GE(value_index, 0);
649 DCHECK_LT(value_index, masks_[var_index].size());
650 if (masks_[var_index][value_index].empty()) {
651 masks_[var_index][value_index].assign(word_length_, 0);
653 SetBit64(masks_[var_index][value_index].data(), tuple_index);
657 active_tuples_.Init(solver(), actives);
660 void RemoveUnsupportedValues() {
662 for (
int var_index = 0; var_index < arity_; ++var_index) {
663 IntVar*
const var = vars_[var_index];
665 for (
const int64_t value : InitAndGetValues(iterators_[var_index])) {
666 if (masks_[var_index][value - original_min_[var_index]].empty()) {
667 to_remove_.push_back(value);
670 if (!to_remove_.empty()) {
671 var->RemoveValues(to_remove_);
676 void ComputeMasksBoundaries() {
677 for (
int var_index = 0; var_index < arity_; ++var_index) {
678 mask_starts_[var_index].resize(masks_[var_index].size());
679 mask_ends_[var_index].resize(masks_[var_index].size());
680 for (
int value_index = 0; value_index < masks_[var_index].size();
682 const std::vector<uint64_t>& mask = masks_[var_index][value_index];
687 while (start < word_length_ && mask[start] == 0) {
690 DCHECK_LT(start, word_length_);
691 int end = word_length_ - 1;
692 while (
end > start && mask[
end] == 0) {
695 DCHECK_LE(start,
end);
696 DCHECK_NE(mask[start], 0);
697 DCHECK_NE(mask[
end], 0);
698 mask_starts_[var_index][value_index] = start;
699 mask_ends_[var_index][value_index] =
end;
704 void BuildSupports() {
705 for (
int var_index = 0; var_index < arity_; ++var_index) {
706 supports_[var_index].resize(masks_[var_index].size());
712 bool AndMaskWithActive(
const std::vector<uint64_t>& mask) {
713 const bool result = active_tuples_.RevAnd(solver(), mask);
714 if (active_tuples_.Empty()) {
720 bool SubtractMaskFromActive(
const std::vector<uint64_t>& mask) {
721 const bool result = active_tuples_.RevSubtract(solver(), mask);
722 if (active_tuples_.Empty()) {
728 bool Supported(
int var_index, int64_t value_index) {
729 DCHECK_GE(var_index, 0);
730 DCHECK_LT(var_index, arity_);
731 DCHECK_GE(value_index, 0);
732 DCHECK_LT(value_index, masks_[var_index].size());
733 const std::vector<uint64_t>& mask = masks_[var_index][value_index];
734 DCHECK(!mask.empty());
735 return active_tuples_.Intersects(mask, &supports_[var_index][value_index]);
738 void OrTempMask(
int var_index, int64_t value_index) {
739 const std::vector<uint64_t>& mask = masks_[var_index][value_index];
741 const int mask_span = mask_ends_[var_index][value_index] -
742 mask_starts_[var_index][value_index] + 1;
743 if (active_tuples_.ActiveWordSize() < mask_span) {
744 for (
int i : active_tuples_.active_words()) {
745 temp_mask_[
i] |= mask[
i];
748 for (
int i = mask_starts_[var_index][value_index];
749 i <= mask_ends_[var_index][value_index]; ++
i) {
750 temp_mask_[
i] |= mask[
i];
756 void SetTempMask(
int var_index, int64_t value_index) {
762 if (active_tuples_.ActiveWordSize() < word_length_ / 4) {
763 for (
int i : active_tuples_.active_words()) {
764 temp_mask_[
i] = masks_[var_index][value_index][
i];
767 temp_mask_ = masks_[var_index][value_index];
771 void ClearTempMask() {
773 if (active_tuples_.ActiveWordSize() < word_length_ / 4) {
774 for (
int i : active_tuples_.active_words()) {
778 temp_mask_.assign(word_length_, 0);
783 int64_t word_length_;
785 UnsortedNullableRevBitset active_tuples_;
787 std::vector<std::vector<std::vector<uint64_t>>> masks_;
789 std::vector<std::vector<int>> mask_starts_;
790 std::vector<std::vector<int>> mask_ends_;
792 std::vector<int64_t> original_min_;
794 std::vector<uint64_t> temp_mask_;
797 std::vector<std::vector<int>> supports_;
800 RevArray<int64_t> var_sizes_;
807class SmallCompactPositiveTableConstraint :
public BasePositiveTableConstraint {
809 SmallCompactPositiveTableConstraint(Solver*
const s,
810 const std::vector<IntVar*>& vars,
811 const IntTupleSet& tuples)
812 : BasePositiveTableConstraint(s, vars, tuples),
816 original_min_(arity_, 0),
819 CHECK_GE(tuple_count_, 0);
821 CHECK_LE(tuples.NumTuples(), kBitsInUint64);
824 ~SmallCompactPositiveTableConstraint()
override {}
826 void Post()
override {
828 solver(),
this, &SmallCompactPositiveTableConstraint::Propagate,
830 for (
int i = 0;
i < arity_; ++
i) {
831 if (!vars_[i]->Bound()) {
833 solver(),
this, &SmallCompactPositiveTableConstraint::Update,
835 vars_[
i]->WhenDomain(update_demon);
843 for (
int i = 0;
i < arity_; ++
i) {
844 original_min_[
i] = vars_[
i]->Min();
845 const int64_t span = vars_[
i]->Max() - original_min_[
i] + 1;
846 masks_[
i].assign(span, 0);
850 bool IsTupleSupported(
int tuple_index) {
851 for (
int var_index = 0; var_index < arity_; ++var_index) {
853 if (!TupleValue(tuple_index, var_index, &value) ||
854 !vars_[var_index]->Contains(value)) {
861 void ComputeActiveTuples() {
864 for (
int tuple_index = 0; tuple_index < tuple_count_; ++tuple_index) {
865 if (IsTupleSupported(tuple_index)) {
866 const uint64_t local_mask =
OneBit64(tuple_index);
867 active_tuples_ |= local_mask;
868 for (
int var_index = 0; var_index < arity_; ++var_index) {
869 const int64_t value = UnsafeTupleValue(tuple_index, var_index);
870 masks_[var_index][value - original_min_[var_index]] |= local_mask;
874 if (!active_tuples_) {
879 void RemoveUnsupportedValues() {
881 for (
int var_index = 0; var_index < arity_; ++var_index) {
882 IntVar*
const var = vars_[var_index];
883 const int64_t original_min = original_min_[var_index];
885 for (
const int64_t value : InitAndGetValues(iterators_[var_index])) {
886 if (masks_[var_index][value - original_min] == 0) {
887 to_remove_.push_back(value);
890 if (!to_remove_.empty()) {
891 var->RemoveValues(to_remove_);
896 void InitialPropagate()
override {
898 ComputeActiveTuples();
899 RemoveUnsupportedValues();
909 if (touched_var_ == -2) {
914 const uint64_t actives = active_tuples_;
917 for (
int var_index = 0; var_index < arity_; ++var_index) {
922 if (var_index == touched_var_) {
926 const std::vector<uint64_t>& var_mask = masks_[var_index];
927 const int64_t original_min = original_min_[var_index];
928 IntVar*
const var = vars_[var_index];
929 const int64_t var_size = var->Size();
932 if ((var_mask[var->Min() - original_min] & actives) == 0) {
942 const int64_t var_min = var->Min();
943 const int64_t var_max = var->Max();
944 const bool min_support =
945 (var_mask[var_min - original_min] & actives) != 0;
946 const bool max_support =
947 (var_mask[var_max - original_min] & actives) != 0;
948 if (!min_support && !max_support) {
950 }
else if (!min_support) {
951 var->SetValue(var_max);
952 }
else if (!max_support) {
953 var->SetValue(var_min);
959 const int64_t var_min = var->Min();
960 const int64_t var_max = var->Max();
961 int64_t new_min = var_min;
962 int64_t new_max = var_max;
963 if (var_max - var_min + 1 == var_size) {
965 for (; new_min <= var_max; ++new_min) {
966 if ((var_mask[new_min - original_min] & actives) != 0) {
970 for (; new_max >= new_min; --new_max) {
971 if ((var_mask[new_max - original_min] & actives) != 0) {
975 var->SetRange(new_min, new_max);
976 for (int64_t value = new_min + 1; value < new_max; ++value) {
977 if ((var_mask[value - original_min] & actives) == 0) {
978 to_remove_.push_back(value);
982 bool min_set =
false;
984 for (
const int64_t value :
985 InitAndGetValues(iterators_[var_index])) {
988 if ((var_mask[value - original_min] & actives) == 0) {
990 to_remove_.push_back(value);
998 last_size = to_remove_.size();
1002 var->SetRange(new_min, new_max);
1006 to_remove_.resize(last_size);
1008 var->RemoveValues(to_remove_);
1014 void Update(
int var_index) {
1018 IntVar*
const var = vars_[var_index];
1019 const int64_t original_min = original_min_[var_index];
1020 const int64_t var_size = var->Size();
1023 ApplyMask(var_index, masks_[var_index][var->Min() - original_min]);
1027 ApplyMask(var_index, masks_[var_index][var->Min() - original_min] |
1028 masks_[var_index][var->Max() - original_min]);
1034 const std::vector<uint64_t>& var_mask = masks_[var_index];
1035 const int64_t old_min = var->OldMin();
1036 const int64_t old_max = var->OldMax();
1037 const int64_t var_min = var->Min();
1038 const int64_t var_max = var->Max();
1039 const bool contiguous = var_size == var_max - var_min + 1;
1040 const bool nearly_contiguous =
1041 var_size > (var_max - var_min + 1) * 7 / 10;
1048 uint64_t hole_mask = 0;
1050 for (
const int64_t value : InitAndGetValues(holes_[var_index])) {
1051 hole_mask |= var_mask[value - original_min];
1054 const int64_t hole_operations = var_min - old_min + old_max - var_max;
1056 const int64_t domain_operations = contiguous ? var_size : 4 * var_size;
1057 if (hole_operations < domain_operations) {
1058 for (int64_t value = old_min; value < var_min; ++value) {
1059 hole_mask |= var_mask[value - original_min];
1061 for (int64_t value = var_max + 1; value <= old_max; ++value) {
1062 hole_mask |= var_mask[value - original_min];
1065 ApplyMask(var_index, ~hole_mask);
1067 uint64_t domain_mask = 0;
1069 for (int64_t value = var_min; value <= var_max; ++value) {
1070 domain_mask |= var_mask[value - original_min];
1072 }
else if (nearly_contiguous) {
1073 for (int64_t value = var_min; value <= var_max; ++value) {
1074 if (var->Contains(value)) {
1075 domain_mask |= var_mask[value - original_min];
1079 for (
const int64_t value :
1080 InitAndGetValues(iterators_[var_index])) {
1081 domain_mask |= var_mask[value - original_min];
1084 ApplyMask(var_index, domain_mask);
1090 std::string DebugString()
const override {
1091 return absl::StrFormat(
1092 "SmallCompactPositiveTableConstraint([%s], %d tuples)",
1097 void ApplyMask(
int var_index, uint64_t mask) {
1098 if ((~mask & active_tuples_) != 0) {
1100 const uint64_t current_stamp = solver()->stamp();
1101 if (stamp_ < current_stamp) {
1102 stamp_ = current_stamp;
1103 solver()->SaveValue(&active_tuples_);
1105 active_tuples_ &= mask;
1106 if (active_tuples_) {
1108 if (touched_var_ == -1 || touched_var_ == var_index) {
1109 touched_var_ = var_index;
1113 EnqueueDelayedDemon(demon_);
1123 uint64_t active_tuples_;
1127 std::vector<std::vector<uint64_t>> masks_;
1129 std::vector<int64_t> original_min_;
1134bool HasCompactDomains(
const std::vector<IntVar*>& vars) {
1145class TransitionConstraint :
public Constraint {
1147 static const int kStatePosition;
1148 static const int kNextStatePosition;
1149 static const int kTransitionTupleSize;
1150 TransitionConstraint(Solver*
const s,
const std::vector<IntVar*>& vars,
1151 const IntTupleSet& transition_table,
1152 int64_t initial_state,
1153 const std::vector<int64_t>& final_states)
1156 transition_table_(transition_table),
1157 initial_state_(initial_state),
1158 final_states_(final_states) {}
1160 TransitionConstraint(Solver*
const s,
const std::vector<IntVar*>& vars,
1161 const IntTupleSet& transition_table,
1162 int64_t initial_state,
1163 absl::Span<const int> final_states)
1166 transition_table_(transition_table),
1167 initial_state_(initial_state),
1168 final_states_(final_states.size()) {
1169 for (
int i = 0;
i < final_states.size(); ++
i) {
1170 final_states_[
i] = final_states[
i];
1174 ~TransitionConstraint()
override {}
1176 void Post()
override {
1177 Solver*
const s = solver();
1178 int64_t state_min = std::numeric_limits<int64_t>::max();
1179 int64_t state_max = std::numeric_limits<int64_t>::min();
1180 const int nb_vars = vars_.size();
1181 for (
int i = 0;
i < transition_table_.NumTuples(); ++
i) {
1183 std::max(state_max, transition_table_.Value(i, kStatePosition));
1185 std::max(state_max, transition_table_.Value(i, kNextStatePosition));
1187 std::min(state_min, transition_table_.Value(i, kStatePosition));
1189 std::min(state_min, transition_table_.Value(i, kNextStatePosition));
1192 std::vector<IntVar*> states;
1193 states.push_back(s->MakeIntConst(initial_state_));
1194 for (
int var_index = 1; var_index < nb_vars; ++var_index) {
1195 states.push_back(s->MakeIntVar(state_min, state_max));
1197 states.push_back(s->MakeIntVar(final_states_));
1198 CHECK_EQ(nb_vars + 1, states.size());
1200 const int num_tuples = transition_table_.NumTuples();
1202 for (
int var_index = 0; var_index < nb_vars; ++var_index) {
1203 std::vector<IntVar*> tmp_vars(3);
1204 tmp_vars[0] = states[var_index];
1205 tmp_vars[1] = vars_[var_index];
1206 tmp_vars[2] = states[var_index + 1];
1208 if (num_tuples <= kBitsInUint64) {
1209 s->AddConstraint(s->RevAlloc(
new SmallCompactPositiveTableConstraint(
1210 s, tmp_vars, transition_table_)));
1212 s->AddConstraint(s->RevAlloc(
new CompactPositiveTableConstraint(
1213 s, tmp_vars, transition_table_)));
1218 void InitialPropagate()
override {}
1220 void Accept(ModelVisitor*
const visitor)
const override {
1232 std::string DebugString()
const override {
1233 return absl::StrFormat(
1234 "TransitionConstraint([%s], %d transitions, initial = %d, final = "
1237 initial_state_, absl::StrJoin(final_states_,
", "));
1242 const std::vector<IntVar*> vars_;
1244 const IntTupleSet transition_table_;
1246 const int64_t initial_state_;
1248 std::vector<int64_t> final_states_;
1251const int TransitionConstraint::kStatePosition = 0;
1252const int TransitionConstraint::kNextStatePosition = 2;
1253const int TransitionConstraint::kTransitionTupleSize = 3;
1260 if (HasCompactDomains(vars)) {
1261 if (tuples.
NumTuples() < kBitsInUint64 && parameters_.use_small_table()) {
1263 new SmallCompactPositiveTableConstraint(
this, vars, tuples));
1265 return RevAlloc(
new CompactPositiveTableConstraint(
this, vars, tuples));
1268 return RevAlloc(
new PositiveTableConstraint(
this, vars, tuples));
1272 const std::vector<IntVar*>& vars,
const IntTupleSet& transition_table,
1273 int64_t initial_state,
const std::vector<int64_t>& final_states) {
1274 return RevAlloc(
new TransitionConstraint(
this, vars, transition_table,
1275 initial_state, final_states));
1279 const std::vector<IntVar*>& vars,
const IntTupleSet& transition_table,
1280 int64_t initial_state,
const std::vector<int>& final_states) {
1281 return RevAlloc(
new TransitionConstraint(
this, vars, transition_table,
1282 initial_state, final_states));
static const char kDifferenceOperation[]
static const char kInitialState[]
static const char kTraceOperation[]
static const char kSumOperation[]
static const char kFinalStatesArgument[]
static const char kTuplesArgument[]
static const char kTransition[]
static const char kProductOperation[]
static const char kVarsArgument[]
static const char kAllowedAssignments[]
Constraint * MakeAllowedAssignments(const std::vector< IntVar * > &vars, const IntTupleSet &tuples)
Constraint * MakeTransitionConstraint(const std::vector< IntVar * > &vars, const IntTupleSet &transition_table, int64_t initial_state, const std::vector< int64_t > &final_states)
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)
ClosedInterval::Iterator end(ClosedInterval interval)
uint64_t OneBit64(int pos)
uint64_t BitLength64(uint64_t size)
Demon * MakeConstraintDemon1(Solver *const s, T *const ct, void(T::*method)(P), const std::string &name, P param1)
void SetBit64(uint64_t *const bitset, uint64_t pos)
BeginEndReverseIteratorWrapper< Container > Reverse(const Container &c)