30 : num_tasks_(helper->NumTasks()),
33 integer_trail_(integer_trail),
38 profile_.reserve(2 * num_tasks_ + 4);
41 forward_num_tasks_to_sweep_ = num_tasks_;
42 forward_tasks_to_sweep_.resize(num_tasks_);
43 backward_num_tasks_to_sweep_ = num_tasks_;
44 backward_tasks_to_sweep_.resize(num_tasks_);
46 num_profile_tasks_ = 0;
47 profile_tasks_.resize(num_tasks_);
48 positions_in_profile_tasks_.resize(num_tasks_);
51 starting_profile_height_ = IntegerValue(0);
53 for (
int t = 0; t < num_tasks_; ++t) {
54 forward_tasks_to_sweep_[t] = t;
55 backward_tasks_to_sweep_[t] = t;
56 profile_tasks_[t] = t;
57 positions_in_profile_tasks_[t] = t;
62 const int id = watcher->
Register(
this);
65 for (
int t = 0; t < num_tasks_; t++) {
75 profile_changed_ =
true;
76 while (profile_changed_) {
77 profile_changed_ =
false;
79 if (!BuildProfile())
return false;
81 if (!SweepAllTasks(
true))
return false;
85 if (!SweepAllTasks(
false))
return false;
91 bool TimeTablingPerTask::BuildProfile() {
97 for (
int i = num_profile_tasks_; i < num_tasks_; ++i) {
98 const int t1 = profile_tasks_[i];
101 const int t2 = profile_tasks_[num_profile_tasks_];
102 profile_tasks_[i] = t2;
103 profile_tasks_[num_profile_tasks_] = t1;
104 positions_in_profile_tasks_[t1] = num_profile_tasks_;
105 positions_in_profile_tasks_[t2] = i;
106 num_profile_tasks_++;
126 IntegerValue current_height = starting_profile_height_;
130 int next_start = num_tasks_ - 1;
132 while (next_end < num_tasks_) {
133 const IntegerValue old_height = current_height;
135 IntegerValue t = by_end_min[next_end].time;
136 if (next_start >= 0) {
137 t =
std::min(t, by_decreasing_start_max[next_start].
time);
141 while (next_start >= 0 && by_decreasing_start_max[next_start].
time == t) {
142 const int task_index = by_decreasing_start_max[next_start].task_index;
143 if (IsInProfile(task_index)) current_height += DemandMin(task_index);
148 while (next_end < num_tasks_ && by_end_min[next_end].
time == t) {
149 const int task_index = by_end_min[next_end].task_index;
150 if (IsInProfile(task_index)) current_height -= DemandMin(task_index);
155 if (current_height != old_height) {
156 profile_.emplace_back(current_start, old_height);
157 if (current_height > profile_max_height_) {
158 profile_max_height_ = current_height;
159 max_height_start = t;
166 DCHECK_GE(current_height, 0);
167 profile_.emplace_back(current_start, IntegerValue(0));
173 return IncreaseCapacity(max_height_start, profile_max_height_);
176 void TimeTablingPerTask::ReverseProfile() {
180 for (
int i = 1; i + 1 < profile_.size(); ++i) {
181 profile_[i].start = -profile_[i + 1].start;
183 std::reverse(profile_.begin() + 1, profile_.end() - 1);
186 bool TimeTablingPerTask::SweepAllTasks(
bool is_forward) {
188 const IntegerValue demand_threshold(
189 CapSub(CapacityMax().
value(), profile_max_height_.value()));
193 is_forward ? forward_num_tasks_to_sweep_ : backward_num_tasks_to_sweep_;
194 std::vector<int>& tasks =
195 is_forward ? forward_tasks_to_sweep_ : backward_tasks_to_sweep_;
200 for (
int i = num_tasks - 1; i >= 0; --i) {
201 const int t = tasks[i];
207 std::swap(tasks[i], tasks[--num_tasks]);
212 if (DemandMin(t) <= demand_threshold) {
213 if (DemandMax(t) == 0) {
215 std::swap(tasks[i], tasks[--num_tasks]);
226 std::swap(tasks[i], tasks[--num_tasks]);
231 if (!SweepTask(t))
return false;
237 bool TimeTablingPerTask::SweepTask(
int task_id) {
239 const IntegerValue duration_min = helper_->
DurationMin(task_id);
240 const IntegerValue initial_start_min = helper_->
StartMin(task_id);
241 const IntegerValue initial_end_min = helper_->
EndMin(task_id);
243 IntegerValue new_start_min = initial_start_min;
244 IntegerValue new_end_min = initial_end_min;
248 DCHECK(is_sorted(profile_.begin(), profile_.end()));
250 std::upper_bound(profile_.begin(), profile_.end(), new_start_min,
251 [&](IntegerValue
value,
const ProfileRectangle& rect) {
252 return value < rect.start;
259 const IntegerValue conflict_height = CapacityMax() - DemandMin(task_id);
262 bool conflict_found =
false;
275 for (; profile_[rec_id].start < limit; ++rec_id) {
277 if (profile_[rec_id].height <= conflict_height)
continue;
279 conflict_found =
true;
283 new_start_min = profile_[rec_id + 1].start;
285 if (IsInProfile(task_id)) {
295 new_end_min =
std::max(new_end_min, new_start_min + duration_min);
298 if (profile_[rec_id].start < initial_end_min) {
299 last_initial_conflict =
std::min(new_start_min, initial_end_min) - 1;
303 if (!conflict_found)
return true;
305 if (initial_start_min != new_start_min &&
306 !UpdateStartingTime(task_id, last_initial_conflict, new_start_min)) {
321 if (helper_->
StartMin(task_id) != initial_start_min) {
322 profile_changed_ =
true;
328 bool TimeTablingPerTask::UpdateStartingTime(
int task_id, IntegerValue left,
329 IntegerValue right) {
332 AddProfileReason(left, right);
350 void TimeTablingPerTask::AddProfileReason(IntegerValue left,
351 IntegerValue right) {
352 for (
int i = 0; i < num_profile_tasks_; ++i) {
353 const int t = profile_tasks_[i];
371 bool TimeTablingPerTask::IncreaseCapacity(IntegerValue
time,
372 IntegerValue new_min) {
373 if (new_min <= CapacityMin())
return true;