32 #include "absl/container/flat_hash_map.h"
33 #include "absl/strings/str_cat.h"
34 #include "absl/strings/str_format.h"
35 #include "absl/strings/str_join.h"
57 bool StartMinLessThan(Task*
const w1, Task*
const w2) {
58 return (w1->interval->StartMin() < w2->interval->StartMin());
65 bool ShortestDurationStartMinLessThan(Task*
const w1, Task*
const w2) {
66 return w1->interval->EndMin() - w1->interval->DurationMin() <
67 w2->interval->EndMin() - w2->interval->DurationMin();
71 bool StartMaxLessThan(Task*
const w1, Task*
const w2) {
72 return (w1->interval->StartMax() < w2->interval->StartMax());
76 bool EndMinLessThan(Task*
const w1, Task*
const w2) {
77 return (w1->interval->EndMin() < w2->interval->EndMin());
81 bool EndMaxLessThan(Task*
const w1, Task*
const w2) {
82 return (w1->interval->EndMax() < w2->interval->EndMax());
85 bool IntervalStartMinLessThan(IntervalVar* i1, IntervalVar* i2) {
86 return i1->StartMin() < i2->StartMin();
95 struct DisjunctiveTask {
96 explicit DisjunctiveTask(IntervalVar*
const interval_)
99 std::string DebugString()
const {
return interval->DebugString(); }
110 struct CumulativeTask {
111 CumulativeTask(IntervalVar*
const interval_, int64_t demand_)
114 int64_t EnergyMin()
const {
return interval->DurationMin() *
demand; }
116 int64_t DemandMin()
const {
return demand; }
118 void WhenAnything(Demon*
const demon) {
interval->WhenAnything(demon); }
120 std::string DebugString()
const {
121 return absl::StrFormat(
"Task{ %s, demand: %d }",
interval->DebugString(),
136 struct VariableCumulativeTask {
137 VariableCumulativeTask(IntervalVar*
const interval_, IntVar* demand_)
140 int64_t EnergyMin()
const {
return interval->DurationMin() *
demand->Min(); }
142 int64_t DemandMin()
const {
return demand->Min(); }
144 void WhenAnything(Demon*
const demon) {
149 std::string DebugString()
const {
150 return absl::StrFormat(
"Task{ %s, demand: %s }",
interval->DebugString(),
171 explicit ThetaNode(
const IntervalVar*
const interval)
184 void Compute(
const ThetaNode& left,
const ThetaNode& right) {
190 bool IsIdentity()
const {
195 std::string DebugString()
const {
211 class ThetaTree :
public MonoidOperationTree<ThetaNode> {
213 explicit ThetaTree(
int size) : MonoidOperationTree<ThetaNode>(size) {}
215 int64_t Ect()
const {
return result().total_ect; }
217 void Insert(
const DisjunctiveTask*
const task) {
218 Set(task->index, ThetaNode(task->interval));
221 void Remove(
const DisjunctiveTask*
const task) { Reset(task->index); }
223 bool IsInserted(
const DisjunctiveTask*
const task)
const {
224 return !GetOperand(task->index).IsIdentity();
234 struct LambdaThetaNode {
248 LambdaThetaNode(int64_t
capacity,
const CumulativeTask& task)
249 :
energy(task.EnergyMin()),
257 LambdaThetaNode(int64_t
capacity,
const CumulativeTask& task,
int index)
269 LambdaThetaNode(int64_t
capacity,
const VariableCumulativeTask& task)
270 :
energy(task.EnergyMin()),
278 LambdaThetaNode(int64_t
capacity,
const VariableCumulativeTask& task,
291 explicit LambdaThetaNode(
const IntervalVar*
const interval)
301 LambdaThetaNode(
const IntervalVar*
const interval,
int index)
318 void Compute(
const LambdaThetaNode& left,
const LambdaThetaNode& right) {
321 CapAdd(left.energetic_end_min, right.energy));
322 const int64_t energy_left_opt =
CapAdd(left.energy_opt, right.energy);
323 const int64_t energy_right_opt =
CapAdd(left.energy, right.energy_opt);
324 if (energy_left_opt > energy_right_opt) {
331 const int64_t ect1 = right.energetic_end_min_opt;
332 const int64_t ect2 =
CapAdd(left.energetic_end_min, right.energy_opt);
333 const int64_t ect3 =
CapAdd(left.energetic_end_min_opt, right.energy);
334 if (ect1 >= ect2 && ect1 >= ect3) {
337 }
else if (ect2 >= ect1 && ect2 >= ect3) {
379 class DisjunctiveLambdaThetaTree :
public MonoidOperationTree<LambdaThetaNode> {
381 explicit DisjunctiveLambdaThetaTree(
int size)
382 : MonoidOperationTree<LambdaThetaNode>(size) {}
384 void Insert(
const DisjunctiveTask& task) {
385 Set(task.index, LambdaThetaNode(task.interval));
388 void Grey(
const DisjunctiveTask& task) {
389 const int index = task.index;
390 Set(
index, LambdaThetaNode(task.interval,
index));
393 int64_t Ect()
const {
return result().energetic_end_min; }
394 int64_t EctOpt()
const {
return result().energetic_end_min_opt; }
395 int ResponsibleOpt()
const {
return result().argmax_energetic_end_min_opt; }
399 class CumulativeLambdaThetaTree :
public MonoidOperationTree<LambdaThetaNode> {
401 CumulativeLambdaThetaTree(
int size, int64_t capacity_max)
402 : MonoidOperationTree<LambdaThetaNode>(size),
403 capacity_max_(capacity_max) {}
405 void Init(int64_t capacity_max) {
407 capacity_max_ = capacity_max;
410 void Insert(
const CumulativeTask& task) {
411 Set(task.index, LambdaThetaNode(capacity_max_, task));
414 void Grey(
const CumulativeTask& task) {
415 const int index = task.index;
416 Set(
index, LambdaThetaNode(capacity_max_, task,
index));
419 void Insert(
const VariableCumulativeTask& task) {
420 Set(task.index, LambdaThetaNode(capacity_max_, task));
423 void Grey(
const VariableCumulativeTask& task) {
424 const int index = task.index;
425 Set(
index, LambdaThetaNode(capacity_max_, task,
index));
430 return result().energetic_end_min_opt;
432 int64_t Ect()
const {
435 int64_t EctOpt()
const {
439 return result().argmax_energetic_end_min_opt;
443 int64_t capacity_max_;
452 NotLast(Solver*
const solver,
const std::vector<IntervalVar*>& intervals,
453 bool mirror,
bool strict);
460 ThetaTree theta_tree_;
461 std::vector<DisjunctiveTask*> by_start_min_;
462 std::vector<DisjunctiveTask*> by_end_max_;
463 std::vector<DisjunctiveTask*> by_start_max_;
464 std::vector<int64_t> new_lct_;
468 NotLast::NotLast(Solver*
const solver,
469 const std::vector<IntervalVar*>& intervals,
bool mirror,
471 : theta_tree_(intervals.size()),
472 by_start_min_(intervals.size()),
473 by_end_max_(intervals.size()),
474 by_start_max_(intervals.size()),
475 new_lct_(intervals.size(), -1LL),
478 for (
int i = 0; i < intervals.size(); ++i) {
479 IntervalVar*
const underlying =
480 mirror ? solver->MakeMirrorInterval(intervals[i]) : intervals[i];
481 IntervalVar*
const relaxed = solver->MakeIntervalRelaxedMin(underlying);
482 by_start_min_[i] =
new DisjunctiveTask(relaxed);
483 by_end_max_[i] = by_start_min_[i];
484 by_start_max_[i] = by_start_min_[i];
488 bool NotLast::Propagate() {
490 std::sort(by_start_max_.begin(), by_start_max_.end(),
491 StartMaxLessThan<DisjunctiveTask>);
492 std::sort(by_end_max_.begin(), by_end_max_.end(),
493 EndMaxLessThan<DisjunctiveTask>);
495 std::sort(by_start_min_.begin(), by_start_min_.end(),
496 StartMinLessThan<DisjunctiveTask>);
497 for (
int i = 0; i < by_start_min_.size(); ++i) {
498 by_start_min_[i]->index = i;
501 for (
int i = 0; i < by_start_min_.size(); ++i) {
502 new_lct_[i] = by_start_min_[i]->interval->EndMax();
507 for (DisjunctiveTask*
const twi : by_end_max_) {
508 while (j < by_start_max_.size() &&
509 twi->interval->EndMax() > by_start_max_[j]->interval->StartMax()) {
510 if (j > 0 && theta_tree_.Ect() > by_start_max_[j]->interval->StartMax()) {
511 const int64_t new_end_max = by_start_max_[j - 1]->interval->StartMax();
512 new_lct_[by_start_max_[j]->index] =
515 theta_tree_.Insert(by_start_max_[j]);
518 const bool inserted = theta_tree_.IsInserted(twi);
520 theta_tree_.Remove(twi);
522 const int64_t ect_theta_less_i = theta_tree_.Ect();
524 theta_tree_.Insert(twi);
527 if (ect_theta_less_i > twi->interval->StartMax() && j > 0) {
528 const int64_t new_end_max = by_start_max_[j - 1]->interval->StartMax();
529 if (new_end_max < new_lct_[twi->index]) {
530 new_lct_[twi->index] = new_end_max;
536 bool modified =
false;
537 for (
int i = 0; i < by_start_min_.size(); ++i) {
538 IntervalVar*
const var = by_start_min_[i]->interval;
539 if ((strict_ ||
var->DurationMin() > 0) &&
var->EndMax() > new_lct_[i]) {
541 var->SetEndMax(new_lct_[i]);
552 class EdgeFinderAndDetectablePrecedences {
554 EdgeFinderAndDetectablePrecedences(Solver*
const solver,
555 const std::vector<IntervalVar*>& intervals,
556 bool mirror,
bool strict);
557 ~EdgeFinderAndDetectablePrecedences() {
560 int64_t size()
const {
return by_start_min_.size(); }
563 void OverloadChecking();
564 bool DetectablePrecedences();
568 Solver*
const solver_;
579 ThetaTree theta_tree_;
580 std::vector<DisjunctiveTask*> by_end_min_;
581 std::vector<DisjunctiveTask*> by_start_min_;
582 std::vector<DisjunctiveTask*> by_end_max_;
583 std::vector<DisjunctiveTask*> by_start_max_;
585 std::vector<int64_t> new_est_;
587 std::vector<int64_t> new_lct_;
588 DisjunctiveLambdaThetaTree lt_tree_;
592 EdgeFinderAndDetectablePrecedences::EdgeFinderAndDetectablePrecedences(
593 Solver*
const solver,
const std::vector<IntervalVar*>& intervals,
594 bool mirror,
bool strict)
596 theta_tree_(intervals.size()),
597 lt_tree_(intervals.size()),
600 for (IntervalVar*
const interval : intervals) {
601 IntervalVar*
const underlying =
603 IntervalVar*
const relaxed = solver->MakeIntervalRelaxedMax(underlying);
604 DisjunctiveTask*
const task =
new DisjunctiveTask(relaxed);
605 by_end_min_.push_back(task);
606 by_start_min_.push_back(task);
607 by_end_max_.push_back(task);
608 by_start_max_.push_back(task);
613 void EdgeFinderAndDetectablePrecedences::UpdateEst() {
614 std::sort(by_start_min_.begin(), by_start_min_.end(),
615 ShortestDurationStartMinLessThan<DisjunctiveTask>);
616 for (
int i = 0; i < size(); ++i) {
617 by_start_min_[i]->index = i;
621 void EdgeFinderAndDetectablePrecedences::OverloadChecking() {
624 std::sort(by_end_max_.begin(), by_end_max_.end(),
625 EndMaxLessThan<DisjunctiveTask>);
628 for (DisjunctiveTask*
const task : by_end_max_) {
629 theta_tree_.Insert(task);
630 if (theta_tree_.Ect() > task->interval->EndMax()) {
636 bool EdgeFinderAndDetectablePrecedences::DetectablePrecedences() {
642 std::sort(by_end_min_.begin(), by_end_min_.end(),
643 EndMinLessThan<DisjunctiveTask>);
644 std::sort(by_start_max_.begin(), by_start_max_.end(),
645 StartMaxLessThan<DisjunctiveTask>);
648 for (DisjunctiveTask*
const task_i : by_end_min_) {
650 DisjunctiveTask* task_j = by_start_max_[j];
651 while (task_i->interval->EndMin() > task_j->interval->StartMax()) {
652 theta_tree_.Insert(task_j);
654 if (j == size())
break;
655 task_j = by_start_max_[j];
658 const int64_t esti = task_i->interval->StartMin();
659 bool inserted = theta_tree_.IsInserted(task_i);
661 theta_tree_.Remove(task_i);
663 const int64_t oesti = theta_tree_.Ect();
665 theta_tree_.Insert(task_i);
668 new_est_[task_i->index] = oesti;
675 bool modified =
false;
676 for (
int i = 0; i < size(); ++i) {
677 IntervalVar*
const var = by_start_min_[i]->interval;
679 (strict_ ||
var->DurationMin() > 0)) {
681 by_start_min_[i]->interval->SetStartMin(new_est_[i]);
687 bool EdgeFinderAndDetectablePrecedences::EdgeFinder() {
690 for (
int i = 0; i < size(); ++i) {
691 new_est_[i] = by_start_min_[i]->interval->StartMin();
695 std::sort(by_end_max_.begin(), by_end_max_.end(),
696 EndMaxLessThan<DisjunctiveTask>);
698 for (
int i = 0; i < size(); ++i) {
699 lt_tree_.Insert(*by_start_min_[i]);
700 DCHECK_EQ(i, by_start_min_[i]->
index);
702 for (
int j = size() - 2; j >= 0; --j) {
703 lt_tree_.Grey(*by_end_max_[j + 1]);
704 DisjunctiveTask*
const twj = by_end_max_[j];
706 DCHECK_LE(lt_tree_.Ect(), twj->interval->EndMax());
707 while (lt_tree_.EctOpt() > twj->interval->EndMax()) {
708 const int i = lt_tree_.ResponsibleOpt();
710 if (lt_tree_.Ect() > new_est_[i]) {
711 new_est_[i] = lt_tree_.Ect();
718 bool modified =
false;
719 for (
int i = 0; i < size(); ++i) {
720 IntervalVar*
const var = by_start_min_[i]->interval;
721 if (
var->StartMin() < new_est_[i] && (strict_ ||
var->DurationMin() > 0)) {
723 var->SetStartMin(new_est_[i]);
733 class RankedPropagator :
public Constraint {
735 RankedPropagator(Solver*
const solver,
const std::vector<IntVar*>& nexts,
736 const std::vector<IntervalVar*>& intervals,
737 const std::vector<IntVar*>& slacks,
738 DisjunctiveConstraint*
const disjunctive)
739 : Constraint(solver),
741 intervals_(intervals),
743 disjunctive_(disjunctive),
744 partial_sequence_(intervals.size()),
745 previous_(intervals.size() + 2, 0) {}
747 ~RankedPropagator()
override {}
749 void Post()
override {
750 Demon*
const delayed =
751 solver()->MakeDelayedConstraintInitialPropagateCallback(
this);
752 for (
int i = 0; i < intervals_.size(); ++i) {
753 nexts_[i]->WhenBound(delayed);
754 intervals_[i]->WhenAnything(delayed);
755 slacks_[i]->WhenRange(delayed);
757 nexts_.back()->WhenBound(delayed);
760 void InitialPropagate()
override {
765 void PropagateNexts() {
766 Solver*
const s = solver();
767 const int ranked_first = partial_sequence_.NumFirstRanked();
768 const int ranked_last = partial_sequence_.NumLastRanked();
772 : partial_sequence_[intervals_.size() - ranked_last] + 1;
775 while (nexts_[first]->Bound()) {
776 DCHECK_NE(first, nexts_[first]->Min());
777 first = nexts_[first]->Min();
778 if (first == sentinel) {
781 if (++counter > ranked_first) {
782 DCHECK(intervals_[first - 1]->MayBePerformed());
783 partial_sequence_.RankFirst(s, first - 1);
784 VLOG(2) <<
"RankFirst " << first - 1 <<
" -> "
785 << partial_sequence_.DebugString();
788 previous_.assign(previous_.size(), -1);
789 for (
int i = 0; i < nexts_.size(); ++i) {
790 if (nexts_[i]->Bound()) {
791 previous_[nexts_[i]->Min()] = i;
794 int last = previous_.size() - 1;
796 while (previous_[last] != -1) {
797 last = previous_[last];
798 if (++counter > ranked_last) {
799 partial_sequence_.RankLast(s, last - 1);
800 VLOG(2) <<
"RankLast " << last - 1 <<
" -> "
801 << partial_sequence_.DebugString();
806 void PropagateSequence() {
807 const int last_position = intervals_.size() - 1;
808 const int first_sentinel = partial_sequence_.NumFirstRanked();
809 const int last_sentinel = last_position - partial_sequence_.NumLastRanked();
811 for (
int i = 0; i < first_sentinel - 1; ++i) {
812 IntervalVar*
const interval = RankedInterval(i);
813 IntervalVar*
const next_interval = RankedInterval(i + 1);
814 IntVar*
const slack = RankedSlack(i);
815 const int64_t transition_time = RankedTransitionTime(i, i + 1);
816 next_interval->SetStartRange(
821 for (
int i = last_position; i > last_sentinel + 1; --i) {
822 IntervalVar*
const interval = RankedInterval(i - 1);
823 IntervalVar*
const next_interval = RankedInterval(i);
824 IntVar*
const slack = RankedSlack(i - 1);
825 const int64_t transition_time = RankedTransitionTime(i - 1, i);
827 CapAdd(slack->Max(), transition_time)),
828 CapSub(next_interval->StartMax(),
829 CapAdd(slack->Min(), transition_time)));
832 IntervalVar*
const first_interval =
833 first_sentinel > 0 ? RankedInterval(first_sentinel - 1) : nullptr;
834 IntVar*
const first_slack =
835 first_sentinel > 0 ? RankedSlack(first_sentinel - 1) : nullptr;
836 IntervalVar*
const last_interval = last_sentinel < last_position
837 ? RankedInterval(last_sentinel + 1)
841 if (first_interval ==
nullptr && last_interval ==
nullptr) {
846 for (
int i = first_sentinel; i <= last_sentinel; ++i) {
847 IntervalVar*
const interval = RankedInterval(i);
848 IntVar*
const slack = RankedSlack(i);
851 if (first_interval !=
nullptr) {
852 const int64_t transition_time =
853 RankedTransitionTime(first_sentinel - 1, i);
855 CapAdd(first_interval->StartMin(),
856 CapAdd(first_slack->Min(), transition_time)),
857 CapAdd(first_interval->StartMax(),
858 CapAdd(first_slack->Max(), transition_time)));
860 first_interval->SetStartRange(
862 CapAdd(first_slack->Max(), transition_time)),
864 CapAdd(first_slack->Min(), transition_time)));
867 if (last_interval !=
nullptr) {
868 const int64_t transition_time =
869 RankedTransitionTime(i, last_sentinel + 1);
871 CapSub(last_interval->StartMin(),
872 CapAdd(slack->Max(), transition_time)),
873 CapSub(last_interval->StartMax(),
874 CapAdd(slack->Min(), transition_time)));
876 last_interval->SetStartRange(
878 CapAdd(slack->Min(), transition_time)),
880 CapAdd(slack->Max(), transition_time)));
887 for (
int i =
std::min(first_sentinel - 2, last_position - 1); i >= 0; --i) {
888 IntervalVar*
const interval = RankedInterval(i);
889 IntervalVar*
const next_interval = RankedInterval(i + 1);
890 IntVar*
const slack = RankedSlack(i);
891 const int64_t transition_time = RankedTransitionTime(i, i + 1);
893 CapAdd(slack->Max(), transition_time)),
894 CapSub(next_interval->StartMax(),
895 CapAdd(slack->Min(), transition_time)));
898 for (
int i = last_sentinel + 1; i < last_position - 1; ++i) {
899 IntervalVar*
const interval = RankedInterval(i);
900 IntervalVar*
const next_interval = RankedInterval(i + 1);
901 IntVar*
const slack = RankedSlack(i);
902 const int64_t transition_time = RankedTransitionTime(i, i + 1);
903 next_interval->SetStartRange(
910 IntervalVar* RankedInterval(
int i)
const {
911 const int index = partial_sequence_[i];
912 return intervals_[
index];
915 IntVar* RankedSlack(
int i)
const {
916 const int index = partial_sequence_[i];
917 return slacks_[
index];
920 int64_t RankedTransitionTime(
int before,
int after)
const {
921 const int before_index = partial_sequence_[before];
922 const int after_index = partial_sequence_[after];
924 return disjunctive_->TransitionTime(before_index, after_index);
927 std::string DebugString()
const override {
928 return absl::StrFormat(
929 "RankedPropagator([%s], nexts = [%s], intervals = [%s])",
934 void Accept(ModelVisitor*
const visitor)
const override {
935 LOG(FATAL) <<
"Not yet implemented";
940 std::vector<IntVar*> nexts_;
941 std::vector<IntervalVar*> intervals_;
942 std::vector<IntVar*> slacks_;
943 DisjunctiveConstraint*
const disjunctive_;
944 RevPartialSequence partial_sequence_;
945 std::vector<int> previous_;
951 class FullDisjunctiveConstraint :
public DisjunctiveConstraint {
953 FullDisjunctiveConstraint(Solver*
const s,
954 const std::vector<IntervalVar*>& intervals,
955 const std::string&
name,
bool strict)
956 : DisjunctiveConstraint(s, intervals,
name),
957 sequence_var_(nullptr),
958 straight_(s, intervals, false, strict),
959 mirror_(s, intervals, true, strict),
960 straight_not_last_(s, intervals, false, strict),
961 mirror_not_last_(s, intervals, true, strict),
964 ~FullDisjunctiveConstraint()
override {}
966 void Post()
override {
968 solver(),
this, &FullDisjunctiveConstraint::InitialPropagate,
970 for (int32_t i = 0; i < straight_.size(); ++i) {
971 straight_.interval(i)->WhenAnything(d);
975 void InitialPropagate()
override {
976 bool all_optional_or_unperformed =
true;
977 for (
const IntervalVar*
const interval : intervals_) {
979 all_optional_or_unperformed =
false;
983 if (all_optional_or_unperformed) {
987 bool all_times_fixed =
true;
988 for (
const IntervalVar*
const interval : intervals_) {
993 all_times_fixed =
false;
998 if (all_times_fixed) {
999 PropagatePerformed();
1006 straight_.OverloadChecking();
1007 }
while (straight_.DetectablePrecedences() ||
1008 mirror_.DetectablePrecedences());
1009 }
while (straight_not_last_.Propagate() ||
1010 mirror_not_last_.Propagate());
1011 }
while (straight_.EdgeFinder() || mirror_.EdgeFinder());
1015 bool Intersect(IntervalVar*
const i1, IntervalVar*
const i2)
const {
1016 return i1->StartMin() < i2->EndMax() && i2->StartMin() < i1->EndMax();
1019 void PropagatePerformed() {
1022 for (IntervalVar*
const interval : intervals_) {
1025 }
else if (
interval->MayBePerformed()) {
1030 if (performed_.empty())
return;
1031 std::sort(performed_.begin(), performed_.end(), IntervalStartMinLessThan);
1032 for (
int i = 0; i < performed_.size() - 1; ++i) {
1033 if (performed_[i]->EndMax() > performed_[i + 1]->StartMin()) {
1039 if (optional_.empty())
return;
1041 const int num_performed = performed_.size();
1042 std::sort(optional_.begin(), optional_.end(), IntervalStartMinLessThan);
1043 for (IntervalVar*
const candidate : optional_) {
1044 const int64_t
start = candidate->StartMin();
1045 while (index < num_performed && start >= performed_[
index]->EndMax()) {
1048 if (
index == num_performed)
return;
1049 if (Intersect(candidate, performed_[
index]) ||
1050 (
index < num_performed - 1 &&
1051 Intersect(candidate, performed_[
index + 1]))) {
1052 candidate->SetPerformed(
false);
1057 void Accept(ModelVisitor*
const visitor)
const override {
1058 visitor->BeginVisitConstraint(ModelVisitor::kDisjunctive,
this);
1059 visitor->VisitIntervalArrayArgument(ModelVisitor::kIntervalsArgument,
1061 if (sequence_var_ !=
nullptr) {
1062 visitor->VisitSequenceArgument(ModelVisitor::kSequenceArgument,
1065 visitor->EndVisitConstraint(ModelVisitor::kDisjunctive,
this);
1068 SequenceVar* MakeSequenceVar()
override {
1069 BuildNextModelIfNeeded();
1070 if (sequence_var_ ==
nullptr) {
1071 solver()->SaveValue(
reinterpret_cast<void**
>(&sequence_var_));
1072 sequence_var_ = solver()->RevAlloc(
1073 new SequenceVar(solver(), intervals_, nexts_,
name()));
1075 return sequence_var_;
1078 std::string DebugString()
const override {
1079 return absl::StrFormat(
"FullDisjunctiveConstraint([%s], %i)",
1083 const std::vector<IntVar*>& nexts()
const override {
return nexts_; }
1085 const std::vector<IntVar*>& actives()
const override {
return actives_; }
1087 const std::vector<IntVar*>& time_cumuls()
const override {
1088 return time_cumuls_;
1091 const std::vector<IntVar*>& time_slacks()
const override {
1092 return time_slacks_;
1096 int64_t
Distance(int64_t activity_plus_one, int64_t next_activity_plus_one) {
1097 return (activity_plus_one == 0 ||
1098 next_activity_plus_one > intervals_.size())
1100 : transition_time_(activity_plus_one - 1,
1101 next_activity_plus_one - 1);
1104 void BuildNextModelIfNeeded() {
1105 if (!nexts_.empty()) {
1108 Solver*
const s = solver();
1109 const std::string& ct_name =
name();
1110 const int num_intervals = intervals_.size();
1111 const int num_nodes = intervals_.size() + 1;
1112 int64_t horizon = 0;
1113 for (
int i = 0; i < intervals_.size(); ++i) {
1114 if (intervals_[i]->MayBePerformed()) {
1115 horizon =
std::max(horizon, intervals_[i]->EndMax());
1120 s->MakeIntVarArray(num_nodes, 1, num_nodes, ct_name +
"_nexts", &nexts_);
1122 s->AddConstraint(s->MakeAllDifferent(nexts_));
1124 actives_.resize(num_nodes);
1125 for (
int i = 0; i < num_intervals; ++i) {
1126 actives_[i + 1] = intervals_[i]->PerformedExpr()->Var();
1128 s->MakeIsDifferentCstCt(nexts_[i + 1], i + 1, actives_[i + 1]));
1130 std::vector<IntVar*> short_actives(actives_.begin() + 1, actives_.end());
1131 actives_[0] = s->MakeMax(short_actives)->Var();
1134 s->AddConstraint(s->MakeNoCycle(nexts_, actives_));
1137 time_cumuls_.resize(num_nodes + 1);
1139 time_slacks_.resize(num_nodes);
1141 time_slacks_[0] = s->MakeIntVar(0, horizon,
"initial_slack");
1143 time_cumuls_[0] = s->MakeIntConst(0);
1145 for (int64_t i = 0; i < num_intervals; ++i) {
1146 IntervalVar*
const var = intervals_[i];
1147 if (
var->MayBePerformed()) {
1148 const int64_t duration_min =
var->DurationMin();
1149 time_slacks_[i + 1] = s->MakeIntVar(
1150 duration_min, horizon, absl::StrFormat(
"time_slacks(%d)", i + 1));
1152 time_cumuls_[i + 1] =
var->SafeStartExpr(
var->StartMin())->Var();
1153 if (
var->DurationMax() != duration_min) {
1154 s->AddConstraint(s->MakeGreaterOrEqual(
1155 time_slacks_[i + 1],
var->SafeDurationExpr(duration_min)));
1158 time_slacks_[i + 1] = s->MakeIntVar(
1159 0, horizon, absl::StrFormat(
"time_slacks(%d)", i + 1));
1160 time_cumuls_[i + 1] = s->MakeIntConst(horizon);
1164 time_cumuls_[num_nodes] = s->MakeIntVar(0, 2 * horizon, ct_name +
"_ect");
1165 s->AddConstraint(s->MakePathCumul(
1166 nexts_, actives_, time_cumuls_, time_slacks_,
1167 [
this](int64_t x, int64_t y) { return Distance(x, y); }));
1169 std::vector<IntVar*> short_slacks(time_slacks_.begin() + 1,
1170 time_slacks_.end());
1171 s->AddConstraint(s->RevAlloc(
1172 new RankedPropagator(s, nexts_, intervals_, short_slacks,
this)));
1175 SequenceVar* sequence_var_;
1176 EdgeFinderAndDetectablePrecedences straight_;
1177 EdgeFinderAndDetectablePrecedences mirror_;
1178 NotLast straight_not_last_;
1179 NotLast mirror_not_last_;
1180 std::vector<IntVar*> nexts_;
1181 std::vector<IntVar*> actives_;
1182 std::vector<IntVar*> time_cumuls_;
1183 std::vector<IntVar*> time_slacks_;
1184 std::vector<IntervalVar*> performed_;
1185 std::vector<IntervalVar*> optional_;
1196 struct DualCapacityThetaNode {
1198 static const int kNone;
1201 DualCapacityThetaNode()
1207 DualCapacityThetaNode(int64_t
capacity, int64_t residual_capacity,
1208 const CumulativeTask& task)
1209 :
energy(task.EnergyMin()),
1215 DualCapacityThetaNode(int64_t
capacity, int64_t residual_capacity,
1216 const VariableCumulativeTask& task)
1217 :
energy(task.EnergyMin()),
1228 void Compute(
const DualCapacityThetaNode& left,
1229 const DualCapacityThetaNode& right) {
1232 right.energetic_end_min);
1235 right.residual_energetic_end_min);
1252 class DualCapacityThetaTree
1253 :
public MonoidOperationTree<DualCapacityThetaNode> {
1257 explicit DualCapacityThetaTree(
int size)
1258 : MonoidOperationTree<DualCapacityThetaNode>(size),
1260 residual_capacity_(-1) {}
1262 virtual ~DualCapacityThetaTree() {}
1264 void Init(int64_t capacity_max, int64_t residual_capacity) {
1265 DCHECK_LE(0, residual_capacity);
1266 DCHECK_LE(residual_capacity, capacity_max);
1268 capacity_max_ = capacity_max;
1269 residual_capacity_ = residual_capacity;
1272 void Insert(
const CumulativeTask* task) {
1274 DualCapacityThetaNode(capacity_max_, residual_capacity_, *task));
1277 void Insert(
const VariableCumulativeTask* task) {
1279 DualCapacityThetaNode(capacity_max_, residual_capacity_, *task));
1283 int64_t capacity_max_;
1284 int64_t residual_capacity_;
1300 class EnvJCComputeDiver {
1303 explicit EnvJCComputeDiver(
int energy_threshold)
1304 : energy_threshold_(energy_threshold),
1307 void OnArgumentReached(
int index,
const DualCapacityThetaNode& argument) {
1308 energy_alpha_ = argument.energy;
1309 energetic_end_min_alpha_ = argument.energetic_end_min;
1314 bool ChooseGoLeft(
const DualCapacityThetaNode& current,
1315 const DualCapacityThetaNode& left_child,
1317 if (
right_child.residual_energetic_end_min > energy_threshold_) {
1324 void OnComeBackFromLeft(
const DualCapacityThetaNode& current,
1325 const DualCapacityThetaNode& left_child,
1332 void OnComeBackFromRight(
const DualCapacityThetaNode& current,
1333 const DualCapacityThetaNode& left_child,
1337 energetic_end_min_alpha_ =
1339 CapAdd(left_child.energetic_end_min, energy_alpha_));
1340 energy_alpha_ += left_child.energy;
1342 int64_t GetEnvJC(
const DualCapacityThetaNode& root)
const {
1343 const int64_t
energy = root.energy;
1344 const int64_t energy_beta =
CapSub(
energy, energy_alpha_);
1345 return CapAdd(energetic_end_min_alpha_, energy_beta);
1354 int64_t energy_threshold_;
1360 int64_t energy_alpha_;
1365 int64_t energetic_end_min_alpha_;
1377 class UpdatesForADemand {
1379 explicit UpdatesForADemand(
int size)
1380 : updates_(size, 0), up_to_date_(false) {}
1382 const int64_t Update(
int index) {
return updates_[
index]; }
1383 void Reset() { up_to_date_ =
false; }
1384 void SetUpdate(
int index, int64_t update) {
1385 DCHECK(!up_to_date_);
1386 DCHECK_LT(
index, updates_.size());
1387 updates_[
index] = update;
1389 bool up_to_date()
const {
return up_to_date_; }
1390 void set_up_to_date() { up_to_date_ =
true; }
1393 std::vector<int64_t> updates_;
1399 template <
class Task>
1400 class EdgeFinder :
public Constraint {
1402 EdgeFinder(Solver*
const solver,
const std::vector<Task*>& tasks,
1404 : Constraint(solver),
1407 by_start_min_(tasks.size()),
1408 by_end_max_(tasks.size()),
1409 by_end_min_(tasks.size()),
1410 lt_tree_(tasks.size(), capacity_->Max()),
1411 dual_capacity_tree_(tasks.size()),
1412 has_zero_demand_tasks_(true) {}
1414 ~EdgeFinder()
override {
1419 void Post()
override {
1422 solver(),
this, &EdgeFinder::InitialPropagate,
"RangeChanged");
1423 for (Task*
const task : tasks_) {
1426 task->WhenAnything(demon);
1428 capacity_->WhenRange(demon);
1433 void InitialPropagate()
override {
1435 PropagateBasedOnEndMinGreaterThanEndMax();
1437 PropagateBasedOnEnergy();
1441 void Accept(ModelVisitor*
const visitor)
const override {
1442 LOG(FATAL) <<
"Should Not Be Visited";
1445 std::string DebugString()
const override {
return "EdgeFinder"; }
1448 UpdatesForADemand* GetOrMakeUpdate(int64_t demand_min) {
1450 if (update ==
nullptr) {
1451 update =
new UpdatesForADemand(tasks_.size());
1452 update_map_[demand_min] = update;
1458 void InitPropagation() {
1460 start_min_update_.clear();
1462 if (has_zero_demand_tasks_.Value()) {
1463 by_start_min_.clear();
1464 by_end_min_.clear();
1465 by_end_max_.clear();
1467 bool zero_demand =
false;
1468 for (Task*
const task : tasks_) {
1469 if (task->DemandMin() > 0) {
1470 by_start_min_.push_back(task);
1471 by_end_min_.push_back(task);
1472 by_end_max_.push_back(task);
1478 has_zero_demand_tasks_.SetValue(solver(),
false);
1483 std::sort(by_start_min_.begin(), by_start_min_.end(),
1484 StartMinLessThan<Task>);
1485 for (
int i = 0; i < by_start_min_.size(); ++i) {
1486 by_start_min_[i]->index = i;
1489 std::sort(by_end_max_.begin(), by_end_max_.end(), EndMaxLessThan<Task>);
1491 std::sort(by_end_min_.begin(), by_end_min_.end(), EndMinLessThan<Task>);
1493 lt_tree_.Init(capacity_->Max());
1495 for (
const auto& entry : update_map_) {
1496 entry.second->Reset();
1504 void ComputeConditionalStartMins(UpdatesForADemand* updates,
1505 int64_t demand_min) {
1506 DCHECK_GT(demand_min, 0);
1507 DCHECK(updates !=
nullptr);
1508 const int64_t capacity_max = capacity_->Max();
1509 const int64_t residual_capacity =
CapSub(capacity_max, demand_min);
1510 dual_capacity_tree_.Init(capacity_max, residual_capacity);
1515 int64_t update = IntervalVar::kMinValidValue;
1516 for (
int i = 0; i < by_end_max_.size(); ++i) {
1517 Task*
const task = by_end_max_[i];
1518 if (task->EnergyMin() == 0)
continue;
1519 const int64_t current_end_max = task->interval->EndMax();
1520 dual_capacity_tree_.Insert(task);
1521 const int64_t energy_threshold = residual_capacity * current_end_max;
1522 const DualCapacityThetaNode& root = dual_capacity_tree_.result();
1523 const int64_t res_energetic_end_min = root.residual_energetic_end_min;
1524 if (res_energetic_end_min > energy_threshold) {
1525 EnvJCComputeDiver diver(energy_threshold);
1526 dual_capacity_tree_.DiveInTree(&diver);
1527 const int64_t enjv = diver.GetEnvJC(dual_capacity_tree_.result());
1528 const int64_t numerator =
CapSub(enjv, energy_threshold);
1532 updates->SetUpdate(i, update);
1534 updates->set_up_to_date();
1539 int64_t ConditionalStartMin(
const Task& task_to_push,
int end_max_index) {
1540 if (task_to_push.EnergyMin() == 0) {
1541 return task_to_push.interval->StartMin();
1543 const int64_t demand_min = task_to_push.DemandMin();
1544 UpdatesForADemand*
const updates = GetOrMakeUpdate(demand_min);
1545 if (!updates->up_to_date()) {
1546 ComputeConditionalStartMins(updates, demand_min);
1548 DCHECK(updates->up_to_date());
1549 return updates->Update(end_max_index);
1557 void PropagateBasedOnEndMinGreaterThanEndMax() {
1558 int end_max_index = 0;
1560 for (Task*
const task : by_end_min_) {
1561 const int64_t
end_min = task->interval->EndMin();
1562 while (end_max_index < by_start_min_.size() &&
1563 by_end_max_[end_max_index]->interval->EndMax() <=
end_min) {
1565 max_start_min, by_end_max_[end_max_index]->
interval->StartMin());
1568 if (end_max_index > 0 && task->interval->StartMin() <= max_start_min &&
1569 task->interval->EndMax() > task->interval->EndMin()) {
1570 DCHECK_LE(by_end_max_[end_max_index - 1]->
interval->EndMax(),
end_min);
1583 const int64_t update = ConditionalStartMin(*task, end_max_index - 1);
1584 start_min_update_.push_back(std::make_pair(task->interval, update));
1591 for (Task*
const task : by_end_max_) {
1592 lt_tree_.Insert(*task);
1594 const int64_t max_feasible =
1595 CapProd(capacity_->Max(), task->interval->EndMax());
1596 if (lt_tree_.energetic_end_min() > max_feasible) {
1604 void PropagateBasedOnEnergy() {
1605 for (
int j = by_start_min_.size() - 2; j >= 0; --j) {
1606 lt_tree_.Grey(*by_end_max_[j + 1]);
1607 Task*
const twj = by_end_max_[j];
1609 const int64_t max_feasible =
1610 CapProd(capacity_->Max(), twj->interval->EndMax());
1611 DCHECK_LE(lt_tree_.energetic_end_min(), max_feasible);
1612 while (lt_tree_.energetic_end_min_opt() > max_feasible) {
1613 const int i = lt_tree_.argmax_energetic_end_min_opt();
1615 PropagateTaskCannotEndBefore(i, j);
1623 void PropagateTaskCannotEndBefore(
int index,
int end_max_index) {
1624 Task*
const task_to_push = by_start_min_[
index];
1625 const int64_t update = ConditionalStartMin(*task_to_push, end_max_index);
1626 start_min_update_.push_back(std::make_pair(task_to_push->interval, update));
1630 void ApplyNewBounds() {
1631 for (
const std::pair<IntervalVar*, int64_t>& update : start_min_update_) {
1632 update.first->SetStartMin(update.second);
1637 IntVar*
const capacity_;
1640 std::vector<Task*> tasks_;
1643 std::vector<Task*> by_start_min_;
1646 std::vector<Task*> by_end_max_;
1649 std::vector<Task*> by_end_min_;
1652 CumulativeLambdaThetaTree lt_tree_;
1655 DualCapacityThetaTree dual_capacity_tree_;
1658 std::vector<std::pair<IntervalVar*, int64_t>> start_min_update_;
1663 absl::flat_hash_map<int64_t, UpdatesForADemand*> update_map_;
1666 Rev<bool> has_zero_demand_tasks_;
1692 struct ProfileDelta {
1693 ProfileDelta(int64_t _time, int64_t _delta) :
time(_time),
delta(_delta) {}
1698 bool TimeLessThan(
const ProfileDelta& delta1,
const ProfileDelta& delta2) {
1699 return delta1.time < delta2.time;
1714 template <
class Task>
1715 class CumulativeTimeTable :
public Constraint {
1717 CumulativeTimeTable(Solver*
const solver,
const std::vector<Task*>& tasks,
1719 : Constraint(solver), by_start_min_(tasks), capacity_(
capacity) {
1722 const int profile_max_size = 2 * by_start_min_.size() + 2;
1723 profile_non_unique_time_.reserve(profile_max_size);
1724 profile_unique_time_.reserve(profile_max_size);
1729 void InitialPropagate()
override {
1736 void Post()
override {
1738 solver(),
this, &CumulativeTimeTable::InitialPropagate,
1739 "InitialPropagate");
1740 for (Task*
const task : by_start_min_) {
1741 task->WhenAnything(demon);
1743 capacity_->WhenRange(demon);
1746 void Accept(ModelVisitor*
const visitor)
const override {
1747 LOG(FATAL) <<
"Should not be visited";
1750 std::string DebugString()
const override {
return "CumulativeTimeTable"; }
1754 void BuildProfile() {
1756 profile_non_unique_time_.clear();
1757 for (
const Task*
const task : by_start_min_) {
1758 const IntervalVar*
const interval = task->interval;
1762 const int64_t demand_min = task->DemandMin();
1763 if (demand_min > 0) {
1764 profile_non_unique_time_.emplace_back(
start_max, +demand_min);
1765 profile_non_unique_time_.emplace_back(
end_min, -demand_min);
1770 std::sort(profile_non_unique_time_.begin(), profile_non_unique_time_.end(),
1773 profile_unique_time_.clear();
1776 for (
const ProfileDelta& step : profile_non_unique_time_) {
1777 if (step.time == profile_unique_time_.back().time) {
1778 profile_unique_time_.back().delta += step.delta;
1780 profile_unique_time_.push_back(step);
1783 usage += step.delta;
1786 DCHECK_EQ(0, usage);
1788 int64_t max_usage = 0;
1789 for (
const ProfileDelta& step : profile_unique_time_) {
1790 usage += step.delta;
1791 if (usage > max_usage) {
1795 DCHECK_EQ(0, usage);
1796 capacity_->SetMin(max_usage);
1803 std::sort(by_start_min_.begin(), by_start_min_.end(),
1804 StartMinLessThan<Task>);
1806 int profile_index = 0;
1807 for (
const Task*
const task : by_start_min_) {
1808 const IntervalVar*
const interval = task->interval;
1813 while (
interval->StartMin() > profile_unique_time_[profile_index].time) {
1814 DCHECK(profile_index < profile_unique_time_.size());
1816 usage += profile_unique_time_[profile_index].delta;
1818 PushTask(task, profile_index, usage);
1826 void PushTask(
const Task*
const task,
int profile_index, int64_t usage) {
1828 const IntervalVar*
const interval = task->interval;
1829 const int64_t demand_min = task->DemandMin();
1830 if (demand_min == 0) {
1833 const int64_t residual_capacity =
CapSub(capacity_->Max(), demand_min);
1834 const int64_t duration = task->interval->DurationMin();
1835 const ProfileDelta& first_prof_delta = profile_unique_time_[profile_index];
1837 int64_t new_start_min =
interval->StartMin();
1839 DCHECK_GE(first_prof_delta.time,
interval->StartMin());
1841 if (first_prof_delta.time >
interval->StartMin()) {
1846 DCHECK((
interval->StartMax() >= first_prof_delta.time) ||
1850 const int64_t usage_at_start_min =
CapSub(usage, first_prof_delta.delta);
1851 if (usage_at_start_min > residual_capacity) {
1852 new_start_min = profile_unique_time_[profile_index].time;
1860 ProfileDelta delta_end(
end_min, 0);
1862 delta_start.delta = +demand_min;
1863 delta_end.delta = -demand_min;
1865 while (profile_unique_time_[profile_index].
time <
1866 CapAdd(duration, new_start_min)) {
1867 const ProfileDelta& profile_delta = profile_unique_time_[profile_index];
1868 DCHECK(profile_index < profile_unique_time_.size());
1870 if (profile_delta.time == delta_start.time) {
1871 usage -= delta_start.delta;
1873 if (profile_delta.time == delta_end.time) {
1874 usage -= delta_end.delta;
1878 DCHECK(profile_index < profile_unique_time_.size());
1880 if (usage > residual_capacity) {
1881 new_start_min = profile_unique_time_[profile_index].time;
1883 usage += profile_unique_time_[profile_index].delta;
1885 task->interval->SetStartMin(new_start_min);
1888 typedef std::vector<ProfileDelta> Profile;
1890 Profile profile_unique_time_;
1891 Profile profile_non_unique_time_;
1892 std::vector<Task*> by_start_min_;
1893 IntVar*
const capacity_;
1908 template <
class Task>
1909 class TimeTableSync :
public Constraint {
1911 TimeTableSync(Solver*
const solver,
const std::vector<Task*>& tasks,
1913 : Constraint(solver), tasks_(tasks), capacity_(
capacity) {
1914 num_tasks_ = tasks_.size();
1920 start_min_.reserve(num_tasks_);
1921 start_max_.reserve(num_tasks_);
1922 end_min_.reserve(num_tasks_);
1923 durations_.reserve(num_tasks_);
1924 demands_.reserve(num_tasks_);
1929 void InitialPropagate()
override {
1932 while (!events_scp_.empty() && !events_ecp_.empty()) {
1934 pos_ = NextEventTime();
1939 capacity_->SetMin(capacity_->Max() - gap_);
1941 next_pos_ = NextScpTime();
1949 void Post()
override {
1951 solver(),
this, &TimeTableSync::InitialPropagate,
"InitialPropagate");
1952 for (Task*
const task : tasks_) {
1953 task->WhenAnything(demon);
1955 capacity_->WhenRange(demon);
1958 void Accept(ModelVisitor*
const visitor)
const override {
1959 LOG(FATAL) <<
"Should not be visited";
1962 std::string DebugString()
const override {
return "TimeTableSync"; }
1966 enum State { NONE, READY, CHECK, CONFLICT };
1968 inline int64_t NextScpTime() {
1969 return !events_scp_.empty() ? events_scp_.top().first
1973 inline int64_t NextEventTime() {
1975 if (!events_pr_.empty()) {
1976 time = events_pr_.top().first;
1978 if (!events_scp_.empty()) {
1979 int64_t t = events_scp_.top().first;
1982 if (!events_ecp_.empty()) {
1983 int64_t t = events_ecp_.top().first;
1989 void ProcessEventsScp() {
1990 while (!events_scp_.empty() && events_scp_.top().first == pos_) {
1991 const int64_t task_id = events_scp_.top().second;
1993 const int64_t old_end_min = end_min_[task_id];
1994 if (states_[task_id] == State::CONFLICT) {
1996 const int64_t new_end_min = pos_ + durations_[task_id];
1997 start_min_[task_id] = pos_;
1998 end_min_[task_id] = new_end_min;
2000 tasks_[task_id]->interval->SetStartMin(pos_);
2003 states_[task_id] = State::READY;
2005 if (pos_ < end_min_[task_id]) {
2006 gap_ -= demands_[task_id];
2007 if (old_end_min <= pos_) {
2008 events_ecp_.push(kv(end_min_[task_id], task_id));
2014 void ProcessEventsEcp() {
2015 while (!events_ecp_.empty() && events_ecp_.top().first == pos_) {
2016 const int64_t task_id = events_ecp_.top().second;
2019 if (pos_ < end_min_[task_id]) {
2020 events_ecp_.push(kv(end_min_[task_id], task_id));
2022 gap_ += demands_[task_id];
2027 void ProcessEventsPr() {
2028 while (!events_pr_.empty() && events_pr_.top().first == pos_) {
2029 const int64_t task_id = events_pr_.top().second;
2032 if (demands_[task_id] > gap_) {
2033 states_[task_id] = State::CONFLICT;
2034 conflict_.push(kv(demands_[task_id], task_id));
2038 if (next_pos_ < end_min_[task_id]) {
2039 states_[task_id] = State::CHECK;
2040 check_.push(kv(demands_[task_id], task_id));
2044 states_[task_id] = State::READY;
2050 capacity_->SetMin(capacity_->Max() - gap_);
2052 if (gap_ < prev_gap_) {
2054 while (!check_.empty() && demands_[check_.top().second] > gap_) {
2055 const int64_t task_id = check_.top().second;
2057 if (states_[task_id] == State::CHECK && pos_ < end_min_[task_id]) {
2058 states_[task_id] = State::CONFLICT;
2059 conflict_.push(kv(demands_[task_id], task_id));
2062 states_[task_id] = State::READY;
2067 if (gap_ > prev_gap_) {
2069 while (!conflict_.empty() && demands_[conflict_.top().second] <= gap_) {
2070 const int64_t task_id = conflict_.top().second;
2072 if (states_[task_id] != State::CONFLICT) {
2075 const int64_t old_end_min = end_min_[task_id];
2077 start_min_[task_id] = pos_;
2078 end_min_[task_id] = pos_ + durations_[task_id];
2080 tasks_[task_id]->interval->SetStartMin(pos_);
2082 if (next_pos_ < end_min_[task_id]) {
2083 states_[task_id] = State::CHECK;
2084 check_.push(kv(demands_[task_id], task_id));
2086 states_[task_id] = State::READY;
2089 const int64_t
start_max = start_max_[task_id];
2091 events_ecp_.push(kv(end_min_[task_id], task_id));
2098 void BuildEvents() {
2102 gap_ = capacity_->Max();
2103 prev_gap_ = capacity_->Max();
2105 conflict_ = min_heap();
2106 check_ = max_heap();
2108 events_pr_ = min_heap();
2109 events_scp_ = min_heap();
2110 events_ecp_ = min_heap();
2119 for (
int i = 0; i < num_tasks_; i++) {
2120 const int64_t s_min = tasks_[i]->interval->StartMin();
2121 const int64_t s_max = tasks_[i]->interval->StartMax();
2122 const int64_t e_min = tasks_[i]->interval->EndMin();
2124 start_min_.push_back(s_min);
2125 start_max_.push_back(s_max);
2126 end_min_.push_back(e_min);
2127 durations_.push_back(tasks_[i]->
interval->DurationMin());
2128 demands_.push_back(tasks_[i]->DemandMin());
2130 states_.push_back(State::NONE);
2132 events_scp_.push(kv(s_max, i));
2134 if (s_min != s_max) {
2135 events_pr_.push(kv(s_min, i));
2138 if (s_max < e_min) {
2139 events_ecp_.push(kv(e_min, i));
2145 std::vector<Task*> tasks_;
2146 IntVar*
const capacity_;
2148 std::vector<int64_t> start_min_;
2149 std::vector<int64_t> start_max_;
2150 std::vector<int64_t> end_min_;
2151 std::vector<int64_t> end_max_;
2152 std::vector<int64_t> durations_;
2153 std::vector<int64_t> demands_;
2156 typedef std::pair<int64_t, int64_t> kv;
2157 typedef std::priority_queue<kv, std::vector<kv>, std::greater<kv>> min_heap;
2158 typedef std::priority_queue<kv, std::vector<kv>, std::less<kv>> max_heap;
2161 min_heap events_pr_;
2162 min_heap events_scp_;
2163 min_heap events_ecp_;
2166 std::vector<State> states_;
2177 class CumulativeConstraint :
public Constraint {
2179 CumulativeConstraint(Solver*
const s,
2180 const std::vector<IntervalVar*>& intervals,
2181 const std::vector<int64_t>& demands,
2185 intervals_(intervals),
2187 tasks_.reserve(intervals.size());
2188 for (
int i = 0; i < intervals.size(); ++i) {
2189 tasks_.push_back(CumulativeTask(intervals[i], demands[i]));
2193 void Post()
override {
2197 const ConstraintSolverParameters& params = solver()->const_parameters();
2198 if (params.use_cumulative_time_table()) {
2199 if (params.use_cumulative_time_table_sync()) {
2200 PostOneSidedConstraint(
false,
false,
true);
2201 PostOneSidedConstraint(
true,
false,
true);
2203 PostOneSidedConstraint(
false,
false,
false);
2204 PostOneSidedConstraint(
true,
false,
false);
2207 if (params.use_cumulative_edge_finder()) {
2208 PostOneSidedConstraint(
false,
true,
false);
2209 PostOneSidedConstraint(
true,
true,
false);
2211 if (params.use_sequence_high_demand_tasks()) {
2212 PostHighDemandSequenceConstraint();
2214 if (params.use_all_possible_disjunctions()) {
2215 PostAllDisjunctions();
2219 void InitialPropagate()
override {
2223 void Accept(ModelVisitor*
const visitor)
const override {
2225 visitor->BeginVisitConstraint(ModelVisitor::kCumulative,
this);
2226 visitor->VisitIntervalArrayArgument(ModelVisitor::kIntervalsArgument,
2228 visitor->VisitIntegerArrayArgument(ModelVisitor::kDemandsArgument,
2230 visitor->VisitIntegerExpressionArgument(ModelVisitor::kCapacityArgument,
2232 visitor->EndVisitConstraint(ModelVisitor::kCumulative,
this);
2235 std::string DebugString()
const override {
2236 return absl::StrFormat(
"CumulativeConstraint([%s], %s)",
2238 capacity_->DebugString());
2243 void PostAllDisjunctions() {
2244 for (
int i = 0; i < intervals_.size(); ++i) {
2245 IntervalVar*
const interval_i = intervals_[i];
2246 if (interval_i->MayBePerformed()) {
2247 for (
int j = i + 1; j < intervals_.size(); ++j) {
2248 IntervalVar*
const interval_j = intervals_[j];
2249 if (interval_j->MayBePerformed()) {
2251 Constraint*
const constraint =
2252 solver()->MakeTemporalDisjunction(interval_i, interval_j);
2253 solver()->AddConstraint(constraint);
2263 void PostHighDemandSequenceConstraint() {
2264 Constraint* constraint =
nullptr;
2266 std::vector<IntervalVar*> high_demand_intervals;
2267 high_demand_intervals.reserve(intervals_.size());
2268 for (
int i = 0; i < demands_.size(); ++i) {
2269 const int64_t
demand = tasks_[i].demand;
2276 if (
demand * 2 > capacity_->Max() &&
2277 tasks_[i].interval->MayBePerformed()) {
2278 high_demand_intervals.push_back(tasks_[i].
interval);
2281 if (high_demand_intervals.size() >= 2) {
2284 std::string seq_name = absl::StrCat(
name(),
"-HighDemandSequence");
2285 constraint = solver()->MakeDisjunctiveConstraint(high_demand_intervals,
2289 if (constraint !=
nullptr) {
2290 solver()->AddConstraint(constraint);
2296 void PopulateVectorUsefulTasks(
2297 bool mirror, std::vector<CumulativeTask*>*
const useful_tasks) {
2298 DCHECK(useful_tasks->empty());
2299 for (
int i = 0; i < tasks_.size(); ++i) {
2300 const CumulativeTask& original_task = tasks_[i];
2301 IntervalVar*
const interval = original_task.interval;
2303 if (original_task.demand > capacity_->Max()) {
2308 if (
interval->MayBePerformed() && original_task.demand > 0) {
2309 Solver*
const s = solver();
2310 IntervalVar*
const original_interval = original_task.interval;
2312 mirror ? s->MakeMirrorInterval(original_interval)
2313 : original_interval;
2314 IntervalVar*
const relaxed_max = s->MakeIntervalRelaxedMax(
interval);
2315 useful_tasks->push_back(
2316 new CumulativeTask(relaxed_max, original_task.demand));
2323 Constraint* MakeOneSidedConstraint(
bool mirror,
bool edge_finder,
2325 std::vector<CumulativeTask*> useful_tasks;
2326 PopulateVectorUsefulTasks(mirror, &useful_tasks);
2327 if (useful_tasks.empty()) {
2330 Solver*
const s = solver();
2332 const ConstraintSolverParameters& params = solver()->const_parameters();
2333 return useful_tasks.size() < params.max_edge_finder_size()
2334 ? s->RevAlloc(
new EdgeFinder<CumulativeTask>(s, useful_tasks,
2340 new TimeTableSync<CumulativeTask>(s, useful_tasks, capacity_));
2343 new CumulativeTimeTable<CumulativeTask>(s, useful_tasks, capacity_));
2348 void PostOneSidedConstraint(
bool mirror,
bool edge_finder,
bool tt_sync) {
2349 Constraint*
const constraint =
2350 MakeOneSidedConstraint(mirror, edge_finder, tt_sync);
2351 if (constraint !=
nullptr) {
2352 solver()->AddConstraint(constraint);
2357 IntVar*
const capacity_;
2360 std::vector<CumulativeTask> tasks_;
2363 const std::vector<IntervalVar*> intervals_;
2365 const std::vector<int64_t> demands_;
2370 class VariableDemandCumulativeConstraint :
public Constraint {
2372 VariableDemandCumulativeConstraint(Solver*
const s,
2373 const std::vector<IntervalVar*>& intervals,
2374 const std::vector<IntVar*>& demands,
2376 const std::string&
name)
2379 intervals_(intervals),
2381 tasks_.reserve(intervals.size());
2382 for (
int i = 0; i < intervals.size(); ++i) {
2383 tasks_.push_back(VariableCumulativeTask(intervals[i], demands[i]));
2387 void Post()
override {
2391 const ConstraintSolverParameters& params = solver()->const_parameters();
2392 if (params.use_cumulative_time_table()) {
2393 PostOneSidedConstraint(
false,
false,
false);
2394 PostOneSidedConstraint(
true,
false,
false);
2396 if (params.use_cumulative_edge_finder()) {
2397 PostOneSidedConstraint(
false,
true,
false);
2398 PostOneSidedConstraint(
true,
true,
false);
2400 if (params.use_sequence_high_demand_tasks()) {
2401 PostHighDemandSequenceConstraint();
2403 if (params.use_all_possible_disjunctions()) {
2404 PostAllDisjunctions();
2408 void InitialPropagate()
override {
2412 void Accept(ModelVisitor*
const visitor)
const override {
2414 visitor->BeginVisitConstraint(ModelVisitor::kCumulative,
this);
2415 visitor->VisitIntervalArrayArgument(ModelVisitor::kIntervalsArgument,
2417 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kDemandsArgument,
2419 visitor->VisitIntegerExpressionArgument(ModelVisitor::kCapacityArgument,
2421 visitor->EndVisitConstraint(ModelVisitor::kCumulative,
this);
2424 std::string DebugString()
const override {
2425 return absl::StrFormat(
"VariableDemandCumulativeConstraint([%s], %s)",
2427 capacity_->DebugString());
2432 void PostAllDisjunctions() {
2433 for (
int i = 0; i < intervals_.size(); ++i) {
2434 IntervalVar*
const interval_i = intervals_[i];
2435 if (interval_i->MayBePerformed()) {
2436 for (
int j = i + 1; j < intervals_.size(); ++j) {
2437 IntervalVar*
const interval_j = intervals_[j];
2438 if (interval_j->MayBePerformed()) {
2439 if (
CapAdd(tasks_[i].
demand->Min(), tasks_[j].demand->Min()) >
2441 Constraint*
const constraint =
2442 solver()->MakeTemporalDisjunction(interval_i, interval_j);
2443 solver()->AddConstraint(constraint);
2453 void PostHighDemandSequenceConstraint() {
2454 Constraint* constraint =
nullptr;
2456 std::vector<IntervalVar*> high_demand_intervals;
2457 high_demand_intervals.reserve(intervals_.size());
2458 for (
int i = 0; i < demands_.size(); ++i) {
2459 const int64_t
demand = tasks_[i].demand->Min();
2466 if (
demand * 2 > capacity_->Max() &&
2467 tasks_[i].interval->MayBePerformed()) {
2468 high_demand_intervals.push_back(tasks_[i].
interval);
2471 if (high_demand_intervals.size() >= 2) {
2474 const std::string seq_name =
2475 absl::StrCat(
name(),
"-HighDemandSequence");
2476 constraint = solver()->MakeStrictDisjunctiveConstraint(
2477 high_demand_intervals, seq_name);
2480 if (constraint !=
nullptr) {
2481 solver()->AddConstraint(constraint);
2487 void PopulateVectorUsefulTasks(
2488 bool mirror, std::vector<VariableCumulativeTask*>*
const useful_tasks) {
2489 DCHECK(useful_tasks->empty());
2490 for (
int i = 0; i < tasks_.size(); ++i) {
2491 const VariableCumulativeTask& original_task = tasks_[i];
2492 IntervalVar*
const interval = original_task.interval;
2494 if (original_task.demand->Min() > capacity_->Max()) {
2499 if (
interval->MayBePerformed() && original_task.demand->Max() > 0) {
2500 Solver*
const s = solver();
2501 IntervalVar*
const original_interval = original_task.interval;
2503 mirror ? s->MakeMirrorInterval(original_interval)
2504 : original_interval;
2505 IntervalVar*
const relaxed_max = s->MakeIntervalRelaxedMax(
interval);
2506 useful_tasks->push_back(
2507 new VariableCumulativeTask(relaxed_max, original_task.demand));
2514 Constraint* MakeOneSidedConstraint(
bool mirror,
bool edge_finder,
2516 std::vector<VariableCumulativeTask*> useful_tasks;
2517 PopulateVectorUsefulTasks(mirror, &useful_tasks);
2518 if (useful_tasks.empty()) {
2521 Solver*
const s = solver();
2524 new EdgeFinder<VariableCumulativeTask>(s, useful_tasks, capacity_));
2527 return s->RevAlloc(
new TimeTableSync<VariableCumulativeTask>(
2528 s, useful_tasks, capacity_));
2530 return s->RevAlloc(
new CumulativeTimeTable<VariableCumulativeTask>(
2531 s, useful_tasks, capacity_));
2536 void PostOneSidedConstraint(
bool mirror,
bool edge_finder,
bool tt_sync) {
2537 Constraint*
const constraint =
2538 MakeOneSidedConstraint(mirror, edge_finder, tt_sync);
2539 if (constraint !=
nullptr) {
2540 solver()->AddConstraint(constraint);
2545 IntVar*
const capacity_;
2548 std::vector<VariableCumulativeTask> tasks_;
2551 const std::vector<IntervalVar*> intervals_;
2553 const std::vector<IntVar*> demands_;
2563 DisjunctiveConstraint::DisjunctiveConstraint(
2564 Solver*
const s,
const std::vector<IntervalVar*>& intervals,
2565 const std::string&
name)
2567 if (!
name.empty()) {
2576 std::function<int64_t(int64_t, int64_t)> transition_time) {
2577 if (transition_time !=
nullptr) {
2587 const std::vector<IntervalVar*>& intervals,
const std::string&
name) {
2588 return RevAlloc(
new FullDisjunctiveConstraint(
this, intervals,
name,
false));
2592 const std::vector<IntervalVar*>& intervals,
const std::string&
name) {
2593 return RevAlloc(
new FullDisjunctiveConstraint(
this, intervals,
name,
true));
2599 const std::vector<int64_t>& demands,
2601 CHECK_EQ(intervals.size(), demands.size());
2602 for (
int i = 0; i < intervals.size(); ++i) {
2603 CHECK_GE(demands[i], 0);
2608 return RevAlloc(
new CumulativeConstraint(
this, intervals, demands,
2613 const std::vector<int>& demands,
2619 const std::vector<int64_t>& demands,
2621 const std::string&
name) {
2622 CHECK_EQ(intervals.size(), demands.size());
2623 for (
int i = 0; i < intervals.size(); ++i) {
2624 CHECK_GE(demands[i], 0);
2627 new CumulativeConstraint(
this, intervals, demands,
capacity,
name));
2631 const std::vector<int>& demands,
2633 const std::string&
name) {
2640 const std::vector<IntVar*>& demands,
2642 CHECK_EQ(intervals.size(), demands.size());
2643 for (
int i = 0; i < intervals.size(); ++i) {
2644 CHECK_GE(demands[i]->Min(), 0);
2647 std::vector<int64_t> fixed_demands(demands.size());
2648 for (
int i = 0; i < demands.size(); ++i) {
2649 fixed_demands[i] = demands[i]->Value();
2653 return RevAlloc(
new VariableDemandCumulativeConstraint(
2658 const std::vector<IntVar*>& demands,
2660 const std::string&
name) {
2661 CHECK_EQ(intervals.size(), demands.size());
2662 for (
int i = 0; i < intervals.size(); ++i) {
2663 CHECK_GE(demands[i]->Min(), 0);
2666 std::vector<int64_t> fixed_demands(demands.size());
2667 for (
int i = 0; i < demands.size(); ++i) {
2668 fixed_demands[i] = demands[i]->Value();
2672 return RevAlloc(
new VariableDemandCumulativeConstraint(
A constraint is the main modeling object.
~DisjunctiveConstraint() override
void SetTransitionTime(Solver::IndexEvaluator2 transition_time)
Add a transition time between intervals.
Solver::IndexEvaluator2 transition_time_
The class IntVar is a subset of IntExpr.
static IntegralType CeilOfRatio(IntegralType numerator, IntegralType denominator)
virtual std::string name() const
Object naming.
void set_name(const std::string &name)
DisjunctiveConstraint * MakeStrictDisjunctiveConstraint(const std::vector< IntervalVar * > &intervals, const std::string &name)
This constraint forces all interval vars into an non-overlapping sequence.
DisjunctiveConstraint * MakeDisjunctiveConstraint(const std::vector< IntervalVar * > &intervals, const std::string &name)
This constraint forces all interval vars into an non-overlapping sequence.
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...
T * RevAlloc(T *object)
Registers the given object as being reversible.
IntVar * MakeIntConst(int64_t val, const std::string &name)
IntConst will create a constant expression.
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
const Collection::value_type::second_type FindPtrOrNull(const Collection &collection, const typename Collection::value_type::first_type &key)
void STLDeleteValues(T *v)
void STLDeleteElements(T *container)
double Distance(const VectorXd &vector1, const VectorXd &vector2, const Sharder &sharder)
IntType CeilOfRatio(IntType numerator, IntType denominator)
Collection of objects used to extend the Constraint Solver library.
int64_t CapAdd(int64_t x, int64_t y)
int64_t CapSub(int64_t x, int64_t y)
Demon * MakeDelayedConstraintDemon0(Solver *const s, T *const ct, void(T::*method)(), const std::string &name)
std::string JoinDebugStringPtr(const std::vector< T > &v, const std::string &separator)
int64_t CapProd(int64_t x, int64_t y)
std::vector< int64_t > ToInt64Vector(const std::vector< int > &input)
bool AreAllOnes(const std::vector< T > &values)
bool AreAllBound(const std::vector< IntVar * > &vars)
std::string JoinDebugString(const std::vector< T > &v, const std::string &separator)
int64_t residual_energetic_end_min
int64_t energetic_end_min
int64_t energetic_end_min_opt
static const int64_t kNotInitialized
int argmax_energetic_end_min_opt
static const int64_t kNotAvailable
#define VLOG(verboselevel)