31 #include "absl/container/flat_hash_map.h" 32 #include "absl/strings/str_cat.h" 33 #include "absl/strings/str_format.h" 34 #include "absl/strings/str_join.h" 56 bool StartMinLessThan(Task*
const w1, Task*
const w2) {
57 return (w1->interval->StartMin() < w2->interval->StartMin());
64 bool ShortestDurationStartMinLessThan(Task*
const w1, Task*
const w2) {
65 return w1->interval->EndMin() - w1->interval->DurationMin() <
66 w2->interval->EndMin() - w2->interval->DurationMin();
70 bool StartMaxLessThan(Task*
const w1, Task*
const w2) {
71 return (w1->interval->StartMax() < w2->interval->StartMax());
75 bool EndMinLessThan(Task*
const w1, Task*
const w2) {
76 return (w1->interval->EndMin() < w2->interval->EndMin());
80 bool EndMaxLessThan(Task*
const w1, Task*
const w2) {
81 return (w1->interval->EndMax() < w2->interval->EndMax());
84 bool IntervalStartMinLessThan(IntervalVar* i1, IntervalVar* i2) {
85 return i1->StartMin() < i2->StartMin();
94 struct DisjunctiveTask {
95 explicit DisjunctiveTask(IntervalVar*
const interval_)
98 std::string DebugString()
const {
return interval->DebugString(); }
109 struct CumulativeTask {
110 CumulativeTask(IntervalVar*
const interval_, int64_t demand_)
113 int64_t EnergyMin()
const {
return interval->DurationMin() *
demand; }
115 int64_t DemandMin()
const {
return demand; }
117 void WhenAnything(Demon*
const demon) {
interval->WhenAnything(demon); }
119 std::string DebugString()
const {
120 return absl::StrFormat(
"Task{ %s, demand: %d }",
interval->DebugString(),
135 struct VariableCumulativeTask {
136 VariableCumulativeTask(IntervalVar*
const interval_, IntVar* demand_)
139 int64_t EnergyMin()
const {
return interval->DurationMin() *
demand->Min(); }
141 int64_t DemandMin()
const {
return demand->Min(); }
143 void WhenAnything(Demon*
const demon) {
148 std::string DebugString()
const {
149 return absl::StrFormat(
"Task{ %s, demand: %s }",
interval->DebugString(),
170 explicit ThetaNode(
const IntervalVar*
const interval)
183 void Compute(
const ThetaNode& left,
const ThetaNode& right) {
189 bool IsIdentity()
const {
194 std::string DebugString()
const {
210 class ThetaTree :
public MonoidOperationTree<ThetaNode> {
212 explicit ThetaTree(
int size) : MonoidOperationTree<ThetaNode>(size) {}
214 int64_t Ect()
const {
return result().total_ect; }
216 void Insert(
const DisjunctiveTask*
const task) {
217 Set(task->index, ThetaNode(task->interval));
220 void Remove(
const DisjunctiveTask*
const task) { Reset(task->index); }
222 bool IsInserted(
const DisjunctiveTask*
const task)
const {
223 return !GetOperand(task->index).IsIdentity();
233 struct LambdaThetaNode {
247 LambdaThetaNode(int64_t
capacity,
const CumulativeTask& task)
248 :
energy(task.EnergyMin()),
256 LambdaThetaNode(int64_t
capacity,
const CumulativeTask& task,
int index)
268 LambdaThetaNode(int64_t
capacity,
const VariableCumulativeTask& task)
269 :
energy(task.EnergyMin()),
277 LambdaThetaNode(int64_t
capacity,
const VariableCumulativeTask& task,
290 explicit LambdaThetaNode(
const IntervalVar*
const interval)
300 LambdaThetaNode(
const IntervalVar*
const interval,
int index)
317 void Compute(
const LambdaThetaNode& left,
const LambdaThetaNode& right) {
320 CapAdd(left.energetic_end_min, right.energy));
321 const int64_t energy_left_opt =
CapAdd(left.energy_opt, right.energy);
322 const int64_t energy_right_opt =
CapAdd(left.energy, right.energy_opt);
323 if (energy_left_opt > energy_right_opt) {
330 const int64_t ect1 = right.energetic_end_min_opt;
331 const int64_t ect2 =
CapAdd(left.energetic_end_min, right.energy_opt);
332 const int64_t ect3 =
CapAdd(left.energetic_end_min_opt, right.energy);
333 if (ect1 >= ect2 && ect1 >= ect3) {
336 }
else if (ect2 >= ect1 && ect2 >= ect3) {
378 class DisjunctiveLambdaThetaTree :
public MonoidOperationTree<LambdaThetaNode> {
380 explicit DisjunctiveLambdaThetaTree(
int size)
381 : MonoidOperationTree<LambdaThetaNode>(size) {}
383 void Insert(
const DisjunctiveTask& task) {
384 Set(task.index, LambdaThetaNode(task.interval));
387 void Grey(
const DisjunctiveTask& task) {
388 const int index = task.index;
389 Set(
index, LambdaThetaNode(task.interval,
index));
392 int64_t Ect()
const {
return result().energetic_end_min; }
393 int64_t EctOpt()
const {
return result().energetic_end_min_opt; }
394 int ResponsibleOpt()
const {
return result().argmax_energetic_end_min_opt; }
398 class CumulativeLambdaThetaTree :
public MonoidOperationTree<LambdaThetaNode> {
400 CumulativeLambdaThetaTree(
int size, int64_t capacity_max)
401 : MonoidOperationTree<LambdaThetaNode>(size),
402 capacity_max_(capacity_max) {}
404 void Init(int64_t capacity_max) {
406 capacity_max_ = capacity_max;
409 void Insert(
const CumulativeTask& task) {
410 Set(task.index, LambdaThetaNode(capacity_max_, task));
413 void Grey(
const CumulativeTask& task) {
414 const int index = task.index;
415 Set(
index, LambdaThetaNode(capacity_max_, task,
index));
418 void Insert(
const VariableCumulativeTask& task) {
419 Set(task.index, LambdaThetaNode(capacity_max_, task));
422 void Grey(
const VariableCumulativeTask& task) {
423 const int index = task.index;
424 Set(
index, LambdaThetaNode(capacity_max_, task,
index));
429 return result().energetic_end_min_opt;
431 int64_t Ect()
const {
434 int64_t EctOpt()
const {
438 return result().argmax_energetic_end_min_opt;
442 int64_t capacity_max_;
451 NotLast(Solver*
const solver,
const std::vector<IntervalVar*>& intervals,
452 bool mirror,
bool strict);
459 ThetaTree theta_tree_;
460 std::vector<DisjunctiveTask*> by_start_min_;
461 std::vector<DisjunctiveTask*> by_end_max_;
462 std::vector<DisjunctiveTask*> by_start_max_;
463 std::vector<int64_t> new_lct_;
467 NotLast::NotLast(Solver*
const solver,
468 const std::vector<IntervalVar*>& intervals,
bool mirror,
470 : theta_tree_(intervals.size()),
471 by_start_min_(intervals.size()),
472 by_end_max_(intervals.size()),
473 by_start_max_(intervals.size()),
474 new_lct_(intervals.size(), -1LL),
477 for (
int i = 0; i < intervals.size(); ++i) {
478 IntervalVar*
const underlying =
479 mirror ? solver->MakeMirrorInterval(intervals[i]) : intervals[i];
480 IntervalVar*
const relaxed = solver->MakeIntervalRelaxedMin(underlying);
481 by_start_min_[i] =
new DisjunctiveTask(relaxed);
482 by_end_max_[i] = by_start_min_[i];
483 by_start_max_[i] = by_start_min_[i];
487 bool NotLast::Propagate() {
489 std::sort(by_start_max_.begin(), by_start_max_.end(),
490 StartMaxLessThan<DisjunctiveTask>);
491 std::sort(by_end_max_.begin(), by_end_max_.end(),
492 EndMaxLessThan<DisjunctiveTask>);
494 std::sort(by_start_min_.begin(), by_start_min_.end(),
495 StartMinLessThan<DisjunctiveTask>);
496 for (
int i = 0; i < by_start_min_.size(); ++i) {
497 by_start_min_[i]->index = i;
500 for (
int i = 0; i < by_start_min_.size(); ++i) {
501 new_lct_[i] = by_start_min_[i]->interval->EndMax();
506 for (DisjunctiveTask*
const twi : by_end_max_) {
507 while (j < by_start_max_.size() &&
508 twi->interval->EndMax() > by_start_max_[j]->interval->StartMax()) {
509 if (j > 0 && theta_tree_.Ect() > by_start_max_[j]->interval->StartMax()) {
510 const int64_t new_end_max = by_start_max_[j - 1]->interval->StartMax();
511 new_lct_[by_start_max_[j]->index] = new_end_max;
513 theta_tree_.Insert(by_start_max_[j]);
516 const bool inserted = theta_tree_.IsInserted(twi);
518 theta_tree_.Remove(twi);
520 const int64_t ect_theta_less_i = theta_tree_.Ect();
522 theta_tree_.Insert(twi);
524 if (ect_theta_less_i > twi->interval->EndMax() && j > 0) {
525 const int64_t new_end_max = by_start_max_[j - 1]->interval->EndMax();
526 if (new_end_max > new_lct_[twi->index]) {
527 new_lct_[twi->index] = new_end_max;
533 bool modified =
false;
534 for (
int i = 0; i < by_start_min_.size(); ++i) {
535 IntervalVar*
const var = by_start_min_[i]->interval;
536 if ((strict_ ||
var->DurationMin() > 0) &&
var->EndMax() > new_lct_[i]) {
538 var->SetEndMax(new_lct_[i]);
549 class EdgeFinderAndDetectablePrecedences {
551 EdgeFinderAndDetectablePrecedences(Solver*
const solver,
552 const std::vector<IntervalVar*>& intervals,
553 bool mirror,
bool strict);
554 ~EdgeFinderAndDetectablePrecedences() {
557 int64_t size()
const {
return by_start_min_.size(); }
560 void OverloadChecking();
561 bool DetectablePrecedences();
565 Solver*
const solver_;
576 ThetaTree theta_tree_;
577 std::vector<DisjunctiveTask*> by_end_min_;
578 std::vector<DisjunctiveTask*> by_start_min_;
579 std::vector<DisjunctiveTask*> by_end_max_;
580 std::vector<DisjunctiveTask*> by_start_max_;
582 std::vector<int64_t> new_est_;
584 std::vector<int64_t> new_lct_;
585 DisjunctiveLambdaThetaTree lt_tree_;
589 EdgeFinderAndDetectablePrecedences::EdgeFinderAndDetectablePrecedences(
590 Solver*
const solver,
const std::vector<IntervalVar*>& intervals,
591 bool mirror,
bool strict)
593 theta_tree_(intervals.size()),
594 lt_tree_(intervals.size()),
597 for (IntervalVar*
const interval : intervals) {
598 IntervalVar*
const underlying =
600 IntervalVar*
const relaxed = solver->MakeIntervalRelaxedMax(underlying);
601 DisjunctiveTask*
const task =
new DisjunctiveTask(relaxed);
602 by_end_min_.push_back(task);
603 by_start_min_.push_back(task);
604 by_end_max_.push_back(task);
605 by_start_max_.push_back(task);
610 void EdgeFinderAndDetectablePrecedences::UpdateEst() {
611 std::sort(by_start_min_.begin(), by_start_min_.end(),
612 ShortestDurationStartMinLessThan<DisjunctiveTask>);
613 for (
int i = 0; i < size(); ++i) {
614 by_start_min_[i]->index = i;
618 void EdgeFinderAndDetectablePrecedences::OverloadChecking() {
621 std::sort(by_end_max_.begin(), by_end_max_.end(),
622 EndMaxLessThan<DisjunctiveTask>);
625 for (DisjunctiveTask*
const task : by_end_max_) {
626 theta_tree_.Insert(task);
627 if (theta_tree_.Ect() > task->interval->EndMax()) {
633 bool EdgeFinderAndDetectablePrecedences::DetectablePrecedences() {
639 std::sort(by_end_min_.begin(), by_end_min_.end(),
640 EndMinLessThan<DisjunctiveTask>);
641 std::sort(by_start_max_.begin(), by_start_max_.end(),
642 StartMaxLessThan<DisjunctiveTask>);
645 for (DisjunctiveTask*
const task_i : by_end_min_) {
647 DisjunctiveTask* task_j = by_start_max_[j];
648 while (task_i->interval->EndMin() > task_j->interval->StartMax()) {
649 theta_tree_.Insert(task_j);
651 if (j == size())
break;
652 task_j = by_start_max_[j];
655 const int64_t esti = task_i->interval->StartMin();
656 bool inserted = theta_tree_.IsInserted(task_i);
658 theta_tree_.Remove(task_i);
660 const int64_t oesti = theta_tree_.Ect();
662 theta_tree_.Insert(task_i);
665 new_est_[task_i->index] = oesti;
672 bool modified =
false;
673 for (
int i = 0; i < size(); ++i) {
674 IntervalVar*
const var = by_start_min_[i]->interval;
676 (strict_ ||
var->DurationMin() > 0)) {
678 by_start_min_[i]->interval->SetStartMin(new_est_[i]);
684 bool EdgeFinderAndDetectablePrecedences::EdgeFinder() {
687 for (
int i = 0; i < size(); ++i) {
688 new_est_[i] = by_start_min_[i]->interval->StartMin();
692 std::sort(by_end_max_.begin(), by_end_max_.end(),
693 EndMaxLessThan<DisjunctiveTask>);
695 for (
int i = 0; i < size(); ++i) {
696 lt_tree_.Insert(*by_start_min_[i]);
699 for (
int j = size() - 2; j >= 0; --j) {
700 lt_tree_.Grey(*by_end_max_[j + 1]);
701 DisjunctiveTask*
const twj = by_end_max_[j];
703 DCHECK_LE(lt_tree_.Ect(), twj->interval->EndMax());
704 while (lt_tree_.EctOpt() > twj->interval->EndMax()) {
705 const int i = lt_tree_.ResponsibleOpt();
707 if (lt_tree_.Ect() > new_est_[i]) {
708 new_est_[i] = lt_tree_.Ect();
715 bool modified =
false;
716 for (
int i = 0; i < size(); ++i) {
717 IntervalVar*
const var = by_start_min_[i]->interval;
718 if (
var->StartMin() < new_est_[i] && (strict_ ||
var->DurationMin() > 0)) {
720 var->SetStartMin(new_est_[i]);
730 class RankedPropagator :
public Constraint {
732 RankedPropagator(Solver*
const solver,
const std::vector<IntVar*>& nexts,
733 const std::vector<IntervalVar*>& intervals,
734 const std::vector<IntVar*>& slacks,
735 DisjunctiveConstraint*
const disjunctive)
736 : Constraint(solver),
738 intervals_(intervals),
740 disjunctive_(disjunctive),
741 partial_sequence_(intervals.size()),
742 previous_(intervals.size() + 2, 0) {}
744 ~RankedPropagator()
override {}
746 void Post()
override {
747 Demon*
const delayed =
748 solver()->MakeDelayedConstraintInitialPropagateCallback(
this);
749 for (
int i = 0; i < intervals_.size(); ++i) {
750 nexts_[i]->WhenBound(delayed);
751 intervals_[i]->WhenAnything(delayed);
752 slacks_[i]->WhenRange(delayed);
754 nexts_.back()->WhenBound(delayed);
757 void InitialPropagate()
override {
762 void PropagateNexts() {
763 Solver*
const s = solver();
764 const int ranked_first = partial_sequence_.NumFirstRanked();
765 const int ranked_last = partial_sequence_.NumLastRanked();
769 : partial_sequence_[intervals_.size() - ranked_last] + 1;
772 while (nexts_[first]->Bound()) {
774 first = nexts_[first]->Min();
775 if (first == sentinel) {
778 if (++counter > ranked_first) {
779 DCHECK(intervals_[first - 1]->MayBePerformed());
780 partial_sequence_.RankFirst(s, first - 1);
781 VLOG(2) <<
"RankFirst " << first - 1 <<
" -> " 782 << partial_sequence_.DebugString();
785 previous_.assign(previous_.size(), -1);
786 for (
int i = 0; i < nexts_.size(); ++i) {
787 if (nexts_[i]->Bound()) {
788 previous_[nexts_[i]->Min()] = i;
791 int last = previous_.size() - 1;
793 while (previous_[last] != -1) {
794 last = previous_[last];
795 if (++counter > ranked_last) {
796 partial_sequence_.RankLast(s, last - 1);
797 VLOG(2) <<
"RankLast " << last - 1 <<
" -> " 798 << partial_sequence_.DebugString();
803 void PropagateSequence() {
804 const int last_position = intervals_.size() - 1;
805 const int first_sentinel = partial_sequence_.NumFirstRanked();
806 const int last_sentinel = last_position - partial_sequence_.NumLastRanked();
808 for (
int i = 0; i < first_sentinel - 1; ++i) {
809 IntervalVar*
const interval = RankedInterval(i);
810 IntervalVar*
const next_interval = RankedInterval(i + 1);
811 IntVar*
const slack = RankedSlack(i);
812 const int64_t transition_time = RankedTransitionTime(i, i + 1);
813 next_interval->SetStartRange(
818 for (
int i = last_position; i > last_sentinel + 1; --i) {
819 IntervalVar*
const interval = RankedInterval(i - 1);
820 IntervalVar*
const next_interval = RankedInterval(i);
821 IntVar*
const slack = RankedSlack(i - 1);
822 const int64_t transition_time = RankedTransitionTime(i - 1, i);
824 CapAdd(slack->Max(), transition_time)),
825 CapSub(next_interval->StartMax(),
826 CapAdd(slack->Min(), transition_time)));
829 IntervalVar*
const first_interval =
830 first_sentinel > 0 ? RankedInterval(first_sentinel - 1) : nullptr;
831 IntVar*
const first_slack =
832 first_sentinel > 0 ? RankedSlack(first_sentinel - 1) : nullptr;
833 IntervalVar*
const last_interval = last_sentinel < last_position
834 ? RankedInterval(last_sentinel + 1)
838 if (first_interval ==
nullptr && last_interval ==
nullptr) {
843 for (
int i = first_sentinel; i <= last_sentinel; ++i) {
844 IntervalVar*
const interval = RankedInterval(i);
845 IntVar*
const slack = RankedSlack(i);
848 if (first_interval !=
nullptr) {
849 const int64_t transition_time =
850 RankedTransitionTime(first_sentinel - 1, i);
852 CapAdd(first_interval->StartMin(),
853 CapAdd(first_slack->Min(), transition_time)),
854 CapAdd(first_interval->StartMax(),
855 CapAdd(first_slack->Max(), transition_time)));
857 first_interval->SetStartRange(
859 CapAdd(first_slack->Max(), transition_time)),
861 CapAdd(first_slack->Min(), transition_time)));
864 if (last_interval !=
nullptr) {
865 const int64_t transition_time =
866 RankedTransitionTime(i, last_sentinel + 1);
868 CapSub(last_interval->StartMin(),
869 CapAdd(slack->Max(), transition_time)),
870 CapSub(last_interval->StartMax(),
871 CapAdd(slack->Min(), transition_time)));
873 last_interval->SetStartRange(
875 CapAdd(slack->Min(), transition_time)),
877 CapAdd(slack->Max(), transition_time)));
884 for (
int i =
std::min(first_sentinel - 2, last_position - 1); i >= 0; --i) {
885 IntervalVar*
const interval = RankedInterval(i);
886 IntervalVar*
const next_interval = RankedInterval(i + 1);
887 IntVar*
const slack = RankedSlack(i);
888 const int64_t transition_time = RankedTransitionTime(i, i + 1);
890 CapAdd(slack->Max(), transition_time)),
891 CapSub(next_interval->StartMax(),
892 CapAdd(slack->Min(), transition_time)));
895 for (
int i = last_sentinel + 1; i < last_position - 1; ++i) {
896 IntervalVar*
const interval = RankedInterval(i);
897 IntervalVar*
const next_interval = RankedInterval(i + 1);
898 IntVar*
const slack = RankedSlack(i);
899 const int64_t transition_time = RankedTransitionTime(i, i + 1);
900 next_interval->SetStartRange(
907 IntervalVar* RankedInterval(
int i)
const {
908 const int index = partial_sequence_[i];
909 return intervals_[
index];
912 IntVar* RankedSlack(
int i)
const {
913 const int index = partial_sequence_[i];
914 return slacks_[
index];
917 int64_t RankedTransitionTime(
int before,
int after)
const {
918 const int before_index = partial_sequence_[before];
919 const int after_index = partial_sequence_[after];
921 return disjunctive_->TransitionTime(before_index, after_index);
924 std::string DebugString()
const override {
925 return absl::StrFormat(
926 "RankedPropagator([%s], nexts = [%s], intervals = [%s])",
931 void Accept(ModelVisitor*
const visitor)
const override {
932 LOG(
FATAL) <<
"Not yet implemented";
937 std::vector<IntVar*> nexts_;
938 std::vector<IntervalVar*> intervals_;
939 std::vector<IntVar*> slacks_;
940 DisjunctiveConstraint*
const disjunctive_;
941 RevPartialSequence partial_sequence_;
942 std::vector<int> previous_;
948 class FullDisjunctiveConstraint :
public DisjunctiveConstraint {
950 FullDisjunctiveConstraint(Solver*
const s,
951 const std::vector<IntervalVar*>& intervals,
952 const std::string&
name,
bool strict)
953 : DisjunctiveConstraint(s, intervals,
name),
954 sequence_var_(nullptr),
955 straight_(s, intervals, false, strict),
956 mirror_(s, intervals, true, strict),
957 straight_not_last_(s, intervals, false, strict),
958 mirror_not_last_(s, intervals, true, strict),
961 ~FullDisjunctiveConstraint()
override {}
963 void Post()
override {
965 solver(),
this, &FullDisjunctiveConstraint::InitialPropagate,
967 for (int32_t i = 0; i < straight_.size(); ++i) {
968 straight_.interval(i)->WhenAnything(d);
972 void InitialPropagate()
override {
973 bool all_optional_or_unperformed =
true;
974 for (
const IntervalVar*
const interval : intervals_) {
976 all_optional_or_unperformed =
false;
980 if (all_optional_or_unperformed) {
984 bool all_times_fixed =
true;
985 for (
const IntervalVar*
const interval : intervals_) {
990 all_times_fixed =
false;
995 if (all_times_fixed) {
996 PropagatePerformed();
1003 straight_.OverloadChecking();
1004 }
while (straight_.DetectablePrecedences() ||
1005 mirror_.DetectablePrecedences());
1006 }
while (straight_not_last_.Propagate() ||
1007 mirror_not_last_.Propagate());
1008 }
while (straight_.EdgeFinder() || mirror_.EdgeFinder());
1012 bool Intersect(IntervalVar*
const i1, IntervalVar*
const i2)
const {
1013 return i1->StartMin() < i2->EndMax() && i2->StartMin() < i1->EndMax();
1016 void PropagatePerformed() {
1019 for (IntervalVar*
const interval : intervals_) {
1022 }
else if (
interval->MayBePerformed()) {
1027 if (performed_.empty())
return;
1028 std::sort(performed_.begin(), performed_.end(), IntervalStartMinLessThan);
1029 for (
int i = 0; i < performed_.size() - 1; ++i) {
1030 if (performed_[i]->EndMax() > performed_[i + 1]->StartMin()) {
1036 if (optional_.empty())
return;
1038 const int num_performed = performed_.size();
1039 std::sort(optional_.begin(), optional_.end(), IntervalStartMinLessThan);
1040 for (IntervalVar*
const candidate : optional_) {
1041 const int64_t start = candidate->StartMin();
1042 while (index < num_performed && start >= performed_[
index]->EndMax()) {
1045 if (
index == num_performed)
return;
1046 if (Intersect(candidate, performed_[
index]) ||
1047 (
index < num_performed - 1 &&
1048 Intersect(candidate, performed_[
index + 1]))) {
1049 candidate->SetPerformed(
false);
1054 void Accept(ModelVisitor*
const visitor)
const override {
1055 visitor->BeginVisitConstraint(ModelVisitor::kDisjunctive,
this);
1056 visitor->VisitIntervalArrayArgument(ModelVisitor::kIntervalsArgument,
1058 if (sequence_var_ !=
nullptr) {
1059 visitor->VisitSequenceArgument(ModelVisitor::kSequenceArgument,
1062 visitor->EndVisitConstraint(ModelVisitor::kDisjunctive,
this);
1065 SequenceVar* MakeSequenceVar()
override {
1066 BuildNextModelIfNeeded();
1067 if (sequence_var_ ==
nullptr) {
1068 solver()->SaveValue(reinterpret_cast<void**>(&sequence_var_));
1069 sequence_var_ = solver()->RevAlloc(
1070 new SequenceVar(solver(), intervals_, nexts_,
name()));
1072 return sequence_var_;
1075 std::string DebugString()
const override {
1076 return absl::StrFormat(
"FullDisjunctiveConstraint([%s], %i)",
1080 const std::vector<IntVar*>& nexts()
const override {
return nexts_; }
1082 const std::vector<IntVar*>& actives()
const override {
return actives_; }
1084 const std::vector<IntVar*>& time_cumuls()
const override {
1085 return time_cumuls_;
1088 const std::vector<IntVar*>& time_slacks()
const override {
1089 return time_slacks_;
1093 int64_t Distance(int64_t activity_plus_one, int64_t next_activity_plus_one) {
1094 return (activity_plus_one == 0 ||
1095 next_activity_plus_one > intervals_.size())
1097 : transition_time_(activity_plus_one - 1,
1098 next_activity_plus_one - 1);
1101 void BuildNextModelIfNeeded() {
1102 if (!nexts_.empty()) {
1105 Solver*
const s = solver();
1106 const std::string& ct_name =
name();
1107 const int num_intervals = intervals_.size();
1108 const int num_nodes = intervals_.size() + 1;
1109 int64_t horizon = 0;
1110 for (
int i = 0; i < intervals_.size(); ++i) {
1111 if (intervals_[i]->MayBePerformed()) {
1112 horizon =
std::max(horizon, intervals_[i]->EndMax());
1117 s->MakeIntVarArray(num_nodes, 1, num_nodes, ct_name +
"_nexts", &nexts_);
1119 s->AddConstraint(s->MakeAllDifferent(nexts_));
1121 actives_.resize(num_nodes);
1122 for (
int i = 0; i < num_intervals; ++i) {
1123 actives_[i + 1] = intervals_[i]->PerformedExpr()->Var();
1125 s->MakeIsDifferentCstCt(nexts_[i + 1], i + 1, actives_[i + 1]));
1127 std::vector<IntVar*> short_actives(actives_.begin() + 1, actives_.end());
1128 actives_[0] = s->MakeMax(short_actives)->Var();
1131 s->AddConstraint(s->MakeNoCycle(nexts_, actives_));
1134 time_cumuls_.resize(num_nodes + 1);
1136 time_slacks_.resize(num_nodes);
1138 time_slacks_[0] = s->MakeIntVar(0, horizon,
"initial_slack");
1140 time_cumuls_[0] = s->MakeIntConst(0);
1142 for (int64_t i = 0; i < num_intervals; ++i) {
1143 IntervalVar*
const var = intervals_[i];
1144 if (
var->MayBePerformed()) {
1145 const int64_t duration_min =
var->DurationMin();
1146 time_slacks_[i + 1] = s->MakeIntVar(
1147 duration_min, horizon, absl::StrFormat(
"time_slacks(%d)", i + 1));
1149 time_cumuls_[i + 1] =
var->SafeStartExpr(
var->StartMin())->Var();
1150 if (
var->DurationMax() != duration_min) {
1151 s->AddConstraint(s->MakeGreaterOrEqual(
1152 time_slacks_[i + 1],
var->SafeDurationExpr(duration_min)));
1155 time_slacks_[i + 1] = s->MakeIntVar(
1156 0, horizon, absl::StrFormat(
"time_slacks(%d)", i + 1));
1157 time_cumuls_[i + 1] = s->MakeIntConst(horizon);
1161 time_cumuls_[num_nodes] = s->MakeIntVar(0, 2 * horizon, ct_name +
"_ect");
1162 s->AddConstraint(s->MakePathCumul(
1163 nexts_, actives_, time_cumuls_, time_slacks_,
1164 [
this](int64_t x, int64_t y) { return Distance(x, y); }));
1166 std::vector<IntVar*> short_slacks(time_slacks_.begin() + 1,
1167 time_slacks_.end());
1168 s->AddConstraint(s->RevAlloc(
1169 new RankedPropagator(s, nexts_, intervals_, short_slacks,
this)));
1172 SequenceVar* sequence_var_;
1173 EdgeFinderAndDetectablePrecedences straight_;
1174 EdgeFinderAndDetectablePrecedences mirror_;
1175 NotLast straight_not_last_;
1176 NotLast mirror_not_last_;
1177 std::vector<IntVar*> nexts_;
1178 std::vector<IntVar*> actives_;
1179 std::vector<IntVar*> time_cumuls_;
1180 std::vector<IntVar*> time_slacks_;
1181 std::vector<IntervalVar*> performed_;
1182 std::vector<IntervalVar*> optional_;
1193 struct DualCapacityThetaNode {
1195 static const int kNone;
1198 DualCapacityThetaNode()
1204 DualCapacityThetaNode(int64_t
capacity, int64_t residual_capacity,
1205 const CumulativeTask& task)
1206 :
energy(task.EnergyMin()),
1212 DualCapacityThetaNode(int64_t
capacity, int64_t residual_capacity,
1213 const VariableCumulativeTask& task)
1214 :
energy(task.EnergyMin()),
1225 void Compute(
const DualCapacityThetaNode& left,
1226 const DualCapacityThetaNode& right) {
1229 right.energetic_end_min);
1232 right.residual_energetic_end_min);
1249 class DualCapacityThetaTree
1250 :
public MonoidOperationTree<DualCapacityThetaNode> {
1254 explicit DualCapacityThetaTree(
int size)
1255 : MonoidOperationTree<DualCapacityThetaNode>(size),
1257 residual_capacity_(-1) {}
1259 virtual ~DualCapacityThetaTree() {}
1261 void Init(int64_t capacity_max, int64_t residual_capacity) {
1263 DCHECK_LE(residual_capacity, capacity_max);
1265 capacity_max_ = capacity_max;
1266 residual_capacity_ = residual_capacity;
1269 void Insert(
const CumulativeTask* task) {
1271 DualCapacityThetaNode(capacity_max_, residual_capacity_, *task));
1274 void Insert(
const VariableCumulativeTask* task) {
1276 DualCapacityThetaNode(capacity_max_, residual_capacity_, *task));
1280 int64_t capacity_max_;
1281 int64_t residual_capacity_;
1297 class EnvJCComputeDiver {
1300 explicit EnvJCComputeDiver(
int energy_threshold)
1301 : energy_threshold_(energy_threshold),
1304 void OnArgumentReached(
int index,
const DualCapacityThetaNode& argument) {
1305 energy_alpha_ = argument.energy;
1306 energetic_end_min_alpha_ = argument.energetic_end_min;
1311 bool ChooseGoLeft(
const DualCapacityThetaNode& current,
1312 const DualCapacityThetaNode& left_child,
1313 const DualCapacityThetaNode& right_child) {
1314 if (right_child.residual_energetic_end_min > energy_threshold_) {
1317 energy_threshold_ -= right_child.energy;
1321 void OnComeBackFromLeft(
const DualCapacityThetaNode& current,
1322 const DualCapacityThetaNode& left_child,
1323 const DualCapacityThetaNode& right_child) {
1329 void OnComeBackFromRight(
const DualCapacityThetaNode& current,
1330 const DualCapacityThetaNode& left_child,
1331 const DualCapacityThetaNode& right_child) {
1334 energetic_end_min_alpha_ =
1336 CapAdd(left_child.energetic_end_min, energy_alpha_));
1337 energy_alpha_ += left_child.energy;
1339 int64_t GetEnvJC(
const DualCapacityThetaNode& root)
const {
1340 const int64_t
energy = root.energy;
1341 const int64_t energy_beta =
CapSub(
energy, energy_alpha_);
1342 return CapAdd(energetic_end_min_alpha_, energy_beta);
1351 int64_t energy_threshold_;
1357 int64_t energy_alpha_;
1362 int64_t energetic_end_min_alpha_;
1374 class UpdatesForADemand {
1376 explicit UpdatesForADemand(
int size)
1377 : updates_(size, 0), up_to_date_(false) {}
1379 const int64_t Update(
int index) {
return updates_[
index]; }
1380 void Reset() { up_to_date_ =
false; }
1381 void SetUpdate(
int index, int64_t update) {
1384 updates_[
index] = update;
1386 bool up_to_date()
const {
return up_to_date_; }
1387 void set_up_to_date() { up_to_date_ =
true; }
1390 std::vector<int64_t> updates_;
1396 template <
class Task>
1397 class EdgeFinder :
public Constraint {
1399 EdgeFinder(Solver*
const solver,
const std::vector<Task*>& tasks,
1401 : Constraint(solver),
1404 by_start_min_(tasks.size()),
1405 by_end_max_(tasks.size()),
1406 by_end_min_(tasks.size()),
1407 lt_tree_(tasks.size(), capacity_->Max()),
1408 dual_capacity_tree_(tasks.size()),
1409 has_zero_demand_tasks_(true) {}
1411 ~EdgeFinder()
override {
1416 void Post()
override {
1419 solver(),
this, &EdgeFinder::InitialPropagate,
"RangeChanged");
1420 for (Task*
const task : tasks_) {
1423 task->WhenAnything(demon);
1425 capacity_->WhenRange(demon);
1430 void InitialPropagate()
override {
1432 PropagateBasedOnEndMinGreaterThanEndMax();
1434 PropagateBasedOnEnergy();
1438 void Accept(ModelVisitor*
const visitor)
const override {
1439 LOG(
FATAL) <<
"Should Not Be Visited";
1442 std::string DebugString()
const override {
return "EdgeFinder"; }
1445 UpdatesForADemand* GetOrMakeUpdate(int64_t demand_min) {
1447 if (update ==
nullptr) {
1448 update =
new UpdatesForADemand(tasks_.size());
1449 update_map_[demand_min] = update;
1455 void InitPropagation() {
1457 start_min_update_.clear();
1459 if (has_zero_demand_tasks_.Value()) {
1460 by_start_min_.clear();
1461 by_end_min_.clear();
1462 by_end_max_.clear();
1464 bool zero_demand =
false;
1465 for (Task*
const task : tasks_) {
1466 if (task->DemandMin() > 0) {
1467 by_start_min_.push_back(task);
1468 by_end_min_.push_back(task);
1469 by_end_max_.push_back(task);
1475 has_zero_demand_tasks_.SetValue(solver(),
false);
1480 std::sort(by_start_min_.begin(), by_start_min_.end(),
1481 StartMinLessThan<Task>);
1482 for (
int i = 0; i < by_start_min_.size(); ++i) {
1483 by_start_min_[i]->index = i;
1486 std::sort(by_end_max_.begin(), by_end_max_.end(), EndMaxLessThan<Task>);
1488 std::sort(by_end_min_.begin(), by_end_min_.end(), EndMinLessThan<Task>);
1490 lt_tree_.Init(capacity_->Max());
1492 for (
const auto& entry : update_map_) {
1493 entry.second->Reset();
1501 void ComputeConditionalStartMins(UpdatesForADemand* updates,
1502 int64_t demand_min) {
1504 DCHECK(updates !=
nullptr);
1505 const int64_t capacity_max = capacity_->Max();
1506 const int64_t residual_capacity =
CapSub(capacity_max, demand_min);
1507 dual_capacity_tree_.Init(capacity_max, residual_capacity);
1512 int64_t update = IntervalVar::kMinValidValue;
1513 for (
int i = 0; i < by_end_max_.size(); ++i) {
1514 Task*
const task = by_end_max_[i];
1515 if (task->EnergyMin() == 0)
continue;
1516 const int64_t current_end_max = task->interval->EndMax();
1517 dual_capacity_tree_.Insert(task);
1518 const int64_t energy_threshold = residual_capacity * current_end_max;
1519 const DualCapacityThetaNode& root = dual_capacity_tree_.result();
1520 const int64_t res_energetic_end_min = root.residual_energetic_end_min;
1521 if (res_energetic_end_min > energy_threshold) {
1522 EnvJCComputeDiver diver(energy_threshold);
1523 dual_capacity_tree_.DiveInTree(&diver);
1524 const int64_t enjv = diver.GetEnvJC(dual_capacity_tree_.result());
1525 const int64_t numerator =
CapSub(enjv, energy_threshold);
1526 const int64_t diff = MathUtil::CeilOfRatio(numerator, demand_min);
1529 updates->SetUpdate(i, update);
1531 updates->set_up_to_date();
1536 int64_t ConditionalStartMin(
const Task& task_to_push,
int end_max_index) {
1537 if (task_to_push.EnergyMin() == 0) {
1538 return task_to_push.interval->StartMin();
1540 const int64_t demand_min = task_to_push.DemandMin();
1541 UpdatesForADemand*
const updates = GetOrMakeUpdate(demand_min);
1542 if (!updates->up_to_date()) {
1543 ComputeConditionalStartMins(updates, demand_min);
1545 DCHECK(updates->up_to_date());
1546 return updates->Update(end_max_index);
1554 void PropagateBasedOnEndMinGreaterThanEndMax() {
1555 int end_max_index = 0;
1557 for (Task*
const task : by_end_min_) {
1558 const int64_t
end_min = task->interval->EndMin();
1559 while (end_max_index < by_start_min_.size() &&
1560 by_end_max_[end_max_index]->interval->EndMax() <=
end_min) {
1562 max_start_min, by_end_max_[end_max_index]->
interval->StartMin());
1565 if (end_max_index > 0 && task->interval->StartMin() <= max_start_min &&
1566 task->interval->EndMax() > task->interval->EndMin()) {
1580 const int64_t update = ConditionalStartMin(*task, end_max_index - 1);
1581 start_min_update_.push_back(std::make_pair(task->interval, update));
1588 for (Task*
const task : by_end_max_) {
1589 lt_tree_.Insert(*task);
1591 const int64_t max_feasible =
1592 CapProd(capacity_->Max(), task->interval->EndMax());
1593 if (lt_tree_.energetic_end_min() > max_feasible) {
1601 void PropagateBasedOnEnergy() {
1602 for (
int j = by_start_min_.size() - 2; j >= 0; --j) {
1603 lt_tree_.Grey(*by_end_max_[j + 1]);
1604 Task*
const twj = by_end_max_[j];
1606 const int64_t max_feasible =
1607 CapProd(capacity_->Max(), twj->interval->EndMax());
1608 DCHECK_LE(lt_tree_.energetic_end_min(), max_feasible);
1609 while (lt_tree_.energetic_end_min_opt() > max_feasible) {
1610 const int i = lt_tree_.argmax_energetic_end_min_opt();
1612 PropagateTaskCannotEndBefore(i, j);
1620 void PropagateTaskCannotEndBefore(
int index,
int end_max_index) {
1621 Task*
const task_to_push = by_start_min_[
index];
1622 const int64_t update = ConditionalStartMin(*task_to_push, end_max_index);
1623 start_min_update_.push_back(std::make_pair(task_to_push->interval, update));
1627 void ApplyNewBounds() {
1628 for (
const std::pair<IntervalVar*, int64_t>& update : start_min_update_) {
1629 update.first->SetStartMin(update.second);
1634 IntVar*
const capacity_;
1637 std::vector<Task*> tasks_;
1640 std::vector<Task*> by_start_min_;
1643 std::vector<Task*> by_end_max_;
1646 std::vector<Task*> by_end_min_;
1649 CumulativeLambdaThetaTree lt_tree_;
1652 DualCapacityThetaTree dual_capacity_tree_;
1655 std::vector<std::pair<IntervalVar*, int64_t>> start_min_update_;
1660 absl::flat_hash_map<int64_t, UpdatesForADemand*> update_map_;
1663 Rev<bool> has_zero_demand_tasks_;
1689 struct ProfileDelta {
1690 ProfileDelta(int64_t _time, int64_t _delta) :
time(_time),
delta(_delta) {}
1695 bool TimeLessThan(
const ProfileDelta& delta1,
const ProfileDelta& delta2) {
1696 return delta1.time < delta2.time;
1711 template <
class Task>
1712 class CumulativeTimeTable :
public Constraint {
1714 CumulativeTimeTable(Solver*
const solver,
const std::vector<Task*>& tasks,
1716 : Constraint(solver), by_start_min_(tasks), capacity_(
capacity) {
1719 const int profile_max_size = 2 * by_start_min_.size() + 2;
1720 profile_non_unique_time_.reserve(profile_max_size);
1721 profile_unique_time_.reserve(profile_max_size);
1726 void InitialPropagate()
override {
1733 void Post()
override {
1735 solver(),
this, &CumulativeTimeTable::InitialPropagate,
1736 "InitialPropagate");
1737 for (Task*
const task : by_start_min_) {
1738 task->WhenAnything(demon);
1740 capacity_->WhenRange(demon);
1743 void Accept(ModelVisitor*
const visitor)
const override {
1744 LOG(
FATAL) <<
"Should not be visited";
1747 std::string DebugString()
const override {
return "CumulativeTimeTable"; }
1751 void BuildProfile() {
1753 profile_non_unique_time_.clear();
1754 for (
const Task*
const task : by_start_min_) {
1755 const IntervalVar*
const interval = task->interval;
1759 const int64_t demand_min = task->DemandMin();
1760 if (demand_min > 0) {
1761 profile_non_unique_time_.emplace_back(
start_max, +demand_min);
1762 profile_non_unique_time_.emplace_back(
end_min, -demand_min);
1767 std::sort(profile_non_unique_time_.begin(), profile_non_unique_time_.end(),
1770 profile_unique_time_.clear();
1773 for (
const ProfileDelta& step : profile_non_unique_time_) {
1774 if (step.time == profile_unique_time_.back().time) {
1775 profile_unique_time_.back().delta += step.delta;
1777 profile_unique_time_.push_back(step);
1780 usage += step.delta;
1785 int64_t max_usage = 0;
1786 for (
const ProfileDelta& step : profile_unique_time_) {
1787 usage += step.delta;
1788 if (usage > max_usage) {
1793 capacity_->SetMin(max_usage);
1800 std::sort(by_start_min_.begin(), by_start_min_.end(),
1801 StartMinLessThan<Task>);
1803 int profile_index = 0;
1804 for (
const Task*
const task : by_start_min_) {
1805 const IntervalVar*
const interval = task->interval;
1810 while (
interval->StartMin() > profile_unique_time_[profile_index].time) {
1811 DCHECK(profile_index < profile_unique_time_.size());
1813 usage += profile_unique_time_[profile_index].delta;
1815 PushTask(task, profile_index, usage);
1823 void PushTask(
const Task*
const task,
int profile_index, int64_t usage) {
1825 const IntervalVar*
const interval = task->interval;
1826 const int64_t demand_min = task->DemandMin();
1827 if (demand_min == 0) {
1830 const int64_t residual_capacity =
CapSub(capacity_->Max(), demand_min);
1831 const int64_t duration = task->interval->DurationMin();
1832 const ProfileDelta& first_prof_delta = profile_unique_time_[profile_index];
1834 int64_t new_start_min =
interval->StartMin();
1838 if (first_prof_delta.time >
interval->StartMin()) {
1847 const int64_t usage_at_start_min =
CapSub(usage, first_prof_delta.delta);
1848 if (usage_at_start_min > residual_capacity) {
1849 new_start_min = profile_unique_time_[profile_index].time;
1857 ProfileDelta delta_end(
end_min, 0);
1859 delta_start.delta = +demand_min;
1860 delta_end.delta = -demand_min;
1862 while (profile_unique_time_[profile_index].
time <
1863 CapAdd(duration, new_start_min)) {
1864 const ProfileDelta& profile_delta = profile_unique_time_[profile_index];
1865 DCHECK(profile_index < profile_unique_time_.size());
1867 if (profile_delta.time == delta_start.time) {
1868 usage -= delta_start.delta;
1870 if (profile_delta.time == delta_end.time) {
1871 usage -= delta_end.delta;
1875 DCHECK(profile_index < profile_unique_time_.size());
1877 if (usage > residual_capacity) {
1878 new_start_min = profile_unique_time_[profile_index].time;
1880 usage += profile_unique_time_[profile_index].delta;
1882 task->interval->SetStartMin(new_start_min);
1885 typedef std::vector<ProfileDelta> Profile;
1887 Profile profile_unique_time_;
1888 Profile profile_non_unique_time_;
1889 std::vector<Task*> by_start_min_;
1890 IntVar*
const capacity_;
1905 template <
class Task>
1906 class TimeTableSync :
public Constraint {
1908 TimeTableSync(Solver*
const solver,
const std::vector<Task*>& tasks,
1910 : Constraint(solver), tasks_(tasks), capacity_(
capacity) {
1911 num_tasks_ = tasks_.size();
1917 start_min_.reserve(num_tasks_);
1918 start_max_.reserve(num_tasks_);
1919 end_min_.reserve(num_tasks_);
1920 durations_.reserve(num_tasks_);
1921 demands_.reserve(num_tasks_);
1926 void InitialPropagate()
override {
1929 while (!events_scp_.empty() && !events_ecp_.empty()) {
1931 pos_ = NextEventTime();
1936 capacity_->SetMin(capacity_->Max() - gap_);
1938 next_pos_ = NextScpTime();
1946 void Post()
override {
1948 solver(),
this, &TimeTableSync::InitialPropagate,
"InitialPropagate");
1949 for (Task*
const task : tasks_) {
1950 task->WhenAnything(demon);
1952 capacity_->WhenRange(demon);
1955 void Accept(ModelVisitor*
const visitor)
const override {
1956 LOG(
FATAL) <<
"Should not be visited";
1959 std::string DebugString()
const override {
return "TimeTableSync"; }
1963 enum State { NONE, READY,
CHECK, CONFLICT };
1965 inline int64_t NextScpTime() {
1966 return !events_scp_.empty() ? events_scp_.top().first
1970 inline int64_t NextEventTime() {
1972 if (!events_pr_.empty()) {
1973 time = events_pr_.top().first;
1975 if (!events_scp_.empty()) {
1976 int64_t t = events_scp_.top().first;
1979 if (!events_ecp_.empty()) {
1980 int64_t t = events_ecp_.top().first;
1986 void ProcessEventsScp() {
1987 while (!events_scp_.empty() && events_scp_.top().first == pos_) {
1988 const int64_t task_id = events_scp_.top().second;
1990 const int64_t old_end_min = end_min_[task_id];
1991 if (states_[task_id] == State::CONFLICT) {
1993 const int64_t new_end_min = pos_ + durations_[task_id];
1994 start_min_[task_id] = pos_;
1995 end_min_[task_id] = new_end_min;
1997 tasks_[task_id]->interval->SetStartMin(pos_);
2000 states_[task_id] = State::READY;
2002 if (pos_ < end_min_[task_id]) {
2003 gap_ -= demands_[task_id];
2004 if (old_end_min <= pos_) {
2005 events_ecp_.push(kv(end_min_[task_id], task_id));
2011 void ProcessEventsEcp() {
2012 while (!events_ecp_.empty() && events_ecp_.top().first == pos_) {
2013 const int64_t task_id = events_ecp_.top().second;
2016 if (pos_ < end_min_[task_id]) {
2017 events_ecp_.push(kv(end_min_[task_id], task_id));
2019 gap_ += demands_[task_id];
2024 void ProcessEventsPr() {
2025 while (!events_pr_.empty() && events_pr_.top().first == pos_) {
2026 const int64_t task_id = events_pr_.top().second;
2029 if (demands_[task_id] > gap_) {
2030 states_[task_id] = State::CONFLICT;
2031 conflict_.push(kv(demands_[task_id], task_id));
2035 if (next_pos_ < end_min_[task_id]) {
2037 check_.push(kv(demands_[task_id], task_id));
2041 states_[task_id] = State::READY;
2047 capacity_->SetMin(capacity_->Max() - gap_);
2049 if (gap_ < prev_gap_) {
2051 while (!check_.empty() && demands_[check_.top().second] > gap_) {
2052 const int64_t task_id = check_.top().second;
2054 if (states_[task_id] ==
State::CHECK && pos_ < end_min_[task_id]) {
2055 states_[task_id] = State::CONFLICT;
2056 conflict_.push(kv(demands_[task_id], task_id));
2059 states_[task_id] = State::READY;
2064 if (gap_ > prev_gap_) {
2066 while (!conflict_.empty() && demands_[conflict_.top().second] <= gap_) {
2067 const int64_t task_id = conflict_.top().second;
2069 if (states_[task_id] != State::CONFLICT) {
2072 const int64_t old_end_min = end_min_[task_id];
2074 start_min_[task_id] = pos_;
2075 end_min_[task_id] = pos_ + durations_[task_id];
2077 tasks_[task_id]->interval->SetStartMin(pos_);
2079 if (next_pos_ < end_min_[task_id]) {
2081 check_.push(kv(demands_[task_id], task_id));
2083 states_[task_id] = State::READY;
2086 const int64_t
start_max = start_max_[task_id];
2088 events_ecp_.push(kv(end_min_[task_id], task_id));
2095 void BuildEvents() {
2099 gap_ = capacity_->Max();
2100 prev_gap_ = capacity_->Max();
2102 conflict_ = min_heap();
2103 check_ = max_heap();
2105 events_pr_ = min_heap();
2106 events_scp_ = min_heap();
2107 events_ecp_ = min_heap();
2116 for (
int i = 0; i < num_tasks_; i++) {
2117 const int64_t s_min = tasks_[i]->interval->StartMin();
2118 const int64_t s_max = tasks_[i]->interval->StartMax();
2119 const int64_t e_min = tasks_[i]->interval->EndMin();
2121 start_min_.push_back(s_min);
2122 start_max_.push_back(s_max);
2123 end_min_.push_back(e_min);
2124 durations_.push_back(tasks_[i]->
interval->DurationMin());
2125 demands_.push_back(tasks_[i]->DemandMin());
2127 states_.push_back(State::NONE);
2129 events_scp_.push(kv(s_max, i));
2131 if (s_min != s_max) {
2132 events_pr_.push(kv(s_min, i));
2135 if (s_max < e_min) {
2136 events_ecp_.push(kv(e_min, i));
2142 std::vector<Task*> tasks_;
2143 IntVar*
const capacity_;
2145 std::vector<int64_t> start_min_;
2146 std::vector<int64_t> start_max_;
2147 std::vector<int64_t> end_min_;
2148 std::vector<int64_t> end_max_;
2149 std::vector<int64_t> durations_;
2150 std::vector<int64_t> demands_;
2153 typedef std::pair<int64_t, int64_t> kv;
2154 typedef std::priority_queue<kv, std::vector<kv>, std::greater<kv>> min_heap;
2155 typedef std::priority_queue<kv, std::vector<kv>, std::less<kv>> max_heap;
2158 min_heap events_pr_;
2159 min_heap events_scp_;
2160 min_heap events_ecp_;
2163 std::vector<State> states_;
2174 class CumulativeConstraint :
public Constraint {
2176 CumulativeConstraint(Solver*
const s,
2177 const std::vector<IntervalVar*>& intervals,
2178 const std::vector<int64_t>& demands,
2182 intervals_(intervals),
2184 tasks_.reserve(intervals.size());
2185 for (
int i = 0; i < intervals.size(); ++i) {
2186 tasks_.push_back(CumulativeTask(intervals[i], demands[i]));
2190 void Post()
override {
2194 const ConstraintSolverParameters& params = solver()->parameters();
2195 if (params.use_cumulative_time_table()) {
2196 if (params.use_cumulative_time_table_sync()) {
2197 PostOneSidedConstraint(
false,
false,
true);
2198 PostOneSidedConstraint(
true,
false,
true);
2200 PostOneSidedConstraint(
false,
false,
false);
2201 PostOneSidedConstraint(
true,
false,
false);
2204 if (params.use_cumulative_edge_finder()) {
2205 PostOneSidedConstraint(
false,
true,
false);
2206 PostOneSidedConstraint(
true,
true,
false);
2208 if (params.use_sequence_high_demand_tasks()) {
2209 PostHighDemandSequenceConstraint();
2211 if (params.use_all_possible_disjunctions()) {
2212 PostAllDisjunctions();
2216 void InitialPropagate()
override {
2220 void Accept(ModelVisitor*
const visitor)
const override {
2222 visitor->BeginVisitConstraint(ModelVisitor::kCumulative,
this);
2223 visitor->VisitIntervalArrayArgument(ModelVisitor::kIntervalsArgument,
2225 visitor->VisitIntegerArrayArgument(ModelVisitor::kDemandsArgument,
2227 visitor->VisitIntegerExpressionArgument(ModelVisitor::kCapacityArgument,
2229 visitor->EndVisitConstraint(ModelVisitor::kCumulative,
this);
2232 std::string DebugString()
const override {
2233 return absl::StrFormat(
"CumulativeConstraint([%s], %s)",
2235 capacity_->DebugString());
2240 void PostAllDisjunctions() {
2241 for (
int i = 0; i < intervals_.size(); ++i) {
2242 IntervalVar*
const interval_i = intervals_[i];
2243 if (interval_i->MayBePerformed()) {
2244 for (
int j = i + 1; j < intervals_.size(); ++j) {
2245 IntervalVar*
const interval_j = intervals_[j];
2246 if (interval_j->MayBePerformed()) {
2248 Constraint*
const constraint =
2249 solver()->MakeTemporalDisjunction(interval_i, interval_j);
2250 solver()->AddConstraint(constraint);
2260 void PostHighDemandSequenceConstraint() {
2261 Constraint* constraint =
nullptr;
2263 std::vector<IntervalVar*> high_demand_intervals;
2264 high_demand_intervals.reserve(intervals_.size());
2265 for (
int i = 0; i < demands_.size(); ++i) {
2266 const int64_t
demand = tasks_[i].demand;
2273 if (
demand * 2 > capacity_->Max() &&
2274 tasks_[i].interval->MayBePerformed()) {
2275 high_demand_intervals.push_back(tasks_[i].
interval);
2278 if (high_demand_intervals.size() >= 2) {
2281 std::string seq_name = absl::StrCat(
name(),
"-HighDemandSequence");
2282 constraint = solver()->MakeDisjunctiveConstraint(high_demand_intervals,
2286 if (constraint !=
nullptr) {
2287 solver()->AddConstraint(constraint);
2293 void PopulateVectorUsefulTasks(
2294 bool mirror, std::vector<CumulativeTask*>*
const useful_tasks) {
2295 DCHECK(useful_tasks->empty());
2296 for (
int i = 0; i < tasks_.size(); ++i) {
2297 const CumulativeTask& original_task = tasks_[i];
2298 IntervalVar*
const interval = original_task.interval;
2300 if (original_task.demand > capacity_->Max()) {
2305 if (
interval->MayBePerformed() && original_task.demand > 0) {
2306 Solver*
const s = solver();
2307 IntervalVar*
const original_interval = original_task.interval;
2309 mirror ? s->MakeMirrorInterval(original_interval)
2310 : original_interval;
2311 IntervalVar*
const relaxed_max = s->MakeIntervalRelaxedMax(
interval);
2312 useful_tasks->push_back(
2313 new CumulativeTask(relaxed_max, original_task.demand));
2320 Constraint* MakeOneSidedConstraint(
bool mirror,
bool edge_finder,
2322 std::vector<CumulativeTask*> useful_tasks;
2323 PopulateVectorUsefulTasks(mirror, &useful_tasks);
2324 if (useful_tasks.empty()) {
2327 Solver*
const s = solver();
2329 const ConstraintSolverParameters& params = solver()->parameters();
2330 return useful_tasks.size() < params.max_edge_finder_size()
2331 ? s->RevAlloc(
new EdgeFinder<CumulativeTask>(s, useful_tasks,
2337 new TimeTableSync<CumulativeTask>(s, useful_tasks, capacity_));
2340 new CumulativeTimeTable<CumulativeTask>(s, useful_tasks, capacity_));
2345 void PostOneSidedConstraint(
bool mirror,
bool edge_finder,
bool tt_sync) {
2346 Constraint*
const constraint =
2347 MakeOneSidedConstraint(mirror, edge_finder, tt_sync);
2348 if (constraint !=
nullptr) {
2349 solver()->AddConstraint(constraint);
2354 IntVar*
const capacity_;
2357 std::vector<CumulativeTask> tasks_;
2360 const std::vector<IntervalVar*> intervals_;
2362 const std::vector<int64_t> demands_;
2367 class VariableDemandCumulativeConstraint :
public Constraint {
2369 VariableDemandCumulativeConstraint(Solver*
const s,
2370 const std::vector<IntervalVar*>& intervals,
2371 const std::vector<IntVar*>& demands,
2373 const std::string&
name)
2376 intervals_(intervals),
2378 tasks_.reserve(intervals.size());
2379 for (
int i = 0; i < intervals.size(); ++i) {
2380 tasks_.push_back(VariableCumulativeTask(intervals[i], demands[i]));
2384 void Post()
override {
2388 const ConstraintSolverParameters& params = solver()->parameters();
2389 if (params.use_cumulative_time_table()) {
2390 PostOneSidedConstraint(
false,
false,
false);
2391 PostOneSidedConstraint(
true,
false,
false);
2393 if (params.use_cumulative_edge_finder()) {
2394 PostOneSidedConstraint(
false,
true,
false);
2395 PostOneSidedConstraint(
true,
true,
false);
2397 if (params.use_sequence_high_demand_tasks()) {
2398 PostHighDemandSequenceConstraint();
2400 if (params.use_all_possible_disjunctions()) {
2401 PostAllDisjunctions();
2405 void InitialPropagate()
override {
2409 void Accept(ModelVisitor*
const visitor)
const override {
2411 visitor->BeginVisitConstraint(ModelVisitor::kCumulative,
this);
2412 visitor->VisitIntervalArrayArgument(ModelVisitor::kIntervalsArgument,
2414 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kDemandsArgument,
2416 visitor->VisitIntegerExpressionArgument(ModelVisitor::kCapacityArgument,
2418 visitor->EndVisitConstraint(ModelVisitor::kCumulative,
this);
2421 std::string DebugString()
const override {
2422 return absl::StrFormat(
"VariableDemandCumulativeConstraint([%s], %s)",
2424 capacity_->DebugString());
2429 void PostAllDisjunctions() {
2430 for (
int i = 0; i < intervals_.size(); ++i) {
2431 IntervalVar*
const interval_i = intervals_[i];
2432 if (interval_i->MayBePerformed()) {
2433 for (
int j = i + 1; j < intervals_.size(); ++j) {
2434 IntervalVar*
const interval_j = intervals_[j];
2435 if (interval_j->MayBePerformed()) {
2436 if (
CapAdd(tasks_[i].
demand->Min(), tasks_[j].demand->Min()) >
2438 Constraint*
const constraint =
2439 solver()->MakeTemporalDisjunction(interval_i, interval_j);
2440 solver()->AddConstraint(constraint);
2450 void PostHighDemandSequenceConstraint() {
2451 Constraint* constraint =
nullptr;
2453 std::vector<IntervalVar*> high_demand_intervals;
2454 high_demand_intervals.reserve(intervals_.size());
2455 for (
int i = 0; i < demands_.size(); ++i) {
2456 const int64_t
demand = tasks_[i].demand->Min();
2463 if (
demand * 2 > capacity_->Max() &&
2464 tasks_[i].interval->MayBePerformed()) {
2465 high_demand_intervals.push_back(tasks_[i].
interval);
2468 if (high_demand_intervals.size() >= 2) {
2471 const std::string seq_name =
2472 absl::StrCat(
name(),
"-HighDemandSequence");
2473 constraint = solver()->MakeStrictDisjunctiveConstraint(
2474 high_demand_intervals, seq_name);
2477 if (constraint !=
nullptr) {
2478 solver()->AddConstraint(constraint);
2484 void PopulateVectorUsefulTasks(
2485 bool mirror, std::vector<VariableCumulativeTask*>*
const useful_tasks) {
2486 DCHECK(useful_tasks->empty());
2487 for (
int i = 0; i < tasks_.size(); ++i) {
2488 const VariableCumulativeTask& original_task = tasks_[i];
2489 IntervalVar*
const interval = original_task.interval;
2491 if (original_task.demand->Min() > capacity_->Max()) {
2496 if (
interval->MayBePerformed() && original_task.demand->Max() > 0) {
2497 Solver*
const s = solver();
2498 IntervalVar*
const original_interval = original_task.interval;
2500 mirror ? s->MakeMirrorInterval(original_interval)
2501 : original_interval;
2502 IntervalVar*
const relaxed_max = s->MakeIntervalRelaxedMax(
interval);
2503 useful_tasks->push_back(
2504 new VariableCumulativeTask(relaxed_max, original_task.demand));
2511 Constraint* MakeOneSidedConstraint(
bool mirror,
bool edge_finder,
2513 std::vector<VariableCumulativeTask*> useful_tasks;
2514 PopulateVectorUsefulTasks(mirror, &useful_tasks);
2515 if (useful_tasks.empty()) {
2518 Solver*
const s = solver();
2521 new EdgeFinder<VariableCumulativeTask>(s, useful_tasks, capacity_));
2524 return s->RevAlloc(
new TimeTableSync<VariableCumulativeTask>(
2525 s, useful_tasks, capacity_));
2527 return s->RevAlloc(
new CumulativeTimeTable<VariableCumulativeTask>(
2528 s, useful_tasks, capacity_));
2533 void PostOneSidedConstraint(
bool mirror,
bool edge_finder,
bool tt_sync) {
2534 Constraint*
const constraint =
2535 MakeOneSidedConstraint(mirror, edge_finder, tt_sync);
2536 if (constraint !=
nullptr) {
2537 solver()->AddConstraint(constraint);
2542 IntVar*
const capacity_;
2545 std::vector<VariableCumulativeTask> tasks_;
2548 const std::vector<IntervalVar*> intervals_;
2550 const std::vector<IntVar*> demands_;
2560 DisjunctiveConstraint::DisjunctiveConstraint(
2561 Solver*
const s,
const std::vector<IntervalVar*>& intervals,
2562 const std::string&
name)
2564 if (!
name.empty()) {
2573 std::function<int64_t(int64_t, int64_t)> transition_time) {
2574 if (transition_time !=
nullptr) {
2584 const std::vector<IntervalVar*>& intervals,
const std::string&
name) {
2585 return RevAlloc(
new FullDisjunctiveConstraint(
this, intervals,
name,
false));
2589 const std::vector<IntervalVar*>& intervals,
const std::string&
name) {
2590 return RevAlloc(
new FullDisjunctiveConstraint(
this, intervals,
name,
true));
2596 const std::vector<int64_t>& demands,
2598 CHECK_EQ(intervals.size(), demands.size());
2599 for (
int i = 0; i < intervals.size(); ++i) {
2605 return RevAlloc(
new CumulativeConstraint(
this, intervals, demands,
2610 const std::vector<int>& demands,
2616 const std::vector<int64_t>& demands,
2618 const std::string&
name) {
2619 CHECK_EQ(intervals.size(), demands.size());
2620 for (
int i = 0; i < intervals.size(); ++i) {
2624 new CumulativeConstraint(
this, intervals, demands,
capacity,
name));
2628 const std::vector<int>& demands,
2630 const std::string&
name) {
2637 const std::vector<IntVar*>& demands,
2639 CHECK_EQ(intervals.size(), demands.size());
2640 for (
int i = 0; i < intervals.size(); ++i) {
2644 std::vector<int64_t> fixed_demands(demands.size());
2645 for (
int i = 0; i < demands.size(); ++i) {
2646 fixed_demands[i] = demands[i]->Value();
2650 return RevAlloc(
new VariableDemandCumulativeConstraint(
2655 const std::vector<IntVar*>& demands,
2657 const std::string&
name) {
2658 CHECK_EQ(intervals.size(), demands.size());
2659 for (
int i = 0; i < intervals.size(); ++i) {
2663 std::vector<int64_t> fixed_demands(demands.size());
2664 for (
int i = 0; i < demands.size(); ++i) {
2665 fixed_demands[i] = demands[i]->Value();
2669 return RevAlloc(
new VariableDemandCumulativeConstraint(
int64_t CapSub(int64_t x, int64_t y)
void SetTransitionTime(Solver::IndexEvaluator2 transition_time)
Add a transition time between intervals.
#define CHECK_GE(val1, val2)
#define VLOG(verboselevel)
int64_t residual_energetic_end_min
int argmax_energetic_end_min_opt
virtual std::string name() const
Object naming.
DisjunctiveConstraint * MakeDisjunctiveConstraint(const std::vector< IntervalVar * > &intervals, const std::string &name)
This constraint forces all interval vars into an non-overlapping sequence.
int64_t CapProd(int64_t x, int64_t y)
A constraint is the main modeling object.
#define DCHECK_GT(val1, val2)
static IntegralType CeilOfRatio(IntegralType numerator, IntegralType denominator)
const Collection::value_type::second_type FindPtrOrNull(const Collection &collection, const typename Collection::value_type::first_type &key)
void STLDeleteValues(T *v)
DisjunctiveConstraint * MakeStrictDisjunctiveConstraint(const std::vector< IntervalVar * > &intervals, const std::string &name)
This constraint forces all interval vars into an non-overlapping sequence.
static const int64_t kNotInitialized
int64_t energetic_end_min
std::vector< int64_t > ToInt64Vector(const std::vector< int > &input)
int64_t CapAdd(int64_t x, int64_t y)
#define DCHECK_NE(val1, val2)
int64_t energetic_end_min_opt
void STLDeleteElements(T *container)
void set_name(const std::string &name)
~DisjunctiveConstraint() override
The class IntVar is a subset of IntExpr.
#define DCHECK_GE(val1, val2)
bool AreAllOnes(const std::vector< T > &values)
#define CHECK_EQ(val1, val2)
std::string JoinDebugString(const std::vector< T > &v, const std::string &separator)
T * RevAlloc(T *object)
Registers the given object as being reversible.
Solver::IndexEvaluator2 transition_time_
#define DCHECK(condition)
bool AreAllBound(const std::vector< IntVar * > &vars)
IntVar * MakeIntConst(int64_t val, const std::string &name)
IntConst will create a constant expression.
#define DCHECK_EQ(val1, val2)
Constraint * MakeCumulative(const std::vector< IntervalVar * > &intervals, const std::vector< int64_t > &demands, int64_t capacity, const std::string &name)
This constraint forces that, for any integer t, the sum of the demands corresponding to an interval c...
#define DCHECK_LE(val1, val2)
static const int64_t kNotAvailable
Collection of objects used to extend the Constraint Solver library.
std::string JoinDebugStringPtr(const std::vector< T > &v, const std::string &separator)
Demon * MakeDelayedConstraintDemon0(Solver *const s, T *const ct, void(T::*method)(), const std::string &name)
#define DCHECK_LT(val1, val2)
#define DISALLOW_COPY_AND_ASSIGN(TypeName)