34 : num_tasks_(helper->NumTasks()),
40 mandatory_energy_before_end_max_.resize(num_tasks_);
41 mandatory_energy_before_start_min_.resize(num_tasks_);
44 size_free_.resize(num_tasks_);
45 energy_free_.resize(num_tasks_);
49 const int id = watcher->
Register(
this);
52 for (
int t = 0; t < num_tasks_; t++) {
61 if (!TimeTableEdgeFindingPass())
return false;
63 if (!TimeTableEdgeFindingPass())
return false;
67 void TimeTableEdgeFinding::BuildTimeTable() {
72 for (
const auto task_time :
74 const int t = task_time.task_index;
76 if (task_time.time < helper_->
EndMin(t)) {
77 scp_.push_back(task_time);
83 const int t = task_time.task_index;
85 if (helper_->
StartMax(t) < task_time.time) {
86 ecp_.push_back(task_time);
90 DCHECK_EQ(scp_.size(), ecp_.size());
92 const std::vector<TaskTime>& by_decreasing_end_max =
94 const std::vector<TaskTime>& by_start_min =
97 IntegerValue
height = IntegerValue(0);
98 IntegerValue
energy = IntegerValue(0);
102 IntegerValue previous_time = IntegerValue(0);
107 int index_emax = num_tasks_ - 1;
109 while (index_emax >= 0) {
111 IntegerValue
time = by_decreasing_end_max[index_emax].time;
112 if (index_smin < num_tasks_) {
115 if (index_scp < scp_.size()) {
118 if (index_ecp < ecp_.size()) {
124 previous_time =
time;
127 while (index_smin < num_tasks_ && by_start_min[index_smin].
time ==
time) {
128 mandatory_energy_before_start_min_[by_start_min[index_smin].task_index] =
134 while (index_emax >= 0 && by_decreasing_end_max[index_emax].
time ==
time) {
135 mandatory_energy_before_end_max_[by_decreasing_end_max[index_emax]
141 while (index_scp < scp_.size() && scp_[index_scp].time ==
time) {
147 while (index_ecp < ecp_.size() && ecp_[index_ecp].time ==
time) {
154 bool TimeTableEdgeFinding::TimeTableEdgeFindingPass() {
159 for (
int t = 0; t < num_tasks_; ++t) {
163 const IntegerValue demand_min = demands_->
DemandMin(t);
164 IntegerValue mandatory_energy(0);
167 size_free_[t] = helper_->
SizeMin(t);
170 size_free_[t] = helper_->
SizeMin(t) - mandatory_size;
171 mandatory_energy = mandatory_size * demand_min;
174 const IntegerValue min_energy = demands_->
EnergyMin(t);
175 energy_free_[t] = min_energy - mandatory_energy;
176 DCHECK_GE(energy_free_[t], 0);
191 const int end_task = end_task_time.task_index;
194 if (!helper_->
IsPresent(end_task))
continue;
195 if (energy_free_[end_task] == 0)
continue;
198 if (end_task_time.time == previous_end)
continue;
199 previous_end = end_task_time.time;
203 IntegerValue energy_free_parts = IntegerValue(0);
204 reason_tasks_fully_included_in_window_.clear();
205 reason_tasks_partially_included_in_window_.clear();
211 IntegerValue free_energy_of_max_task_in_window(0);
215 const IntegerValue window_max = end_task_time.time;
217 const int begin_task = begin_task_time.task_index;
221 const IntegerValue window_min = begin_task_time.time;
224 if (window_max <= window_min)
continue;
227 if (!helper_->
IsPresent(begin_task))
continue;
228 if (energy_free_[begin_task] == 0)
continue;
249 reason_tasks_fully_included_in_window_.push_back(begin_task);
250 energy_free_parts += energy_free_[begin_task];
252 const IntegerValue demand_min = demands_->
DemandMin(begin_task);
253 const IntegerValue extra_energy =
254 std::min(size_free_[begin_task], (window_max - window_min)) *
259 const IntegerValue free_energy_in_window =
261 size_free_[begin_task] - (
end_max - window_max)) *
266 if (extra_energy > extra_energy_required_by_max_task) {
267 if (max_task != -1 && free_energy_of_max_task_in_window > 0) {
268 reason_tasks_partially_included_in_window_.push_back(max_task);
271 max_task = begin_task;
272 extra_energy_required_by_max_task = extra_energy;
276 energy_free_parts += free_energy_of_max_task_in_window;
277 free_energy_of_max_task_in_window = free_energy_in_window;
278 }
else if (free_energy_in_window > 0) {
279 reason_tasks_partially_included_in_window_.push_back(begin_task);
280 energy_free_parts += free_energy_in_window;
288 if (max_task == -1)
continue;
291 const IntegerValue window_energy =
292 CapacityMax() * (window_max - window_min);
293 const IntegerValue energy_mandatory =
294 mandatory_energy_before_end_max_[end_task] -
295 mandatory_energy_before_start_min_[begin_task];
296 const IntegerValue available_energy =
297 window_energy - energy_free_parts - energy_mandatory;
303 if (extra_energy_required_by_max_task <= available_energy) {
310 if (energy_free_[max_task] > available_energy &&
311 helper_->
EndMin(max_task) <= window_max) {
312 FillEnergyInWindowReason(window_min, window_max, max_task);
315 if (!helper_->
IncreaseEndMin(max_task, window_max + 1))
return false;
326 const IntegerValue mandatory_size_in_window =
332 const IntegerValue max_free_size_that_fit =
333 available_energy / demands_->
DemandMin(max_task);
334 const IntegerValue new_start =
335 window_max - mandatory_size_in_window - max_free_size_that_fit;
338 if (helper_->
StartMin(max_task) < new_start) {
339 FillEnergyInWindowReason(window_min, window_max, max_task);
354 void TimeTableEdgeFinding::FillEnergyInWindowReason(IntegerValue window_min,
355 IntegerValue window_max,
366 for (
int t = 0; t < num_tasks_; ++t) {
367 if (t == task_index)
continue;
369 const IntegerValue smax = helper_->
StartMax(t);
370 const IntegerValue emin = helper_->
EndMin(t);
371 if (smax >= emin)
continue;
372 if (emin <= window_min)
continue;
373 if (smax >= window_max)
continue;
384 for (
const int t : reason_tasks_fully_included_in_window_) {
385 DCHECK_NE(t, task_index);
387 DCHECK_GT(helper_->
EndMax(t), window_min);
388 DCHECK_LT(helper_->
StartMin(t), window_max);
389 DCHECK_GE(helper_->
StartMin(t), window_min);
396 for (
const int t : reason_tasks_partially_included_in_window_) {
397 DCHECK_NE(t, task_index);
399 DCHECK_GT(helper_->
EndMax(t), window_min);
400 DCHECK_LT(helper_->
StartMin(t), window_max);
401 DCHECK_GE(helper_->
StartMin(t), window_min);
void WatchLowerBound(IntegerVariable var, int id, int watch_index=-1)
void WatchUpperBound(IntegerVariable var, int id, int watch_index=-1)
void SetPropagatorPriority(int id, int priority)
int Register(PropagatorInterface *propagator)
void NotifyThatPropagatorMayNotReachFixedPointInOnePass(int id)
IntegerLiteral UpperBoundAsLiteral(IntegerVariable i) const
Class that owns everything related to a particular optimization model.
IntegerValue EndMin(int t) const
const std::vector< TaskTime > & TaskByDecreasingEndMax()
ABSL_MUST_USE_RESULT bool IncreaseStartMin(int t, IntegerValue value)
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)
const std::vector< TaskTime > & TaskByIncreasingEndMin()
ABSL_MUST_USE_RESULT bool IncreaseEndMin(int t, IntegerValue value)
std::vector< IntegerLiteral > * MutableIntegerReason()
bool IsPresent(int t) const
void AddEndMinReason(int t, IntegerValue lower_bound)
IntegerValue EndMax(int t) const
ABSL_MUST_USE_RESULT bool SynchronizeAndSetTimeDirection(bool is_forward)
IntegerValue StartMin(int t) const
const std::vector< TaskTime > & TaskByDecreasingStartMax()
void AddEndMaxReason(int t, IntegerValue upper_bound)
IntegerValue StartMax(int t) const
void AddStartMaxReason(int t, IntegerValue upper_bound)
IntegerValue SizeMin(int t) const
IntegerValue EnergyMin(int t) const
void CacheAllEnergyValues()
void AddDemandMinReason(int t)
const std::vector< AffineExpression > & Demands() const
IntegerValue DemandMin(int t) const
void AddEnergyMinReason(int t)
TimeTableEdgeFinding(AffineExpression capacity, SchedulingConstraintHelper *helper, SchedulingDemandHelper *demands, Model *model)
void RegisterWith(GenericLiteralWatcher *watcher)
ReverseView< Container > reversed_view(const Container &c)
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue.value())
const IntegerVariable kNoIntegerVariable(-1)
Collection of objects used to extend the Constraint Solver library.