28#include "ortools/sat/sat_parameters.pb.h"
39 const std::vector<IntervalVariable>& vars) {
41 bool is_all_different =
true;
43 for (
const IntervalVariable
var : vars) {
46 is_all_different =
false;
50 if (is_all_different) {
51 std::vector<AffineExpression> starts;
52 starts.reserve(vars.size());
53 for (
const IntervalVariable
interval : vars) {
61 const auto& sat_parameters = *
model->GetOrCreate<SatParameters>();
62 if (vars.size() > 2 && sat_parameters.use_combined_no_overlap()) {
70 model->TakeOwnership(helper);
75 std::vector<AffineExpression> demands(vars.size(), one);
79 model->TakeOwnership(timetable);
83 if (vars.size() == 2) {
86 model->TakeOwnership(propagator);
95 watcher->SetPropagatorPriority(
id, 1);
96 model->TakeOwnership(overload_checker);
98 for (
const bool time_direction : {
true,
false}) {
101 const int id = detectable_precedences->
RegisterWith(watcher);
102 watcher->SetPropagatorPriority(
id, 2);
103 model->TakeOwnership(detectable_precedences);
105 for (
const bool time_direction : {
true,
false}) {
109 watcher->SetPropagatorPriority(
id, 3);
110 model->TakeOwnership(not_last);
112 for (
const bool time_direction : {
true,
false}) {
116 watcher->SetPropagatorPriority(
id, 4);
117 model->TakeOwnership(edge_finding);
124 if (sat_parameters.use_precedences_in_disjunctive_constraint() &&
125 !sat_parameters.use_combined_no_overlap()) {
126 for (
const bool time_direction : {
true,
false}) {
131 watcher->SetPropagatorPriority(
id, 5);
132 model->TakeOwnership(precedences);
139 const std::vector<IntervalVariable>& vars) {
145 for (
int i = 0; i < vars.size(); ++i) {
146 for (
int j = 0; j < i; ++j) {
150 precedences->AddConditionalPrecedence(repository->EndVar(vars[i]),
151 repository->StartVar(vars[j]),
153 precedences->AddConditionalPrecedence(repository->EndVar(vars[j]),
154 repository->StartVar(vars[i]),
162 const std::vector<IntervalVariable>& vars) {
170 int j = sorted_tasks_.size();
171 sorted_tasks_.push_back(e);
173 sorted_tasks_[j] = sorted_tasks_[j - 1];
176 sorted_tasks_[j] = e;
177 DCHECK(std::is_sorted(sorted_tasks_.begin(), sorted_tasks_.end()));
181 if (j <= optimized_restart_) optimized_restart_ = 0;
186 const IntegerValue dmin = helper.
SizeMin(t);
191 const int size = sorted_tasks_.size();
192 for (
int i = 0;; ++i) {
193 if (i == size)
return;
194 if (sorted_tasks_[i].task == e.
task) {
195 sorted_tasks_.erase(sorted_tasks_.begin() + i);
200 optimized_restart_ = sorted_tasks_.size();
201 sorted_tasks_.push_back(e);
202 DCHECK(std::is_sorted(sorted_tasks_.begin(), sorted_tasks_.end()));
206 sorted_tasks_.erase(sorted_tasks_.begin() +
index);
207 optimized_restart_ = 0;
211 DCHECK(std::is_sorted(sorted_tasks_.begin(), sorted_tasks_.end()));
212 const int size = sorted_tasks_.size();
214 for (
int i = optimized_restart_; i < size; ++i) {
215 const Entry& e = sorted_tasks_[i];
217 optimized_restart_ = i;
227 int* critical_index)
const {
229 DCHECK(std::is_sorted(sorted_tasks_.begin(), sorted_tasks_.end()));
230 bool ignored =
false;
231 const int size = sorted_tasks_.size();
236 if (optimized_restart_ + 1 == size &&
237 sorted_tasks_[optimized_restart_].task == task_to_ignore) {
238 optimized_restart_ = 0;
241 for (
int i = optimized_restart_; i < size; ++i) {
242 const Entry& e = sorted_tasks_[i];
243 if (e.
task == task_to_ignore) {
249 if (!ignored) optimized_restart_ = i;
285 const IntegerValue end_min_before = helper_->
EndMin(task_before);
286 if (helper_->
StartMin(task_after) < end_min_before) {
301 const IntegerValue start_max_after = helper_->
StartMax(task_after);
302 if (helper_->
EndMax(task_before) > start_max_after) {
320 const int id = watcher->
Register(
this);
326template <
bool time_direction>
329 task_to_disjunctives_.resize(helper_->
NumTasks());
332 const int id = watcher->
Register(
this);
335 watcher->NotifyThatPropagatorMayNotReachFixedPointInOnePass(
id);
338template <
bool time_direction>
340 const std::vector<IntervalVariable>& vars) {
341 const int index = task_sets_.size();
342 task_sets_.emplace_back(vars.size());
344 for (
const IntervalVariable
var : vars) {
345 task_to_disjunctives_[
var.value()].push_back(
index);
349template <
bool time_direction>
351 if (!helper_->SynchronizeAndSetTimeDirection(time_direction))
return false;
352 const auto& task_by_increasing_end_min = helper_->TaskByIncreasingEndMin();
353 const auto& task_by_decreasing_start_max =
354 helper_->TaskByDecreasingStartMax();
356 for (
auto& task_set : task_sets_) task_set.Clear();
360 const int num_tasks = helper_->NumTasks();
361 task_is_added_.assign(num_tasks,
false);
362 int queue_index = num_tasks - 1;
363 for (
const auto task_time : task_by_increasing_end_min) {
364 const int t = task_time.task_index;
365 const IntegerValue
end_min = task_time.time;
366 if (helper_->IsAbsent(t))
continue;
369 while (queue_index >= 0) {
370 const auto to_insert = task_by_decreasing_start_max[queue_index];
371 const int task_index = to_insert.task_index;
372 const IntegerValue
start_max = to_insert.time;
374 if (helper_->IsPresent(task_index)) {
375 task_is_added_[task_index] =
true;
376 const IntegerValue shifted_smin = helper_->ShiftedStartMin(task_index);
377 const IntegerValue size_min = helper_->SizeMin(task_index);
378 for (
const int d_index : task_to_disjunctives_[task_index]) {
380 task_sets_[d_index].AddEntry({task_index, shifted_smin, size_min});
381 end_mins_[d_index] = task_sets_[d_index].ComputeEndMin();
382 max_of_end_min =
std::max(max_of_end_min, end_mins_[d_index]);
390 IntegerValue new_start_min = helper_->StartMin(t);
391 if (new_start_min >= max_of_end_min)
continue;
392 int best_critical_index = 0;
393 int best_d_index = -1;
394 if (task_is_added_[t]) {
395 for (
const int d_index : task_to_disjunctives_[t]) {
396 if (new_start_min >= end_mins_[d_index])
continue;
397 int critical_index = 0;
398 const IntegerValue end_min_of_critical_tasks =
399 task_sets_[d_index].ComputeEndMin(t,
401 DCHECK_LE(end_min_of_critical_tasks, max_of_end_min);
402 if (end_min_of_critical_tasks > new_start_min) {
403 new_start_min = end_min_of_critical_tasks;
404 best_d_index = d_index;
405 best_critical_index = critical_index;
411 for (
const int d_index : task_to_disjunctives_[t]) {
412 if (end_mins_[d_index] > new_start_min) {
413 new_start_min = end_mins_[d_index];
414 best_d_index = d_index;
417 if (best_d_index != -1) {
418 const IntegerValue end_min_of_critical_tasks =
419 task_sets_[best_d_index].ComputeEndMin(t,
420 &best_critical_index);
421 CHECK_EQ(end_min_of_critical_tasks, new_start_min);
426 if (best_d_index == -1)
continue;
431 helper_->ClearReason();
432 const std::vector<TaskSet::Entry>& sorted_tasks =
433 task_sets_[best_d_index].SortedTasks();
434 const IntegerValue window_start =
435 sorted_tasks[best_critical_index].start_min;
436 for (
int i = best_critical_index; i < sorted_tasks.size(); ++i) {
437 const int ct = sorted_tasks[i].task;
438 if (
ct == t)
continue;
439 helper_->AddPresenceReason(
ct);
440 helper_->AddEnergyAfterReason(
ct, sorted_tasks[i].size_min, window_start);
441 helper_->AddStartMaxReason(
ct,
end_min - 1);
443 helper_->AddEndMinReason(t,
end_min);
444 if (!helper_->IncreaseStartMin(t, new_start_min)) {
452 if (task_is_added_[t]) {
453 const IntegerValue shifted_smin = helper_->ShiftedStartMin(t);
454 const IntegerValue size_min = helper_->SizeMin(t);
455 for (
const int d_index : task_to_disjunctives_[t]) {
456 task_sets_[d_index].NotifyEntryIsNowLastIfPresent(
457 {t, shifted_smin, size_min});
458 end_mins_[d_index] = task_sets_[d_index].ComputeEndMin();
459 max_of_end_min =
std::max(max_of_end_min, end_mins_[d_index]);
483 IntegerValue relevant_end;
484 int relevant_size = 0;
486 const int task = task_time.task_index;
487 if (helper_->
IsAbsent(task))
continue;
489 const IntegerValue
start_min = task_time.time;
491 window_.push_back(task_time);
492 window_end += helper_->
SizeMin(task);
493 if (window_end > helper_->
EndMax(task)) {
494 relevant_size = window_.size();
495 relevant_end = window_end;
503 window_.resize(relevant_size);
504 if (relevant_size > 0 && !PropagateSubwindow(relevant_end)) {
510 window_.push_back(task_time);
516 window_.resize(relevant_size);
517 if (relevant_size > 0 && !PropagateSubwindow(relevant_end)) {
531bool DisjunctiveOverloadChecker::PropagateSubwindow(
532 IntegerValue global_window_end) {
534 const int window_size = window_.size();
535 theta_tree_.
Reset(window_size);
536 task_by_increasing_end_max_.clear();
537 for (
int i = 0; i < window_size; ++i) {
539 const int task = window_[i].task_index;
541 if (
end_max < global_window_end) {
542 task_to_event_[task] = i;
543 task_by_increasing_end_max_.push_back({task,
end_max});
548 std::sort(task_by_increasing_end_max_.begin(),
549 task_by_increasing_end_max_.end());
550 for (
const auto task_time : task_by_increasing_end_max_) {
551 const int current_task = task_time.task_index;
556 if (helper_->
IsAbsent(current_task))
continue;
558 DCHECK_NE(task_to_event_[current_task], -1);
560 const int current_event = task_to_event_[current_task];
561 const IntegerValue energy_min = helper_->
SizeMin(current_task);
567 energy_min, energy_min);
570 current_event, window_[current_event].
time, energy_min);
574 const IntegerValue current_end = task_time.time;
578 const int critical_event =
580 const IntegerValue window_start = window_[critical_event].time;
581 const IntegerValue window_end =
583 for (
int event = critical_event;
event < window_size;
event++) {
584 const IntegerValue energy_min = theta_tree_.
EnergyMin(event);
585 if (energy_min > 0) {
586 const int task = window_[event].task_index;
603 IntegerValue available_energy;
605 current_end, &critical_event, &optional_event, &available_energy);
607 const int optional_task = window_[optional_event].task_index;
611 if (!helper_->
IsAbsent(optional_task)) {
612 const IntegerValue optional_size_min = helper_->
SizeMin(optional_task);
613 const IntegerValue window_start = window_[critical_event].time;
614 const IntegerValue window_end =
615 current_end + optional_size_min - available_energy - 1;
616 for (
int event = critical_event;
event < window_size;
event++) {
617 const IntegerValue energy_min = theta_tree_.
EnergyMin(event);
618 if (energy_min > 0) {
619 const int task = window_[event].task_index;
642 const int id = watcher->
Register(
this);
652 to_propagate_.clear();
653 processed_.assign(helper_->
NumTasks(),
false);
662 task_by_increasing_end_min_.clear();
665 const int task = task_time.task_index;
666 if (helper_->
IsAbsent(task))
continue;
670 const IntegerValue size_min = helper_->
SizeMin(task);
675 task_by_increasing_end_min_.push_back({task,
end_min});
681 if (task_by_increasing_end_min_.size() > 1 && !PropagateSubwindow()) {
686 task_by_increasing_end_min_.clear();
687 task_by_increasing_end_min_.push_back({task,
end_min});
691 if (task_by_increasing_end_min_.size() > 1 && !PropagateSubwindow()) {
698bool DisjunctiveDetectablePrecedences::PropagateSubwindow() {
699 DCHECK(!task_by_increasing_end_min_.empty());
704 task_by_increasing_end_min_.end());
705 const IntegerValue max_end_min = task_by_increasing_end_min_.back().time;
711 task_by_increasing_start_max_.clear();
712 for (
const TaskTime entry : task_by_increasing_end_min_) {
713 const int task = entry.task_index;
715 if (start_max < max_end_min && helper_->IsPresent(task)) {
716 task_by_increasing_start_max_.push_back({task,
start_max});
719 if (task_by_increasing_start_max_.empty())
return true;
720 std::sort(task_by_increasing_start_max_.begin(),
721 task_by_increasing_start_max_.end());
729 to_propagate_.clear();
730 bool need_update =
false;
734 int blocking_task = -1;
735 const int queue_size = task_by_increasing_start_max_.size();
736 for (
const auto task_time : task_by_increasing_end_min_) {
740 const int current_task = task_time.task_index;
741 const IntegerValue current_end_min = task_time.time;
742 if (helper_->
IsAbsent(current_task))
continue;
744 for (; queue_index < queue_size; ++queue_index) {
745 const auto to_insert = task_by_increasing_start_max_[queue_index];
746 const IntegerValue
start_max = to_insert.time;
749 const int t = to_insert.task_index;
763 if (!processed_[t]) {
764 if (blocking_task != -1) {
774 <<
" task should have mandatory part: "
776 DCHECK(to_propagate_.empty());
778 to_propagate_.push_back(t);
787 if (blocking_task != current_task) {
788 to_propagate_.push_back(current_task);
789 if (blocking_task != -1)
continue;
791 for (
const int t : to_propagate_) {
793 processed_[t] =
true;
812 if (task_set_end_min > helper_->
StartMin(t)) {
814 const std::vector<TaskSet::Entry>& sorted_tasks =
821 const IntegerValue end_min_if_present =
823 const IntegerValue window_start =
824 sorted_tasks[critical_index].start_min;
825 for (
int i = critical_index; i < sorted_tasks.size(); ++i) {
826 const int ct = sorted_tasks[i].task;
848 if (t == blocking_task) {
859 to_propagate_.clear();
866 const int id = watcher->
Register(
this);
879 const int task = task_time.task_index;
882 const IntegerValue
start_min = task_time.time;
884 window_.push_back(task_time);
885 window_end += helper_->
SizeMin(task);
889 if (window_.size() > 1 && !PropagateSubwindow()) {
895 window_.push_back(task_time);
898 if (window_.size() > 1 && !PropagateSubwindow()) {
904bool DisjunctivePrecedences::PropagateSubwindow() {
910 index_to_end_vars_.clear();
912 for (
const auto task_time : window_) {
913 const int task = task_time.task_index;
919 window_[new_size++] = task_time;
920 index_to_end_vars_.push_back(end_exp.
var);
922 window_.resize(new_size);
925 const int size = before_.size();
926 for (
int i = 0; i < size;) {
927 const IntegerVariable
var = before_[i].var;
931 const int initial_i = i;
933 for (; i < size && before_[i].var ==
var; ++i) {
935 const TaskTime task_time = window_[before_[i].index];
940 const AffineExpression& end_exp = helper_->
Ends()[task_time.task_index];
941 min_offset =
std::min(min_offset, before_[i].offset - end_exp.constant);
946 helper_->
SizeMin(task_time.task_index)});
953 const IntegerValue new_lb = task_set_.
ComputeEndMin() + min_offset;
955 const std::vector<TaskSet::Entry>& sorted_tasks = task_set_.
SortedTasks();
960 for (
int j = initial_i; j < i; ++j) {
961 const int task = window_[before_[j].index].task_index;
962 task_to_arc_index_[task] = before_[j].arc_index;
966 const IntegerValue window_start = sorted_tasks[critical_index].start_min;
967 for (
int i = critical_index; i < sorted_tasks.size(); ++i) {
968 const int ct = sorted_tasks[i].task;
973 const AffineExpression& end_exp = helper_->
Ends()[
ct];
975 task_to_arc_index_[
ct], min_offset + end_exp.constant,
992 const int id = watcher->
Register(
this);
1002 const auto& task_by_decreasing_start_max =
1004 const auto& task_by_increasing_shifted_start_min =
1018 int queue_index = task_by_decreasing_start_max.size() - 1;
1019 const int num_tasks = task_by_increasing_shifted_start_min.size();
1020 for (
int i = 0; i < num_tasks;) {
1021 start_min_window_.clear();
1023 for (; i < num_tasks; ++i) {
1024 const TaskTime task_time = task_by_increasing_shifted_start_min[i];
1026 if (!helper_->
IsPresent(task))
continue;
1029 if (start_min_window_.empty()) {
1030 start_min_window_.push_back(task_time);
1033 start_min_window_.push_back(task_time);
1034 window_end += helper_->
SizeMin(task);
1042 start_max_window_.clear();
1043 for (; queue_index >= 0; queue_index--) {
1044 const auto task_time = task_by_decreasing_start_max[queue_index];
1047 if (task_time.time >= window_end)
break;
1048 if (helper_->
IsAbsent(task_time.task_index))
continue;
1049 start_max_window_.push_back(task_time);
1055 if (start_min_window_.size() <= 1)
continue;
1058 if (!start_max_window_.empty() && !PropagateSubwindow()) {
1065bool DisjunctiveNotLast::PropagateSubwindow() {
1066 auto& task_by_increasing_end_max = start_max_window_;
1067 for (
TaskTime& entry : task_by_increasing_end_max) {
1068 entry.time = helper_->
EndMax(entry.task_index);
1071 task_by_increasing_end_max.end());
1073 const IntegerValue threshold = task_by_increasing_end_max.back().time;
1074 auto& task_by_increasing_start_max = start_min_window_;
1076 for (
const TaskTime entry : task_by_increasing_start_max) {
1077 const int task = entry.task_index;
1081 task_by_increasing_start_max[queue_size++] = {task,
start_max};
1087 if (queue_size <= 1)
return true;
1089 task_by_increasing_start_max.resize(queue_size);
1090 std::sort(task_by_increasing_start_max.begin(),
1091 task_by_increasing_start_max.end());
1094 int queue_index = 0;
1095 for (
const auto task_time : task_by_increasing_end_max) {
1096 const int t = task_time.task_index;
1097 const IntegerValue
end_max = task_time.time;
1101 if (helper_->
IsAbsent(t))
continue;
1106 while (queue_index < queue_size) {
1107 const auto to_insert = task_by_increasing_start_max[queue_index];
1108 const IntegerValue
start_max = to_insert.time;
1111 const int task_index = to_insert.task_index;
1114 helper_->
SizeMin(task_index)});
1128 int critical_index = 0;
1129 const IntegerValue end_min_of_critical_tasks =
1131 if (end_min_of_critical_tasks <= helper_->StartMax(t))
continue;
1136 const std::vector<TaskSet::Entry>& sorted_tasks = task_set_.
SortedTasks();
1137 const int sorted_tasks_size = sorted_tasks.size();
1138 for (
int i = critical_index; i < sorted_tasks_size; ++i) {
1139 const int ct = sorted_tasks[i].task;
1140 if (t ==
ct)
continue;
1150 end_max > largest_ct_start_max);
1151 if (
end_max > largest_ct_start_max) {
1154 const IntegerValue window_start = sorted_tasks[critical_index].start_min;
1155 for (
int i = critical_index; i < sorted_tasks_size; ++i) {
1156 const int ct = sorted_tasks[i].task;
1157 if (
ct == t)
continue;
1169 if (!helper_->
DecreaseEndMax(t, largest_ct_start_max))
return false;
1176 const int id = watcher->
Register(
this);
1183 const int num_tasks = helper_->
NumTasks();
1185 is_gray_.resize(num_tasks,
false);
1186 non_gray_task_to_event_.resize(num_tasks);
1191 const int task = task_time.task_index;
1192 if (helper_->
IsAbsent(task))
continue;
1196 if (helper_->
StartMin(task) < window_end) {
1197 window_.push_back(task_time);
1198 window_end += helper_->
SizeMin(task);
1204 if (window_.size() > 2 && !PropagateSubwindow(window_end)) {
1210 window_.push_back(task_time);
1211 window_end = task_time.time + helper_->
SizeMin(task);
1213 if (window_.size() > 2 && !PropagateSubwindow(window_end)) {
1219bool DisjunctiveEdgeFinding::PropagateSubwindow(IntegerValue window_end_min) {
1221 task_by_increasing_end_max_.clear();
1222 for (
const auto task_time : window_) {
1223 const int task = task_time.task_index;
1236 is_gray_[task] =
false;
1237 task_by_increasing_end_max_.push_back({task,
end_max});
1239 is_gray_[task] =
true;
1245 if (task_by_increasing_end_max_.size() < 2)
return true;
1246 std::sort(task_by_increasing_end_max_.begin(),
1247 task_by_increasing_end_max_.end());
1258 const int window_size = window_.size();
1259 event_size_.clear();
1260 theta_tree_.
Reset(window_size);
1261 for (
int event = 0;
event < window_size; ++event) {
1262 const TaskTime task_time = window_[event];
1263 const int task = task_time.task_index;
1264 const IntegerValue energy_min = helper_->
SizeMin(task);
1265 event_size_.push_back(energy_min);
1266 if (is_gray_[task]) {
1269 non_gray_task_to_event_[task] = event;
1278 DCHECK(!is_gray_[task_by_increasing_end_max_.back().task_index]);
1279 const IntegerValue non_gray_end_max =
1280 task_by_increasing_end_max_.back().time;
1283 const IntegerValue non_gray_end_min = theta_tree_.
GetEnvelope();
1284 if (non_gray_end_min > non_gray_end_max) {
1288 const int critical_event =
1290 const IntegerValue window_start = window_[critical_event].time;
1291 const IntegerValue window_end =
1293 for (
int event = critical_event;
event < window_size;
event++) {
1294 const int task = window_[event].task_index;
1295 if (is_gray_[task])
continue;
1313 int critical_event_with_gray;
1315 IntegerValue available_energy;
1317 non_gray_end_max, &critical_event_with_gray, &gray_event,
1319 const int gray_task = window_[gray_event].task_index;
1320 DCHECK(is_gray_[gray_task]);
1324 if (helper_->
IsAbsent(gray_task)) {
1330 if (helper_->
StartMin(gray_task) < non_gray_end_min) {
1333 const int critical_event =
1336 const int first_event =
1337 std::min(critical_event, critical_event_with_gray);
1338 const int second_event =
1339 std::max(critical_event, critical_event_with_gray);
1340 const IntegerValue first_start = window_[first_event].time;
1341 const IntegerValue second_start = window_[second_event].time;
1345 const IntegerValue window_end =
1346 non_gray_end_max + event_size_[gray_event] - available_energy - 1;
1347 CHECK_GE(window_end, non_gray_end_max);
1351 for (
int event = first_event;
event < window_size;
event++) {
1352 const int task = window_[event].task_index;
1353 if (is_gray_[task])
continue;
1356 task, event_size_[event],
1357 event >= second_event ? second_start : first_start);
1364 window_[critical_event_with_gray].
time);
1381 if (task_by_increasing_end_max_.size() <= 2)
break;
1384 if (task_by_increasing_end_max_[0].
time >=
1390 const int new_gray_task = task_by_increasing_end_max_.back().task_index;
1391 task_by_increasing_end_max_.pop_back();
1392 const int new_gray_event = non_gray_task_to_event_[new_gray_task];
1393 DCHECK(!is_gray_[new_gray_task]);
1394 is_gray_[new_gray_task] =
true;
1396 window_[new_gray_event].
time,
1397 event_size_[new_gray_event]);
1404 const int id = watcher->
Register(
this);
#define DCHECK_LE(val1, val2)
#define DCHECK_NE(val1, val2)
#define CHECK_EQ(val1, val2)
#define CHECK_GE(val1, val2)
#define DCHECK_GE(val1, val2)
#define DCHECK_LT(val1, val2)
#define DCHECK(condition)
#define DCHECK_EQ(val1, val2)
void AddNoOverlap(const std::vector< IntervalVariable > &var)
CombinedDisjunctive(Model *model)
int RegisterWith(GenericLiteralWatcher *watcher)
int RegisterWith(GenericLiteralWatcher *watcher)
int RegisterWith(GenericLiteralWatcher *watcher)
int RegisterWith(GenericLiteralWatcher *watcher)
int RegisterWith(GenericLiteralWatcher *watcher)
int RegisterWith(GenericLiteralWatcher *watcher)
int Register(PropagatorInterface *propagator)
void NotifyThatPropagatorMayNotReachFixedPointInOnePass(int id)
bool IsCurrentlyIgnored(IntegerVariable i) const
IntegerValue LowerBound(IntegerVariable i) const
IntegerValue MaxSize(IntervalVariable i) const
AffineExpression Start(IntervalVariable i) const
IntegerValue MinSize(IntervalVariable i) const
bool IsOptional(IntervalVariable i) const
Class that owns everything related to a particular optimization model.
void AddPrecedenceReason(int arc_index, IntegerValue min_offset, std::vector< Literal > *literal_reason, std::vector< IntegerLiteral > *integer_reason) const
void ComputePrecedences(const std::vector< IntegerVariable > &vars, std::vector< IntegerPrecedences > *output)
BooleanVariable NewBooleanVariable()
std::vector< Literal > * MutableLiteralReason()
IntegerValue ShiftedStartMin(int t) const
IntegerValue EndMin(int t) const
ABSL_MUST_USE_RESULT bool PushIntegerLiteral(IntegerLiteral lit)
std::vector< IntegerLiteral > * MutableIntegerReason()
ABSL_MUST_USE_RESULT bool PushTaskAbsence(int t)
const std::vector< TaskTime > & TaskByIncreasingStartMin()
void WatchAllTasks(int id, GenericLiteralWatcher *watcher, bool watch_start_max=true, bool watch_end_max=true) const
void AddPresenceReason(int t)
bool IsPresent(int t) const
void AddEnergyAfterReason(int t, IntegerValue energy_min, IntegerValue time)
bool InPropagationLoop() const
std::string TaskDebugString(int t) const
void AddEndMinReason(int t, IntegerValue lower_bound)
ABSL_MUST_USE_RESULT bool IncreaseStartMin(int t, IntegerValue new_start_min)
bool IsAbsent(int t) const
IntegerValue EndMax(int t) const
ABSL_MUST_USE_RESULT bool ReportConflict()
ABSL_MUST_USE_RESULT bool SynchronizeAndSetTimeDirection(bool is_forward)
IntegerValue StartMin(int t) const
const std::vector< TaskTime > & TaskByDecreasingStartMax()
void AddEndMaxReason(int t, IntegerValue upper_bound)
IntegerValue StartMax(int t) const
const std::vector< TaskTime > & TaskByIncreasingShiftedStartMin()
void AddReasonForBeingBefore(int before, int after)
void AddStartMaxReason(int t, IntegerValue upper_bound)
void SetTimeDirection(bool is_forward)
ABSL_MUST_USE_RESULT bool DecreaseEndMax(int t, IntegerValue new_end_max)
const std::vector< AffineExpression > & Ends() const
IntegerValue SizeMin(int t) const
void AddUnsortedEntry(const Entry &e)
void NotifyEntryIsNowLastIfPresent(const Entry &e)
void RemoveEntryWithIndex(int index)
int GetCriticalIndex() const
const std::vector< Entry > & SortedTasks() const
void AddShiftedStartMinEntry(const SchedulingConstraintHelper &helper, int t)
IntegerValue ComputeEndMin() const
void AddEntry(const Entry &e)
IntegerValue ComputeEndMin(int task_to_ignore, int *critical_index) const
IntegerType GetEnvelopeOf(int event) const
void GetEventsWithOptionalEnvelopeGreaterThan(IntegerType target_envelope, int *critical_event, int *optional_event, IntegerType *available_energy) const
IntegerType GetOptionalEnvelope() const
void RemoveEvent(int event)
int GetMaxEventWithEnvelopeGreaterThan(IntegerType target_envelope) const
void Reset(int num_events)
void AddOrUpdateOptionalEvent(int event, IntegerType initial_envelope_opt, IntegerType energy_max)
IntegerType EnergyMin(int event) const
void AddOrUpdateEvent(int event, IntegerType initial_envelope, IntegerType energy_min, IntegerType energy_max)
IntegerType GetEnvelope() const
void RegisterWith(GenericLiteralWatcher *watcher)
void swap(IdMap< K, V > &a, IdMap< K, V > &b)
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue.value())
const IntegerVariable kNoIntegerVariable(-1)
std::function< void(Model *)> DisjunctiveWithBooleanPrecedencesOnly(const std::vector< IntervalVariable > &vars)
std::function< void(Model *)> DisjunctiveWithBooleanPrecedences(const std::vector< IntervalVariable > &vars)
std::function< void(Model *)> Disjunctive(const std::vector< IntervalVariable > &vars)
std::function< void(Model *)> AllDifferentOnBounds(const std::vector< AffineExpression > &expressions)
Collection of objects used to extend the Constraint Solver library.
void IncrementalSort(int max_comparisons, Iterator begin, Iterator end, Compare comp=Compare{}, bool is_stable=false)
static IntegerLiteral GreaterOrEqual(IntegerVariable i, IntegerValue bound)