89 if (!helper_->SynchronizeAndSetTimeDirection(
true))
return false;
90 if (!demands_->CacheAllEnergyValues())
return true;
92 const IntegerValue capacity_max = integer_trail_->UpperBound(capacity_);
94 if (capacity_max <= 0)
return true;
97 start_event_task_time_.clear();
99 for (
const auto task_time : helper_->TaskByIncreasingStartMin()) {
100 const int task = task_time.task_index;
101 if (helper_->IsAbsent(task) || demands_->EnergyMax(task) == 0) {
102 task_to_start_event_[task] = -1;
105 start_event_task_time_.emplace_back(task_time);
106 task_to_start_event_[task] = num_events;
109 start_event_is_present_.assign(num_events,
false);
110 theta_tree_.Reset(num_events);
112 bool tree_has_mandatory_intervals =
false;
114 const IntegerValue start_end_magnitude =
116 helper_->TaskByDecreasingEndMax().front().task_index)),
117 IntTypeAbs(helper_->TaskByIncreasingStartMin().front().time));
123 const auto by_decreasing_end_max = helper_->TaskByDecreasingEndMax();
124 for (
const auto [current_task, current_end] :
126 if (task_to_start_event_[current_task] == -1)
continue;
130 const int current_event = task_to_start_event_[current_task];
131 const IntegerValue start_min = start_event_task_time_[current_event].time;
132 const bool is_present = helper_->IsPresent(current_task);
133 start_event_is_present_[current_event] = is_present;
135 tree_has_mandatory_intervals =
true;
136 theta_tree_.AddOrUpdateEvent(current_event, start_min * capacity_max,
137 demands_->EnergyMin(current_task),
138 demands_->EnergyMax(current_task));
140 theta_tree_.AddOrUpdateOptionalEvent(current_event,
141 start_min * capacity_max,
142 demands_->EnergyMax(current_task));
146 if (tree_has_mandatory_intervals) {
148 const IntegerValue envelope = theta_tree_.GetEnvelope();
149 const int critical_event =
150 theta_tree_.GetMaxEventWithEnvelopeGreaterThan(envelope - 1);
151 const IntegerValue window_start =
152 start_event_task_time_[critical_event].time;
153 const IntegerValue window_end = current_end;
154 const IntegerValue window_size = window_end - window_start;
155 if (window_size == 0)
continue;
156 const IntegerValue new_capacity_min =
157 CeilRatio(envelope - window_start * capacity_max, window_size);
165 if (new_capacity_min > integer_trail_->LowerBound(capacity_)) {
166 helper_->ClearReason();
167 for (
int event = critical_event;
event < num_events;
event++) {
168 if (start_event_is_present_[event]) {
169 const int task = start_event_task_time_[event].task_index;
170 helper_->AddPresenceReason(task);
171 demands_->AddEnergyMinReason(task);
172 helper_->AddStartMinReason(task, window_start);
173 helper_->AddEndMaxReason(task, window_end);
177 return helper_->ReportConflict();
179 if (!helper_->PushIntegerLiteral(
180 capacity_.GreaterOrEqual(new_capacity_min))) {
189 while (theta_tree_.GetOptionalEnvelope() > current_end * capacity_max) {
199 helper_->ClearReason();
201 int event_with_new_energy_max;
202 IntegerValue new_energy_max;
203 theta_tree_.GetEventsWithOptionalEnvelopeGreaterThan(
204 current_end * capacity_max, &critical_event,
205 &event_with_new_energy_max, &new_energy_max);
207 const IntegerValue window_start =
208 start_event_task_time_[critical_event].time;
211 const IntegerValue window_end = current_end;
212 for (
int event = critical_event;
event < num_events;
event++) {
213 if (start_event_is_present_[event]) {
214 if (event == event_with_new_energy_max)
continue;
215 const int task = start_event_task_time_[event].task_index;
216 helper_->AddPresenceReason(task);
217 helper_->AddStartMinReason(task, window_start);
218 helper_->AddEndMaxReason(task, window_end);
219 demands_->AddEnergyMinReason(task);
223 helper_->MutableIntegerReason()->push_back(
224 integer_trail_->UpperBoundAsLiteral(capacity_.var));
227 const int task_with_new_energy_max =
228 start_event_task_time_[event_with_new_energy_max].task_index;
229 helper_->AddStartMinReason(task_with_new_energy_max, window_start);
230 helper_->AddEndMaxReason(task_with_new_energy_max, window_end);
231 if (!demands_->DecreaseEnergyMax(task_with_new_energy_max,
236 if (helper_->IsPresent(task_with_new_energy_max)) {
237 theta_tree_.AddOrUpdateEvent(
238 task_to_start_event_[task_with_new_energy_max],
239 start_event_task_time_[event_with_new_energy_max].time *
241 demands_->EnergyMin(task_with_new_energy_max), new_energy_max);
243 theta_tree_.RemoveEvent(event_with_new_energy_max);
270 if (!helper_->SynchronizeAndSetTimeDirection(
true))
return false;
276 IntegerValue energy_after_time(0);
277 IntegerValue profile_height(0);
282 const IntegerValue capacity_max = integer_trail_->UpperBound(capacity_);
283 dp_.Reset(capacity_max.value());
287 const auto& profile = helper_->GetEnergyProfile();
289 for (
int i = profile.size() - 1;
i >= 0;) {
292 const int t = profile[
i].task;
293 if (!helper_->IsPresent(t) || !is_in_subtasks_[t]) {
299 const IntegerValue time = profile[
i].time;
300 if (profile_height > 0) {
301 energy_after_time += profile_height * (previous_time - time);
303 previous_time = time;
307 const IntegerValue saved_capa_max = dp_.CurrentMax();
308 const IntegerValue saved_min_offset = min_offset;
310 for (;
i >= 0 && profile[
i].time == time; --
i) {
312 const int t = profile[
i].task;
313 if (!helper_->IsPresent(t) || !is_in_subtasks_[t])
continue;
315 min_offset = std::min(min_offset, task_offsets_[t]);
316 const IntegerValue demand_min = demands_->DemandMin(t);
317 if (profile[
i].is_first) {
318 profile_height -= demand_min;
320 profile_height += demand_min;
321 if (demands_->Demands()[t].IsConstant()) {
322 dp_.Add(demand_min.value());
324 dp_.Add(capacity_max.value());
336 if (energy_after_time == 0)
continue;
337 DCHECK_GT(saved_capa_max, 0);
339 const IntegerValue end_min_with_offset =
340 time +
CeilRatio(energy_after_time, saved_capa_max) + saved_min_offset;
341 if (end_min_with_offset > best_bound) {
343 best_bound = end_min_with_offset;
346 DCHECK_EQ(profile_height, 0);
349 if (best_bound > integer_trail_->LowerBound(var_to_push_)) {
352 helper_->ClearReason();
353 for (
int t = 0; t < helper_->NumTasks(); ++t) {
354 if (!is_in_subtasks_[t])
continue;
355 if (!helper_->IsPresent(t))
continue;
357 const IntegerValue size_min = helper_->SizeMin(t);
358 if (size_min == 0)
continue;
360 const IntegerValue demand_min = demands_->DemandMin(t);
361 if (demand_min == 0)
continue;
363 const IntegerValue end_min = helper_->EndMin(t);
364 if (end_min <= best_time)
continue;
366 helper_->AddEndMinReason(t, std::min(best_time + size_min, end_min));
367 helper_->AddSizeMinReason(t);
368 helper_->AddPresenceReason(t);
369 demands_->AddDemandMinReason(t);
372 helper_->MutableIntegerReason()->push_back(
373 integer_trail_->UpperBoundAsLiteral(capacity_.var));
377 if (!helper_->PushIntegerLiteral(
518 if (!helper_->SynchronizeAndSetTimeDirection(
true))
return false;
519 if (!demands_->CacheAllEnergyValues())
return true;
521 const IntegerValue capacity_max = integer_trail_->UpperBound(capacity_);
522 if (capacity_max <= 0)
return true;
525 start_event_task_time_.clear();
527 for (
const auto task_time : helper_->TaskByIncreasingStartMin()) {
528 const int task = task_time.task_index;
529 if (!helper_->IsPresent(task) || demands_->DemandMin(task) == 0) {
530 task_to_start_event_[task] = -1;
533 start_event_task_time_.emplace_back(task_time);
534 task_to_start_event_[task] = num_events;
538 if (num_events == 0)
return true;
541 const IntegerValue start_end_magnitude =
543 helper_->TaskByDecreasingEndMax().front().task_index)),
544 IntTypeAbs(helper_->TaskByIncreasingStartMin().front().time));
545 if (start_end_magnitude == 0)
return true;
547 const IntegerValue max_energy =
553 const IntegerValue max_for_fixpoint_inverse =
554 std::numeric_limits<IntegerValue>::max() / max_energy;
556 theta_tree_.Reset(num_events);
582 std::vector<std::pair<IntegerValue, IntegerValue>> candidates_for_conflict;
583 const auto by_decreasing_end_max = helper_->TaskByDecreasingEndMax();
584 for (
const auto [current_task, current_end] :
586 if (task_to_start_event_[current_task] == -1)
continue;
587 if (!helper_->IsPresent(current_task))
continue;
588 if (helper_->SizeMin(current_task) == 0)
continue;
589 if (demands_->DemandMin(current_task) == 0)
continue;
591 if (demands_->DemandMin(current_task) > capacity_max) {
594 demands_->AddDemandMinReason(current_task);
597 helper_->MutableIntegerReason()->push_back(
598 integer_trail_->UpperBoundAsLiteral(capacity_));
603 helper_->MutableIntegerReason()->push_back(size.
GreaterOrEqual(1));
606 return helper_->ReportConflict();
611 const IntegerValue current_pseudo_energy =
612 helper_->SizeMin(current_task) *
613 (max_for_fixpoint_inverse /
614 (capacity_max / demands_->DemandMin(current_task)));
615 const int current_event = task_to_start_event_[current_task];
616 const IntegerValue start_min = start_event_task_time_[current_event].time;
617 theta_tree_.AddOrUpdateEvent(
618 current_event, start_min * max_for_fixpoint_inverse,
619 current_pseudo_energy, current_pseudo_energy);
624 const IntegerValue envelope = theta_tree_.GetEnvelope();
625 const int critical_event =
626 theta_tree_.GetMaxEventWithEnvelopeGreaterThan(envelope - 1);
627 const IntegerValue window_start =
628 start_event_task_time_[critical_event].time;
629 const IntegerValue window_end = current_end;
630 const IntegerValue window_size = window_end - window_start;
631 if (window_size == 0)
continue;
633 if (envelope > window_end * max_for_fixpoint_inverse) {
634 candidates_for_conflict.push_back({window_start, window_end});
638 VLOG_EVERY_N_SEC(2, 3) <<
"Found " << candidates_for_conflict.size()
639 <<
" intervals with potential energy conflict using a "
640 "DFF on a problem of size "
641 << num_events <<
".";
643 if (candidates_for_conflict.empty()) {
644 ++num_no_potential_window_;
653 absl::InlinedVector<std::pair<IntegerValue, IntegerValue>, 3>
655 std::sample(candidates_for_conflict.begin(), candidates_for_conflict.end(),
656 std::back_inserter(sampled_candidates), 3, *random_);
657 for (
const auto& [window_start, window_end] : sampled_candidates) {
658 if (!FindAndPropagateConflict(window_start, window_end)) {