21 #include "absl/container/flat_hash_set.h"
22 #include "absl/strings/str_cat.h"
23 #include "absl/strings/str_format.h"
24 #include "absl/strings/str_join.h"
48 class NoCycle :
public Constraint {
50 NoCycle(Solver*
const s,
const std::vector<IntVar*>& nexts,
53 ~NoCycle()
override {}
55 void InitialPropagate()
override;
56 void NextChange(
int index);
57 void ActiveBound(
int index);
58 void NextBound(
int index);
59 void ComputeSupports();
60 void ComputeSupport(
int index);
61 std::string DebugString()
const override;
63 void Accept(ModelVisitor*
const visitor)
const override {
69 visitor->VisitIntegerArgument(
"assume_paths", assume_paths_);
70 visitor->VisitInt64ToBoolExtension(sink_handler_, -size(), size());
75 int64 size()
const {
return nexts_.size(); }
77 const std::vector<IntVar*> nexts_;
78 const std::vector<IntVar*> active_;
80 RevArray<int64> starts_;
81 RevArray<int64> ends_;
82 RevArray<bool> marked_;
83 bool all_nexts_bound_;
84 std::vector<int64> outbound_supports_;
85 std::vector<int64> support_leaves_;
86 std::vector<int64> unsupported_;
88 std::vector<int64> sinks_;
92 NoCycle::NoCycle(Solver*
const s,
const std::vector<IntVar*>& nexts,
93 const std::vector<IntVar*>& active,
99 starts_(nexts.size(), -1),
100 ends_(nexts.size(), -1),
101 marked_(nexts.size(), false),
102 all_nexts_bound_(false),
103 outbound_supports_(nexts.size(), -1),
104 sink_handler_(std::move(sink_handler)),
105 assume_paths_(assume_paths) {
106 support_leaves_.reserve(size());
107 unsupported_.reserve(size());
108 for (
int i = 0; i < size(); ++i) {
109 starts_.SetValue(s, i, i);
110 ends_.SetValue(s, i, i);
111 iterators_[i] = nexts_[i]->MakeDomainIterator(
true);
115 void NoCycle::InitialPropagate() {
117 for (
int i = 0; i < size(); ++i) {
118 outbound_supports_[i] = -1;
119 IntVar*
next = nexts_[i];
120 for (
int j =
next->Min(); j < 0; ++j) {
121 if (!sink_handler_(j)) {
122 next->RemoveValue(j);
125 for (
int j =
next->Max(); j >= size(); --j) {
126 if (!sink_handler_(j)) {
127 next->RemoveValue(j);
131 solver()->SaveAndSetValue(&all_nexts_bound_,
true);
132 for (
int i = 0; i < size(); ++i) {
133 if (nexts_[i]->Bound()) {
136 solver()->SaveAndSetValue(&all_nexts_bound_,
false);
142 void NoCycle::Post() {
143 if (size() == 0)
return;
144 for (
int i = 0; i < size(); ++i) {
145 IntVar*
next = nexts_[i];
147 solver(),
this, &NoCycle::NextChange,
"NextChange", i);
148 next->WhenDomain(support_demon);
150 solver(),
this, &NoCycle::ActiveBound,
"ActiveBound", i);
151 active_[i]->WhenBound(active_demon);
154 int64 min_min = nexts_[0]->Min();
155 int64 max_max = nexts_[0]->Max();
156 for (
int i = 1; i < size(); ++i) {
157 const IntVar*
next = nexts_[i];
162 for (
int i = min_min; i <= max_max; ++i) {
163 if (sink_handler_(i)) {
169 void NoCycle::NextChange(
int index) {
170 IntVar*
const next_var = nexts_[
index];
171 if (next_var->Bound()) {
174 if (!all_nexts_bound_) {
175 bool all_nexts_bound =
true;
176 for (
int i = 0; i < size(); ++i) {
177 if (!nexts_[i]->Bound()) {
178 all_nexts_bound =
false;
182 solver()->SaveAndSetValue(&all_nexts_bound_, all_nexts_bound);
184 if (all_nexts_bound_) {
187 if (!next_var->Contains(outbound_supports_[
index])) {
188 ComputeSupport(
index);
192 void NoCycle::ActiveBound(
int index) {
193 if (nexts_[
index]->Bound()) {
198 void NoCycle::NextBound(
int index) {
199 if (active_[
index]->Min() == 0)
return;
200 if (marked_[
index])
return;
201 Solver*
const s = solver();
204 marked_.SetValue(s,
index,
true);
208 if (!sink_handler_(chain_start)) {
209 ends_.SetValue(s, chain_start, chain_end);
210 if (!sink_handler_(chain_end)) {
211 starts_.SetValue(s, chain_end, chain_start);
212 nexts_[chain_end]->RemoveValue(chain_start);
213 if (!assume_paths_) {
214 for (
int i = 0; i < size(); ++i) {
216 bool found = (current == chain_end);
219 while (!found && count < size() && !sink_handler_(current) &&
220 nexts_[current]->Bound()) {
221 current = nexts_[current]->Value();
222 found = (current == chain_end);
226 nexts_[chain_end]->RemoveValue(i);
242 void NoCycle::ComputeSupports() {
244 unsupported_.clear();
247 support_leaves_.clear();
250 const int sink_size = sinks_.size();
251 for (
int i = 0; i < size(); ++i) {
252 const IntVar*
next = nexts_[i];
254 if (active_[i]->Max() != 0) {
255 const int64 current_support = outbound_supports_[i];
258 if (current_support >= 0 && sink_handler_(current_support) &&
259 next->Contains(current_support)) {
260 support_leaves_.push_back(i);
264 outbound_supports_[i] = -1;
265 if (sink_size < next->Size()) {
266 for (
int j = 0; j < sink_size; ++j) {
267 if (
next->Contains(sinks_[j])) {
268 outbound_supports_[i] = sinks_[j];
269 support_leaves_.push_back(i);
275 if (sink_handler_(
value)) {
276 outbound_supports_[i] =
value;
277 support_leaves_.push_back(i);
283 if (outbound_supports_[i] == -1) {
284 unsupported_.push_back(i);
291 size_t leaves_begin = 0;
292 size_t leaves_end = support_leaves_.size();
293 while (!unsupported_.empty()) {
295 for (
int64 unsupported_index = 0; unsupported_index < unsupported_.size();
296 ++unsupported_index) {
297 const int64 unsupported = unsupported_[unsupported_index];
298 const IntVar*
const next = nexts_[unsupported];
299 for (
int i = leaves_begin; i < leaves_end; ++i) {
300 if (
next->Contains(support_leaves_[i])) {
301 outbound_supports_[unsupported] = support_leaves_[i];
302 support_leaves_.push_back(unsupported);
304 unsupported_[unsupported_index] = unsupported_.back();
305 unsupported_.pop_back();
314 if (leaves_end == support_leaves_.size()) {
317 leaves_begin = leaves_end;
318 leaves_end = support_leaves_.size();
321 for (
int64 unsupported_index = 0; unsupported_index < unsupported_.size();
322 ++unsupported_index) {
323 active_[unsupported_[unsupported_index]]->SetMax(0);
327 void NoCycle::ComputeSupport(
int index) {
330 if (active_[
index]->Max() != 0) {
332 if (sink_handler_(
next)) {
337 int64 next_support = outbound_supports_[
next];
338 if (next_support >= 0) {
340 bool ancestor_found =
false;
341 while (next_support < outbound_supports_.size() &&
342 !sink_handler_(next_support)) {
343 if (next_support ==
index) {
344 ancestor_found =
true;
347 next_support = outbound_supports_[next_support];
349 if (!ancestor_found) {
361 std::string NoCycle::DebugString()
const {
367 class Circuit :
public Constraint {
369 Circuit(Solver*
const s,
const std::vector<IntVar*>& nexts,
bool sub_circuit)
372 size_(nexts_.size()),
377 outbound_support_(size_, -1),
378 inbound_support_(size_, -1),
379 temp_support_(size_, -1),
380 inbound_demon_(nullptr),
381 outbound_demon_(nullptr),
384 sub_circuit_(sub_circuit) {
385 for (
int i = 0; i < size_; ++i) {
386 domains_[i] = nexts_[i]->MakeDomainIterator(
true);
390 ~Circuit()
override {}
392 void Post()
override {
394 solver(),
this, &Circuit::CheckReachabilityToRoot,
395 "CheckReachabilityToRoot");
397 solver(),
this, &Circuit::CheckReachabilityFromRoot,
398 "CheckReachabilityFromRoot");
399 for (
int i = 0; i < size_; ++i) {
400 if (!nexts_[i]->Bound()) {
402 solver(),
this, &Circuit::NextBound,
"NextBound", i);
403 nexts_[i]->WhenBound(bound_demon);
405 solver(),
this, &Circuit::NextDomain,
"NextDomain", i);
406 nexts_[i]->WhenDomain(domain_demon);
409 solver()->AddConstraint(solver()->MakeAllDifferent(nexts_));
412 void InitialPropagate()
override {
413 Solver*
const s = solver();
417 for (
int i = 0; i < size_; ++i) {
418 nexts_[i]->SetRange(0, size_ - 1);
420 nexts_[i]->RemoveValue(i);
423 for (
int i = 0; i < size_; ++i) {
424 starts_.SetValue(s, i, i);
425 ends_.SetValue(s, i, i);
426 lengths_.SetValue(s, i, 1);
428 for (
int i = 0; i < size_; ++i) {
429 if (nexts_[i]->Bound()) {
433 CheckReachabilityFromRoot();
434 CheckReachabilityToRoot();
437 std::string DebugString()
const override {
438 return absl::StrFormat(
"%sCircuit(%s)", sub_circuit_ ?
"Sub" :
"",
442 void Accept(ModelVisitor*
const visitor)
const override {
443 visitor->BeginVisitConstraint(ModelVisitor::kCircuit,
this);
444 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kNextsArgument,
446 visitor->VisitIntegerArgument(ModelVisitor::kPartialArgument, sub_circuit_);
447 visitor->EndVisitConstraint(ModelVisitor::kCircuit,
this);
451 bool Inactive(
int index)
const {
455 void NextBound(
int index) {
456 Solver*
const s = solver();
457 const int destination = nexts_[
index]->Value();
458 const int root = root_.
Value();
459 if (destination !=
index) {
463 const int new_end = ends_.Value(destination);
464 const int new_start = starts_.Value(
index);
465 starts_.SetValue(s, new_end, new_start);
466 ends_.SetValue(s, new_start, new_end);
469 lengths_.Value(new_start) + lengths_.Value(destination));
472 nexts_[destination]->RemoveValue(destination);
474 if (lengths_.Value(new_start) < size_ - 1 - num_inactives_.
Value()) {
475 nexts_[new_end]->RemoveValue(new_start);
479 num_inactives_.
Incr(solver());
491 void NextDomain(
int index) {
492 if (root_.
Value() == -1) {
495 if (!nexts_[
index]->Contains(outbound_support_[
index])) {
496 EnqueueDelayedDemon(outbound_demon_);
498 if (!nexts_[
index]->Contains(inbound_support_[
index])) {
499 EnqueueDelayedDemon(inbound_demon_);
503 void TryInsertReached(
int candidate,
int64 after) {
504 if (!reached_[after]) {
505 reached_[after] =
true;
506 insertion_queue_.push_back(after);
507 temp_support_[candidate] = after;
511 void CheckReachabilityFromRoot() {
512 if (root_.
Value() == -1) {
517 temp_support_.assign(size_, -1);
520 reached_.assign(size_,
false);
521 insertion_queue_.clear();
523 const int root_value = root_.
Value();
524 reached_[root_value] =
true;
525 insertion_queue_.push_back(root_value);
527 while (processed < insertion_queue_.size() &&
528 insertion_queue_.size() + num_inactives_.
Value() < size_) {
529 const int candidate = insertion_queue_[processed++];
530 IntVar*
const var = nexts_[candidate];
531 switch (
var->Size()) {
533 TryInsertReached(candidate,
var->Min());
537 TryInsertReached(candidate,
var->Min());
538 TryInsertReached(candidate,
var->Max());
542 IntVarIterator*
const domain = domains_[candidate];
543 for (
const int64 value : InitAndGetValues(domain)) {
544 TryInsertReached(candidate,
value);
551 for (
int i = 0; i < size_; ++i) {
553 nexts_[i]->SetValue(i);
557 outbound_support_.swap(temp_support_);
560 void CheckReachabilityToRoot() {
562 if (root_.
Value() == -1) {
566 insertion_queue_.clear();
567 insertion_queue_.push_back(root_.
Value());
568 temp_support_[root_.
Value()] = nexts_[root_.
Value()]->Min();
571 for (
int i = 0; i < size_; ++i) {
572 if (!Inactive(i) && i != root_.
Value()) {
573 to_visit_.push_back(i);
576 const int inactive = num_inactives_.
Value();
577 while (processed < insertion_queue_.size() &&
578 insertion_queue_.size() + inactive < size_) {
579 const int inserted = insertion_queue_[processed++];
580 std::vector<int> rejected;
582 const int candidate = to_visit_[
index];
583 if (nexts_[candidate]->Contains(inserted)) {
584 insertion_queue_.push_back(candidate);
585 temp_support_[candidate] = inserted;
587 rejected.push_back(candidate);
590 to_visit_.swap(rejected);
592 for (
int i = 0; i < to_visit_.size(); ++i) {
593 const int node = to_visit_[i];
594 nexts_[node]->SetValue(node);
596 temp_support_.swap(inbound_support_);
599 const std::vector<IntVar*> nexts_;
601 std::vector<int> insertion_queue_;
602 std::vector<int> to_visit_;
603 std::vector<bool> reached_;
604 RevArray<int> starts_;
606 RevArray<int> lengths_;
607 std::vector<IntVarIterator*> domains_;
608 std::vector<int> outbound_support_;
609 std::vector<int> inbound_support_;
610 std::vector<int> temp_support_;
611 Demon* inbound_demon_;
612 Demon* outbound_demon_;
614 NumericalRev<int> num_inactives_;
615 const bool sub_circuit_;
619 Constraint* Solver::MakeNoCycle(
const std::vector<IntVar*>& nexts,
620 const std::vector<IntVar*>& active,
623 CHECK_EQ(nexts.size(), active.size());
624 if (sink_handler ==
nullptr) {
625 const int64 size = nexts.size();
628 return RevAlloc(
new NoCycle(
this, nexts, active, sink_handler, assume_paths));
631 Constraint* Solver::MakeNoCycle(
const std::vector<IntVar*>& nexts,
632 const std::vector<IntVar*>& active,
634 return MakeNoCycle(nexts, active, std::move(sink_handler),
true);
638 Constraint* Solver::MakeCircuit(
const std::vector<IntVar*>& nexts) {
639 return RevAlloc(
new Circuit(
this, nexts,
false));
642 Constraint* Solver::MakeSubCircuit(
const std::vector<IntVar*>& nexts) {
643 return RevAlloc(
new Circuit(
this, nexts,
true));
651 BasePathCumul(
Solver*
const s,
const std::vector<IntVar*>& nexts,
652 const std::vector<IntVar*>& active,
653 const std::vector<IntVar*>& cumuls);
654 ~BasePathCumul()
override {}
655 void Post()
override;
657 void ActiveBound(
int index);
658 virtual void NextBound(
int index) = 0;
659 virtual bool AcceptLink(
int i,
int j)
const = 0;
660 void UpdateSupport(
int index);
661 void CumulRange(
int index);
665 int64 size()
const {
return nexts_.size(); }
666 int cumul_size()
const {
return cumuls_.size(); }
668 const std::vector<IntVar*> nexts_;
669 const std::vector<IntVar*> active_;
675 BasePathCumul::BasePathCumul(Solver*
const s,
const std::vector<IntVar*>& nexts,
676 const std::vector<IntVar*>& active,
677 const std::vector<IntVar*>& cumuls)
682 prevs_(cumuls.size(), -1),
685 for (
int i = 0; i < size(); ++i) {
690 void BasePathCumul::InitialPropagate() {
691 for (
int i = 0; i < size(); ++i) {
692 if (nexts_[i]->Bound()) {
700 void BasePathCumul::Post() {
701 for (
int i = 0; i < size(); ++i) {
702 IntVar*
var = nexts_[i];
707 solver(),
this, &BasePathCumul::UpdateSupport,
"UpdateSupport", i);
710 solver(),
this, &BasePathCumul::ActiveBound,
"ActiveBound", i);
711 active_[i]->WhenBound(active_demon);
713 for (
int i = 0; i < cumul_size(); ++i) {
721 void BasePathCumul::ActiveBound(
int index) {
722 if (nexts_[
index]->Bound()) {
727 void BasePathCumul::CumulRange(
int index) {
728 if (
index < size()) {
729 if (nexts_[
index]->Bound()) {
732 UpdateSupport(
index);
738 for (
int i = 0; i < size(); ++i) {
746 void BasePathCumul::UpdateSupport(
int index) {
748 if (support < 0 || !AcceptLink(
index, support)) {
750 for (
int i =
var->Min(); i <= var->Max(); ++i) {
751 if (i != support && AcceptLink(
index, i)) {
756 active_[
index]->SetMax(0);
760 std::string BasePathCumul::DebugString()
const {
761 std::string out =
"PathCumul(";
762 for (
int i = 0; i < size(); ++i) {
763 out += nexts_[i]->DebugString() +
" " +
cumuls_[i]->DebugString();
771 class PathCumul :
public BasePathCumul {
773 PathCumul(Solver*
const s,
const std::vector<IntVar*>& nexts,
774 const std::vector<IntVar*>& active,
775 const std::vector<IntVar*>& cumuls,
776 const std::vector<IntVar*>& transits)
777 : BasePathCumul(s, nexts, active, cumuls), transits_(transits) {}
778 ~PathCumul()
override {}
779 void Post()
override;
780 void NextBound(
int index)
override;
781 bool AcceptLink(
int i,
int j)
const override;
782 void TransitRange(
int index);
784 void Accept(ModelVisitor*
const visitor)
const override {
785 visitor->BeginVisitConstraint(ModelVisitor::kPathCumul,
this);
786 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kNextsArgument,
788 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kActiveArgument,
790 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kCumulsArgument,
792 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kTransitsArgument,
794 visitor->EndVisitConstraint(ModelVisitor::kPathCumul,
this);
798 const std::vector<IntVar*> transits_;
801 void PathCumul::Post() {
802 BasePathCumul::Post();
803 for (
int i = 0; i < size(); ++i) {
805 solver(),
this, &PathCumul::TransitRange,
"TransitRange", i);
806 transits_[i]->WhenRange(transit_demon);
810 void PathCumul::NextBound(
int index) {
811 if (active_[
index]->Min() == 0)
return;
815 IntVar* transit = transits_[
index];
816 cumul_next->SetMin(cumul->Min() + transit->Min());
817 cumul_next->SetMax(
CapAdd(cumul->Max(), transit->Max()));
818 cumul->SetMin(
CapSub(cumul_next->Min(), transit->Max()));
819 cumul->SetMax(
CapSub(cumul_next->Max(), transit->Min()));
820 transit->SetMin(
CapSub(cumul_next->Min(), cumul->Max()));
821 transit->SetMax(
CapSub(cumul_next->Max(), cumul->Min()));
827 void PathCumul::TransitRange(
int index) {
828 if (nexts_[
index]->Bound()) {
831 UpdateSupport(
index);
836 for (
int i = 0; i < size(); ++i) {
844 bool PathCumul::AcceptLink(
int i,
int j)
const {
845 const IntVar*
const cumul_i =
cumuls_[i];
846 const IntVar*
const cumul_j =
cumuls_[j];
847 const IntVar*
const transit_i = transits_[i];
848 return transit_i->Min() <=
CapSub(cumul_j->Max(), cumul_i->Min()) &&
849 CapSub(cumul_j->Min(), cumul_i->Max()) <= transit_i->Max();
854 class StampedVector {
856 StampedVector() :
stamp_(0) {}
857 const std::vector<T>& Values(Solver* solver) {
861 void PushBack(Solver* solver,
const T&
value) {
863 values_.push_back(
value);
865 void Clear(Solver* solver) {
867 stamp_ = solver->fail_stamp();
871 void CheckStamp(Solver* solver) {
872 if (solver->fail_stamp() >
stamp_) {
877 std::vector<T> values_;
882 class DelayedPathCumul :
public Constraint {
884 DelayedPathCumul(Solver*
const solver,
const std::vector<IntVar*>& nexts,
885 const std::vector<IntVar*>& active,
886 const std::vector<IntVar*>& cumuls,
887 const std::vector<IntVar*>& transits)
888 : Constraint(solver),
893 cumul_transit_demons_(cumuls.size(), nullptr),
894 path_demon_(nullptr),
896 chain_starts_(cumuls.size(), -1),
897 chain_ends_(cumuls.size(), -1),
898 is_chain_start_(cumuls.size(), false),
899 prevs_(cumuls.size(), -1),
901 was_bound_(nexts.size(), false),
902 has_cumul_demon_(cumuls.size(), false) {
905 solver,
this, &DelayedPathCumul::CumulRange,
"CumulRange", i);
906 chain_starts_[i] = i;
910 solver,
this, &DelayedPathCumul::PropagatePaths,
"PropagatePaths");
911 for (
int i = 0; i < nexts_.size(); ++i) {
915 ~DelayedPathCumul()
override {}
916 void Post()
override {
917 solver()->RegisterDemon(path_demon_);
918 for (
int i = 0; i < nexts_.size(); ++i) {
919 if (!nexts_[i]->Bound()) {
921 solver(),
this, &DelayedPathCumul::NextBound,
"NextBound", i);
922 nexts_[i]->WhenBound(demon);
925 for (
int i = 0; i < active_.size(); ++i) {
926 if (!active_[i]->Bound()) {
928 solver(),
this, &DelayedPathCumul::ActiveBound,
"ActiveBound", i);
929 active_[i]->WhenBound(demon);
933 void InitialPropagate()
override {
934 touched_.Clear(solver());
935 for (
int i = 0; i < nexts_.size(); ++i) {
936 if (nexts_[i]->Bound()) {
940 for (
int i = 0; i < active_.size(); ++i) {
941 if (active_[i]->Bound()) {
948 void NextBound(
int index) {
949 if (active_[
index]->Min() > 0) {
952 touched_.PushBack(solver(),
index);
953 EnqueueDelayedDemon(path_demon_);
956 void ActiveBound(
int index) {
957 if (nexts_[
index]->Bound()) {
961 void PropagatePaths() {
963 const std::vector<int>& touched_values = touched_.Values(solver());
964 for (
const int touched : touched_values) {
965 chain_starts_[touched] = touched;
966 chain_ends_[touched] = touched;
967 is_chain_start_[touched] =
false;
968 const int next = nexts_[touched]->Min();
971 is_chain_start_[
next] =
false;
973 for (
const int touched : touched_values) {
974 if (touched >= nexts_.size())
continue;
975 IntVar*
const next_var = nexts_[touched];
976 if (!was_bound_[touched] && next_var->Bound() &&
977 active_[touched]->Min() > 0) {
979 was_bound_.SetValue(solver(), touched,
true);
980 chain_starts_[chain_ends_[
next]] = chain_starts_[touched];
981 chain_ends_[chain_starts_[touched]] = chain_ends_[
next];
982 is_chain_start_[
next] =
false;
983 is_chain_start_[chain_starts_[touched]] =
true;
987 for (
const int touched : touched_values) {
989 if (is_chain_start_[touched]) {
991 int64 current = touched;
993 while (current != chain_ends_[touched]) {
995 PropagateLink(current,
next);
997 if (current != chain_ends_[touched]) {
998 next = nexts_[current]->Min();
1003 while (current != touched) {
1004 PropagateLink(prev, current);
1006 if (current != touched) {
1014 while (current != chain_ends_[touched]) {
1015 if (!has_cumul_demon_[current]) {
1016 Demon*
const demon = cumul_transit_demons_[current];
1017 cumuls_[current]->WhenRange(demon);
1018 transits_[current]->WhenRange(demon);
1019 has_cumul_demon_.SetValue(solver(), current,
true);
1021 current = nexts_[current]->Min();
1023 if (!has_cumul_demon_[current]) {
1024 Demon*
const demon = cumul_transit_demons_[current];
1025 cumuls_[current]->WhenRange(demon);
1026 if (current < transits_.size()) {
1027 transits_[current]->WhenRange(demon);
1028 UpdateSupport(current);
1030 has_cumul_demon_.SetValue(solver(), current,
true);
1034 touched_.Clear(solver());
1037 void Accept(ModelVisitor*
const visitor)
const override {
1038 visitor->BeginVisitConstraint(ModelVisitor::kDelayedPathCumul,
this);
1039 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kNextsArgument,
1041 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kActiveArgument,
1043 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kCumulsArgument,
1045 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kTransitsArgument,
1047 visitor->EndVisitConstraint(ModelVisitor::kDelayedPathCumul,
this);
1050 std::string DebugString()
const override {
1051 std::string out =
"DelayedPathCumul(";
1052 for (
int i = 0; i < nexts_.size(); ++i) {
1053 out += nexts_[i]->DebugString() +
" " +
cumuls_[i]->DebugString();
1061 if (
index < nexts_.size()) {
1062 if (nexts_[
index]->Bound()) {
1063 if (active_[
index]->Min() > 0) {
1067 UpdateSupport(
index);
1073 for (
int i = 0; i < nexts_.size(); ++i) {
1080 void UpdateSupport(
int index) {
1082 if (support < 0 || !AcceptLink(
index, support)) {
1084 for (
int i =
next->Min(); i <= next->Max(); ++i) {
1085 if (i != support && AcceptLink(
index, i)) {
1090 active_[
index]->SetMax(0);
1096 IntVar*
const transit = transits_[
index];
1097 const int64 transit_min = transit->Min();
1098 const int64 transit_max = transit->Max();
1099 next_cumul_var->SetMin(
CapAdd(cumul_var->Min(), transit_min));
1100 next_cumul_var->SetMax(
CapAdd(cumul_var->Max(), transit_max));
1101 const int64 next_cumul_min = next_cumul_var->Min();
1102 const int64 next_cumul_max = next_cumul_var->Max();
1103 cumul_var->SetMin(
CapSub(next_cumul_min, transit_max));
1104 cumul_var->SetMax(
CapSub(next_cumul_max, transit_min));
1105 transit->SetMin(
CapSub(next_cumul_min, cumul_var->Max()));
1106 transit->SetMax(
CapSub(next_cumul_max, cumul_var->Min()));
1108 bool AcceptLink(
int index,
int next)
const {
1111 IntVar*
const transit = transits_[
index];
1112 return transit->Min() <=
CapSub(next_cumul_var->Max(), cumul_var->Min()) &&
1113 CapSub(next_cumul_var->Min(), cumul_var->Max()) <= transit->Max();
1116 const std::vector<IntVar*> nexts_;
1117 const std::vector<IntVar*> active_;
1118 const std::vector<IntVar*>
cumuls_;
1119 const std::vector<IntVar*> transits_;
1120 std::vector<Demon*> cumul_transit_demons_;
1122 StampedVector<int> touched_;
1123 std::vector<int64> chain_starts_;
1124 std::vector<int64> chain_ends_;
1125 std::vector<bool> is_chain_start_;
1128 RevArray<bool> was_bound_;
1129 RevArray<bool> has_cumul_demon_;
1134 class IndexEvaluator2PathCumul :
public BasePathCumul {
1136 IndexEvaluator2PathCumul(Solver*
const s,
const std::vector<IntVar*>& nexts,
1137 const std::vector<IntVar*>& active,
1138 const std::vector<IntVar*>& cumuls,
1139 Solver::IndexEvaluator2 transit_evaluator);
1140 ~IndexEvaluator2PathCumul()
override {}
1141 void NextBound(
int index)
override;
1142 bool AcceptLink(
int i,
int j)
const override;
1144 void Accept(ModelVisitor*
const visitor)
const override {
1145 visitor->BeginVisitConstraint(ModelVisitor::kPathCumul,
this);
1146 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kNextsArgument,
1148 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kActiveArgument,
1150 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kCumulsArgument,
1156 visitor->EndVisitConstraint(ModelVisitor::kPathCumul,
this);
1160 Solver::IndexEvaluator2 transits_evaluator_;
1163 IndexEvaluator2PathCumul::IndexEvaluator2PathCumul(
1164 Solver*
const s,
const std::vector<IntVar*>& nexts,
1165 const std::vector<IntVar*>& active,
const std::vector<IntVar*>& cumuls,
1166 Solver::IndexEvaluator2 transit_evaluator)
1167 : BasePathCumul(s, nexts, active, cumuls),
1168 transits_evaluator_(std::move(transit_evaluator)) {}
1170 void IndexEvaluator2PathCumul::NextBound(
int index) {
1171 if (active_[
index]->Min() == 0)
return;
1176 cumul_next->SetMin(cumul->Min() + transit);
1177 cumul_next->SetMax(
CapAdd(cumul->Max(), transit));
1178 cumul->SetMin(
CapSub(cumul_next->Min(), transit));
1179 cumul->SetMax(
CapSub(cumul_next->Max(), transit));
1185 bool IndexEvaluator2PathCumul::AcceptLink(
int i,
int j)
const {
1186 const IntVar*
const cumul_i =
cumuls_[i];
1187 const IntVar*
const cumul_j =
cumuls_[j];
1188 const int64 transit = transits_evaluator_(i, j);
1189 return transit <=
CapSub(cumul_j->Max(), cumul_i->Min()) &&
1190 CapSub(cumul_j->Min(), cumul_i->Max()) <= transit;
1195 class IndexEvaluator2SlackPathCumul :
public BasePathCumul {
1197 IndexEvaluator2SlackPathCumul(Solver*
const s,
1198 const std::vector<IntVar*>& nexts,
1199 const std::vector<IntVar*>& active,
1200 const std::vector<IntVar*>& cumuls,
1201 const std::vector<IntVar*>& slacks,
1202 Solver::IndexEvaluator2 transit_evaluator);
1203 ~IndexEvaluator2SlackPathCumul()
override {}
1204 void Post()
override;
1205 void NextBound(
int index)
override;
1206 bool AcceptLink(
int i,
int j)
const override;
1207 void SlackRange(
int index);
1209 void Accept(ModelVisitor*
const visitor)
const override {
1210 visitor->BeginVisitConstraint(ModelVisitor::kPathCumul,
this);
1211 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kNextsArgument,
1213 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kActiveArgument,
1215 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kCumulsArgument,
1221 visitor->EndVisitConstraint(ModelVisitor::kPathCumul,
this);
1225 const std::vector<IntVar*> slacks_;
1226 Solver::IndexEvaluator2 transits_evaluator_;
1229 IndexEvaluator2SlackPathCumul::IndexEvaluator2SlackPathCumul(
1230 Solver*
const s,
const std::vector<IntVar*>& nexts,
1231 const std::vector<IntVar*>& active,
const std::vector<IntVar*>& cumuls,
1232 const std::vector<IntVar*>& slacks,
1233 Solver::IndexEvaluator2 transit_evaluator)
1234 : BasePathCumul(s, nexts, active, cumuls),
1236 transits_evaluator_(std::move(transit_evaluator)) {}
1238 void IndexEvaluator2SlackPathCumul::Post() {
1239 BasePathCumul::Post();
1240 for (
int i = 0; i < size(); ++i) {
1242 solver(),
this, &IndexEvaluator2SlackPathCumul::SlackRange,
1244 slacks_[i]->WhenRange(slack_demon);
1248 void IndexEvaluator2SlackPathCumul::SlackRange(
int index) {
1249 if (nexts_[
index]->Bound()) {
1252 UpdateSupport(
index);
1257 for (
int i = 0; i < size(); ++i) {
1265 void IndexEvaluator2SlackPathCumul::NextBound(
int index) {
1266 if (active_[
index]->Min() == 0)
return;
1270 IntVar*
const slack = slacks_[
index];
1272 const int64 cumul_next_minus_transit_min =
CapSub(cumul_next->Min(), transit);
1273 const int64 cumul_next_minus_transit_max =
CapSub(cumul_next->Max(), transit);
1274 cumul_next->SetMin(
CapAdd(
CapAdd(cumul->Min(), transit), slack->Min()));
1275 cumul_next->SetMax(
CapAdd(
CapAdd(cumul->Max(), transit), slack->Max()));
1276 cumul->SetMin(
CapSub(cumul_next_minus_transit_min, slack->Max()));
1277 cumul->SetMax(
CapSub(cumul_next_minus_transit_max, slack->Min()));
1278 slack->SetMin(
CapSub(cumul_next_minus_transit_min, cumul->Max()));
1279 slack->SetMax(
CapSub(cumul_next_minus_transit_max, cumul->Min()));
1285 bool IndexEvaluator2SlackPathCumul::AcceptLink(
int i,
int j)
const {
1286 const IntVar*
const cumul_i =
cumuls_[i];
1287 const IntVar*
const cumul_j =
cumuls_[j];
1288 const IntVar*
const slack = slacks_[i];
1289 const int64 transit = transits_evaluator_(i, j);
1290 return CapAdd(transit, slack->Min()) <=
1291 CapSub(cumul_j->Max(), cumul_i->Min()) &&
1292 CapSub(cumul_j->Min(), cumul_i->Max()) <=
1293 CapAdd(slack->Max(), transit);
1297 Constraint* Solver::MakePathCumul(
const std::vector<IntVar*>& nexts,
1298 const std::vector<IntVar*>& active,
1299 const std::vector<IntVar*>& cumuls,
1300 const std::vector<IntVar*>& transits) {
1301 CHECK_EQ(nexts.size(), active.size());
1302 CHECK_EQ(transits.size(), nexts.size());
1303 return RevAlloc(
new PathCumul(
this, nexts, active, cumuls, transits));
1306 Constraint* Solver::MakePathCumul(
const std::vector<IntVar*>& nexts,
1307 const std::vector<IntVar*>& active,
1308 const std::vector<IntVar*>& cumuls,
1310 CHECK_EQ(nexts.size(), active.size());
1311 return RevAlloc(
new IndexEvaluator2PathCumul(
this, nexts, active, cumuls,
1312 std::move(transit_evaluator)));
1315 Constraint* Solver::MakePathCumul(
const std::vector<IntVar*>& nexts,
1316 const std::vector<IntVar*>& active,
1317 const std::vector<IntVar*>& cumuls,
1318 const std::vector<IntVar*>& slacks,
1320 CHECK_EQ(nexts.size(), active.size());
1321 return RevAlloc(
new IndexEvaluator2SlackPathCumul(
1322 this, nexts, active, cumuls, slacks, std::move(transit_evaluator)));
1325 Constraint* Solver::MakeDelayedPathCumul(
const std::vector<IntVar*>& nexts,
1326 const std::vector<IntVar*>& active,
1327 const std::vector<IntVar*>& cumuls,
1328 const std::vector<IntVar*>& transits) {
1329 CHECK_EQ(nexts.size(), active.size());
1330 CHECK_EQ(transits.size(), nexts.size());
1331 return RevAlloc(
new DelayedPathCumul(
this, nexts, active, cumuls, transits));
1337 class PathConnectedConstraint :
public Constraint {
1339 PathConnectedConstraint(
Solver* solver, std::vector<IntVar*> nexts,
1340 const std::vector<int64>& sources,
1341 std::vector<int64> sinks, std::vector<IntVar*> status)
1343 sources_(sources.size(), -1),
1344 index_to_path_(nexts.size(), -1),
1345 sinks_(std::move(sinks)),
1346 nexts_(std::move(nexts)),
1347 status_(std::move(status)),
1348 touched_(nexts_.size()) {
1349 CHECK_EQ(status_.size(), sources_.size());
1350 CHECK_EQ(status_.size(), sinks_.size());
1351 for (
int i = 0; i < status_.size(); ++i) {
1352 const int64 source = sources[i];
1353 sources_.SetValue(solver, i, source);
1354 if (source < index_to_path_.size()) {
1355 index_to_path_.SetValue(solver, source, i);
1359 void Post()
override {
1360 for (
int i = 0; i < nexts_.size(); ++i) {
1362 solver(),
this, &PathConnectedConstraint::NextBound,
"NextValue", i));
1364 for (
int i = 0; i < status_.size(); ++i) {
1365 if (sources_[i] < nexts_.size()) {
1366 status_[i]->SetRange(0, 1);
1368 status_[i]->SetValue(0);
1373 for (
int i = 0; i < status_.size(); ++i) {
1378 std::string output =
"PathConnected(";
1379 std::vector<std::string> elements;
1380 for (IntVar*
const next : nexts_) {
1381 elements.push_back(
next->DebugString());
1383 for (
int i = 0; i < sources_.size(); ++i) {
1384 elements.push_back(absl::StrCat(sources_[i]));
1386 for (
int64 sink : sinks_) {
1387 elements.push_back(absl::StrCat(sink));
1389 for (IntVar*
const status : status_) {
1390 elements.push_back(status->DebugString());
1392 output += absl::StrJoin(elements,
",") +
")";
1397 void NextBound(
int index) {
1398 const int path = index_to_path_[
index];
1403 void EvaluatePath(
int path) {
1404 touched_.SparseClearAll();
1405 int64 source = sources_[path];
1406 const int64 end = sinks_[path];
1407 while (source != end) {
1408 if (source >= nexts_.size() || touched_[source]) {
1409 status_[path]->SetValue(0);
1412 touched_.Set(source);
1413 IntVar*
const next = nexts_[source];
1414 if (
next->Bound()) {
1415 source =
next->Min();
1417 sources_.SetValue(
solver(), path, source);
1418 index_to_path_.SetValue(
solver(), source, path);
1422 status_[path]->SetValue(1);
1425 RevArray<int64> sources_;
1426 RevArray<int> index_to_path_;
1427 const std::vector<int64> sinks_;
1428 const std::vector<IntVar*> nexts_;
1429 const std::vector<IntVar*> status_;
1430 SparseBitset<int64> touched_;
1434 Constraint* Solver::MakePathConnected(std::vector<IntVar*> nexts,
1435 std::vector<int64> sources,
1436 std::vector<int64> sinks,
1437 std::vector<IntVar*> status) {
1438 return RevAlloc(
new PathConnectedConstraint(
1439 this, std::move(nexts), sources, std::move(sinks), std::move(status)));
1443 class PathTransitPrecedenceConstraint :
public Constraint {
1445 enum PrecedenceType {
1450 PathTransitPrecedenceConstraint(
1451 Solver* solver, std::vector<IntVar*> nexts, std::vector<IntVar*> transits,
1452 const std::vector<std::pair<int, int>>& precedences,
1453 absl::flat_hash_map<int, PrecedenceType> precedence_types)
1454 : Constraint(solver),
1455 nexts_(std::move(nexts)),
1456 transits_(std::move(transits)),
1457 predecessors_(nexts_.size()),
1458 successors_(nexts_.size()),
1459 precedence_types_(std::move(precedence_types)),
1460 starts_(nexts_.size(), -1),
1461 ends_(nexts_.size(), -1),
1462 transit_cumuls_(nexts_.size(), 0) {
1463 for (
int i = 0; i < nexts_.size(); ++i) {
1464 starts_.SetValue(solver, i, i);
1465 ends_.SetValue(solver, i, i);
1467 for (
const auto& precedence : precedences) {
1468 if (precedence.second < nexts_.size()) {
1469 predecessors_[precedence.second].push_back(precedence.first);
1471 if (precedence.first < nexts_.size()) {
1472 successors_[precedence.first].push_back(precedence.second);
1476 ~PathTransitPrecedenceConstraint()
override {}
1477 void Post()
override {
1478 for (
int i = 0; i < nexts_.size(); ++i) {
1480 solver(),
this, &PathTransitPrecedenceConstraint::NextBound,
1483 for (
int i = 0; i < transits_.size(); ++i) {
1485 solver(),
this, &PathTransitPrecedenceConstraint::NextBound,
1486 "TransitRange", i));
1490 for (
int i = 0; i < nexts_.size(); ++i) {
1491 if (nexts_[i]->Bound()) {
1497 std::string output =
"PathPrecedence(";
1499 if (!transits_.empty()) {
1502 for (
int i = 0; i < predecessors_.size(); ++i) {
1503 for (
const int predecessor : predecessors_[i]) {
1504 elements.push_back(absl::StrCat(
"(", predecessor,
", ", i,
")"));
1507 output += absl::StrJoin(elements,
",") +
")";
1510 void Accept(ModelVisitor*
const visitor)
const override {
1515 void NextBound(
int index) {
1516 if (!nexts_[
index]->Bound())
return;
1518 const int start = starts_[
index];
1519 const int end = (
next < nexts_.size()) ? ends_[
next] :
next;
1520 if (end < nexts_.size()) starts_.SetValue(solver(), end, start);
1521 ends_.SetValue(
solver(), start, end);
1522 int current = start;
1523 PrecedenceType type = ANY;
1524 auto it = precedence_types_.find(start);
1525 if (it != precedence_types_.end()) {
1531 int64 transit_cumul = 0;
1532 const bool has_transits = !transits_.empty();
1533 while (current < nexts_.size() && current != end) {
1534 transit_cumuls_[current] = transit_cumul;
1535 marked_.insert(current);
1537 if (!predecessors_[current].empty() && !pushed_.empty()) {
1540 for (
const int predecessor : predecessors_[current]) {
1541 if (pushed_.back() == predecessor) {
1549 if (forbidden_.find(current) != forbidden_.end()) {
1550 for (
const int successor : successors_[current]) {
1551 if (marked_.find(successor) != marked_.end()) {
1552 if (!has_transits ||
1553 CapSub(transit_cumul, transit_cumuls_[successor]) > 0) {
1559 if (!successors_[current].empty()) {
1562 pushed_.push_back(current);
1565 pushed_.push_front(current);
1571 for (
const int predecessor : predecessors_[current]) {
1572 forbidden_.insert(predecessor);
1575 transit_cumul =
CapAdd(transit_cumul, transits_[current]->Min());
1577 current = nexts_[current]->Min();
1579 if (forbidden_.find(current) != forbidden_.end()) {
1580 for (
const int successor : successors_[current]) {
1581 if (marked_.find(successor) != marked_.end()) {
1582 if (!has_transits ||
1583 CapSub(transit_cumul, transit_cumuls_[successor]) > 0) {
1591 const std::vector<IntVar*> nexts_;
1592 const std::vector<IntVar*> transits_;
1593 std::vector<std::vector<int>> predecessors_;
1594 std::vector<std::vector<int>> successors_;
1595 const absl::flat_hash_map<int, PrecedenceType> precedence_types_;
1596 RevArray<int> starts_;
1597 RevArray<int> ends_;
1598 absl::flat_hash_set<int> forbidden_;
1599 absl::flat_hash_set<int> marked_;
1600 std::deque<int> pushed_;
1601 std::vector<int64> transit_cumuls_;
1604 Constraint* MakePathTransitTypedPrecedenceConstraint(
1605 Solver* solver, std::vector<IntVar*> nexts, std::vector<IntVar*> transits,
1606 const std::vector<std::pair<int, int>>& precedences,
1607 absl::flat_hash_map<int, PathTransitPrecedenceConstraint::PrecedenceType>
1609 if (precedences.empty()) {
1610 return solver->MakeTrueConstraint();
1612 return solver->RevAlloc(
new PathTransitPrecedenceConstraint(
1613 solver, std::move(nexts), std::move(transits), precedences,
1614 std::move(precedence_types)));
1620 std::vector<IntVar*> nexts,
1621 const std::vector<std::pair<int, int>>& precedences) {
1622 return MakePathTransitPrecedenceConstraint(std::move(nexts), {}, precedences);
1626 std::vector<IntVar*> nexts,
1627 const std::vector<std::pair<int, int>>& precedences,
1628 const std::vector<int>& lifo_path_starts,
1629 const std::vector<int>& fifo_path_starts) {
1630 absl::flat_hash_map<int, PathTransitPrecedenceConstraint::PrecedenceType>
1632 for (
int start : lifo_path_starts) {
1633 precedence_types[start] = PathTransitPrecedenceConstraint::LIFO;
1635 for (
int start : fifo_path_starts) {
1636 precedence_types[start] = PathTransitPrecedenceConstraint::FIFO;
1638 return MakePathTransitTypedPrecedenceConstraint(
1639 this, std::move(nexts), {}, precedences, std::move(precedence_types));
1643 std::vector<IntVar*> nexts, std::vector<IntVar*> transits,
1644 const std::vector<std::pair<int, int>>& precedences) {
1645 return MakePathTransitTypedPrecedenceConstraint(
1646 this, std::move(nexts), std::move(transits), precedences, {{}});