22#include "absl/container/flat_hash_set.h"
23#include "absl/strings/str_cat.h"
24#include "absl/strings/str_format.h"
25#include "absl/strings/str_join.h"
26#include "absl/types/span.h"
50class NoCycle :
public Constraint {
52 NoCycle(Solver* s,
const std::vector<IntVar*>& nexts,
55 ~NoCycle()
override {}
57 void InitialPropagate()
override;
58 void NextChange(
int index);
59 void ActiveBound(
int index);
60 void NextBound(
int index);
61 void ComputeSupports();
62 void ComputeSupport(
int index);
63 std::string DebugString()
const override;
65 void Accept(ModelVisitor*
const visitor)
const override {
71 visitor->VisitIntegerArgument(
"assume_paths", assume_paths_);
72 visitor->VisitInt64ToBoolExtension(sink_handler_, -
size(),
size());
77 int64_t
size()
const {
return nexts_.size(); }
79 const std::vector<IntVar*> nexts_;
80 const std::vector<IntVar*> active_;
81 std::vector<IntVarIterator*> iterators_;
82 RevArray<int64_t> starts_;
83 RevArray<int64_t> ends_;
84 RevArray<bool> marked_;
85 bool all_nexts_bound_;
86 std::vector<int64_t> outbound_supports_;
87 std::vector<int64_t> support_leaves_;
88 std::vector<int64_t> unsupported_;
90 std::vector<int64_t> sinks_;
94NoCycle::NoCycle(Solver*
const s,
const std::vector<IntVar*>& nexts,
95 const std::vector<IntVar*>& active,
100 iterators_(nexts.
size(), nullptr),
101 starts_(nexts.
size(), -1),
102 ends_(nexts.
size(), -1),
104 all_nexts_bound_(
false),
105 outbound_supports_(nexts.
size(), -1),
106 sink_handler_(
std::move(sink_handler)),
107 assume_paths_(assume_paths) {
108 support_leaves_.reserve(
size());
109 unsupported_.reserve(
size());
110 for (
int i = 0;
i <
size(); ++
i) {
111 starts_.SetValue(s, i, i);
112 ends_.SetValue(s, i, i);
113 iterators_[
i] = nexts_[
i]->MakeDomainIterator(
true);
117void NoCycle::InitialPropagate() {
119 for (
int i = 0;
i <
size(); ++
i) {
120 outbound_supports_[
i] = -1;
121 IntVar*
next = nexts_[
i];
122 for (
int j =
next->Min(); j < 0; ++j) {
123 if (!sink_handler_(j)) {
124 next->RemoveValue(j);
127 for (
int j =
next->Max(); j >=
size(); --j) {
128 if (!sink_handler_(j)) {
129 next->RemoveValue(j);
133 solver()->SaveAndSetValue(&all_nexts_bound_,
true);
134 for (
int i = 0;
i <
size(); ++
i) {
135 if (nexts_[i]->Bound()) {
138 solver()->SaveAndSetValue(&all_nexts_bound_,
false);
144void NoCycle::Post() {
145 if (
size() == 0)
return;
146 for (
int i = 0;
i <
size(); ++
i) {
147 IntVar*
next = nexts_[
i];
149 solver(),
this, &NoCycle::NextChange,
"NextChange", i);
150 next->WhenDomain(support_demon);
152 solver(),
this, &NoCycle::ActiveBound,
"ActiveBound", i);
153 active_[
i]->WhenBound(active_demon);
156 int64_t min_min = nexts_[0]->Min();
157 int64_t max_max = nexts_[0]->Max();
158 for (
int i = 1;
i <
size(); ++
i) {
159 const IntVar*
next = nexts_[
i];
160 min_min = std::min(min_min,
next->Min());
161 max_max = std::max(max_max,
next->Max());
164 for (
int i = min_min;
i <= max_max; ++
i) {
165 if (sink_handler_(i)) {
171void NoCycle::NextChange(
int index) {
172 IntVar*
const next_var = nexts_[
index];
173 if (next_var->Bound()) {
176 if (!all_nexts_bound_) {
177 bool all_nexts_bound =
true;
178 for (
int i = 0;
i <
size(); ++
i) {
179 if (!nexts_[i]->Bound()) {
180 all_nexts_bound =
false;
184 solver()->SaveAndSetValue(&all_nexts_bound_, all_nexts_bound);
186 if (all_nexts_bound_) {
189 if (!next_var->Contains(outbound_supports_[
index])) {
190 ComputeSupport(
index);
194void NoCycle::ActiveBound(
int index) {
195 if (nexts_[
index]->Bound()) {
200void NoCycle::NextBound(
int index) {
201 if (active_[
index]->Min() == 0)
return;
202 if (marked_[
index])
return;
203 Solver*
const s = solver();
206 marked_.SetValue(s,
index,
true);
207 const int64_t
next = nexts_[
index]->Value();
208 const int64_t chain_start = starts_[
index];
209 const int64_t chain_end = !sink_handler_(
next) ? ends_[
next] :
next;
210 if (!sink_handler_(chain_start)) {
211 ends_.SetValue(s, chain_start, chain_end);
212 if (!sink_handler_(chain_end)) {
213 starts_.SetValue(s, chain_end, chain_start);
214 nexts_[chain_end]->RemoveValue(chain_start);
215 if (!assume_paths_) {
216 for (
int i = 0;
i <
size(); ++
i) {
218 bool found = (current == chain_end);
221 while (!found && count <
size() && !sink_handler_(current) &&
222 nexts_[current]->Bound()) {
223 current = nexts_[current]->Value();
224 found = (current == chain_end);
228 nexts_[chain_end]->RemoveValue(i);
244void NoCycle::ComputeSupports() {
246 unsupported_.clear();
249 support_leaves_.clear();
252 const int sink_size = sinks_.size();
253 for (
int i = 0;
i <
size(); ++
i) {
254 const IntVar*
next = nexts_[
i];
256 if (active_[i]->Max() != 0) {
257 const int64_t current_support = outbound_supports_[
i];
260 if (current_support >= 0 && sink_handler_(current_support) &&
261 next->Contains(current_support)) {
262 support_leaves_.push_back(i);
266 outbound_supports_[
i] = -1;
267 if (sink_size < next->Size()) {
268 for (
int j = 0; j < sink_size; ++j) {
269 if (
next->Contains(sinks_[j])) {
270 outbound_supports_[
i] = sinks_[j];
271 support_leaves_.push_back(i);
276 for (
const int64_t
value : InitAndGetValues(iterators_[i])) {
277 if (sink_handler_(
value)) {
278 outbound_supports_[
i] =
value;
279 support_leaves_.push_back(i);
285 if (outbound_supports_[i] == -1) {
286 unsupported_.push_back(i);
293 size_t leaves_begin = 0;
294 size_t leaves_end = support_leaves_.size();
295 while (!unsupported_.empty()) {
297 for (int64_t unsupported_index = 0; unsupported_index < unsupported_.size();
298 ++unsupported_index) {
299 const int64_t unsupported = unsupported_[unsupported_index];
300 const IntVar*
const next = nexts_[unsupported];
301 for (
int i = leaves_begin;
i < leaves_end; ++
i) {
302 if (
next->Contains(support_leaves_[i])) {
303 outbound_supports_[unsupported] = support_leaves_[
i];
304 support_leaves_.push_back(unsupported);
306 unsupported_[unsupported_index] = unsupported_.back();
307 unsupported_.pop_back();
316 if (leaves_end == support_leaves_.size()) {
319 leaves_begin = leaves_end;
320 leaves_end = support_leaves_.size();
323 for (int64_t unsupported_index = 0; unsupported_index < unsupported_.size();
324 ++unsupported_index) {
325 active_[unsupported_[unsupported_index]]->SetMax(0);
329void NoCycle::ComputeSupport(
int index) {
332 if (active_[
index]->Max() != 0) {
333 for (
const int64_t
next : InitAndGetValues(iterators_[
index])) {
334 if (sink_handler_(
next)) {
339 int64_t next_support = outbound_supports_[
next];
340 if (next_support >= 0) {
342 bool ancestor_found =
false;
343 while (next_support < outbound_supports_.size() &&
344 !sink_handler_(next_support)) {
345 if (next_support ==
index) {
346 ancestor_found =
true;
349 next_support = outbound_supports_[next_support];
351 if (!ancestor_found) {
363std::string NoCycle::DebugString()
const {
369class Circuit :
public Constraint {
371 Circuit(Solver*
const s,
const std::vector<IntVar*>& nexts,
bool sub_circuit)
374 size_(nexts_.
size()),
379 outbound_support_(size_, -1),
380 inbound_support_(size_, -1),
381 temp_support_(size_, -1),
382 inbound_demon_(nullptr),
383 outbound_demon_(nullptr),
386 sub_circuit_(sub_circuit) {
387 for (
int i = 0;
i < size_; ++
i) {
388 domains_[
i] = nexts_[
i]->MakeDomainIterator(
true);
392 ~Circuit()
override {}
394 void Post()
override {
396 solver(),
this, &Circuit::CheckReachabilityToRoot,
397 "CheckReachabilityToRoot");
399 solver(),
this, &Circuit::CheckReachabilityFromRoot,
400 "CheckReachabilityFromRoot");
401 for (
int i = 0;
i < size_; ++
i) {
402 if (!nexts_[i]->Bound()) {
404 solver(),
this, &Circuit::NextBound,
"NextBound", i);
405 nexts_[
i]->WhenBound(bound_demon);
407 solver(),
this, &Circuit::NextDomain,
"NextDomain", i);
408 nexts_[
i]->WhenDomain(domain_demon);
411 solver()->AddConstraint(solver()->MakeAllDifferent(nexts_));
414 void InitialPropagate()
override {
415 Solver*
const s = solver();
417 root_.SetValue(solver(), 0);
419 for (
int i = 0;
i < size_; ++
i) {
420 nexts_[
i]->SetRange(0, size_ - 1);
422 nexts_[
i]->RemoveValue(i);
425 for (
int i = 0;
i < size_; ++
i) {
426 starts_.SetValue(s, i, i);
427 ends_.SetValue(s, i, i);
428 lengths_.SetValue(s, i, 1);
430 for (
int i = 0;
i < size_; ++
i) {
431 if (nexts_[i]->Bound()) {
435 CheckReachabilityFromRoot();
436 CheckReachabilityToRoot();
439 std::string DebugString()
const override {
440 return absl::StrFormat(
"%sCircuit(%s)", sub_circuit_ ?
"Sub" :
"",
444 void Accept(ModelVisitor*
const visitor)
const override {
445 visitor->BeginVisitConstraint(ModelVisitor::kCircuit,
this);
446 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kNextsArgument,
448 visitor->VisitIntegerArgument(ModelVisitor::kPartialArgument, sub_circuit_);
449 visitor->EndVisitConstraint(ModelVisitor::kCircuit,
this);
453 bool Inactive(
int index)
const {
457 void NextBound(
int index) {
458 Solver*
const s = solver();
459 const int destination = nexts_[
index]->Value();
460 const int root = root_.Value();
461 if (destination !=
index) {
463 root_.SetValue(s,
index);
465 const int new_end = ends_.Value(destination);
466 const int new_start = starts_.Value(
index);
467 starts_.SetValue(s, new_end, new_start);
468 ends_.SetValue(s, new_start, new_end);
471 lengths_.Value(new_start) + lengths_.Value(destination));
474 nexts_[destination]->RemoveValue(destination);
476 if (lengths_.Value(new_start) < size_ - 1 - num_inactives_.Value()) {
477 nexts_[new_end]->RemoveValue(new_start);
481 num_inactives_.Incr(solver());
493 void NextDomain(
int index) {
494 if (root_.Value() == -1) {
497 if (!nexts_[
index]->Contains(outbound_support_[
index])) {
498 EnqueueDelayedDemon(outbound_demon_);
500 if (!nexts_[
index]->Contains(inbound_support_[
index])) {
501 EnqueueDelayedDemon(inbound_demon_);
505 void TryInsertReached(
int candidate, int64_t after) {
506 if (!reached_[after]) {
507 reached_[after] =
true;
508 insertion_queue_.push_back(after);
509 temp_support_[candidate] = after;
513 void CheckReachabilityFromRoot() {
514 if (root_.Value() == -1) {
519 temp_support_.assign(size_, -1);
522 reached_.assign(size_,
false);
523 insertion_queue_.clear();
525 const int root_value = root_.Value();
526 reached_[root_value] =
true;
527 insertion_queue_.push_back(root_value);
529 while (processed < insertion_queue_.size() &&
530 insertion_queue_.size() + num_inactives_.Value() < size_) {
531 const int candidate = insertion_queue_[processed++];
532 IntVar*
const var = nexts_[candidate];
533 switch (
var->Size()) {
535 TryInsertReached(candidate,
var->Min());
539 TryInsertReached(candidate,
var->Min());
540 TryInsertReached(candidate,
var->Max());
544 IntVarIterator*
const domain = domains_[candidate];
545 for (
const int64_t
value : InitAndGetValues(domain)) {
546 TryInsertReached(candidate,
value);
553 for (
int i = 0;
i < size_; ++
i) {
555 nexts_[
i]->SetValue(i);
559 outbound_support_.swap(temp_support_);
562 void CheckReachabilityToRoot() {
564 if (root_.Value() == -1) {
568 insertion_queue_.clear();
569 insertion_queue_.push_back(root_.Value());
570 temp_support_[root_.Value()] = nexts_[root_.Value()]->Min();
573 for (
int i = 0;
i < size_; ++
i) {
574 if (!Inactive(i) && i != root_.Value()) {
575 to_visit_.push_back(i);
578 const int inactive = num_inactives_.Value();
579 while (processed < insertion_queue_.size() &&
580 insertion_queue_.size() + inactive < size_) {
581 const int inserted = insertion_queue_[processed++];
582 std::vector<int> rejected;
584 const int candidate = to_visit_[
index];
585 if (nexts_[candidate]->Contains(inserted)) {
586 insertion_queue_.push_back(candidate);
587 temp_support_[candidate] = inserted;
589 rejected.push_back(candidate);
592 to_visit_.swap(rejected);
594 for (
int i = 0;
i < to_visit_.size(); ++
i) {
595 const int node = to_visit_[
i];
596 nexts_[node]->SetValue(node);
598 temp_support_.swap(inbound_support_);
601 const std::vector<IntVar*> nexts_;
603 std::vector<int> insertion_queue_;
604 std::vector<int> to_visit_;
605 std::vector<bool> reached_;
606 RevArray<int> starts_;
608 RevArray<int> lengths_;
609 std::vector<IntVarIterator*> domains_;
610 std::vector<int> outbound_support_;
611 std::vector<int> inbound_support_;
612 std::vector<int> temp_support_;
613 Demon* inbound_demon_;
614 Demon* outbound_demon_;
616 NumericalRev<int> num_inactives_;
617 const bool sub_circuit_;
621Constraint* Solver::MakeNoCycle(
const std::vector<IntVar*>& nexts,
622 const std::vector<IntVar*>& active,
625 CHECK_EQ(nexts.size(), active.size());
626 if (sink_handler ==
nullptr) {
627 const int64_t
size = nexts.size();
630 return RevAlloc(
new NoCycle(
this, nexts, active, sink_handler, assume_paths));
633Constraint* Solver::MakeNoCycle(
const std::vector<IntVar*>& nexts,
634 const std::vector<IntVar*>& active,
636 return MakeNoCycle(nexts, active, std::move(sink_handler),
true);
640Constraint* Solver::MakeCircuit(
const std::vector<IntVar*>& nexts) {
641 return RevAlloc(
new Circuit(
this, nexts,
false));
644Constraint* Solver::MakeSubCircuit(
const std::vector<IntVar*>& nexts) {
645 return RevAlloc(
new Circuit(
this, nexts,
true));
653 BasePathCumul(
Solver* s,
const std::vector<IntVar*>& nexts,
654 const std::vector<IntVar*>& active,
655 const std::vector<IntVar*>& cumuls);
656 ~BasePathCumul()
override {}
657 void Post()
override;
658 void InitialPropagate()
override;
659 void ActiveBound(
int index);
660 virtual void NextBound(
int index) = 0;
661 virtual bool AcceptLink(
int i,
int j)
const = 0;
662 void UpdateSupport(
int index);
663 void CumulRange(
int index);
664 std::string DebugString()
const override;
667 int64_t
size()
const {
return nexts_.size(); }
668 int cumul_size()
const {
return cumuls_.size(); }
670 const std::vector<IntVar*> nexts_;
671 const std::vector<IntVar*> active_;
677BasePathCumul::BasePathCumul(Solver*
const s,
const std::vector<IntVar*>& nexts,
678 const std::vector<IntVar*>& active,
679 const std::vector<IntVar*>& cumuls)
686 CHECK_GE(cumul_size(),
size());
687 for (
int i = 0;
i <
size(); ++
i) {
692void BasePathCumul::InitialPropagate() {
693 for (
int i = 0;
i <
size(); ++
i) {
694 if (nexts_[i]->Bound()) {
702void BasePathCumul::Post() {
703 for (
int i = 0;
i <
size(); ++
i) {
704 IntVar*
var = nexts_[
i];
709 solver(),
this, &BasePathCumul::UpdateSupport,
"UpdateSupport", i);
712 solver(),
this, &BasePathCumul::ActiveBound,
"ActiveBound", i);
713 active_[
i]->WhenBound(active_demon);
715 for (
int i = 0;
i < cumul_size(); ++
i) {
723void BasePathCumul::ActiveBound(
int index) {
724 if (nexts_[
index]->Bound()) {
729void BasePathCumul::CumulRange(
int index) {
731 if (nexts_[
index]->Bound()) {
734 UpdateSupport(
index);
740 for (
int i = 0;
i <
size(); ++
i) {
748void BasePathCumul::UpdateSupport(
int index) {
750 if (support < 0 || !AcceptLink(
index, support)) {
752 for (
int i =
var->Min(); i <= var->Max(); ++
i) {
753 if (i != support && AcceptLink(
index, i)) {
758 active_[
index]->SetMax(0);
762std::string BasePathCumul::DebugString()
const {
763 std::string out =
"PathCumul(";
764 for (
int i = 0;
i <
size(); ++
i) {
765 out += nexts_[
i]->DebugString() +
" " +
cumuls_[
i]->DebugString();
773class PathCumul :
public BasePathCumul {
775 PathCumul(Solver*
const s,
const std::vector<IntVar*>& nexts,
776 const std::vector<IntVar*>& active,
777 const std::vector<IntVar*>& cumuls,
778 const std::vector<IntVar*>& transits)
779 : BasePathCumul(s, nexts, active, cumuls), transits_(transits) {}
780 ~PathCumul()
override {}
781 void Post()
override;
782 void NextBound(
int index)
override;
783 bool AcceptLink(
int i,
int j)
const override;
784 void TransitRange(
int index);
786 void Accept(ModelVisitor*
const visitor)
const override {
787 visitor->BeginVisitConstraint(ModelVisitor::kPathCumul,
this);
788 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kNextsArgument,
790 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kActiveArgument,
792 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kCumulsArgument,
794 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kTransitsArgument,
796 visitor->EndVisitConstraint(ModelVisitor::kPathCumul,
this);
800 const std::vector<IntVar*> transits_;
803void PathCumul::Post() {
804 BasePathCumul::Post();
805 for (
int i = 0;
i <
size(); ++
i) {
807 solver(),
this, &PathCumul::TransitRange,
"TransitRange", i);
808 transits_[
i]->WhenRange(transit_demon);
812void PathCumul::NextBound(
int index) {
813 if (active_[
index]->Min() == 0)
return;
814 const int64_t
next = nexts_[
index]->Value();
817 IntVar* transit = transits_[
index];
818 cumul_next->SetMin(cumul->Min() + transit->Min());
819 cumul_next->SetMax(
CapAdd(cumul->Max(), transit->Max()));
820 cumul->SetMin(
CapSub(cumul_next->Min(), transit->Max()));
821 cumul->SetMax(
CapSub(cumul_next->Max(), transit->Min()));
822 transit->SetMin(
CapSub(cumul_next->Min(), cumul->Max()));
823 transit->SetMax(
CapSub(cumul_next->Max(), cumul->Min()));
829void PathCumul::TransitRange(
int index) {
830 if (nexts_[
index]->Bound()) {
833 UpdateSupport(
index);
838 for (
int i = 0;
i <
size(); ++
i) {
846bool PathCumul::AcceptLink(
int i,
int j)
const {
847 const IntVar*
const cumul_i =
cumuls_[
i];
848 const IntVar*
const cumul_j =
cumuls_[j];
849 const IntVar*
const transit_i = transits_[
i];
850 return transit_i->Min() <=
CapSub(cumul_j->Max(), cumul_i->Min()) &&
851 CapSub(cumul_j->Min(), cumul_i->Max()) <= transit_i->Max();
858 StampedVector() : stamp_(0) {}
859 const std::vector<T>&
Values(Solver* solver) {
863 void PushBack(Solver* solver,
const T&
value) {
865 values_.push_back(
value);
867 void Clear(Solver* solver) {
869 stamp_ = solver->fail_stamp();
873 void CheckStamp(Solver* solver) {
874 if (solver->fail_stamp() > stamp_) {
879 std::vector<T> values_;
884class DelayedPathCumul :
public Constraint {
886 DelayedPathCumul(Solver*
const solver,
const std::vector<IntVar*>& nexts,
887 const std::vector<IntVar*>& active,
888 const std::vector<IntVar*>& cumuls,
889 const std::vector<IntVar*>& transits)
890 : Constraint(solver),
895 cumul_transit_demons_(cumuls.
size(), nullptr),
896 path_demon_(nullptr),
898 chain_starts_(cumuls.
size(), -1),
899 chain_ends_(cumuls.
size(), -1),
905 for (int64_t i = 0;
i <
cumuls_.size(); ++
i) {
907 solver,
this, &DelayedPathCumul::CumulRange,
"CumulRange", i);
908 chain_starts_[
i] =
i;
912 solver,
this, &DelayedPathCumul::PropagatePaths,
"PropagatePaths");
913 for (
int i = 0;
i < nexts_.size(); ++
i) {
917 ~DelayedPathCumul()
override {}
918 void Post()
override {
919 solver()->RegisterDemon(path_demon_);
920 for (
int i = 0;
i < nexts_.size(); ++
i) {
921 if (!nexts_[i]->Bound()) {
923 solver(),
this, &DelayedPathCumul::NextBound,
"NextBound", i);
924 nexts_[
i]->WhenBound(demon);
927 for (
int i = 0;
i < active_.size(); ++
i) {
928 if (!active_[i]->Bound()) {
930 solver(),
this, &DelayedPathCumul::ActiveBound,
"ActiveBound", i);
931 active_[
i]->WhenBound(demon);
935 void InitialPropagate()
override {
936 touched_.Clear(solver());
937 for (
int i = 0;
i < nexts_.size(); ++
i) {
938 if (nexts_[i]->Bound()) {
942 for (
int i = 0;
i < active_.size(); ++
i) {
943 if (active_[i]->Bound()) {
950 void NextBound(
int index) {
951 if (active_[
index]->Min() > 0) {
954 touched_.PushBack(solver(),
index);
955 EnqueueDelayedDemon(path_demon_);
958 void ActiveBound(
int index) {
959 if (nexts_[
index]->Bound()) {
963 void PropagatePaths() {
965 const std::vector<int>& touched_values = touched_.Values(solver());
966 for (
const int touched : touched_values) {
967 chain_starts_[touched] = touched;
968 chain_ends_[touched] = touched;
969 is_chain_start_[touched] =
false;
970 const int next = nexts_[touched]->Min();
973 is_chain_start_[
next] =
false;
975 for (
const int touched : touched_values) {
976 if (touched >= nexts_.size())
continue;
977 IntVar*
const next_var = nexts_[touched];
978 if (!was_bound_[touched] && next_var->Bound() &&
979 active_[touched]->Min() > 0) {
980 const int64_t
next = next_var->Min();
981 was_bound_.SetValue(solver(), touched,
true);
982 chain_starts_[chain_ends_[
next]] = chain_starts_[touched];
983 chain_ends_[chain_starts_[touched]] = chain_ends_[
next];
984 is_chain_start_[
next] =
false;
985 is_chain_start_[chain_starts_[touched]] =
true;
989 for (
const int touched : touched_values) {
991 if (is_chain_start_[touched]) {
993 int64_t current = touched;
994 int64_t
next = nexts_[current]->Min();
995 while (current != chain_ends_[touched]) {
997 PropagateLink(current,
next);
999 if (current != chain_ends_[touched]) {
1000 next = nexts_[current]->Min();
1004 int64_t prev =
prevs_[current];
1005 while (current != touched) {
1006 PropagateLink(prev, current);
1008 if (current != touched) {
1016 while (current != chain_ends_[touched]) {
1017 if (!has_cumul_demon_[current]) {
1018 Demon*
const demon = cumul_transit_demons_[current];
1019 cumuls_[current]->WhenRange(demon);
1020 transits_[current]->WhenRange(demon);
1021 has_cumul_demon_.SetValue(solver(), current,
true);
1023 current = nexts_[current]->Min();
1025 if (!has_cumul_demon_[current]) {
1026 Demon*
const demon = cumul_transit_demons_[current];
1027 cumuls_[current]->WhenRange(demon);
1028 if (current < transits_.size()) {
1029 transits_[current]->WhenRange(demon);
1030 UpdateSupport(current);
1032 has_cumul_demon_.SetValue(solver(), current,
true);
1036 touched_.Clear(solver());
1039 void Accept(ModelVisitor*
const visitor)
const override {
1040 visitor->BeginVisitConstraint(ModelVisitor::kDelayedPathCumul,
this);
1041 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kNextsArgument,
1043 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kActiveArgument,
1045 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kCumulsArgument,
1047 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kTransitsArgument,
1049 visitor->EndVisitConstraint(ModelVisitor::kDelayedPathCumul,
this);
1052 std::string DebugString()
const override {
1053 std::string out =
"DelayedPathCumul(";
1054 for (
int i = 0;
i < nexts_.size(); ++
i) {
1055 out += nexts_[
i]->DebugString() +
" " +
cumuls_[
i]->DebugString();
1062 void CumulRange(int64_t
index) {
1063 if (
index < nexts_.size()) {
1064 if (nexts_[
index]->Bound()) {
1065 if (active_[
index]->Min() > 0) {
1069 UpdateSupport(
index);
1075 for (
int i = 0;
i < nexts_.size(); ++
i) {
1082 void UpdateSupport(
int index) {
1084 if (support < 0 || !AcceptLink(
index, support)) {
1086 for (
int i =
next->Min(); i <= next->Max(); ++
i) {
1087 if (i != support && AcceptLink(
index, i)) {
1092 active_[
index]->SetMax(0);
1095 void PropagateLink(int64_t
index, int64_t
next) {
1098 IntVar*
const transit = transits_[
index];
1099 const int64_t transit_min = transit->Min();
1100 const int64_t transit_max = transit->Max();
1101 next_cumul_var->SetMin(
CapAdd(cumul_var->Min(), transit_min));
1102 next_cumul_var->SetMax(
CapAdd(cumul_var->Max(), transit_max));
1103 const int64_t next_cumul_min = next_cumul_var->Min();
1104 const int64_t next_cumul_max = next_cumul_var->Max();
1105 cumul_var->SetMin(
CapSub(next_cumul_min, transit_max));
1106 cumul_var->SetMax(
CapSub(next_cumul_max, transit_min));
1107 transit->SetMin(
CapSub(next_cumul_min, cumul_var->Max()));
1108 transit->SetMax(
CapSub(next_cumul_max, cumul_var->Min()));
1110 bool AcceptLink(
int index,
int next)
const {
1113 IntVar*
const transit = transits_[
index];
1114 return transit->Min() <=
CapSub(next_cumul_var->Max(), cumul_var->Min()) &&
1115 CapSub(next_cumul_var->Min(), cumul_var->Max()) <= transit->Max();
1118 const std::vector<IntVar*> nexts_;
1119 const std::vector<IntVar*> active_;
1120 const std::vector<IntVar*>
cumuls_;
1121 const std::vector<IntVar*> transits_;
1122 std::vector<Demon*> cumul_transit_demons_;
1124 StampedVector<int> touched_;
1125 std::vector<int64_t> chain_starts_;
1126 std::vector<int64_t> chain_ends_;
1127 std::vector<bool> is_chain_start_;
1130 RevArray<bool> was_bound_;
1131 RevArray<bool> has_cumul_demon_;
1136class IndexEvaluator2PathCumul :
public BasePathCumul {
1138 IndexEvaluator2PathCumul(Solver* s,
const std::vector<IntVar*>& nexts,
1139 const std::vector<IntVar*>& active,
1140 const std::vector<IntVar*>& cumuls,
1141 Solver::IndexEvaluator2 transit_evaluator);
1142 ~IndexEvaluator2PathCumul()
override {}
1143 void NextBound(
int index)
override;
1144 bool AcceptLink(
int i,
int j)
const override;
1146 void Accept(ModelVisitor*
const visitor)
const override {
1147 visitor->BeginVisitConstraint(ModelVisitor::kPathCumul,
this);
1148 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kNextsArgument,
1150 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kActiveArgument,
1152 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kCumulsArgument,
1158 visitor->EndVisitConstraint(ModelVisitor::kPathCumul,
this);
1162 Solver::IndexEvaluator2 transits_evaluator_;
1165IndexEvaluator2PathCumul::IndexEvaluator2PathCumul(
1166 Solver*
const s,
const std::vector<IntVar*>& nexts,
1167 const std::vector<IntVar*>& active,
const std::vector<IntVar*>& cumuls,
1168 Solver::IndexEvaluator2 transit_evaluator)
1169 : BasePathCumul(s, nexts, active, cumuls),
1170 transits_evaluator_(
std::move(transit_evaluator)) {}
1172void IndexEvaluator2PathCumul::NextBound(
int index) {
1173 if (active_[
index]->Min() == 0)
return;
1174 const int64_t
next = nexts_[
index]->Value();
1177 const int64_t transit = transits_evaluator_(
index,
next);
1178 cumul_next->SetMin(cumul->Min() + transit);
1179 cumul_next->SetMax(
CapAdd(cumul->Max(), transit));
1180 cumul->SetMin(
CapSub(cumul_next->Min(), transit));
1181 cumul->SetMax(
CapSub(cumul_next->Max(), transit));
1187bool IndexEvaluator2PathCumul::AcceptLink(
int i,
int j)
const {
1188 const IntVar*
const cumul_i =
cumuls_[
i];
1189 const IntVar*
const cumul_j =
cumuls_[j];
1190 const int64_t transit = transits_evaluator_(i, j);
1191 return transit <=
CapSub(cumul_j->Max(), cumul_i->Min()) &&
1192 CapSub(cumul_j->Min(), cumul_i->Max()) <= transit;
1197class IndexEvaluator2SlackPathCumul :
public BasePathCumul {
1199 IndexEvaluator2SlackPathCumul(Solver* s,
const std::vector<IntVar*>& nexts,
1200 const std::vector<IntVar*>& active,
1201 const std::vector<IntVar*>& cumuls,
1202 const std::vector<IntVar*>& slacks,
1203 Solver::IndexEvaluator2 transit_evaluator);
1204 ~IndexEvaluator2SlackPathCumul()
override {}
1205 void Post()
override;
1206 void NextBound(
int index)
override;
1207 bool AcceptLink(
int i,
int j)
const override;
1208 void SlackRange(
int index);
1210 void Accept(ModelVisitor*
const visitor)
const override {
1211 visitor->BeginVisitConstraint(ModelVisitor::kPathCumul,
this);
1212 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kNextsArgument,
1214 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kActiveArgument,
1216 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kCumulsArgument,
1222 visitor->EndVisitConstraint(ModelVisitor::kPathCumul,
this);
1226 const std::vector<IntVar*> slacks_;
1227 Solver::IndexEvaluator2 transits_evaluator_;
1230IndexEvaluator2SlackPathCumul::IndexEvaluator2SlackPathCumul(
1231 Solver*
const s,
const std::vector<IntVar*>& nexts,
1232 const std::vector<IntVar*>& active,
const std::vector<IntVar*>& cumuls,
1233 const std::vector<IntVar*>& slacks,
1234 Solver::IndexEvaluator2 transit_evaluator)
1235 : BasePathCumul(s, nexts, active, cumuls),
1237 transits_evaluator_(
std::move(transit_evaluator)) {}
1239void IndexEvaluator2SlackPathCumul::Post() {
1240 BasePathCumul::Post();
1241 for (
int i = 0;
i <
size(); ++
i) {
1243 solver(),
this, &IndexEvaluator2SlackPathCumul::SlackRange,
1245 slacks_[
i]->WhenRange(slack_demon);
1249void IndexEvaluator2SlackPathCumul::SlackRange(
int index) {
1250 if (nexts_[
index]->Bound()) {
1253 UpdateSupport(
index);
1258 for (
int i = 0;
i <
size(); ++
i) {
1266void IndexEvaluator2SlackPathCumul::NextBound(
int index) {
1267 if (active_[
index]->Min() == 0)
return;
1268 const int64_t
next = nexts_[
index]->Value();
1271 IntVar*
const slack = slacks_[
index];
1272 const int64_t transit = transits_evaluator_(
index,
next);
1273 const int64_t cumul_next_minus_transit_min =
1274 CapSub(cumul_next->Min(), transit);
1275 const int64_t cumul_next_minus_transit_max =
1276 CapSub(cumul_next->Max(), transit);
1277 cumul_next->SetMin(
CapAdd(
CapAdd(cumul->Min(), transit), slack->Min()));
1278 cumul_next->SetMax(
CapAdd(
CapAdd(cumul->Max(), transit), slack->Max()));
1279 cumul->SetMin(
CapSub(cumul_next_minus_transit_min, slack->Max()));
1280 cumul->SetMax(
CapSub(cumul_next_minus_transit_max, slack->Min()));
1281 slack->SetMin(
CapSub(cumul_next_minus_transit_min, cumul->Max()));
1282 slack->SetMax(
CapSub(cumul_next_minus_transit_max, cumul->Min()));
1288bool IndexEvaluator2SlackPathCumul::AcceptLink(
int i,
int j)
const {
1289 const IntVar*
const cumul_i =
cumuls_[
i];
1290 const IntVar*
const cumul_j =
cumuls_[j];
1291 const IntVar*
const slack = slacks_[
i];
1292 const int64_t transit = transits_evaluator_(i, j);
1293 return CapAdd(transit, slack->Min()) <=
1294 CapSub(cumul_j->Max(), cumul_i->Min()) &&
1295 CapSub(cumul_j->Min(), cumul_i->Max()) <=
1296 CapAdd(slack->Max(), transit);
1300Constraint* Solver::MakePathCumul(
const std::vector<IntVar*>& nexts,
1301 const std::vector<IntVar*>& active,
1302 const std::vector<IntVar*>& cumuls,
1303 const std::vector<IntVar*>& transits) {
1304 CHECK_EQ(nexts.size(), active.size());
1305 CHECK_EQ(transits.size(), nexts.size());
1306 return RevAlloc(
new PathCumul(
this, nexts, active, cumuls, transits));
1309Constraint* Solver::MakePathCumul(
const std::vector<IntVar*>& nexts,
1310 const std::vector<IntVar*>& active,
1311 const std::vector<IntVar*>& cumuls,
1313 CHECK_EQ(nexts.size(), active.size());
1314 return RevAlloc(
new IndexEvaluator2PathCumul(
this, nexts, active, cumuls,
1315 std::move(transit_evaluator)));
1318Constraint* Solver::MakePathCumul(
const std::vector<IntVar*>& nexts,
1319 const std::vector<IntVar*>& active,
1320 const std::vector<IntVar*>& cumuls,
1321 const std::vector<IntVar*>& slacks,
1323 CHECK_EQ(nexts.size(), active.size());
1324 return RevAlloc(
new IndexEvaluator2SlackPathCumul(
1325 this, nexts, active, cumuls, slacks, std::move(transit_evaluator)));
1328Constraint* Solver::MakeDelayedPathCumul(
const std::vector<IntVar*>& nexts,
1329 const std::vector<IntVar*>& active,
1330 const std::vector<IntVar*>& cumuls,
1331 const std::vector<IntVar*>& transits) {
1332 CHECK_EQ(nexts.size(), active.size());
1333 CHECK_EQ(transits.size(), nexts.size());
1334 return RevAlloc(
new DelayedPathCumul(
this, nexts, active, cumuls, transits));
1340class PathConnectedConstraint :
public Constraint {
1342 PathConnectedConstraint(
Solver* solver, std::vector<IntVar*> nexts,
1343 absl::Span<const int64_t> sources,
1344 std::vector<int64_t> sinks,
1345 std::vector<IntVar*>
status)
1347 sources_(sources.
size(), -1),
1348 index_to_path_(nexts.
size(), -1),
1349 sinks_(
std::move(sinks)),
1350 nexts_(
std::move(nexts)),
1352 touched_(nexts_.
size()) {
1353 CHECK_EQ(status_.size(), sources_.size());
1354 CHECK_EQ(status_.size(), sinks_.size());
1355 for (
int i = 0; i < status_.size(); ++i) {
1356 const int64_t source = sources[i];
1357 sources_.SetValue(solver, i, source);
1358 if (source < index_to_path_.size()) {
1359 index_to_path_.SetValue(solver, source, i);
1363 void Post()
override {
1364 for (
int i = 0;
i < nexts_.size(); ++
i) {
1366 solver(),
this, &PathConnectedConstraint::NextBound,
"NextValue", i));
1368 for (
int i = 0;
i < status_.size(); ++
i) {
1369 if (sources_[i] < nexts_.size()) {
1370 status_[
i]->SetRange(0, 1);
1372 status_[
i]->SetValue(0);
1376 void InitialPropagate()
override {
1377 for (
int i = 0;
i < status_.size(); ++
i) {
1381 std::string DebugString()
const override {
1382 std::string output =
"PathConnected(";
1383 std::vector<std::string> elements;
1384 for (IntVar*
const next : nexts_) {
1385 elements.push_back(
next->DebugString());
1387 for (
int i = 0;
i < sources_.size(); ++
i) {
1388 elements.push_back(absl::StrCat(sources_[i]));
1390 for (int64_t sink : sinks_) {
1391 elements.push_back(absl::StrCat(sink));
1393 for (IntVar*
const status : status_) {
1394 elements.push_back(
status->DebugString());
1396 output += absl::StrJoin(elements,
",") +
")";
1401 void NextBound(
int index) {
1402 const int path = index_to_path_[
index];
1407 void EvaluatePath(
int path) {
1408 touched_.SparseClearAll();
1409 int64_t source = sources_[path];
1410 const int64_t
end = sinks_[path];
1411 while (source !=
end) {
1412 if (source >= nexts_.size() || touched_[source]) {
1413 status_[path]->SetValue(0);
1416 touched_.Set(source);
1417 IntVar*
const next = nexts_[source];
1418 if (
next->Bound()) {
1419 source =
next->Min();
1421 sources_.SetValue(solver(), path, source);
1422 index_to_path_.SetValue(solver(), source, path);
1426 status_[path]->SetValue(1);
1429 RevArray<int64_t> sources_;
1430 RevArray<int> index_to_path_;
1431 const std::vector<int64_t> sinks_;
1432 const std::vector<IntVar*> nexts_;
1433 const std::vector<IntVar*> status_;
1434 SparseBitset<int64_t> touched_;
1439 std::vector<int64_t> sources,
1440 std::vector<int64_t> sinks,
1441 std::vector<IntVar*>
status) {
1442 return RevAlloc(
new PathConnectedConstraint(
1443 this, std::move(nexts), sources, std::move(sinks), std::move(
status)));
1447class PathTransitPrecedenceConstraint :
public Constraint {
1449 enum PrecedenceType {
1454 PathTransitPrecedenceConstraint(
1455 Solver* solver, std::vector<IntVar*> nexts, std::vector<IntVar*> transits,
1456 absl::Span<
const std::pair<int, int>> precedences,
1457 absl::flat_hash_map<int, PrecedenceType> precedence_types)
1458 : Constraint(solver),
1459 nexts_(
std::move(nexts)),
1460 transits_(
std::move(transits)),
1461 predecessors_(nexts_.
size()),
1462 successors_(nexts_.
size()),
1463 precedence_types_(
std::move(precedence_types)),
1464 starts_(nexts_.
size(), -1),
1465 ends_(nexts_.
size(), -1),
1466 transit_cumuls_(nexts_.
size(), 0) {
1467 for (
int i = 0; i < nexts_.size(); ++i) {
1468 starts_.SetValue(solver, i, i);
1469 ends_.SetValue(solver, i, i);
1471 for (
const auto& precedence : precedences) {
1472 if (precedence.second < nexts_.size()) {
1473 predecessors_[precedence.second].push_back(precedence.first);
1475 if (precedence.first < nexts_.size()) {
1476 successors_[precedence.first].push_back(precedence.second);
1480 ~PathTransitPrecedenceConstraint()
override {}
1481 void Post()
override {
1482 for (
int i = 0;
i < nexts_.size(); ++
i) {
1484 solver(),
this, &PathTransitPrecedenceConstraint::NextBound,
1487 for (
int i = 0;
i < transits_.size(); ++
i) {
1489 solver(),
this, &PathTransitPrecedenceConstraint::NextBound,
1490 "TransitRange", i));
1493 void InitialPropagate()
override {
1494 for (
int i = 0;
i < nexts_.size(); ++
i) {
1495 if (nexts_[i]->Bound()) {
1500 std::string DebugString()
const override {
1501 std::string output =
"PathPrecedence(";
1503 if (!transits_.empty()) {
1506 for (
int i = 0;
i < predecessors_.size(); ++
i) {
1507 for (
const int predecessor : predecessors_[i]) {
1508 elements.push_back(absl::StrCat(
"(", predecessor,
", ", i,
")"));
1511 output += absl::StrJoin(elements,
",") +
")";
1514 void Accept(ModelVisitor*
const visitor)
const override {
1519 void NextBound(
int index) {
1520 if (!nexts_[
index]->Bound())
return;
1524 if (
end < nexts_.size()) starts_.SetValue(solver(),
end,
start);
1525 ends_.SetValue(solver(),
start,
end);
1526 int current =
start;
1527 PrecedenceType type = ANY;
1528 auto it = precedence_types_.find(
start);
1529 if (it != precedence_types_.end()) {
1535 int64_t transit_cumul = 0;
1536 const bool has_transits = !transits_.empty();
1537 while (current < nexts_.size() && current !=
end) {
1538 transit_cumuls_[current] = transit_cumul;
1539 marked_.insert(current);
1541 if (!predecessors_[current].empty() && !pushed_.empty()) {
1544 for (
const int predecessor : predecessors_[current]) {
1545 if (pushed_.back() == predecessor) {
1550 if (!found) solver()->Fail();
1553 if (forbidden_.find(current) != forbidden_.end()) {
1554 for (
const int successor : successors_[current]) {
1555 if (marked_.find(successor) != marked_.end()) {
1556 if (!has_transits ||
1557 CapSub(transit_cumul, transit_cumuls_[successor]) > 0) {
1563 if (!successors_[current].empty()) {
1566 pushed_.push_back(current);
1569 pushed_.push_front(current);
1575 for (
const int predecessor : predecessors_[current]) {
1576 forbidden_.insert(predecessor);
1579 transit_cumul =
CapAdd(transit_cumul, transits_[current]->Min());
1581 current = nexts_[current]->Min();
1583 if (forbidden_.find(current) != forbidden_.end()) {
1584 for (
const int successor : successors_[current]) {
1585 if (marked_.find(successor) != marked_.end()) {
1586 if (!has_transits ||
1587 CapSub(transit_cumul, transit_cumuls_[successor]) > 0) {
1595 const std::vector<IntVar*> nexts_;
1596 const std::vector<IntVar*> transits_;
1597 std::vector<std::vector<int>> predecessors_;
1598 std::vector<std::vector<int>> successors_;
1599 const absl::flat_hash_map<int, PrecedenceType> precedence_types_;
1600 RevArray<int> starts_;
1601 RevArray<int> ends_;
1602 absl::flat_hash_set<int> forbidden_;
1603 absl::flat_hash_set<int> marked_;
1604 std::deque<int> pushed_;
1605 std::vector<int64_t> transit_cumuls_;
1608Constraint* MakePathTransitTypedPrecedenceConstraint(
1609 Solver* solver, std::vector<IntVar*> nexts, std::vector<IntVar*> transits,
1610 absl::Span<
const std::pair<int, int>> precedences,
1611 absl::flat_hash_map<int, PathTransitPrecedenceConstraint::PrecedenceType>
1613 if (precedences.empty()) {
1614 return solver->MakeTrueConstraint();
1616 return solver->RevAlloc(
new PathTransitPrecedenceConstraint(
1617 solver, std::move(nexts), std::move(transits), precedences,
1618 std::move(precedence_types)));
1624 std::vector<IntVar*> nexts,
1625 const std::vector<std::pair<int, int>>& precedences) {
1626 return MakePathTransitPrecedenceConstraint(std::move(nexts), {}, precedences);
1630 std::vector<IntVar*> nexts,
1631 const std::vector<std::pair<int, int>>& precedences,
1632 absl::Span<const int> lifo_path_starts,
1633 absl::Span<const int> fifo_path_starts) {
1634 absl::flat_hash_map<int, PathTransitPrecedenceConstraint::PrecedenceType>
1636 for (
int start : lifo_path_starts) {
1637 precedence_types[
start] = PathTransitPrecedenceConstraint::LIFO;
1639 for (
int start : fifo_path_starts) {
1640 precedence_types[
start] = PathTransitPrecedenceConstraint::FIFO;
1642 return MakePathTransitTypedPrecedenceConstraint(
1643 this, std::move(nexts), {}, precedences, std::move(precedence_types));
1647 std::vector<IntVar*> nexts, std::vector<IntVar*> transits,
1648 const std::vector<std::pair<int, int>>& precedences) {
1649 return MakePathTransitTypedPrecedenceConstraint(
1650 this, std::move(nexts), std::move(transits), precedences, {{}});
1655class PathEnergyCostConstraint :
public Constraint {
1657 PathEnergyCostConstraint(
1660 :
Constraint(solver), specification_(
std::move(specification)) {
1661 const int num_nexts = specification_.nexts.size();
1662 DCHECK_EQ(num_nexts, specification_.distances.size());
1664 const int num_paths = specification_.path_unit_costs.size();
1665 DCHECK_EQ(num_paths, specification_.costs.size());
1666 DCHECK_EQ(num_paths, specification_.path_used_when_empty.size());
1667 DCHECK_EQ(num_paths, specification_.path_starts.size());
1668 DCHECK_EQ(num_paths, specification_.path_ends.size());
1670 const int num_nodes = specification_.forces.size();
1671 DCHECK_EQ(num_nodes, specification_.paths.size());
1674 void Post()
override;
1675 void InitialPropagate()
override;
1678 void NodeDispatcher(
int node);
1679 void PropagatePath(
int path);
1680 Solver::PathEnergyCostConstraintSpecification specification_;
1681 std::vector<Demon*> path_demons_;
1686void PathEnergyCostConstraint::Post() {
1688 path_demons_.resize(specification_.path_unit_costs.size(),
nullptr);
1689 for (
int path = 0; path < specification_.path_unit_costs.size(); ++path) {
1692 if (specification_.path_unit_costs[path] == 0)
continue;
1694 solver(),
this, &PathEnergyCostConstraint::PropagatePath,
1695 "PropagatePath", path);
1698 const int num_nodes = specification_.forces.size();
1699 const int num_nexts = specification_.nexts.size();
1700 for (
int node = 0; node < num_nodes; ++node) {
1702 solver(),
this, &PathEnergyCostConstraint::NodeDispatcher,
1703 "NodeDispatcher", node);
1704 specification_.forces[node]->WhenRange(demon);
1705 specification_.paths[node]->WhenBound(demon);
1706 if (node < num_nexts) {
1707 specification_.nexts[node]->WhenBound(demon);
1708 specification_.distances[node]->WhenRange(demon);
1713void PathEnergyCostConstraint::InitialPropagate() {
1714 const int num_paths = specification_.path_unit_costs.size();
1715 for (
int path = 0; path < num_paths; ++path) {
1716 if (specification_.path_unit_costs[path] == 0) {
1717 specification_.costs[path]->SetValue(0);
1719 PropagatePath(path);
1725void PathEnergyCostConstraint::NodeDispatcher(
int node) {
1726 if (!specification_.paths[node]->Bound())
return;
1727 const int path = specification_.paths[node]->Min();
1728 if (path < 0)
return;
1729 if (path_demons_[path] ==
nullptr)
return;
1730 EnqueueDelayedDemon(path_demons_[path]);
1734void PathEnergyCostConstraint::PropagatePath(
int path) {
1736 int64_t energy_min = 0;
1737 int64_t energy_max = 0;
1738 int current = specification_.path_starts[path];
1739 const int num_nodes = specification_.nexts.size();
1740 int num_nonend_nodes = 0;
1741 while (current < num_nodes) {
1743 if (!specification_.nexts[current]->Bound())
break;
1744 const int next = specification_.nexts[current]->Min();
1746 const int64_t distance_min = specification_.distances[current]->Min();
1747 const int64_t distance_max = specification_.distances[current]->Max();
1748 DCHECK_GE(distance_min, 0);
1750 energy_min,
CapProd(specification_.forces[
next]->Min(), distance_min));
1752 energy_max,
CapProd(specification_.forces[
next]->Max(), distance_max));
1758 if (current == specification_.path_ends[path]) {
1759 if (num_nonend_nodes == 1 && !specification_.path_used_when_empty[path]) {
1760 specification_.costs[path]->SetValue(0);
1762 specification_.costs[path]->SetRange(
1763 CapProd(energy_min, specification_.path_unit_costs[path]),
1764 CapProd(energy_max, specification_.path_unit_costs[path]));
1773 return RevAlloc(
new PathEnergyCostConstraint(
this, std::move(specification)));
static const char kNoCycle[]
static const char kActiveArgument[]
argument names:
static const char kNextsArgument[]
For the time being, Solver is neither MT_SAFE nor MT_HOT.
std::function< bool(int64_t)> IndexFilter1
std::function< int64_t(int64_t, int64_t)> IndexEvaluator2
const std::vector< IntVar * > cumuls_
std::vector< int > supports_
std::vector< typename Map::mapped_type > Values(const Map &map, const Keys &keys)
For infeasible and unbounded see Not checked if options check_solutions_if_inf_or_unbounded and the If options first_solution_only is false
problem is infeasible or unbounded (default).
In SWIG mode, we don't want anything besides these top-level includes.
int64_t CapAdd(int64_t x, int64_t y)
std::string JoinDebugStringPtr(const std::vector< T > &v, absl::string_view separator)
Join v[i]->DebugString().
int64_t CapSub(int64_t x, int64_t y)
Demon * MakeDelayedConstraintDemon0(Solver *const s, T *const ct, void(T::*method)(), const std::string &name)
int64_t CapProd(int64_t x, int64_t y)
Demon * MakeDelayedConstraintDemon1(Solver *const s, T *const ct, void(T::*method)(P), const std::string &name, P param1)
Demon * MakeConstraintDemon1(Solver *const s, T *const ct, void(T::*method)(P), const std::string &name, P param1)
std::optional< int64_t > end