39 std::move(energies),
capacity, integer_trail, helper);
40 constraint->RegisterWith(watcher);
41 model->TakeOwnership(constraint);
51 std::vector<AffineExpression> energies;
52 const int num_tasks = helper->
NumTasks();
54 for (
int t = 0; t < num_tasks; ++t) {
74 LOG(
INFO) <<
"Overload checker with variable demand and variable size "
75 "is currently not implemented. Skipping.";
83 model->TakeOwnership(constraint);
89 : energies_(
std::move(energies)),
91 integer_trail_(integer_trail),
94 const int num_tasks = helper_->
NumTasks();
95 CHECK_EQ(energies_.size(), num_tasks);
96 task_to_start_event_.resize(num_tasks);
100 const int id = watcher->
Register(
this);
110 const IntegerValue capacity_max = integer_trail_->
UpperBound(capacity_);
112 if (capacity_max <= 0)
return true;
115 start_event_task_time_.clear();
118 const int task = task_time.task_index;
120 integer_trail_->
UpperBound(energies_[task]) == 0) {
121 task_to_start_event_[task] = -1;
124 start_event_task_time_.emplace_back(task_time);
125 task_to_start_event_[task] = num_events;
128 start_event_is_present_.assign(num_events,
false);
129 theta_tree_.
Reset(num_events);
131 bool tree_has_mandatory_intervals =
false;
134 for (
const auto task_time :
136 const int current_task = task_time.task_index;
137 const IntegerValue current_end = task_time.time;
138 if (task_to_start_event_[current_task] == -1)
continue;
142 const int current_event = task_to_start_event_[current_task];
143 const IntegerValue
start_min = start_event_task_time_[current_event].time;
144 const bool is_present = helper_->
IsPresent(current_task);
145 start_event_is_present_[current_event] = is_present;
147 tree_has_mandatory_intervals =
true;
150 integer_trail_->
LowerBound(energies_[current_task]),
151 integer_trail_->
UpperBound(energies_[current_task]));
155 integer_trail_->
UpperBound(energies_[current_task]));
159 if (tree_has_mandatory_intervals) {
161 const IntegerValue envelope = theta_tree_.
GetEnvelope();
162 const int critical_event =
164 const IntegerValue window_start =
165 start_event_task_time_[critical_event].time;
166 const IntegerValue window_end = current_end;
167 const IntegerValue window_size = window_end - window_start;
168 if (window_size == 0)
continue;
169 const IntegerValue new_capacity_min =
170 CeilRatio(envelope - window_start * capacity_max, window_size);
178 if (new_capacity_min > integer_trail_->
LowerBound(capacity_)) {
180 for (
int event = critical_event;
event < num_events;
event++) {
181 if (start_event_is_present_[event]) {
182 const int task = start_event_task_time_[event].task_index;
217 int event_with_new_energy_max;
218 IntegerValue new_energy_max;
220 current_end * capacity_max, &critical_event,
221 &event_with_new_energy_max, &new_energy_max);
223 const IntegerValue window_start =
224 start_event_task_time_[critical_event].time;
227 const IntegerValue window_end = current_end;
228 for (
int event = critical_event;
event < num_events;
event++) {
229 if (start_event_is_present_[event]) {
230 if (event == event_with_new_energy_max)
continue;
231 const int task = start_event_task_time_[event].task_index;
246 const int task_with_new_energy_max =
247 start_event_task_time_[event_with_new_energy_max].task_index;
252 integer_trail_->
LowerBound(energies_[task_with_new_energy_max])) {
253 if (helper_->
IsOptional(task_with_new_energy_max)) {
260 energies_[task_with_new_energy_max].LowerOrEqual(new_energy_max);
267 if (helper_->
IsPresent(task_with_new_energy_max)) {
269 task_to_start_event_[task_with_new_energy_max],
270 start_event_task_time_[event_with_new_energy_max].
time *
272 integer_trail_->
LowerBound(energies_[task_with_new_energy_max]),
275 theta_tree_.
RemoveEvent(event_with_new_energy_max);
284 const std::vector<AffineExpression> demands,
285 const std::vector<int> subtasks,
IntegerTrail* integer_trail,
292 integer_trail_(integer_trail),
294 is_in_subtasks_.assign(helper->
NumTasks(),
false);
295 for (
const int t : subtasks) is_in_subtasks_[t] =
true;
299 const IntegerValue capacity_max = integer_trail_->
UpperBound(capacity_);
307 IntegerValue energy_after_time(0);
308 std::vector<std::pair<IntegerValue, IntegerValue>> energy_changes;
309 for (
int t = 0; t < helper_->
NumTasks(); ++t) {
310 if (!is_in_subtasks_[t])
continue;
312 if (helper_->
SizeMin(t) == 0)
continue;
315 if (
demand == 0)
continue;
317 const IntegerValue size_min = helper_->
SizeMin(t);
321 energy_after_time += size_min *
demand;
328 IntegerValue profile_height(0);
332 std::sort(energy_changes.begin(), energy_changes.end());
333 for (
int i = 0; i < energy_changes.size();) {
334 const IntegerValue
time = energy_changes[i].first;
335 if (profile_height > 0) {
336 energy_after_time -= profile_height * (
time - previous_time);
338 previous_time =
time;
340 while (i < energy_changes.size() && energy_changes[i].first ==
time) {
341 profile_height += energy_changes[i].second;
357 if (best_end_min + offset_ > integer_trail_->
LowerBound(var_to_push_)) {
361 for (
int t = 0; t < helper_->
NumTasks(); ++t) {
362 if (!is_in_subtasks_[t])
continue;
364 if (helper_->
SizeMin(t) == 0)
continue;
367 if (
demand == 0)
continue;
369 const IntegerValue size_min = helper_->
SizeMin(t);
386 var_to_push_, best_end_min + offset_))) {
397 const int id = watcher->
Register(
this);
399 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.value())
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)