Google OR-Tools: ortools/constraint_solver/table.cc Source File
23#include "absl/container/flat_hash_map.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 {
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) {
107 transformation_ = transformation;
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_;
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_) {
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)",
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)) {
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),
244 word_length_(BitLength64(tuples.NumTuples())),
245 active_tuples_(tuples.NumTuples()) {}
247 ~PositiveTableConstraint() 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);
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_);
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()) {
329 for (const int64_t value : InitAndGetValues(holes_[index])) {
330 const auto& it = var_masks.find(value);
331 if (it != var_masks.end()) {
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()) {
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) {
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);
380 SetBit64(mask.data(), tuple_index);
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),
398 word_length_(BitLength64(tuples.NumTuples())),
399 active_tuples_(tuples.NumTuples()),
404 temp_mask_(word_length_, 0),
410 ~CompactPositiveTableConstraint() 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();
431 RemoveUnsupportedValues();
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);
476 var_sizes_.SetValue(solver(), var_index, 1);
478 } else if (!max_support) {
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];
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) {
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;
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) {
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];
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()) {
748 for (int i = mask_starts_[var_index][value_index];
749 i <= mask_ends_[var_index][value_index]; ++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];
773 if (active_tuples_.ActiveWordSize() < word_length_ / 4) {
774 for (int i : active_tuples_.active_words()) {
775 temp_mask_[i] = 0;
778 temp_mask_.assign(word_length_, 0);
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),
819 CHECK_GE(tuple_count_, 0);
821 CHECK_LE(tuples.NumTuples(), kBitsInUint64);
824 ~SmallCompactPositiveTableConstraint() override {}
828 solver(), this, &SmallCompactPositiveTableConstraint::Propagate,
830 for (int i = 0; i < arity_; ++i) {
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;
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 {
899 RemoveUnsupportedValues();
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();
945 (var_mask[var_min - original_min] & actives) != 0;
947 (var_mask[var_max - original_min] & actives) != 0;
948 if (!min_support && !max_support) {
950 } else if (!min_support) {
952 } else if (!max_support) {
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);
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;
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 {
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) {
1103 solver()->SaveValue(&active_tuples_);
1108 if (touched_var_ == -1 || touched_var_ == var_index) {
1109 touched_var_ = var_index;
1113 EnqueueDelayedDemon(demon_);
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,
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,
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 {}
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 {
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,
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,
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)
Definition table.cc:1258
Constraint * MakeTransitionConstraint(const std::vector< IntVar * > &vars, const IntTupleSet &transition_table, int64_t initial_state, const std::vector< int64_t > &final_states)
Definition table.cc:1271
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)