29 #include "absl/container/flat_hash_map.h"
30 #include "absl/strings/str_cat.h"
31 #include "absl/strings/str_format.h"
32 #include "absl/strings/str_join.h"
54 bool StartMinLessThan(Task*
const w1, Task*
const w2) {
55 return (w1->interval->StartMin() < w2->interval->StartMin());
62 bool ShortestDurationStartMinLessThan(Task*
const w1, Task*
const w2) {
63 return w1->interval->EndMin() - w1->interval->DurationMin() <
64 w2->interval->EndMin() - w2->interval->DurationMin();
68 bool StartMaxLessThan(Task*
const w1, Task*
const w2) {
69 return (w1->interval->StartMax() < w2->interval->StartMax());
73 bool EndMinLessThan(Task*
const w1, Task*
const w2) {
74 return (w1->interval->EndMin() < w2->interval->EndMin());
78 bool EndMaxLessThan(Task*
const w1, Task*
const w2) {
79 return (w1->interval->EndMax() < w2->interval->EndMax());
82 bool IntervalStartMinLessThan(IntervalVar* i1, IntervalVar* i2) {
83 return i1->StartMin() < i2->StartMin();
92 struct DisjunctiveTask {
93 explicit DisjunctiveTask(IntervalVar*
const interval_)
96 std::string DebugString()
const {
return interval->DebugString(); }
107 struct CumulativeTask {
108 CumulativeTask(IntervalVar*
const interval_,
int64 demand_)
115 void WhenAnything(Demon*
const demon) {
interval->WhenAnything(demon); }
117 std::string DebugString()
const {
118 return absl::StrFormat(
"Task{ %s, demand: %d }",
interval->DebugString(),
133 struct VariableCumulativeTask {
134 VariableCumulativeTask(IntervalVar*
const interval_, IntVar* demand_)
141 void WhenAnything(Demon*
const demon) {
146 std::string DebugString()
const {
147 return absl::StrFormat(
"Task{ %s, demand: %s }",
interval->DebugString(),
167 explicit ThetaNode(
const IntervalVar*
const interval)
180 void Compute(
const ThetaNode& left,
const ThetaNode& right) {
186 bool IsIdentity()
const {
190 std::string DebugString()
const {
206 class ThetaTree :
public MonoidOperationTree<ThetaNode> {
208 explicit ThetaTree(
int size) : MonoidOperationTree<ThetaNode>(size) {}
210 int64 Ect()
const {
return result().total_ect; }
212 void Insert(
const DisjunctiveTask*
const task) {
213 Set(task->index, ThetaNode(task->interval));
216 void Remove(
const DisjunctiveTask*
const task) { Reset(task->index); }
218 bool IsInserted(
const DisjunctiveTask*
const task)
const {
219 return !GetOperand(task->index).IsIdentity();
229 struct LambdaThetaNode {
244 :
energy(task.EnergyMin()),
264 LambdaThetaNode(
int64 capacity,
const VariableCumulativeTask& task)
265 :
energy(task.EnergyMin()),
285 explicit LambdaThetaNode(
const IntervalVar*
const interval)
295 LambdaThetaNode(
const IntervalVar*
const interval,
int index)
312 void Compute(
const LambdaThetaNode& left,
const LambdaThetaNode& right) {
315 CapAdd(left.energetic_end_min, right.energy));
316 const int64 energy_left_opt =
CapAdd(left.energy_opt, right.energy);
317 const int64 energy_right_opt =
CapAdd(left.energy, right.energy_opt);
318 if (energy_left_opt > energy_right_opt) {
325 const int64 ect1 = right.energetic_end_min_opt;
326 const int64 ect2 =
CapAdd(left.energetic_end_min, right.energy_opt);
327 const int64 ect3 =
CapAdd(left.energetic_end_min_opt, right.energy);
328 if (ect1 >= ect2 && ect1 >= ect3) {
331 }
else if (ect2 >= ect1 && ect2 >= ect3) {
373 class DisjunctiveLambdaThetaTree :
public MonoidOperationTree<LambdaThetaNode> {
375 explicit DisjunctiveLambdaThetaTree(
int size)
376 : MonoidOperationTree<LambdaThetaNode>(size) {}
378 void Insert(
const DisjunctiveTask& task) {
379 Set(task.index, LambdaThetaNode(task.interval));
382 void Grey(
const DisjunctiveTask& task) {
383 const int index = task.index;
384 Set(
index, LambdaThetaNode(task.interval,
index));
387 int64 Ect()
const {
return result().energetic_end_min; }
388 int64 EctOpt()
const {
return result().energetic_end_min_opt; }
389 int ResponsibleOpt()
const {
return result().argmax_energetic_end_min_opt; }
393 class CumulativeLambdaThetaTree :
public MonoidOperationTree<LambdaThetaNode> {
395 CumulativeLambdaThetaTree(
int size,
int64 capacity_max)
396 : MonoidOperationTree<LambdaThetaNode>(size),
397 capacity_max_(capacity_max) {}
399 void Init(
int64 capacity_max) {
401 capacity_max_ = capacity_max;
404 void Insert(
const CumulativeTask& task) {
405 Set(task.index, LambdaThetaNode(capacity_max_, task));
408 void Grey(
const CumulativeTask& task) {
409 const int index = task.index;
410 Set(
index, LambdaThetaNode(capacity_max_, task,
index));
413 void Insert(
const VariableCumulativeTask& task) {
414 Set(task.index, LambdaThetaNode(capacity_max_, task));
417 void Grey(
const VariableCumulativeTask& task) {
418 const int index = task.index;
419 Set(
index, LambdaThetaNode(capacity_max_, task,
index));
427 int64 EctOpt()
const {
431 return result().argmax_energetic_end_min_opt;
444 NotLast(Solver*
const solver,
const std::vector<IntervalVar*>& intervals,
445 bool mirror,
bool strict);
452 ThetaTree theta_tree_;
453 std::vector<DisjunctiveTask*> by_start_min_;
454 std::vector<DisjunctiveTask*> by_end_max_;
455 std::vector<DisjunctiveTask*> by_start_max_;
456 std::vector<int64> new_lct_;
460 NotLast::NotLast(Solver*
const solver,
461 const std::vector<IntervalVar*>& intervals,
bool mirror,
463 : theta_tree_(intervals.size()),
464 by_start_min_(intervals.size()),
465 by_end_max_(intervals.size()),
466 by_start_max_(intervals.size()),
467 new_lct_(intervals.size(), -1LL),
470 for (
int i = 0; i < intervals.size(); ++i) {
471 IntervalVar*
const underlying =
472 mirror ? solver->MakeMirrorInterval(intervals[i]) : intervals[i];
473 IntervalVar*
const relaxed = solver->MakeIntervalRelaxedMin(underlying);
474 by_start_min_[i] =
new DisjunctiveTask(relaxed);
475 by_end_max_[i] = by_start_min_[i];
476 by_start_max_[i] = by_start_min_[i];
480 bool NotLast::Propagate() {
482 std::sort(by_start_max_.begin(), by_start_max_.end(),
483 StartMaxLessThan<DisjunctiveTask>);
484 std::sort(by_end_max_.begin(), by_end_max_.end(),
485 EndMaxLessThan<DisjunctiveTask>);
487 std::sort(by_start_min_.begin(), by_start_min_.end(),
488 StartMinLessThan<DisjunctiveTask>);
489 for (
int i = 0; i < by_start_min_.size(); ++i) {
490 by_start_min_[i]->index = i;
493 for (
int i = 0; i < by_start_min_.size(); ++i) {
494 new_lct_[i] = by_start_min_[i]->interval->EndMax();
499 for (DisjunctiveTask*
const twi : by_end_max_) {
500 while (j < by_start_max_.size() &&
501 twi->interval->EndMax() > by_start_max_[j]->interval->StartMax()) {
502 if (j > 0 && theta_tree_.Ect() > by_start_max_[j]->interval->StartMax()) {
503 const int64 new_end_max = by_start_max_[j - 1]->interval->StartMax();
504 new_lct_[by_start_max_[j]->index] = new_end_max;
506 theta_tree_.Insert(by_start_max_[j]);
509 const bool inserted = theta_tree_.IsInserted(twi);
511 theta_tree_.Remove(twi);
513 const int64 ect_theta_less_i = theta_tree_.Ect();
515 theta_tree_.Insert(twi);
517 if (ect_theta_less_i > twi->interval->EndMax() && j > 0) {
518 const int64 new_end_max = by_start_max_[j - 1]->interval->EndMax();
519 if (new_end_max > new_lct_[twi->index]) {
520 new_lct_[twi->index] = new_end_max;
526 bool modified =
false;
527 for (
int i = 0; i < by_start_min_.size(); ++i) {
528 IntervalVar*
const var = by_start_min_[i]->interval;
529 if ((strict_ ||
var->DurationMin() > 0) &&
var->EndMax() > new_lct_[i]) {
531 var->SetEndMax(new_lct_[i]);
542 class EdgeFinderAndDetectablePrecedences {
544 EdgeFinderAndDetectablePrecedences(Solver*
const solver,
545 const std::vector<IntervalVar*>& intervals,
546 bool mirror,
bool strict);
547 ~EdgeFinderAndDetectablePrecedences() {
550 int64 size()
const {
return by_start_min_.size(); }
553 void OverloadChecking();
554 bool DetectablePrecedences();
558 Solver*
const solver_;
569 ThetaTree theta_tree_;
570 std::vector<DisjunctiveTask*> by_end_min_;
571 std::vector<DisjunctiveTask*> by_start_min_;
572 std::vector<DisjunctiveTask*> by_end_max_;
573 std::vector<DisjunctiveTask*> by_start_max_;
575 std::vector<int64> new_est_;
577 std::vector<int64> new_lct_;
578 DisjunctiveLambdaThetaTree lt_tree_;
582 EdgeFinderAndDetectablePrecedences::EdgeFinderAndDetectablePrecedences(
583 Solver*
const solver,
const std::vector<IntervalVar*>& intervals,
584 bool mirror,
bool strict)
586 theta_tree_(intervals.size()),
587 lt_tree_(intervals.size()),
590 for (IntervalVar*
const interval : intervals) {
591 IntervalVar*
const underlying =
593 IntervalVar*
const relaxed = solver->MakeIntervalRelaxedMax(underlying);
594 DisjunctiveTask*
const task =
new DisjunctiveTask(relaxed);
595 by_end_min_.push_back(task);
596 by_start_min_.push_back(task);
597 by_end_max_.push_back(task);
598 by_start_max_.push_back(task);
603 void EdgeFinderAndDetectablePrecedences::UpdateEst() {
604 std::sort(by_start_min_.begin(), by_start_min_.end(),
605 ShortestDurationStartMinLessThan<DisjunctiveTask>);
606 for (
int i = 0; i < size(); ++i) {
607 by_start_min_[i]->index = i;
611 void EdgeFinderAndDetectablePrecedences::OverloadChecking() {
614 std::sort(by_end_max_.begin(), by_end_max_.end(),
615 EndMaxLessThan<DisjunctiveTask>);
618 for (DisjunctiveTask*
const task : by_end_max_) {
619 theta_tree_.Insert(task);
620 if (theta_tree_.Ect() > task->interval->EndMax()) {
626 bool EdgeFinderAndDetectablePrecedences::DetectablePrecedences() {
632 std::sort(by_end_min_.begin(), by_end_min_.end(),
633 EndMinLessThan<DisjunctiveTask>);
634 std::sort(by_start_max_.begin(), by_start_max_.end(),
635 StartMaxLessThan<DisjunctiveTask>);
638 for (DisjunctiveTask*
const task_i : by_end_min_) {
640 DisjunctiveTask* task_j = by_start_max_[j];
641 while (task_i->interval->EndMin() > task_j->interval->StartMax()) {
642 theta_tree_.Insert(task_j);
644 if (j == size())
break;
645 task_j = by_start_max_[j];
648 const int64 esti = task_i->interval->StartMin();
649 bool inserted = theta_tree_.IsInserted(task_i);
651 theta_tree_.Remove(task_i);
653 const int64 oesti = theta_tree_.Ect();
655 theta_tree_.Insert(task_i);
658 new_est_[task_i->index] = oesti;
665 bool modified =
false;
666 for (
int i = 0; i < size(); ++i) {
667 IntervalVar*
const var = by_start_min_[i]->interval;
668 if (new_est_[i] !=
kint64min && (strict_ ||
var->DurationMin() > 0)) {
670 by_start_min_[i]->interval->SetStartMin(new_est_[i]);
676 bool EdgeFinderAndDetectablePrecedences::EdgeFinder() {
679 for (
int i = 0; i < size(); ++i) {
680 new_est_[i] = by_start_min_[i]->interval->StartMin();
684 std::sort(by_end_max_.begin(), by_end_max_.end(),
685 EndMaxLessThan<DisjunctiveTask>);
687 for (
int i = 0; i < size(); ++i) {
688 lt_tree_.Insert(*by_start_min_[i]);
691 for (
int j = size() - 2; j >= 0; --j) {
692 lt_tree_.Grey(*by_end_max_[j + 1]);
693 DisjunctiveTask*
const twj = by_end_max_[j];
695 DCHECK_LE(lt_tree_.Ect(), twj->interval->EndMax());
696 while (lt_tree_.EctOpt() > twj->interval->EndMax()) {
697 const int i = lt_tree_.ResponsibleOpt();
699 if (lt_tree_.Ect() > new_est_[i]) {
700 new_est_[i] = lt_tree_.Ect();
707 bool modified =
false;
708 for (
int i = 0; i < size(); ++i) {
709 IntervalVar*
const var = by_start_min_[i]->interval;
710 if (
var->StartMin() < new_est_[i] && (strict_ ||
var->DurationMin() > 0)) {
712 var->SetStartMin(new_est_[i]);
722 class RankedPropagator :
public Constraint {
724 RankedPropagator(Solver*
const solver,
const std::vector<IntVar*>& nexts,
725 const std::vector<IntervalVar*>& intervals,
726 const std::vector<IntVar*>& slacks,
727 DisjunctiveConstraint*
const disjunctive)
728 : Constraint(solver),
730 intervals_(intervals),
732 disjunctive_(disjunctive),
733 partial_sequence_(intervals.size()),
734 previous_(intervals.size() + 2, 0) {}
736 ~RankedPropagator()
override {}
738 void Post()
override {
739 Demon*
const delayed =
740 solver()->MakeDelayedConstraintInitialPropagateCallback(
this);
741 for (
int i = 0; i < intervals_.size(); ++i) {
742 nexts_[i]->WhenBound(delayed);
743 intervals_[i]->WhenAnything(delayed);
744 slacks_[i]->WhenRange(delayed);
746 nexts_.back()->WhenBound(delayed);
749 void InitialPropagate()
override {
754 void PropagateNexts() {
755 Solver*
const s = solver();
756 const int ranked_first = partial_sequence_.NumFirstRanked();
757 const int ranked_last = partial_sequence_.NumLastRanked();
761 : partial_sequence_[intervals_.size() - ranked_last] + 1;
764 while (nexts_[first]->Bound()) {
766 first = nexts_[first]->Min();
767 if (first == sentinel) {
770 if (++counter > ranked_first) {
771 DCHECK(intervals_[first - 1]->MayBePerformed());
772 partial_sequence_.RankFirst(s, first - 1);
773 VLOG(2) <<
"RankFirst " << first - 1 <<
" -> "
774 << partial_sequence_.DebugString();
777 previous_.assign(previous_.size(), -1);
778 for (
int i = 0; i < nexts_.size(); ++i) {
779 if (nexts_[i]->Bound()) {
780 previous_[nexts_[i]->Min()] = i;
783 int last = previous_.size() - 1;
785 while (previous_[last] != -1) {
786 last = previous_[last];
787 if (++counter > ranked_last) {
788 partial_sequence_.RankLast(s, last - 1);
789 VLOG(2) <<
"RankLast " << last - 1 <<
" -> "
790 << partial_sequence_.DebugString();
795 void PropagateSequence() {
796 const int last_position = intervals_.size() - 1;
797 const int first_sentinel = partial_sequence_.NumFirstRanked();
798 const int last_sentinel = last_position - partial_sequence_.NumLastRanked();
800 for (
int i = 0; i < first_sentinel - 1; ++i) {
801 IntervalVar*
const interval = RankedInterval(i);
802 IntervalVar*
const next_interval = RankedInterval(i + 1);
803 IntVar*
const slack = RankedSlack(i);
804 const int64 transition_time = RankedTransitionTime(i, i + 1);
805 next_interval->SetStartRange(
810 for (
int i = last_position; i > last_sentinel + 1; --i) {
811 IntervalVar*
const interval = RankedInterval(i - 1);
812 IntervalVar*
const next_interval = RankedInterval(i);
813 IntVar*
const slack = RankedSlack(i - 1);
814 const int64 transition_time = RankedTransitionTime(i - 1, i);
816 CapAdd(slack->Max(), transition_time)),
817 CapSub(next_interval->StartMax(),
818 CapAdd(slack->Min(), transition_time)));
821 IntervalVar*
const first_interval =
822 first_sentinel > 0 ? RankedInterval(first_sentinel - 1) : nullptr;
823 IntVar*
const first_slack =
824 first_sentinel > 0 ? RankedSlack(first_sentinel - 1) : nullptr;
825 IntervalVar*
const last_interval = last_sentinel < last_position
826 ? RankedInterval(last_sentinel + 1)
830 if (first_interval ==
nullptr && last_interval ==
nullptr) {
835 for (
int i = first_sentinel; i <= last_sentinel; ++i) {
836 IntervalVar*
const interval = RankedInterval(i);
837 IntVar*
const slack = RankedSlack(i);
840 if (first_interval !=
nullptr) {
841 const int64 transition_time =
842 RankedTransitionTime(first_sentinel - 1, i);
844 CapAdd(first_interval->StartMin(),
845 CapAdd(first_slack->Min(), transition_time)),
846 CapAdd(first_interval->StartMax(),
847 CapAdd(first_slack->Max(), transition_time)));
849 first_interval->SetStartRange(
851 CapAdd(first_slack->Max(), transition_time)),
853 CapAdd(first_slack->Min(), transition_time)));
856 if (last_interval !=
nullptr) {
857 const int64 transition_time =
858 RankedTransitionTime(i, last_sentinel + 1);
860 CapSub(last_interval->StartMin(),
861 CapAdd(slack->Max(), transition_time)),
862 CapSub(last_interval->StartMax(),
863 CapAdd(slack->Min(), transition_time)));
865 last_interval->SetStartRange(
867 CapAdd(slack->Min(), transition_time)),
869 CapAdd(slack->Max(), transition_time)));
876 for (
int i =
std::min(first_sentinel - 2, last_position - 1); i >= 0; --i) {
877 IntervalVar*
const interval = RankedInterval(i);
878 IntervalVar*
const next_interval = RankedInterval(i + 1);
879 IntVar*
const slack = RankedSlack(i);
880 const int64 transition_time = RankedTransitionTime(i, i + 1);
882 CapAdd(slack->Max(), transition_time)),
883 CapSub(next_interval->StartMax(),
884 CapAdd(slack->Min(), transition_time)));
887 for (
int i = last_sentinel + 1; i < last_position - 1; ++i) {
888 IntervalVar*
const interval = RankedInterval(i);
889 IntervalVar*
const next_interval = RankedInterval(i + 1);
890 IntVar*
const slack = RankedSlack(i);
891 const int64 transition_time = RankedTransitionTime(i, i + 1);
892 next_interval->SetStartRange(
899 IntervalVar* RankedInterval(
int i)
const {
900 const int index = partial_sequence_[i];
901 return intervals_[
index];
904 IntVar* RankedSlack(
int i)
const {
905 const int index = partial_sequence_[i];
906 return slacks_[
index];
909 int64 RankedTransitionTime(
int before,
int after)
const {
910 const int before_index = partial_sequence_[before];
911 const int after_index = partial_sequence_[after];
913 return disjunctive_->TransitionTime(before_index, after_index);
916 std::string DebugString()
const override {
917 return absl::StrFormat(
918 "RankedPropagator([%s], nexts = [%s], intervals = [%s])",
923 void Accept(ModelVisitor*
const visitor)
const override {
924 LOG(
FATAL) <<
"Not yet implemented";
929 std::vector<IntVar*> nexts_;
930 std::vector<IntervalVar*> intervals_;
931 std::vector<IntVar*> slacks_;
932 DisjunctiveConstraint*
const disjunctive_;
933 RevPartialSequence partial_sequence_;
934 std::vector<int> previous_;
940 class FullDisjunctiveConstraint :
public DisjunctiveConstraint {
942 FullDisjunctiveConstraint(Solver*
const s,
943 const std::vector<IntervalVar*>& intervals,
944 const std::string&
name,
bool strict)
945 : DisjunctiveConstraint(s, intervals,
name),
946 sequence_var_(nullptr),
947 straight_(s, intervals, false, strict),
948 mirror_(s, intervals, true, strict),
949 straight_not_last_(s, intervals, false, strict),
950 mirror_not_last_(s, intervals, true, strict),
953 ~FullDisjunctiveConstraint()
override {}
955 void Post()
override {
957 solver(),
this, &FullDisjunctiveConstraint::InitialPropagate,
959 for (
int32 i = 0; i < straight_.size(); ++i) {
960 straight_.interval(i)->WhenAnything(d);
964 void InitialPropagate()
override {
965 bool all_optional_or_unperformed =
true;
966 for (
const IntervalVar*
const interval : intervals_) {
968 all_optional_or_unperformed =
false;
972 if (all_optional_or_unperformed) {
976 bool all_times_fixed =
true;
977 for (
const IntervalVar*
const interval : intervals_) {
982 all_times_fixed =
false;
987 if (all_times_fixed) {
988 PropagatePerformed();
995 straight_.OverloadChecking();
996 }
while (straight_.DetectablePrecedences() ||
997 mirror_.DetectablePrecedences());
998 }
while (straight_not_last_.Propagate() ||
999 mirror_not_last_.Propagate());
1000 }
while (straight_.EdgeFinder() || mirror_.EdgeFinder());
1004 bool Intersect(IntervalVar*
const i1, IntervalVar*
const i2)
const {
1005 return i1->StartMin() < i2->EndMax() && i2->StartMin() < i1->EndMax();
1008 void PropagatePerformed() {
1011 for (IntervalVar*
const interval : intervals_) {
1014 }
else if (
interval->MayBePerformed()) {
1019 if (performed_.empty())
return;
1020 std::sort(performed_.begin(), performed_.end(), IntervalStartMinLessThan);
1021 for (
int i = 0; i < performed_.size() - 1; ++i) {
1022 if (performed_[i]->EndMax() > performed_[i + 1]->StartMin()) {
1028 if (optional_.empty())
return;
1030 const int num_performed = performed_.size();
1031 std::sort(optional_.begin(), optional_.end(), IntervalStartMinLessThan);
1032 for (IntervalVar*
const candidate : optional_) {
1033 const int64 start = candidate->StartMin();
1034 while (index < num_performed && start >= performed_[
index]->EndMax()) {
1037 if (
index == num_performed)
return;
1038 if (Intersect(candidate, performed_[
index]) ||
1039 (
index < num_performed - 1 &&
1040 Intersect(candidate, performed_[
index + 1]))) {
1041 candidate->SetPerformed(
false);
1046 void Accept(ModelVisitor*
const visitor)
const override {
1047 visitor->BeginVisitConstraint(ModelVisitor::kDisjunctive,
this);
1048 visitor->VisitIntervalArrayArgument(ModelVisitor::kIntervalsArgument,
1050 if (sequence_var_ !=
nullptr) {
1051 visitor->VisitSequenceArgument(ModelVisitor::kSequenceArgument,
1054 visitor->EndVisitConstraint(ModelVisitor::kDisjunctive,
this);
1057 SequenceVar* MakeSequenceVar()
override {
1058 BuildNextModelIfNeeded();
1059 if (sequence_var_ ==
nullptr) {
1060 solver()->SaveValue(
reinterpret_cast<void**
>(&sequence_var_));
1061 sequence_var_ = solver()->RevAlloc(
1062 new SequenceVar(solver(), intervals_, nexts_,
name()));
1064 return sequence_var_;
1067 std::string DebugString()
const override {
1068 return absl::StrFormat(
"FullDisjunctiveConstraint([%s], %i)",
1072 const std::vector<IntVar*>& nexts()
const override {
return nexts_; }
1074 const std::vector<IntVar*>& actives()
const override {
return actives_; }
1076 const std::vector<IntVar*>& time_cumuls()
const override {
1077 return time_cumuls_;
1080 const std::vector<IntVar*>& time_slacks()
const override {
1081 return time_slacks_;
1085 int64 Distance(
int64 activity_plus_one,
int64 next_activity_plus_one) {
1086 return (activity_plus_one == 0 ||
1087 next_activity_plus_one > intervals_.size())
1089 : transition_time_(activity_plus_one - 1,
1090 next_activity_plus_one - 1);
1093 void BuildNextModelIfNeeded() {
1094 if (!nexts_.empty()) {
1097 Solver*
const s = solver();
1098 const std::string& ct_name =
name();
1099 const int num_intervals = intervals_.size();
1100 const int num_nodes = intervals_.size() + 1;
1102 for (
int i = 0; i < intervals_.size(); ++i) {
1103 if (intervals_[i]->MayBePerformed()) {
1104 horizon =
std::max(horizon, intervals_[i]->EndMax());
1109 s->MakeIntVarArray(num_nodes, 1, num_nodes, ct_name +
"_nexts", &nexts_);
1111 s->AddConstraint(s->MakeAllDifferent(nexts_));
1113 actives_.resize(num_nodes);
1114 for (
int i = 0; i < num_intervals; ++i) {
1115 actives_[i + 1] = intervals_[i]->PerformedExpr()->Var();
1117 s->MakeIsDifferentCstCt(nexts_[i + 1], i + 1, actives_[i + 1]));
1119 std::vector<IntVar*> short_actives(actives_.begin() + 1, actives_.end());
1120 actives_[0] = s->MakeMax(short_actives)->Var();
1123 s->AddConstraint(s->MakeNoCycle(nexts_, actives_));
1126 time_cumuls_.resize(num_nodes + 1);
1128 time_slacks_.resize(num_nodes);
1130 time_slacks_[0] = s->MakeIntVar(0, horizon,
"initial_slack");
1132 time_cumuls_[0] = s->MakeIntConst(0);
1134 for (
int64 i = 0; i < num_intervals; ++i) {
1135 IntervalVar*
const var = intervals_[i];
1136 if (
var->MayBePerformed()) {
1137 const int64 duration_min =
var->DurationMin();
1138 time_slacks_[i + 1] = s->MakeIntVar(
1139 duration_min, horizon, absl::StrFormat(
"time_slacks(%d)", i + 1));
1141 time_cumuls_[i + 1] =
var->SafeStartExpr(
var->StartMin())->Var();
1142 if (
var->DurationMax() != duration_min) {
1143 s->AddConstraint(s->MakeGreaterOrEqual(
1144 time_slacks_[i + 1],
var->SafeDurationExpr(duration_min)));
1147 time_slacks_[i + 1] = s->MakeIntVar(
1148 0, horizon, absl::StrFormat(
"time_slacks(%d)", i + 1));
1149 time_cumuls_[i + 1] = s->MakeIntConst(horizon);
1153 time_cumuls_[num_nodes] = s->MakeIntVar(0, 2 * horizon, ct_name +
"_ect");
1155 s->MakePathCumul(nexts_, actives_, time_cumuls_, time_slacks_,
1156 [
this](
int64 x,
int64 y) { return Distance(x, y); }));
1158 std::vector<IntVar*> short_slacks(time_slacks_.begin() + 1,
1159 time_slacks_.end());
1160 s->AddConstraint(s->RevAlloc(
1161 new RankedPropagator(s, nexts_, intervals_, short_slacks,
this)));
1164 SequenceVar* sequence_var_;
1165 EdgeFinderAndDetectablePrecedences straight_;
1166 EdgeFinderAndDetectablePrecedences mirror_;
1167 NotLast straight_not_last_;
1168 NotLast mirror_not_last_;
1169 std::vector<IntVar*> nexts_;
1170 std::vector<IntVar*> actives_;
1171 std::vector<IntVar*> time_cumuls_;
1172 std::vector<IntVar*> time_slacks_;
1173 std::vector<IntervalVar*> performed_;
1174 std::vector<IntervalVar*> optional_;
1185 struct DualCapacityThetaNode {
1187 static const int kNone;
1190 DualCapacityThetaNode()
1197 const CumulativeTask& task)
1198 :
energy(task.EnergyMin()),
1205 const VariableCumulativeTask& task)
1206 :
energy(task.EnergyMin()),
1217 void Compute(
const DualCapacityThetaNode& left,
1218 const DualCapacityThetaNode& right) {
1221 right.energetic_end_min);
1224 right.residual_energetic_end_min);
1241 class DualCapacityThetaTree
1242 :
public MonoidOperationTree<DualCapacityThetaNode> {
1246 explicit DualCapacityThetaTree(
int size)
1247 : MonoidOperationTree<DualCapacityThetaNode>(size),
1249 residual_capacity_(-1) {}
1251 virtual ~DualCapacityThetaTree() {}
1253 void Init(
int64 capacity_max,
int64 residual_capacity) {
1255 DCHECK_LE(residual_capacity, capacity_max);
1257 capacity_max_ = capacity_max;
1258 residual_capacity_ = residual_capacity;
1261 void Insert(
const CumulativeTask* task) {
1263 DualCapacityThetaNode(capacity_max_, residual_capacity_, *task));
1266 void Insert(
const VariableCumulativeTask* task) {
1268 DualCapacityThetaNode(capacity_max_, residual_capacity_, *task));
1272 int64 capacity_max_;
1273 int64 residual_capacity_;
1289 class EnvJCComputeDiver {
1292 explicit EnvJCComputeDiver(
int energy_threshold)
1293 : energy_threshold_(energy_threshold),
1296 void OnArgumentReached(
int index,
const DualCapacityThetaNode& argument) {
1297 energy_alpha_ = argument.energy;
1298 energetic_end_min_alpha_ = argument.energetic_end_min;
1303 bool ChooseGoLeft(
const DualCapacityThetaNode& current,
1304 const DualCapacityThetaNode& left_child,
1305 const DualCapacityThetaNode& right_child) {
1306 if (right_child.residual_energetic_end_min > energy_threshold_) {
1309 energy_threshold_ -= right_child.energy;
1313 void OnComeBackFromLeft(
const DualCapacityThetaNode& current,
1314 const DualCapacityThetaNode& left_child,
1315 const DualCapacityThetaNode& right_child) {
1321 void OnComeBackFromRight(
const DualCapacityThetaNode& current,
1322 const DualCapacityThetaNode& left_child,
1323 const DualCapacityThetaNode& right_child) {
1326 energetic_end_min_alpha_ =
1328 CapAdd(left_child.energetic_end_min, energy_alpha_));
1329 energy_alpha_ += left_child.energy;
1331 int64 GetEnvJC(
const DualCapacityThetaNode& root)
const {
1334 return CapAdd(energetic_end_min_alpha_, energy_beta);
1343 int64 energy_threshold_;
1349 int64 energy_alpha_;
1354 int64 energetic_end_min_alpha_;
1366 class UpdatesForADemand {
1368 explicit UpdatesForADemand(
int size)
1369 : updates_(size, 0), up_to_date_(false) {}
1372 void Reset() { up_to_date_ =
false; }
1376 updates_[
index] = update;
1378 bool up_to_date()
const {
return up_to_date_; }
1379 void set_up_to_date() { up_to_date_ =
true; }
1382 std::vector<int64> updates_;
1388 template <
class Task>
1389 class EdgeFinder :
public Constraint {
1391 EdgeFinder(Solver*
const solver,
const std::vector<Task*>& tasks,
1393 : Constraint(solver),
1396 by_start_min_(tasks.size()),
1397 by_end_max_(tasks.size()),
1398 by_end_min_(tasks.size()),
1399 lt_tree_(tasks.size(), capacity_->Max()),
1400 dual_capacity_tree_(tasks.size()),
1401 has_zero_demand_tasks_(true) {}
1403 ~EdgeFinder()
override {
1408 void Post()
override {
1411 solver(),
this, &EdgeFinder::InitialPropagate,
"RangeChanged");
1412 for (Task*
const task : tasks_) {
1415 task->WhenAnything(demon);
1417 capacity_->WhenRange(demon);
1422 void InitialPropagate()
override {
1424 PropagateBasedOnEndMinGreaterThanEndMax();
1426 PropagateBasedOnEnergy();
1430 void Accept(ModelVisitor*
const visitor)
const override {
1431 LOG(
FATAL) <<
"Should Not Be Visited";
1434 std::string DebugString()
const override {
return "EdgeFinder"; }
1437 UpdatesForADemand* GetOrMakeUpdate(
int64 demand_min) {
1439 if (update ==
nullptr) {
1440 update =
new UpdatesForADemand(tasks_.size());
1441 update_map_[demand_min] = update;
1447 void InitPropagation() {
1449 start_min_update_.clear();
1451 if (has_zero_demand_tasks_.Value()) {
1452 by_start_min_.clear();
1453 by_end_min_.clear();
1454 by_end_max_.clear();
1456 bool zero_demand =
false;
1457 for (Task*
const task : tasks_) {
1458 if (task->DemandMin() > 0) {
1459 by_start_min_.push_back(task);
1460 by_end_min_.push_back(task);
1461 by_end_max_.push_back(task);
1467 has_zero_demand_tasks_.SetValue(solver(),
false);
1472 std::sort(by_start_min_.begin(), by_start_min_.end(),
1473 StartMinLessThan<Task>);
1474 for (
int i = 0; i < by_start_min_.size(); ++i) {
1475 by_start_min_[i]->index = i;
1478 std::sort(by_end_max_.begin(), by_end_max_.end(), EndMaxLessThan<Task>);
1480 std::sort(by_end_min_.begin(), by_end_min_.end(), EndMinLessThan<Task>);
1482 lt_tree_.Init(capacity_->Max());
1484 for (
const auto& entry : update_map_) {
1485 entry.second->Reset();
1493 void ComputeConditionalStartMins(UpdatesForADemand* updates,
1496 DCHECK(updates !=
nullptr);
1497 const int64 capacity_max = capacity_->Max();
1498 const int64 residual_capacity =
CapSub(capacity_max, demand_min);
1499 dual_capacity_tree_.Init(capacity_max, residual_capacity);
1504 int64 update = IntervalVar::kMinValidValue;
1505 for (
int i = 0; i < by_end_max_.size(); ++i) {
1506 Task*
const task = by_end_max_[i];
1507 if (task->EnergyMin() == 0)
continue;
1508 const int64 current_end_max = task->interval->EndMax();
1509 dual_capacity_tree_.Insert(task);
1510 const int64 energy_threshold = residual_capacity * current_end_max;
1511 const DualCapacityThetaNode& root = dual_capacity_tree_.result();
1512 const int64 res_energetic_end_min = root.residual_energetic_end_min;
1513 if (res_energetic_end_min > energy_threshold) {
1514 EnvJCComputeDiver diver(energy_threshold);
1515 dual_capacity_tree_.DiveInTree(&diver);
1516 const int64 enjv = diver.GetEnvJC(dual_capacity_tree_.result());
1517 const int64 numerator =
CapSub(enjv, energy_threshold);
1518 const int64 diff = MathUtil::CeilOfRatio(numerator, demand_min);
1521 updates->SetUpdate(i, update);
1523 updates->set_up_to_date();
1528 int64 ConditionalStartMin(
const Task& task_to_push,
int end_max_index) {
1529 if (task_to_push.EnergyMin() == 0) {
1530 return task_to_push.interval->StartMin();
1532 const int64 demand_min = task_to_push.DemandMin();
1533 UpdatesForADemand*
const updates = GetOrMakeUpdate(demand_min);
1534 if (!updates->up_to_date()) {
1535 ComputeConditionalStartMins(updates, demand_min);
1537 DCHECK(updates->up_to_date());
1538 return updates->Update(end_max_index);
1546 void PropagateBasedOnEndMinGreaterThanEndMax() {
1547 int end_max_index = 0;
1549 for (Task*
const task : by_end_min_) {
1551 while (end_max_index < by_start_min_.size() &&
1552 by_end_max_[end_max_index]->interval->EndMax() <=
end_min) {
1554 max_start_min, by_end_max_[end_max_index]->
interval->StartMin());
1557 if (end_max_index > 0 && task->interval->StartMin() <= max_start_min &&
1558 task->interval->EndMax() > task->interval->EndMin()) {
1572 const int64 update = ConditionalStartMin(*task, end_max_index - 1);
1573 start_min_update_.push_back(std::make_pair(task->interval, update));
1580 for (Task*
const task : by_end_max_) {
1581 lt_tree_.Insert(*task);
1583 const int64 max_feasible =
1584 CapProd(capacity_->Max(), task->interval->EndMax());
1585 if (lt_tree_.energetic_end_min() > max_feasible) {
1593 void PropagateBasedOnEnergy() {
1594 for (
int j = by_start_min_.size() - 2; j >= 0; --j) {
1595 lt_tree_.Grey(*by_end_max_[j + 1]);
1596 Task*
const twj = by_end_max_[j];
1598 const int64 max_feasible =
1599 CapProd(capacity_->Max(), twj->interval->EndMax());
1600 DCHECK_LE(lt_tree_.energetic_end_min(), max_feasible);
1601 while (lt_tree_.energetic_end_min_opt() > max_feasible) {
1602 const int i = lt_tree_.argmax_energetic_end_min_opt();
1604 PropagateTaskCannotEndBefore(i, j);
1612 void PropagateTaskCannotEndBefore(
int index,
int end_max_index) {
1613 Task*
const task_to_push = by_start_min_[
index];
1614 const int64 update = ConditionalStartMin(*task_to_push, end_max_index);
1615 start_min_update_.push_back(std::make_pair(task_to_push->interval, update));
1619 void ApplyNewBounds() {
1620 for (
const std::pair<IntervalVar*, int64>& update : start_min_update_) {
1621 update.first->SetStartMin(update.second);
1626 IntVar*
const capacity_;
1629 std::vector<Task*> tasks_;
1632 std::vector<Task*> by_start_min_;
1635 std::vector<Task*> by_end_max_;
1638 std::vector<Task*> by_end_min_;
1641 CumulativeLambdaThetaTree lt_tree_;
1644 DualCapacityThetaTree dual_capacity_tree_;
1647 std::vector<std::pair<IntervalVar*, int64>> start_min_update_;
1652 absl::flat_hash_map<int64, UpdatesForADemand*> update_map_;
1655 Rev<bool> has_zero_demand_tasks_;
1681 struct ProfileDelta {
1687 bool TimeLessThan(
const ProfileDelta& delta1,
const ProfileDelta& delta2) {
1688 return delta1.time < delta2.time;
1703 template <
class Task>
1704 class CumulativeTimeTable :
public Constraint {
1706 CumulativeTimeTable(Solver*
const solver,
const std::vector<Task*>& tasks,
1708 : Constraint(solver), by_start_min_(tasks), capacity_(
capacity) {
1711 const int profile_max_size = 2 * by_start_min_.size() + 2;
1712 profile_non_unique_time_.reserve(profile_max_size);
1713 profile_unique_time_.reserve(profile_max_size);
1718 void InitialPropagate()
override {
1725 void Post()
override {
1727 solver(),
this, &CumulativeTimeTable::InitialPropagate,
1728 "InitialPropagate");
1729 for (Task*
const task : by_start_min_) {
1730 task->WhenAnything(demon);
1732 capacity_->WhenRange(demon);
1735 void Accept(ModelVisitor*
const visitor)
const override {
1736 LOG(
FATAL) <<
"Should not be visited";
1739 std::string DebugString()
const override {
return "CumulativeTimeTable"; }
1743 void BuildProfile() {
1745 profile_non_unique_time_.clear();
1746 for (
const Task*
const task : by_start_min_) {
1747 const IntervalVar*
const interval = task->interval;
1751 const int64 demand_min = task->DemandMin();
1752 if (demand_min > 0) {
1753 profile_non_unique_time_.emplace_back(
start_max, +demand_min);
1754 profile_non_unique_time_.emplace_back(
end_min, -demand_min);
1759 std::sort(profile_non_unique_time_.begin(), profile_non_unique_time_.end(),
1762 profile_unique_time_.clear();
1763 profile_unique_time_.emplace_back(
kint64min, 0);
1765 for (
const ProfileDelta& step : profile_non_unique_time_) {
1766 if (step.time == profile_unique_time_.back().time) {
1767 profile_unique_time_.back().delta += step.delta;
1769 profile_unique_time_.push_back(step);
1772 usage += step.delta;
1777 int64 max_usage = 0;
1778 for (
const ProfileDelta& step : profile_unique_time_) {
1779 usage += step.delta;
1780 if (usage > max_usage) {
1785 capacity_->SetMin(max_usage);
1787 profile_unique_time_.emplace_back(
kint64max, 0);
1792 std::sort(by_start_min_.begin(), by_start_min_.end(),
1793 StartMinLessThan<Task>);
1795 int profile_index = 0;
1796 for (
const Task*
const task : by_start_min_) {
1797 const IntervalVar*
const interval = task->interval;
1802 while (
interval->StartMin() > profile_unique_time_[profile_index].time) {
1803 DCHECK(profile_index < profile_unique_time_.size());
1805 usage += profile_unique_time_[profile_index].delta;
1807 PushTask(task, profile_index, usage);
1815 void PushTask(
const Task*
const task,
int profile_index,
int64 usage) {
1817 const IntervalVar*
const interval = task->interval;
1818 const int64 demand_min = task->DemandMin();
1819 if (demand_min == 0) {
1822 const int64 residual_capacity =
CapSub(capacity_->Max(), demand_min);
1823 const int64 duration = task->interval->DurationMin();
1824 const ProfileDelta& first_prof_delta = profile_unique_time_[profile_index];
1830 if (first_prof_delta.time >
interval->StartMin()) {
1839 const int64 usage_at_start_min =
CapSub(usage, first_prof_delta.delta);
1840 if (usage_at_start_min > residual_capacity) {
1841 new_start_min = profile_unique_time_[profile_index].time;
1849 ProfileDelta delta_end(
end_min, 0);
1851 delta_start.delta = +demand_min;
1852 delta_end.delta = -demand_min;
1854 while (profile_unique_time_[profile_index].
time <
1855 CapAdd(duration, new_start_min)) {
1856 const ProfileDelta& profile_delta = profile_unique_time_[profile_index];
1857 DCHECK(profile_index < profile_unique_time_.size());
1859 if (profile_delta.time == delta_start.time) {
1860 usage -= delta_start.delta;
1862 if (profile_delta.time == delta_end.time) {
1863 usage -= delta_end.delta;
1867 DCHECK(profile_index < profile_unique_time_.size());
1869 if (usage > residual_capacity) {
1870 new_start_min = profile_unique_time_[profile_index].time;
1872 usage += profile_unique_time_[profile_index].delta;
1874 task->interval->SetStartMin(new_start_min);
1877 typedef std::vector<ProfileDelta> Profile;
1879 Profile profile_unique_time_;
1880 Profile profile_non_unique_time_;
1881 std::vector<Task*> by_start_min_;
1882 IntVar*
const capacity_;
1897 template <
class Task>
1898 class TimeTableSync :
public Constraint {
1900 TimeTableSync(Solver*
const solver,
const std::vector<Task*>& tasks,
1902 : Constraint(solver), tasks_(tasks), capacity_(
capacity) {
1903 num_tasks_ = tasks_.size();
1909 start_min_.reserve(num_tasks_);
1910 start_max_.reserve(num_tasks_);
1911 end_min_.reserve(num_tasks_);
1912 durations_.reserve(num_tasks_);
1913 demands_.reserve(num_tasks_);
1918 void InitialPropagate()
override {
1921 while (!events_scp_.empty() && !events_ecp_.empty()) {
1923 pos_ = NextEventTime();
1928 capacity_->SetMin(capacity_->Max() - gap_);
1930 next_pos_ = NextScpTime();
1938 void Post()
override {
1940 solver(),
this, &TimeTableSync::InitialPropagate,
"InitialPropagate");
1941 for (Task*
const task : tasks_) {
1942 task->WhenAnything(demon);
1944 capacity_->WhenRange(demon);
1947 void Accept(ModelVisitor*
const visitor)
const override {
1948 LOG(
FATAL) <<
"Should not be visited";
1951 std::string DebugString()
const override {
return "TimeTableSync"; }
1955 enum State { NONE, READY,
CHECK, CONFLICT };
1957 inline int64 NextScpTime() {
1958 return !events_scp_.empty() ? events_scp_.top().first :
kint64max;
1961 inline int64 NextEventTime() {
1963 if (!events_pr_.empty()) {
1964 time = events_pr_.top().first;
1966 if (!events_scp_.empty()) {
1967 int64 t = events_scp_.top().first;
1970 if (!events_ecp_.empty()) {
1971 int64 t = events_ecp_.top().first;
1977 void ProcessEventsScp() {
1978 while (!events_scp_.empty() && events_scp_.top().first == pos_) {
1979 const int64 task_id = events_scp_.top().second;
1981 const int64 old_end_min = end_min_[task_id];
1982 if (states_[task_id] == State::CONFLICT) {
1984 const int64 new_end_min = pos_ + durations_[task_id];
1985 start_min_[task_id] = pos_;
1986 end_min_[task_id] = new_end_min;
1988 tasks_[task_id]->interval->SetStartMin(pos_);
1991 states_[task_id] = State::READY;
1993 if (pos_ < end_min_[task_id]) {
1994 gap_ -= demands_[task_id];
1995 if (old_end_min <= pos_) {
1996 events_ecp_.push(kv(end_min_[task_id], task_id));
2002 void ProcessEventsEcp() {
2003 while (!events_ecp_.empty() && events_ecp_.top().first == pos_) {
2004 const int64 task_id = events_ecp_.top().second;
2007 if (pos_ < end_min_[task_id]) {
2008 events_ecp_.push(kv(end_min_[task_id], task_id));
2010 gap_ += demands_[task_id];
2015 void ProcessEventsPr() {
2016 while (!events_pr_.empty() && events_pr_.top().first == pos_) {
2017 const int64 task_id = events_pr_.top().second;
2020 if (demands_[task_id] > gap_) {
2021 states_[task_id] = State::CONFLICT;
2022 conflict_.push(kv(demands_[task_id], task_id));
2026 if (next_pos_ < end_min_[task_id]) {
2028 check_.push(kv(demands_[task_id], task_id));
2032 states_[task_id] = State::READY;
2038 capacity_->SetMin(capacity_->Max() - gap_);
2040 if (gap_ < prev_gap_) {
2042 while (!check_.empty() && demands_[check_.top().second] > gap_) {
2043 const int64 task_id = check_.top().second;
2045 if (states_[task_id] ==
State::CHECK && pos_ < end_min_[task_id]) {
2046 states_[task_id] = State::CONFLICT;
2047 conflict_.push(kv(demands_[task_id], task_id));
2050 states_[task_id] = State::READY;
2055 if (gap_ > prev_gap_) {
2057 while (!conflict_.empty() && demands_[conflict_.top().second] <= gap_) {
2058 const int64 task_id = conflict_.top().second;
2060 if (states_[task_id] != State::CONFLICT) {
2063 const int64 old_end_min = end_min_[task_id];
2065 start_min_[task_id] = pos_;
2066 end_min_[task_id] = pos_ + durations_[task_id];
2068 tasks_[task_id]->interval->SetStartMin(pos_);
2070 if (next_pos_ < end_min_[task_id]) {
2072 check_.push(kv(demands_[task_id], task_id));
2074 states_[task_id] = State::READY;
2079 events_ecp_.push(kv(end_min_[task_id], task_id));
2086 void BuildEvents() {
2090 gap_ = capacity_->Max();
2091 prev_gap_ = capacity_->Max();
2093 conflict_ = min_heap();
2094 check_ = max_heap();
2096 events_pr_ = min_heap();
2097 events_scp_ = min_heap();
2098 events_ecp_ = min_heap();
2107 for (
int i = 0; i < num_tasks_; i++) {
2108 const int64 s_min = tasks_[i]->interval->StartMin();
2109 const int64 s_max = tasks_[i]->interval->StartMax();
2110 const int64 e_min = tasks_[i]->interval->EndMin();
2112 start_min_.push_back(s_min);
2113 start_max_.push_back(s_max);
2114 end_min_.push_back(e_min);
2115 durations_.push_back(tasks_[i]->
interval->DurationMin());
2116 demands_.push_back(tasks_[i]->DemandMin());
2118 states_.push_back(State::NONE);
2120 events_scp_.push(kv(s_max, i));
2122 if (s_min != s_max) {
2123 events_pr_.push(kv(s_min, i));
2126 if (s_max < e_min) {
2127 events_ecp_.push(kv(e_min, i));
2133 std::vector<Task*> tasks_;
2134 IntVar*
const capacity_;
2136 std::vector<int64> start_min_;
2137 std::vector<int64> start_max_;
2138 std::vector<int64> end_min_;
2139 std::vector<int64> end_max_;
2140 std::vector<int64> durations_;
2141 std::vector<int64> demands_;
2144 typedef std::pair<int64, int64> kv;
2145 typedef std::priority_queue<kv, std::vector<kv>, std::greater<kv>> min_heap;
2146 typedef std::priority_queue<kv, std::vector<kv>, std::less<kv>> max_heap;
2149 min_heap events_pr_;
2150 min_heap events_scp_;
2151 min_heap events_ecp_;
2154 std::vector<State> states_;
2165 class CumulativeConstraint :
public Constraint {
2167 CumulativeConstraint(Solver*
const s,
2168 const std::vector<IntervalVar*>& intervals,
2169 const std::vector<int64>& demands,
2173 intervals_(intervals),
2175 tasks_.reserve(intervals.size());
2176 for (
int i = 0; i < intervals.size(); ++i) {
2177 tasks_.push_back(CumulativeTask(intervals[i], demands[i]));
2181 void Post()
override {
2185 const ConstraintSolverParameters& params = solver()->parameters();
2186 if (params.use_cumulative_time_table()) {
2187 if (params.use_cumulative_time_table_sync()) {
2188 PostOneSidedConstraint(
false,
false,
true);
2189 PostOneSidedConstraint(
true,
false,
true);
2191 PostOneSidedConstraint(
false,
false,
false);
2192 PostOneSidedConstraint(
true,
false,
false);
2195 if (params.use_cumulative_edge_finder()) {
2196 PostOneSidedConstraint(
false,
true,
false);
2197 PostOneSidedConstraint(
true,
true,
false);
2199 if (params.use_sequence_high_demand_tasks()) {
2200 PostHighDemandSequenceConstraint();
2202 if (params.use_all_possible_disjunctions()) {
2203 PostAllDisjunctions();
2207 void InitialPropagate()
override {
2211 void Accept(ModelVisitor*
const visitor)
const override {
2213 visitor->BeginVisitConstraint(ModelVisitor::kCumulative,
this);
2214 visitor->VisitIntervalArrayArgument(ModelVisitor::kIntervalsArgument,
2216 visitor->VisitIntegerArrayArgument(ModelVisitor::kDemandsArgument,
2218 visitor->VisitIntegerExpressionArgument(ModelVisitor::kCapacityArgument,
2220 visitor->EndVisitConstraint(ModelVisitor::kCumulative,
this);
2223 std::string DebugString()
const override {
2224 return absl::StrFormat(
"CumulativeConstraint([%s], %s)",
2226 capacity_->DebugString());
2231 void PostAllDisjunctions() {
2232 for (
int i = 0; i < intervals_.size(); ++i) {
2233 IntervalVar*
const interval_i = intervals_[i];
2234 if (interval_i->MayBePerformed()) {
2235 for (
int j = i + 1; j < intervals_.size(); ++j) {
2236 IntervalVar*
const interval_j = intervals_[j];
2237 if (interval_j->MayBePerformed()) {
2239 Constraint*
const constraint =
2240 solver()->MakeTemporalDisjunction(interval_i, interval_j);
2241 solver()->AddConstraint(constraint);
2251 void PostHighDemandSequenceConstraint() {
2252 Constraint* constraint =
nullptr;
2254 std::vector<IntervalVar*> high_demand_intervals;
2255 high_demand_intervals.reserve(intervals_.size());
2256 for (
int i = 0; i < demands_.size(); ++i) {
2264 if (
demand * 2 > capacity_->Max() &&
2265 tasks_[i].interval->MayBePerformed()) {
2266 high_demand_intervals.push_back(tasks_[i].
interval);
2269 if (high_demand_intervals.size() >= 2) {
2272 std::string seq_name = absl::StrCat(
name(),
"-HighDemandSequence");
2273 constraint = solver()->MakeDisjunctiveConstraint(high_demand_intervals,
2277 if (constraint !=
nullptr) {
2278 solver()->AddConstraint(constraint);
2284 void PopulateVectorUsefulTasks(
2285 bool mirror, std::vector<CumulativeTask*>*
const useful_tasks) {
2286 DCHECK(useful_tasks->empty());
2287 for (
int i = 0; i < tasks_.size(); ++i) {
2288 const CumulativeTask& original_task = tasks_[i];
2289 IntervalVar*
const interval = original_task.interval;
2291 if (original_task.demand > capacity_->Max()) {
2296 if (
interval->MayBePerformed() && original_task.demand > 0) {
2297 Solver*
const s = solver();
2298 IntervalVar*
const original_interval = original_task.interval;
2300 mirror ? s->MakeMirrorInterval(original_interval)
2301 : original_interval;
2302 IntervalVar*
const relaxed_max = s->MakeIntervalRelaxedMax(
interval);
2303 useful_tasks->push_back(
2304 new CumulativeTask(relaxed_max, original_task.demand));
2311 Constraint* MakeOneSidedConstraint(
bool mirror,
bool edge_finder,
2313 std::vector<CumulativeTask*> useful_tasks;
2314 PopulateVectorUsefulTasks(mirror, &useful_tasks);
2315 if (useful_tasks.empty()) {
2318 Solver*
const s = solver();
2320 const ConstraintSolverParameters& params = solver()->parameters();
2321 return useful_tasks.size() < params.max_edge_finder_size()
2322 ? s->RevAlloc(
new EdgeFinder<CumulativeTask>(s, useful_tasks,
2328 new TimeTableSync<CumulativeTask>(s, useful_tasks, capacity_));
2331 new CumulativeTimeTable<CumulativeTask>(s, useful_tasks, capacity_));
2336 void PostOneSidedConstraint(
bool mirror,
bool edge_finder,
bool tt_sync) {
2337 Constraint*
const constraint =
2338 MakeOneSidedConstraint(mirror, edge_finder, tt_sync);
2339 if (constraint !=
nullptr) {
2340 solver()->AddConstraint(constraint);
2345 IntVar*
const capacity_;
2348 std::vector<CumulativeTask> tasks_;
2351 const std::vector<IntervalVar*> intervals_;
2353 const std::vector<int64> demands_;
2358 class VariableDemandCumulativeConstraint :
public Constraint {
2360 VariableDemandCumulativeConstraint(Solver*
const s,
2361 const std::vector<IntervalVar*>& intervals,
2362 const std::vector<IntVar*>& demands,
2364 const std::string&
name)
2367 intervals_(intervals),
2369 tasks_.reserve(intervals.size());
2370 for (
int i = 0; i < intervals.size(); ++i) {
2371 tasks_.push_back(VariableCumulativeTask(intervals[i], demands[i]));
2375 void Post()
override {
2379 const ConstraintSolverParameters& params = solver()->parameters();
2380 if (params.use_cumulative_time_table()) {
2381 PostOneSidedConstraint(
false,
false,
false);
2382 PostOneSidedConstraint(
true,
false,
false);
2384 if (params.use_cumulative_edge_finder()) {
2385 PostOneSidedConstraint(
false,
true,
false);
2386 PostOneSidedConstraint(
true,
true,
false);
2388 if (params.use_sequence_high_demand_tasks()) {
2389 PostHighDemandSequenceConstraint();
2391 if (params.use_all_possible_disjunctions()) {
2392 PostAllDisjunctions();
2396 void InitialPropagate()
override {
2400 void Accept(ModelVisitor*
const visitor)
const override {
2402 visitor->BeginVisitConstraint(ModelVisitor::kCumulative,
this);
2403 visitor->VisitIntervalArrayArgument(ModelVisitor::kIntervalsArgument,
2405 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kDemandsArgument,
2407 visitor->VisitIntegerExpressionArgument(ModelVisitor::kCapacityArgument,
2409 visitor->EndVisitConstraint(ModelVisitor::kCumulative,
this);
2412 std::string DebugString()
const override {
2413 return absl::StrFormat(
"VariableDemandCumulativeConstraint([%s], %s)",
2415 capacity_->DebugString());
2420 void PostAllDisjunctions() {
2421 for (
int i = 0; i < intervals_.size(); ++i) {
2422 IntervalVar*
const interval_i = intervals_[i];
2423 if (interval_i->MayBePerformed()) {
2424 for (
int j = i + 1; j < intervals_.size(); ++j) {
2425 IntervalVar*
const interval_j = intervals_[j];
2426 if (interval_j->MayBePerformed()) {
2427 if (
CapAdd(tasks_[i].
demand->Min(), tasks_[j].demand->Min()) >
2429 Constraint*
const constraint =
2430 solver()->MakeTemporalDisjunction(interval_i, interval_j);
2431 solver()->AddConstraint(constraint);
2441 void PostHighDemandSequenceConstraint() {
2442 Constraint* constraint =
nullptr;
2444 std::vector<IntervalVar*> high_demand_intervals;
2445 high_demand_intervals.reserve(intervals_.size());
2446 for (
int i = 0; i < demands_.size(); ++i) {
2454 if (
demand * 2 > capacity_->Max() &&
2455 tasks_[i].interval->MayBePerformed()) {
2456 high_demand_intervals.push_back(tasks_[i].
interval);
2459 if (high_demand_intervals.size() >= 2) {
2462 const std::string seq_name =
2463 absl::StrCat(
name(),
"-HighDemandSequence");
2464 constraint = solver()->MakeStrictDisjunctiveConstraint(
2465 high_demand_intervals, seq_name);
2468 if (constraint !=
nullptr) {
2469 solver()->AddConstraint(constraint);
2475 void PopulateVectorUsefulTasks(
2476 bool mirror, std::vector<VariableCumulativeTask*>*
const useful_tasks) {
2477 DCHECK(useful_tasks->empty());
2478 for (
int i = 0; i < tasks_.size(); ++i) {
2479 const VariableCumulativeTask& original_task = tasks_[i];
2480 IntervalVar*
const interval = original_task.interval;
2482 if (original_task.demand->Min() > capacity_->Max()) {
2487 if (
interval->MayBePerformed() && original_task.demand->Max() > 0) {
2488 Solver*
const s = solver();
2489 IntervalVar*
const original_interval = original_task.interval;
2491 mirror ? s->MakeMirrorInterval(original_interval)
2492 : original_interval;
2493 IntervalVar*
const relaxed_max = s->MakeIntervalRelaxedMax(
interval);
2494 useful_tasks->push_back(
2495 new VariableCumulativeTask(relaxed_max, original_task.demand));
2502 Constraint* MakeOneSidedConstraint(
bool mirror,
bool edge_finder,
2504 std::vector<VariableCumulativeTask*> useful_tasks;
2505 PopulateVectorUsefulTasks(mirror, &useful_tasks);
2506 if (useful_tasks.empty()) {
2509 Solver*
const s = solver();
2512 new EdgeFinder<VariableCumulativeTask>(s, useful_tasks, capacity_));
2515 return s->RevAlloc(
new TimeTableSync<VariableCumulativeTask>(
2516 s, useful_tasks, capacity_));
2518 return s->RevAlloc(
new CumulativeTimeTable<VariableCumulativeTask>(
2519 s, useful_tasks, capacity_));
2524 void PostOneSidedConstraint(
bool mirror,
bool edge_finder,
bool tt_sync) {
2525 Constraint*
const constraint =
2526 MakeOneSidedConstraint(mirror, edge_finder, tt_sync);
2527 if (constraint !=
nullptr) {
2528 solver()->AddConstraint(constraint);
2533 IntVar*
const capacity_;
2536 std::vector<VariableCumulativeTask> tasks_;
2539 const std::vector<IntervalVar*> intervals_;
2541 const std::vector<IntVar*> demands_;
2551 DisjunctiveConstraint::DisjunctiveConstraint(
2552 Solver*
const s,
const std::vector<IntervalVar*>& intervals,
2553 const std::string&
name)
2555 if (!
name.empty()) {
2565 if (transition_time !=
nullptr) {
2575 const std::vector<IntervalVar*>& intervals,
const std::string&
name) {
2576 return RevAlloc(
new FullDisjunctiveConstraint(
this, intervals,
name,
false));
2580 const std::vector<IntervalVar*>& intervals,
const std::string&
name) {
2581 return RevAlloc(
new FullDisjunctiveConstraint(
this, intervals,
name,
true));
2587 const std::vector<int64>& demands,
2589 CHECK_EQ(intervals.size(), demands.size());
2590 for (
int i = 0; i < intervals.size(); ++i) {
2596 return RevAlloc(
new CumulativeConstraint(
this, intervals, demands,
2601 const std::vector<int>& demands,
2607 const std::vector<int64>& demands,
2609 const std::string&
name) {
2610 CHECK_EQ(intervals.size(), demands.size());
2611 for (
int i = 0; i < intervals.size(); ++i) {
2615 new CumulativeConstraint(
this, intervals, demands,
capacity,
name));
2619 const std::vector<int>& demands,
2621 const std::string&
name) {
2628 const std::vector<IntVar*>& demands,
2630 CHECK_EQ(intervals.size(), demands.size());
2631 for (
int i = 0; i < intervals.size(); ++i) {
2635 std::vector<int64> fixed_demands(demands.size());
2636 for (
int i = 0; i < demands.size(); ++i) {
2637 fixed_demands[i] = demands[i]->Value();
2641 return RevAlloc(
new VariableDemandCumulativeConstraint(
2646 const std::vector<IntVar*>& demands,
2648 const std::string&
name) {
2649 CHECK_EQ(intervals.size(), demands.size());
2650 for (
int i = 0; i < intervals.size(); ++i) {
2654 std::vector<int64> fixed_demands(demands.size());
2655 for (
int i = 0; i < demands.size(); ++i) {
2656 fixed_demands[i] = demands[i]->Value();
2660 return RevAlloc(
new VariableDemandCumulativeConstraint(