88 if (!helper_->SynchronizeAndSetTimeDirection(
true))
return false;
89 if (!demands_->CacheAllEnergyValues())
return true;
91 const IntegerValue capacity_max = integer_trail_->UpperBound(capacity_);
93 if (capacity_max <= 0)
return true;
96 start_event_task_time_.clear();
98 for (
const auto task_time : helper_->TaskByIncreasingStartMin()) {
99 const int task = task_time.task_index;
100 if (helper_->IsAbsent(task) || demands_->EnergyMax(task) == 0) {
101 task_to_start_event_[task] = -1;
104 start_event_task_time_.emplace_back(task_time);
105 task_to_start_event_[task] = num_events;
108 start_event_is_present_.assign(num_events,
false);
109 theta_tree_.Reset(num_events);
111 bool tree_has_mandatory_intervals =
false;
113 const IntegerValue start_end_magnitude =
115 helper_->TaskByDecreasingEndMax().front().task_index)),
116 IntTypeAbs(helper_->TaskByIncreasingStartMin().front().time));
122 const auto by_decreasing_end_max = helper_->TaskByDecreasingEndMax();
123 for (
const auto [current_task, current_end] :
125 if (task_to_start_event_[current_task] == -1)
continue;
129 const int current_event = task_to_start_event_[current_task];
130 const IntegerValue start_min = start_event_task_time_[current_event].time;
131 const bool is_present = helper_->IsPresent(current_task);
132 start_event_is_present_[current_event] = is_present;
134 tree_has_mandatory_intervals =
true;
135 theta_tree_.AddOrUpdateEvent(current_event, start_min * capacity_max,
136 demands_->EnergyMin(current_task),
137 demands_->EnergyMax(current_task));
139 theta_tree_.AddOrUpdateOptionalEvent(current_event,
140 start_min * capacity_max,
141 demands_->EnergyMax(current_task));
145 if (tree_has_mandatory_intervals) {
147 const IntegerValue envelope = theta_tree_.GetEnvelope();
148 const int critical_event =
149 theta_tree_.GetMaxEventWithEnvelopeGreaterThan(envelope - 1);
150 const IntegerValue window_start =
151 start_event_task_time_[critical_event].time;
152 const IntegerValue window_end = current_end;
153 const IntegerValue window_size = window_end - window_start;
154 if (window_size == 0)
continue;
155 const IntegerValue new_capacity_min =
156 CeilRatio(envelope - window_start * capacity_max, window_size);
164 if (new_capacity_min > integer_trail_->LowerBound(capacity_)) {
165 helper_->ClearReason();
166 for (
int event = critical_event;
event < num_events;
event++) {
167 if (start_event_is_present_[event]) {
168 const int task = start_event_task_time_[event].task_index;
169 helper_->AddPresenceReason(task);
170 demands_->AddEnergyMinReason(task);
171 helper_->AddStartMinReason(task, window_start);
172 helper_->AddEndMaxReason(task, window_end);
176 return helper_->ReportConflict();
178 if (!helper_->PushIntegerLiteral(
179 capacity_.GreaterOrEqual(new_capacity_min))) {
188 while (theta_tree_.GetOptionalEnvelope() > current_end * capacity_max) {
198 helper_->ClearReason();
200 int event_with_new_energy_max;
201 IntegerValue new_energy_max;
202 theta_tree_.GetEventsWithOptionalEnvelopeGreaterThan(
203 current_end * capacity_max, &critical_event,
204 &event_with_new_energy_max, &new_energy_max);
206 const IntegerValue window_start =
207 start_event_task_time_[critical_event].time;
210 const IntegerValue window_end = current_end;
211 for (
int event = critical_event;
event < num_events;
event++) {
212 if (start_event_is_present_[event]) {
213 if (event == event_with_new_energy_max)
continue;
214 const int task = start_event_task_time_[event].task_index;
215 helper_->AddPresenceReason(task);
216 helper_->AddStartMinReason(task, window_start);
217 helper_->AddEndMaxReason(task, window_end);
218 demands_->AddEnergyMinReason(task);
222 helper_->MutableIntegerReason()->push_back(
223 integer_trail_->UpperBoundAsLiteral(capacity_.var));
226 const int task_with_new_energy_max =
227 start_event_task_time_[event_with_new_energy_max].task_index;
228 helper_->AddStartMinReason(task_with_new_energy_max, window_start);
229 helper_->AddEndMaxReason(task_with_new_energy_max, window_end);
230 if (!demands_->DecreaseEnergyMax(task_with_new_energy_max,
235 if (helper_->IsPresent(task_with_new_energy_max)) {
236 theta_tree_.AddOrUpdateEvent(
237 task_to_start_event_[task_with_new_energy_max],
238 start_event_task_time_[event_with_new_energy_max].time *
240 demands_->EnergyMin(task_with_new_energy_max), new_energy_max);
242 theta_tree_.RemoveEvent(event_with_new_energy_max);
269 if (!helper_->SynchronizeAndSetTimeDirection(
true))
return false;
275 IntegerValue energy_after_time(0);
276 IntegerValue profile_height(0);
281 const IntegerValue capacity_max = integer_trail_->UpperBound(capacity_);
282 dp_.Reset(capacity_max.value());
286 const auto& profile = helper_->GetEnergyProfile();
288 for (
int i = profile.size() - 1;
i >= 0;) {
291 const int t = profile[
i].task;
292 if (!helper_->IsPresent(t) || !is_in_subtasks_[t]) {
298 const IntegerValue time = profile[
i].time;
299 if (profile_height > 0) {
300 energy_after_time += profile_height * (previous_time - time);
302 previous_time = time;
306 const IntegerValue saved_capa_max = dp_.CurrentMax();
307 const IntegerValue saved_min_offset = min_offset;
309 for (;
i >= 0 && profile[
i].time == time; --
i) {
311 const int t = profile[
i].task;
312 if (!helper_->IsPresent(t) || !is_in_subtasks_[t])
continue;
314 min_offset = std::min(min_offset, task_offsets_[t]);
315 const IntegerValue demand_min = demands_->DemandMin(t);
316 if (profile[
i].is_first) {
317 profile_height -= demand_min;
319 profile_height += demand_min;
320 if (demands_->Demands()[t].IsConstant()) {
321 dp_.Add(demand_min.value());
323 dp_.Add(capacity_max.value());
335 if (energy_after_time == 0)
continue;
336 DCHECK_GT(saved_capa_max, 0);
338 const IntegerValue end_min_with_offset =
339 time +
CeilRatio(energy_after_time, saved_capa_max) + saved_min_offset;
340 if (end_min_with_offset > best_bound) {
342 best_bound = end_min_with_offset;
345 DCHECK_EQ(profile_height, 0);
348 if (best_bound > integer_trail_->LowerBound(var_to_push_)) {
351 helper_->ClearReason();
352 for (
int t = 0; t < helper_->NumTasks(); ++t) {
353 if (!is_in_subtasks_[t])
continue;
354 if (!helper_->IsPresent(t))
continue;
356 const IntegerValue size_min = helper_->SizeMin(t);
357 if (size_min == 0)
continue;
359 const IntegerValue demand_min = demands_->DemandMin(t);
360 if (demand_min == 0)
continue;
362 const IntegerValue end_min = helper_->EndMin(t);
363 if (end_min <= best_time)
continue;
365 helper_->AddEndMinReason(t, std::min(best_time + size_min, end_min));
366 helper_->AddSizeMinReason(t);
367 helper_->AddPresenceReason(t);
368 demands_->AddDemandMinReason(t);
371 helper_->MutableIntegerReason()->push_back(
372 integer_trail_->UpperBoundAsLiteral(capacity_.var));
376 if (!helper_->PushIntegerLiteral(
517 if (!helper_->SynchronizeAndSetTimeDirection(
true))
return false;
518 if (!demands_->CacheAllEnergyValues())
return true;
520 const IntegerValue capacity_max = integer_trail_->UpperBound(capacity_);
521 if (capacity_max <= 0)
return true;
524 start_event_task_time_.clear();
526 for (
const auto task_time : helper_->TaskByIncreasingStartMin()) {
527 const int task = task_time.task_index;
528 if (!helper_->IsPresent(task) || demands_->DemandMin(task) == 0) {
529 task_to_start_event_[task] = -1;
532 start_event_task_time_.emplace_back(task_time);
533 task_to_start_event_[task] = num_events;
537 if (num_events == 0)
return true;
540 const IntegerValue start_end_magnitude =
542 helper_->TaskByDecreasingEndMax().front().task_index)),
543 IntTypeAbs(helper_->TaskByIncreasingStartMin().front().time));
544 if (start_end_magnitude == 0)
return true;
546 const IntegerValue max_energy =
552 const IntegerValue max_for_fixpoint_inverse =
553 std::numeric_limits<IntegerValue>::max() / max_energy;
555 theta_tree_.Reset(num_events);
581 std::vector<std::pair<IntegerValue, IntegerValue>> candidates_for_conflict;
582 const auto by_decreasing_end_max = helper_->TaskByDecreasingEndMax();
583 for (
const auto [current_task, current_end] :
585 if (task_to_start_event_[current_task] == -1)
continue;
586 if (!helper_->IsPresent(current_task))
continue;
587 if (helper_->SizeMin(current_task) == 0)
continue;
588 if (demands_->DemandMin(current_task) == 0)
continue;
590 if (demands_->DemandMin(current_task) > capacity_max) {
593 demands_->AddDemandMinReason(current_task);
596 helper_->MutableIntegerReason()->push_back(
597 integer_trail_->UpperBoundAsLiteral(capacity_));
602 helper_->MutableIntegerReason()->push_back(size.
GreaterOrEqual(1));
605 return helper_->ReportConflict();
610 const IntegerValue current_pseudo_energy =
611 helper_->SizeMin(current_task) *
612 (max_for_fixpoint_inverse /
613 (capacity_max / demands_->DemandMin(current_task)));
614 const int current_event = task_to_start_event_[current_task];
615 const IntegerValue start_min = start_event_task_time_[current_event].time;
616 theta_tree_.AddOrUpdateEvent(
617 current_event, start_min * max_for_fixpoint_inverse,
618 current_pseudo_energy, current_pseudo_energy);
623 const IntegerValue envelope = theta_tree_.GetEnvelope();
624 const int critical_event =
625 theta_tree_.GetMaxEventWithEnvelopeGreaterThan(envelope - 1);
626 const IntegerValue window_start =
627 start_event_task_time_[critical_event].time;
628 const IntegerValue window_end = current_end;
629 const IntegerValue window_size = window_end - window_start;
630 if (window_size == 0)
continue;
632 if (envelope > window_end * max_for_fixpoint_inverse) {
633 candidates_for_conflict.push_back({window_start, window_end});
637 VLOG_EVERY_N_SEC(2, 3) <<
"Found " << candidates_for_conflict.size()
638 <<
" intervals with potential energy conflict using a "
639 "DFF on a problem of size "
640 << num_events <<
".";
642 if (candidates_for_conflict.empty()) {
643 ++num_no_potential_window_;
652 absl::InlinedVector<std::pair<IntegerValue, IntegerValue>, 3>
654 std::sample(candidates_for_conflict.begin(), candidates_for_conflict.end(),
655 std::back_inserter(sampled_candidates), 3, *random_);
656 for (
const auto& [window_start, window_end] : sampled_candidates) {
657 if (!FindAndPropagateConflict(window_start, window_end)) {