35 std::move(energies),
capacity, integer_trail, helper);
36 constraint->RegisterWith(watcher);
37 model->TakeOwnership(constraint);
47 std::vector<AffineExpression> energies;
48 const int num_tasks = helper->
NumTasks();
50 for (
int t = 0; t < num_tasks; ++t) {
70 LOG(
INFO) <<
"Overload checker with variable demand and variable size "
71 "is currently not implemented. Skipping.";
79 model->TakeOwnership(constraint);
85 : energies_(
std::move(energies)),
87 integer_trail_(integer_trail),
90 const int num_tasks = helper_->
NumTasks();
91 CHECK_EQ(energies_.size(), num_tasks);
92 task_to_start_event_.resize(num_tasks);
96 const int id = watcher->
Register(
this);
106 const IntegerValue capacity_max = integer_trail_->
UpperBound(capacity_);
108 if (capacity_max <= 0)
return true;
111 start_event_task_time_.clear();
114 const int task = task_time.task_index;
116 integer_trail_->
UpperBound(energies_[task]) == 0) {
117 task_to_start_event_[task] = -1;
120 start_event_task_time_.emplace_back(task_time);
121 task_to_start_event_[task] = num_events;
124 start_event_is_present_.assign(num_events,
false);
125 theta_tree_.
Reset(num_events);
127 bool tree_has_mandatory_intervals =
false;
130 for (
const auto task_time :
132 const int current_task = task_time.task_index;
133 const IntegerValue current_end = task_time.time;
134 if (task_to_start_event_[current_task] == -1)
continue;
138 const int current_event = task_to_start_event_[current_task];
139 const IntegerValue
start_min = start_event_task_time_[current_event].time;
140 const bool is_present = helper_->
IsPresent(current_task);
141 start_event_is_present_[current_event] = is_present;
143 tree_has_mandatory_intervals =
true;
146 integer_trail_->
LowerBound(energies_[current_task]),
147 integer_trail_->
UpperBound(energies_[current_task]));
151 integer_trail_->
UpperBound(energies_[current_task]));
155 if (tree_has_mandatory_intervals) {
157 const IntegerValue envelope = theta_tree_.
GetEnvelope();
158 const int critical_event =
160 const IntegerValue window_start =
161 start_event_task_time_[critical_event].time;
162 const IntegerValue window_end = current_end;
163 const IntegerValue window_size = window_end - window_start;
164 if (window_size == 0)
continue;
165 const IntegerValue new_capacity_min =
166 CeilRatio(envelope - window_start * capacity_max, window_size);
174 if (new_capacity_min > integer_trail_->
LowerBound(capacity_)) {
176 for (
int event = critical_event;
event < num_events;
event++) {
177 if (start_event_is_present_[event]) {
178 const int task = start_event_task_time_[event].task_index;
213 int event_with_new_energy_max;
214 IntegerValue new_energy_max;
216 current_end * capacity_max, &critical_event,
217 &event_with_new_energy_max, &new_energy_max);
219 const IntegerValue window_start =
220 start_event_task_time_[critical_event].time;
223 const IntegerValue window_end = current_end;
224 for (
int event = critical_event;
event < num_events;
event++) {
225 if (start_event_is_present_[event]) {
226 if (event == event_with_new_energy_max)
continue;
227 const int task = start_event_task_time_[event].task_index;
242 const int task_with_new_energy_max =
243 start_event_task_time_[event_with_new_energy_max].task_index;
248 integer_trail_->
LowerBound(energies_[task_with_new_energy_max])) {
249 if (helper_->
IsOptional(task_with_new_energy_max)) {
256 energies_[task_with_new_energy_max].LowerOrEqual(new_energy_max);
263 if (helper_->
IsPresent(task_with_new_energy_max)) {
265 task_to_start_event_[task_with_new_energy_max],
266 start_event_task_time_[event_with_new_energy_max].
time *
268 integer_trail_->
LowerBound(energies_[task_with_new_energy_max]),
271 theta_tree_.
RemoveEvent(event_with_new_energy_max);
280 const std::vector<AffineExpression> demands,
281 const std::vector<int> subtasks,
IntegerTrail* integer_trail,
288 integer_trail_(integer_trail),
290 is_in_subtasks_.assign(helper->
NumTasks(),
false);
291 for (
const int t : subtasks) is_in_subtasks_[t] =
true;
295 const IntegerValue capacity_max = integer_trail_->
UpperBound(capacity_);
303 IntegerValue energy_after_time(0);
304 std::vector<std::pair<IntegerValue, IntegerValue>> energy_changes;
305 for (
int t = 0; t < helper_->
NumTasks(); ++t) {
306 if (!is_in_subtasks_[t])
continue;
308 if (helper_->
SizeMin(t) == 0)
continue;
311 if (
demand == 0)
continue;
313 const IntegerValue size_min = helper_->
SizeMin(t);
317 energy_after_time += size_min *
demand;
324 IntegerValue profile_height(0);
328 std::sort(energy_changes.begin(), energy_changes.end());
329 for (
int i = 0; i < energy_changes.size();) {
330 const IntegerValue
time = energy_changes[i].first;
331 if (profile_height > 0) {
332 energy_after_time -= profile_height * (
time - previous_time);
334 previous_time =
time;
336 while (i < energy_changes.size() && energy_changes[i].first ==
time) {
337 profile_height += energy_changes[i].second;
353 if (best_end_min + offset_ > integer_trail_->
LowerBound(var_to_push_)) {
357 for (
int t = 0; t < helper_->
NumTasks(); ++t) {
358 if (!is_in_subtasks_[t])
continue;
360 if (helper_->
SizeMin(t) == 0)
continue;
363 if (
demand == 0)
continue;
365 const IntegerValue size_min = helper_->
SizeMin(t);
382 var_to_push_, best_end_min + offset_))) {
393 const int id = watcher->
Register(
this);
395 for (
const int t : subtasks_) {
#define CHECK_EQ(val1, val2)
#define CHECK_GE(val1, val2)
void RegisterWith(GenericLiteralWatcher *watcher)
CumulativeEnergyConstraint(std::vector< AffineExpression > energies, AffineExpression capacity, IntegerTrail *integer_trail, SchedulingConstraintHelper *helper)
CumulativeIsAfterSubsetConstraint(IntegerVariable var, IntegerValue offset, AffineExpression capacity, const std::vector< AffineExpression > demands, const std::vector< int > subtasks, IntegerTrail *integer_trail, SchedulingConstraintHelper *helper)
void RegisterWith(GenericLiteralWatcher *watcher)
void WatchLiteral(Literal l, int id, int watch_index=-1)
void WatchLowerBound(IntegerVariable var, int id, int watch_index=-1)
void WatchUpperBound(IntegerVariable var, int id, int watch_index=-1)
int Register(PropagatorInterface *propagator)
void NotifyThatPropagatorMayNotReachFixedPointInOnePass(int id)
IntegerLiteral LowerBoundAsLiteral(IntegerVariable i) const
IntegerValue UpperBound(IntegerVariable i) const
IntegerValue LowerBound(IntegerVariable i) const
IntegerLiteral UpperBoundAsLiteral(IntegerVariable i) const
Class that owns everything related to a particular optimization model.
IntegerValue EndMin(int t) const
ABSL_MUST_USE_RESULT bool PushIntegerLiteral(IntegerLiteral lit)
const std::vector< AffineExpression > & Starts() const
const std::vector< TaskTime > & TaskByDecreasingEndMax()
std::vector< IntegerLiteral > * MutableIntegerReason()
ABSL_MUST_USE_RESULT bool PushTaskAbsence(int t)
void AddSizeMinReason(int t)
const std::vector< TaskTime > & TaskByIncreasingStartMin()
void AddStartMinReason(int t, IntegerValue lower_bound)
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
ABSL_MUST_USE_RESULT bool PushIntegerLiteralIfTaskPresent(int t, IntegerLiteral lit)
void AddEndMinReason(int t, IntegerValue lower_bound)
const std::vector< AffineExpression > & Sizes() const
bool IsAbsent(int t) const
ABSL_MUST_USE_RESULT bool ReportConflict()
bool IsOptional(int t) const
ABSL_MUST_USE_RESULT bool SynchronizeAndSetTimeDirection(bool is_forward)
Literal PresenceLiteral(int index) const
void AddEndMaxReason(int t, IntegerValue upper_bound)
void SetTimeDirection(bool is_forward)
const std::vector< AffineExpression > & Ends() const
IntegerValue SizeMin(int t) 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)
void AddOrUpdateEvent(int event, IntegerType initial_envelope, IntegerType energy_min, IntegerType energy_max)
IntegerType GetEnvelope() const
ReverseView< Container > reversed_view(const Container &c)
void AddCumulativeOverloadChecker(const std::vector< AffineExpression > &demands, AffineExpression capacity, SchedulingConstraintHelper *helper, Model *model)
IntegerValue CeilRatio(IntegerValue dividend, IntegerValue positive_divisor)
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue)
const IntegerVariable kNoIntegerVariable(-1)
void AddCumulativeEnergyConstraint(std::vector< AffineExpression > energies, AffineExpression capacity, SchedulingConstraintHelper *helper, Model *model)
Collection of objects used to extend the Constraint Solver library.
IntegerLiteral GreaterOrEqual(IntegerValue bound) const
AffineExpression MultipliedBy(IntegerValue multiplier) const
static IntegerLiteral GreaterOrEqual(IntegerVariable i, IntegerValue bound)