31 const std::vector<IntervalVariable>& vars) {
33 bool is_all_different =
true;
35 for (
const IntervalVariable
var : vars) {
38 is_all_different =
false;
42 if (is_all_different) {
43 std::vector<IntegerVariable> starts;
44 starts.reserve(vars.size());
45 for (
const IntervalVariable
var : vars) {
53 const auto& sat_parameters = *
model->GetOrCreate<SatParameters>();
54 if (vars.size() > 2 && sat_parameters.use_combined_no_overlap()) {
62 model->TakeOwnership(helper);
67 std::vector<AffineExpression> demands(vars.size(), one);
71 model->TakeOwnership(timetable);
75 if (vars.size() == 2) {
78 model->TakeOwnership(propagator);
87 watcher->SetPropagatorPriority(
id, 1);
88 model->TakeOwnership(overload_checker);
90 for (
const bool time_direction : {
true,
false}) {
93 const int id = detectable_precedences->
RegisterWith(watcher);
94 watcher->SetPropagatorPriority(
id, 2);
95 model->TakeOwnership(detectable_precedences);
97 for (
const bool time_direction : {
true,
false}) {
101 watcher->SetPropagatorPriority(
id, 3);
102 model->TakeOwnership(not_last);
104 for (
const bool time_direction : {
true,
false}) {
108 watcher->SetPropagatorPriority(
id, 4);
109 model->TakeOwnership(edge_finding);
116 if (sat_parameters.use_precedences_in_disjunctive_constraint() &&
117 !sat_parameters.use_combined_no_overlap()) {
118 for (
const bool time_direction : {
true,
false}) {
123 watcher->SetPropagatorPriority(
id, 5);
124 model->TakeOwnership(precedences);
131 const std::vector<IntervalVariable>& vars) {
137 for (
int i = 0; i < vars.size(); ++i) {
138 for (
int j = 0; j < i; ++j) {
142 precedences->AddConditionalPrecedence(repository->EndVar(vars[i]),
143 repository->StartVar(vars[j]),
145 precedences->AddConditionalPrecedence(repository->EndVar(vars[j]),
146 repository->StartVar(vars[i]),
154 const std::vector<IntervalVariable>& vars) {
162 int j = sorted_tasks_.size();
163 sorted_tasks_.push_back(e);
165 sorted_tasks_[j] = sorted_tasks_[j - 1];
168 sorted_tasks_[j] = e;
169 DCHECK(std::is_sorted(sorted_tasks_.begin(), sorted_tasks_.end()));
173 if (j <= optimized_restart_) optimized_restart_ = 0;
183 const int size = sorted_tasks_.size();
184 for (
int i = 0;; ++i) {
185 if (i == size)
return;
186 if (sorted_tasks_[i].task == e.
task) {
187 sorted_tasks_.erase(sorted_tasks_.begin() + i);
192 optimized_restart_ = sorted_tasks_.size();
193 sorted_tasks_.push_back(e);
194 DCHECK(std::is_sorted(sorted_tasks_.begin(), sorted_tasks_.end()));
198 sorted_tasks_.erase(sorted_tasks_.begin() +
index);
199 optimized_restart_ = 0;
203 DCHECK(std::is_sorted(sorted_tasks_.begin(), sorted_tasks_.end()));
204 const int size = sorted_tasks_.size();
206 for (
int i = optimized_restart_; i < size; ++i) {
207 const Entry& e = sorted_tasks_[i];
209 optimized_restart_ = i;
219 int* critical_index)
const {
221 DCHECK(std::is_sorted(sorted_tasks_.begin(), sorted_tasks_.end()));
222 bool ignored =
false;
223 const int size = sorted_tasks_.size();
228 if (optimized_restart_ + 1 == size &&
229 sorted_tasks_[optimized_restart_].task == task_to_ignore) {
230 optimized_restart_ = 0;
233 for (
int i = optimized_restart_; i < size; ++i) {
234 const Entry& e = sorted_tasks_[i];
235 if (e.
task == task_to_ignore) {
241 if (!ignored) optimized_restart_ = i;
270 std::swap(task_before, task_after);
276 const IntegerValue end_min_before = helper_->
EndMin(task_before);
277 if (helper_->
StartMin(task_after) < end_min_before) {
292 const IntegerValue start_max_after = helper_->
StartMax(task_after);
293 if (helper_->
EndMax(task_before) > start_max_after) {
312 const int id = watcher->
Register(
this);
317 template <
bool time_direction>
321 task_to_disjunctives_.resize(helper_->
NumTasks());
324 const int id = watcher->
Register(
this);
327 watcher->NotifyThatPropagatorMayNotReachFixedPointInOnePass(
id);
330 template <
bool time_direction>
332 const std::vector<IntervalVariable>& vars) {
333 const int index = task_sets_.size();
334 task_sets_.emplace_back(vars.size());
336 for (
const IntervalVariable
var : vars) {
337 task_to_disjunctives_[
var.value()].push_back(
index);
341 template <
bool time_direction>
343 helper_->SetTimeDirection(time_direction);
344 const auto& task_by_increasing_end_min = helper_->TaskByIncreasingEndMin();
345 const auto& task_by_decreasing_start_max =
346 helper_->TaskByDecreasingStartMax();
348 for (
auto& task_set : task_sets_) task_set.Clear();
352 const int num_tasks = helper_->NumTasks();
353 task_is_added_.assign(num_tasks,
false);
354 int queue_index = num_tasks - 1;
355 for (
const auto task_time : task_by_increasing_end_min) {
356 const int t = task_time.task_index;
357 const IntegerValue
end_min = task_time.time;
358 if (helper_->IsAbsent(t))
continue;
361 while (queue_index >= 0) {
362 const auto to_insert = task_by_decreasing_start_max[queue_index];
363 const int task_index = to_insert.task_index;
364 const IntegerValue
start_max = to_insert.time;
366 if (helper_->IsPresent(task_index)) {
367 task_is_added_[task_index] =
true;
368 const IntegerValue shifted_smin = helper_->ShiftedStartMin(task_index);
369 const IntegerValue duration_min = helper_->DurationMin(task_index);
370 for (
const int d_index : task_to_disjunctives_[task_index]) {
372 task_sets_[d_index].AddEntry(
373 {task_index, shifted_smin, duration_min});
374 end_mins_[d_index] = task_sets_[d_index].ComputeEndMin();
375 max_of_end_min =
std::max(max_of_end_min, end_mins_[d_index]);
383 IntegerValue new_start_min = helper_->StartMin(t);
384 if (new_start_min >= max_of_end_min)
continue;
385 int best_critical_index = 0;
386 int best_d_index = -1;
387 if (task_is_added_[t]) {
388 for (
const int d_index : task_to_disjunctives_[t]) {
389 if (new_start_min >= end_mins_[d_index])
continue;
390 int critical_index = 0;
391 const IntegerValue end_min_of_critical_tasks =
392 task_sets_[d_index].ComputeEndMin(t,
394 DCHECK_LE(end_min_of_critical_tasks, max_of_end_min);
395 if (end_min_of_critical_tasks > new_start_min) {
396 new_start_min = end_min_of_critical_tasks;
397 best_d_index = d_index;
398 best_critical_index = critical_index;
404 for (
const int d_index : task_to_disjunctives_[t]) {
405 if (end_mins_[d_index] > new_start_min) {
406 new_start_min = end_mins_[d_index];
407 best_d_index = d_index;
410 if (best_d_index != -1) {
411 const IntegerValue end_min_of_critical_tasks =
412 task_sets_[best_d_index].ComputeEndMin(t,
413 &best_critical_index);
414 CHECK_EQ(end_min_of_critical_tasks, new_start_min);
419 if (best_d_index == -1)
continue;
424 helper_->ClearReason();
425 const std::vector<TaskSet::Entry>& sorted_tasks =
426 task_sets_[best_d_index].SortedTasks();
427 const IntegerValue window_start =
428 sorted_tasks[best_critical_index].start_min;
429 for (
int i = best_critical_index; i < sorted_tasks.size(); ++i) {
430 const int ct = sorted_tasks[i].task;
431 if (
ct == t)
continue;
432 helper_->AddPresenceReason(
ct);
433 helper_->AddEnergyAfterReason(
ct, sorted_tasks[i].duration_min,
435 helper_->AddStartMaxReason(
ct,
end_min - 1);
437 helper_->AddEndMinReason(t,
end_min);
438 if (!helper_->IncreaseStartMin(t, new_start_min)) {
446 if (task_is_added_[t]) {
447 const IntegerValue shifted_smin = helper_->ShiftedStartMin(t);
448 const IntegerValue duration_min = helper_->DurationMin(t);
449 for (
const int d_index : task_to_disjunctives_[t]) {
450 task_sets_[d_index].NotifyEntryIsNowLastIfPresent(
451 {t, shifted_smin, duration_min});
452 end_mins_[d_index] = task_sets_[d_index].ComputeEndMin();
453 max_of_end_min =
std::max(max_of_end_min, end_mins_[d_index]);
476 IntegerValue relevant_end;
477 int relevant_size = 0;
479 const int task = task_time.task_index;
480 if (helper_->
IsAbsent(task))
continue;
482 const IntegerValue
start_min = task_time.time;
484 window_.push_back(task_time);
486 if (window_end > helper_->
EndMax(task)) {
487 relevant_size = window_.size();
488 relevant_end = window_end;
496 window_.resize(relevant_size);
497 if (relevant_size > 0 && !PropagateSubwindow(relevant_end)) {
503 window_.push_back(task_time);
509 window_.resize(relevant_size);
510 if (relevant_size > 0 && !PropagateSubwindow(relevant_end)) {
524 bool DisjunctiveOverloadChecker::PropagateSubwindow(
525 IntegerValue global_window_end) {
527 const int window_size = window_.size();
528 theta_tree_.
Reset(window_size);
529 task_by_increasing_end_max_.clear();
530 for (
int i = 0; i < window_size; ++i) {
532 const int task = window_[i].task_index;
534 if (
end_max < global_window_end) {
535 task_to_event_[task] = i;
536 task_by_increasing_end_max_.push_back({task,
end_max});
541 std::sort(task_by_increasing_end_max_.begin(),
542 task_by_increasing_end_max_.end());
543 for (
const auto task_time : task_by_increasing_end_max_) {
544 const int current_task = task_time.task_index;
549 if (helper_->
IsAbsent(current_task))
continue;
551 DCHECK_NE(task_to_event_[current_task], -1);
553 const int current_event = task_to_event_[current_task];
554 const IntegerValue energy_min = helper_->
DurationMin(current_task);
560 energy_min, energy_min);
563 current_event, window_[current_event].
time, energy_min);
567 const IntegerValue current_end = task_time.time;
571 const int critical_event =
573 const IntegerValue window_start = window_[critical_event].time;
574 const IntegerValue window_end =
576 for (
int event = critical_event;
event < window_size;
event++) {
577 const IntegerValue energy_min = theta_tree_.
EnergyMin(event);
578 if (energy_min > 0) {
579 const int task = window_[event].task_index;
596 IntegerValue available_energy;
598 current_end, &critical_event, &optional_event, &available_energy);
600 const int optional_task = window_[optional_event].task_index;
601 const IntegerValue optional_duration_min =
603 const IntegerValue window_start = window_[critical_event].time;
604 const IntegerValue window_end =
605 current_end + optional_duration_min - available_energy - 1;
606 for (
int event = critical_event;
event < window_size;
event++) {
607 const IntegerValue energy_min = theta_tree_.
EnergyMin(event);
608 if (energy_min > 0) {
609 const int task = window_[event].task_index;
622 if (!helper_->
IsAbsent(optional_task)) {
634 const int id = watcher->
Register(
this);
644 to_propagate_.clear();
645 processed_.assign(helper_->
NumTasks(),
false);
654 task_by_increasing_end_min_.clear();
657 const int task = task_time.task_index;
658 if (helper_->
IsAbsent(task))
continue;
660 const IntegerValue shifted_smin = task_time.time;
661 const IntegerValue duration_min = helper_->
DurationMin(task);
662 const IntegerValue end_min_if_present = shifted_smin + duration_min;
666 if (helper_->
StartMin(task) < window_end) {
667 task_by_increasing_end_min_.push_back({task, end_min_if_present});
668 window_end =
std::max(window_end, task_time.time) + duration_min;
673 if (task_by_increasing_end_min_.size() > 1 && !PropagateSubwindow()) {
678 task_by_increasing_end_min_.clear();
679 task_by_increasing_end_min_.push_back({task, end_min_if_present});
680 window_end = end_min_if_present;
683 if (task_by_increasing_end_min_.size() > 1 && !PropagateSubwindow()) {
690 bool DisjunctiveDetectablePrecedences::PropagateSubwindow() {
691 DCHECK(!task_by_increasing_end_min_.empty());
696 task_by_increasing_end_min_.end());
697 const IntegerValue max_end_min = task_by_increasing_end_min_.back().time;
700 task_by_increasing_start_max_.clear();
701 for (
const TaskTime entry : task_by_increasing_end_min_) {
702 const int task = entry.task_index;
704 if (start_max < max_end_min && helper_->IsPresent(task)) {
705 task_by_increasing_start_max_.push_back({task,
start_max});
708 if (task_by_increasing_start_max_.empty())
return true;
709 std::sort(task_by_increasing_start_max_.begin(),
710 task_by_increasing_start_max_.end());
718 bool need_update =
false;
722 int blocking_task = -1;
723 const int queue_size = task_by_increasing_start_max_.size();
724 for (
const auto task_time : task_by_increasing_end_min_) {
731 const int current_task = task_time.task_index;
733 for (; queue_index < queue_size; ++queue_index) {
734 const auto to_insert = task_by_increasing_start_max_[queue_index];
735 const IntegerValue
start_max = to_insert.time;
736 const IntegerValue current_end_min = task_time.time;
739 const int t = to_insert.task_index;
753 if (!processed_[t]) {
754 if (blocking_task != -1) {
765 DCHECK(to_propagate_.empty());
767 to_propagate_.push_back(t);
776 if (blocking_task != current_task) {
777 to_propagate_.push_back(current_task);
778 if (blocking_task != -1)
continue;
780 for (
const int t : to_propagate_) {
781 DCHECK(!processed_[t]);
782 processed_[t] =
true;
797 if (task_set_end_min > helper_->
StartMin(t)) {
799 const std::vector<TaskSet::Entry>& sorted_tasks =
806 const IntegerValue end_min_if_present =
808 const IntegerValue window_start =
809 sorted_tasks[critical_index].start_min;
810 for (
int i = critical_index; i < sorted_tasks.size(); ++i) {
811 const int ct = sorted_tasks[i].task;
829 if (t == blocking_task) {
840 to_propagate_.clear();
847 const int id = watcher->
Register(
this);
860 const int task = task_time.task_index;
863 const IntegerValue
start_min = task_time.time;
865 window_.push_back(task_time);
870 if (window_.size() > 1 && !PropagateSubwindow()) {
876 window_.push_back(task_time);
879 if (window_.size() > 1 && !PropagateSubwindow()) {
885 bool DisjunctivePrecedences::PropagateSubwindow() {
886 index_to_end_vars_.clear();
887 for (
const auto task_time : window_) {
888 const int task = task_time.task_index;
889 index_to_end_vars_.push_back(helper_->
EndVars()[task]);
893 const int size = before_.size();
894 for (
int i = 0; i < size;) {
895 const IntegerVariable
var = before_[i].var;
899 const int initial_i = i;
900 IntegerValue min_offset = before_[i].offset;
901 for (; i < size && before_[i].var ==
var; ++i) {
902 const TaskTime task_time = window_[before_[i].index];
903 min_offset =
std::min(min_offset, before_[i].offset);
915 const IntegerValue new_lb = task_set_.
ComputeEndMin() + min_offset;
917 const std::vector<TaskSet::Entry>& sorted_tasks = task_set_.
SortedTasks();
922 for (
int j = initial_i; j < i; ++j) {
923 const int task = window_[before_[j].index].task_index;
924 task_to_arc_index_[task] = before_[j].arc_index;
928 const IntegerValue window_start = sorted_tasks[critical_index].start_min;
929 for (
int i = critical_index; i < sorted_tasks.size(); ++i) {
930 const int ct = sorted_tasks[i].task;
952 const int id = watcher->
Register(
this);
962 const auto& task_by_decreasing_start_max =
964 const auto& task_by_increasing_shifted_start_min =
978 int queue_index = task_by_decreasing_start_max.size() - 1;
979 const int num_tasks = task_by_increasing_shifted_start_min.size();
980 for (
int i = 0; i < num_tasks;) {
981 start_min_window_.clear();
983 for (; i < num_tasks; ++i) {
984 const TaskTime task_time = task_by_increasing_shifted_start_min[i];
989 if (start_min_window_.empty()) {
990 start_min_window_.push_back(task_time);
993 start_min_window_.push_back(task_time);
1002 start_max_window_.clear();
1003 for (; queue_index >= 0; queue_index--) {
1004 const auto task_time = task_by_decreasing_start_max[queue_index];
1007 if (task_time.time >= window_end)
break;
1008 if (helper_->
IsAbsent(task_time.task_index))
continue;
1009 start_max_window_.push_back(task_time);
1015 if (start_min_window_.size() <= 1)
continue;
1018 if (!start_max_window_.empty() && !PropagateSubwindow()) {
1025 bool DisjunctiveNotLast::PropagateSubwindow() {
1026 auto& task_by_increasing_end_max = start_max_window_;
1027 for (
TaskTime& entry : task_by_increasing_end_max) {
1028 entry.time = helper_->
EndMax(entry.task_index);
1031 task_by_increasing_end_max.end());
1033 const IntegerValue threshold = task_by_increasing_end_max.back().time;
1034 auto& task_by_increasing_start_max = start_min_window_;
1036 for (
const TaskTime entry : task_by_increasing_start_max) {
1037 const int task = entry.task_index;
1041 task_by_increasing_start_max[queue_size++] = {task,
start_max};
1047 if (queue_size <= 1)
return true;
1049 task_by_increasing_start_max.resize(queue_size);
1050 std::sort(task_by_increasing_start_max.begin(),
1051 task_by_increasing_start_max.end());
1054 int queue_index = 0;
1055 for (
const auto task_time : task_by_increasing_end_max) {
1056 const int t = task_time.task_index;
1057 const IntegerValue
end_max = task_time.time;
1063 while (queue_index < queue_size) {
1064 const auto to_insert = task_by_increasing_start_max[queue_index];
1065 const IntegerValue
start_max = to_insert.time;
1068 const int task_index = to_insert.task_index;
1085 int critical_index = 0;
1086 const IntegerValue end_min_of_critical_tasks =
1088 if (end_min_of_critical_tasks <= helper_->StartMax(t))
continue;
1093 const std::vector<TaskSet::Entry>& sorted_tasks = task_set_.
SortedTasks();
1094 const int sorted_tasks_size = sorted_tasks.size();
1095 for (
int i = critical_index; i < sorted_tasks_size; ++i) {
1096 const int ct = sorted_tasks[i].task;
1097 if (t ==
ct)
continue;
1107 end_max > largest_ct_start_max);
1108 if (
end_max > largest_ct_start_max) {
1111 const IntegerValue window_start = sorted_tasks[critical_index].start_min;
1112 for (
int i = critical_index; i < sorted_tasks_size; ++i) {
1113 const int ct = sorted_tasks[i].task;
1114 if (
ct == t)
continue;
1126 if (!helper_->
DecreaseEndMax(t, largest_ct_start_max))
return false;
1133 const int id = watcher->
Register(
this);
1140 const int num_tasks = helper_->
NumTasks();
1142 is_gray_.resize(num_tasks,
false);
1143 non_gray_task_to_event_.resize(num_tasks);
1148 const int task = task_time.task_index;
1149 if (helper_->
IsAbsent(task))
continue;
1153 if (helper_->
StartMin(task) < window_end) {
1154 window_.push_back(task_time);
1161 if (window_.size() > 2 && !PropagateSubwindow(window_end)) {
1167 window_.push_back(task_time);
1168 window_end = task_time.time + helper_->
DurationMin(task);
1170 if (window_.size() > 2 && !PropagateSubwindow(window_end)) {
1176 bool DisjunctiveEdgeFinding::PropagateSubwindow(IntegerValue window_end_min) {
1178 task_by_increasing_end_max_.clear();
1179 for (
const auto task_time : window_) {
1180 const int task = task_time.task_index;
1193 is_gray_[task] =
false;
1194 task_by_increasing_end_max_.push_back({task,
end_max});
1196 is_gray_[task] =
true;
1202 if (task_by_increasing_end_max_.size() < 2)
return true;
1203 std::sort(task_by_increasing_end_max_.begin(),
1204 task_by_increasing_end_max_.end());
1215 const int window_size = window_.size();
1216 event_size_.clear();
1217 theta_tree_.
Reset(window_size);
1218 for (
int event = 0;
event < window_size; ++event) {
1219 const TaskTime task_time = window_[event];
1220 const int task = task_time.task_index;
1221 const IntegerValue energy_min = helper_->
DurationMin(task);
1222 event_size_.push_back(energy_min);
1223 if (is_gray_[task]) {
1226 non_gray_task_to_event_[task] = event;
1235 DCHECK(!is_gray_[task_by_increasing_end_max_.back().task_index]);
1236 const IntegerValue non_gray_end_max =
1237 task_by_increasing_end_max_.back().time;
1240 const IntegerValue non_gray_end_min = theta_tree_.
GetEnvelope();
1241 if (non_gray_end_min > non_gray_end_max) {
1245 const int critical_event =
1247 const IntegerValue window_start = window_[critical_event].time;
1248 const IntegerValue window_end =
1250 for (
int event = critical_event;
event < window_size;
event++) {
1251 const int task = window_[event].task_index;
1252 if (is_gray_[task])
continue;
1270 int critical_event_with_gray;
1272 IntegerValue available_energy;
1274 non_gray_end_max, &critical_event_with_gray, &gray_event,
1276 const int gray_task = window_[gray_event].task_index;
1279 DCHECK(is_gray_[gray_task]);
1280 if (helper_->
StartMin(gray_task) < non_gray_end_min) {
1283 const int critical_event =
1286 const int first_event =
1287 std::min(critical_event, critical_event_with_gray);
1288 const int second_event =
1289 std::max(critical_event, critical_event_with_gray);
1290 const IntegerValue first_start = window_[first_event].time;
1291 const IntegerValue second_start = window_[second_event].time;
1295 const IntegerValue window_end =
1296 non_gray_end_max + event_size_[gray_event] - available_energy - 1;
1297 CHECK_GE(window_end, non_gray_end_max);
1301 for (
int event = first_event;
event < window_size;
event++) {
1302 const int task = window_[event].task_index;
1303 if (is_gray_[task])
continue;
1306 task, event_size_[event],
1307 event >= second_event ? second_start : first_start);
1314 window_[critical_event_with_gray].
time);
1331 if (task_by_increasing_end_max_.size() <= 2)
break;
1334 if (task_by_increasing_end_max_[0].
time >=
1340 const int new_gray_task = task_by_increasing_end_max_.back().task_index;
1341 task_by_increasing_end_max_.pop_back();
1342 const int new_gray_event = non_gray_task_to_event_[new_gray_task];
1343 DCHECK(!is_gray_[new_gray_task]);
1344 is_gray_[new_gray_task] =
true;
1346 window_[new_gray_event].
time,
1347 event_size_[new_gray_event]);
1354 const int id = watcher->
Register(
this);