27 IntegerValue fixed_size,
28 LiteralIndex is_present) {
39 LiteralIndex is_present,
40 bool add_linear_relation) {
42 const IntervalVariable i(starts_.size());
43 starts_.push_back(start);
45 sizes_.push_back(size);
48 std::vector<Literal> enforcement_literals;
50 enforcement_literals.push_back(
Literal(is_present));
53 if (add_linear_relation) {
66 const std::vector<IntervalVariable>& tasks,
Model*
model)
73 minus_starts_.clear();
75 reason_for_presence_.clear();
78 for (
const IntervalVariable i : tasks) {
79 if (repository->IsOptional(i)) {
80 reason_for_presence_.push_back(repository->PresenceLiteral(i).Index());
84 sizes_.push_back(repository->Size(i));
85 starts_.push_back(repository->Start(i));
86 ends_.push_back(repository->End(i));
87 minus_starts_.push_back(repository->Start(i).Negated());
88 minus_ends_.push_back(repository->End(i).Negated());
101 starts_.resize(num_tasks);
106 recompute_all_cache_ =
true;
111 const std::vector<int>& watch_indices) {
112 for (
const int t : watch_indices) recompute_cache_[t] =
true;
123 if (level < previous_level_) {
124 recompute_all_cache_ =
true;
126 previous_level_ = level;
130 const int id = watcher->
Register(
this);
131 const int num_tasks = starts_.size();
132 for (
int t = 0; t < num_tasks; ++t) {
144 void SchedulingConstraintHelper::UpdateCachedValues(
int t) {
145 recompute_cache_[t] =
false;
147 const IntegerValue dmin = integer_trail_->
LowerBound(sizes_[t]);
148 const IntegerValue smin = integer_trail_->
LowerBound(starts_[t]);
149 const IntegerValue smax = integer_trail_->
UpperBound(starts_[t]);
150 const IntegerValue emin = integer_trail_->
LowerBound(ends_[t]);
151 const IntegerValue emax = integer_trail_->
UpperBound(ends_[t]);
153 cached_duration_min_[t] = dmin;
154 cached_start_min_[t] = smin;
155 cached_negated_end_max_[t] = -emax;
160 cached_end_min_[t] =
std::max(emin, smin + dmin);
161 cached_negated_start_max_[t] = -
std::min(smax, emax - dmin);
164 const IntegerValue new_shifted_start_min =
EndMin(t) - dmin;
165 if (new_shifted_start_min != cached_shifted_start_min_[t]) {
166 recompute_shifted_start_min_ =
true;
167 cached_shifted_start_min_[t] = new_shifted_start_min;
169 const IntegerValue new_negated_shifted_end_max = -(
StartMax(t) + dmin);
170 if (new_negated_shifted_end_max != cached_negated_shifted_end_max_[t]) {
171 recompute_negated_shifted_end_max_ =
true;
172 cached_negated_shifted_end_max_[t] = new_negated_shifted_end_max;
178 current_time_direction_ = other.current_time_direction_;
180 const int num_tasks = tasks.size();
181 starts_.resize(num_tasks);
182 ends_.resize(num_tasks);
183 minus_ends_.resize(num_tasks);
184 minus_starts_.resize(num_tasks);
185 sizes_.resize(num_tasks);
186 reason_for_presence_.resize(num_tasks);
187 for (
int i = 0; i < num_tasks; ++i) {
188 const int t = tasks[i];
189 starts_[i] = other.starts_[t];
190 ends_[i] = other.ends_[t];
191 minus_ends_[i] = other.minus_ends_[t];
192 minus_starts_[i] = other.minus_starts_[t];
193 sizes_[i] = other.sizes_[t];
194 reason_for_presence_[i] = other.reason_for_presence_[t];
201 void SchedulingConstraintHelper::InitSortedVectors() {
202 const int num_tasks = starts_.size();
204 recompute_all_cache_ =
true;
205 recompute_cache_.resize(num_tasks,
true);
207 cached_shifted_start_min_.resize(num_tasks);
208 cached_negated_shifted_end_max_.resize(num_tasks);
209 cached_duration_min_.resize(num_tasks);
210 cached_start_min_.resize(num_tasks);
211 cached_end_min_.resize(num_tasks);
212 cached_negated_start_max_.resize(num_tasks);
213 cached_negated_end_max_.resize(num_tasks);
215 task_by_increasing_start_min_.resize(num_tasks);
216 task_by_increasing_end_min_.resize(num_tasks);
217 task_by_decreasing_start_max_.resize(num_tasks);
218 task_by_decreasing_end_max_.resize(num_tasks);
219 task_by_increasing_shifted_start_min_.resize(num_tasks);
220 task_by_negated_shifted_end_max_.resize(num_tasks);
221 for (
int t = 0; t < num_tasks; ++t) {
222 task_by_increasing_start_min_[t].task_index = t;
223 task_by_increasing_end_min_[t].task_index = t;
224 task_by_decreasing_start_max_[t].task_index = t;
225 task_by_decreasing_end_max_[t].task_index = t;
226 task_by_increasing_shifted_start_min_[t].task_index = t;
227 task_by_negated_shifted_end_max_[t].task_index = t;
230 recompute_shifted_start_min_ =
true;
231 recompute_negated_shifted_end_max_ =
true;
236 if (current_time_direction_ != is_forward) {
237 current_time_direction_ = is_forward;
239 std::swap(starts_, minus_ends_);
240 std::swap(ends_, minus_starts_);
242 std::swap(task_by_increasing_start_min_, task_by_decreasing_end_max_);
243 std::swap(task_by_increasing_end_min_, task_by_decreasing_start_max_);
244 std::swap(task_by_increasing_shifted_start_min_,
245 task_by_negated_shifted_end_max_);
247 std::swap(cached_start_min_, cached_negated_end_max_);
248 std::swap(cached_end_min_, cached_negated_start_max_);
249 std::swap(cached_shifted_start_min_, cached_negated_shifted_end_max_);
250 std::swap(recompute_shifted_start_min_, recompute_negated_shifted_end_max_);
252 if (recompute_all_cache_) {
253 for (
int t = 0; t < recompute_cache_.size(); ++t) {
254 UpdateCachedValues(t);
257 for (
int t = 0; t < recompute_cache_.size(); ++t) {
258 if (recompute_cache_[t]) UpdateCachedValues(t);
261 recompute_all_cache_ =
false;
264 const std::vector<TaskTime>&
267 for (
int i = 0; i < num_tasks; ++i) {
268 TaskTime& ref = task_by_increasing_start_min_[i];
272 task_by_increasing_start_min_.end());
273 return task_by_increasing_start_min_;
276 const std::vector<TaskTime>&
279 for (
int i = 0; i < num_tasks; ++i) {
280 TaskTime& ref = task_by_increasing_end_min_[i];
284 task_by_increasing_end_min_.end());
285 return task_by_increasing_end_min_;
288 const std::vector<TaskTime>&
291 for (
int i = 0; i < num_tasks; ++i) {
292 TaskTime& ref = task_by_decreasing_start_max_[i];
296 task_by_decreasing_start_max_.end(),
297 std::greater<TaskTime>());
298 return task_by_decreasing_start_max_;
301 const std::vector<TaskTime>&
304 for (
int i = 0; i < num_tasks; ++i) {
305 TaskTime& ref = task_by_decreasing_end_max_[i];
309 task_by_decreasing_end_max_.end(), std::greater<TaskTime>());
310 return task_by_decreasing_end_max_;
313 const std::vector<TaskTime>&
315 if (recompute_shifted_start_min_) {
316 recompute_shifted_start_min_ =
false;
318 bool is_sorted =
true;
320 for (
int i = 0; i < num_tasks; ++i) {
321 TaskTime& ref = task_by_increasing_shifted_start_min_[i];
323 is_sorted = is_sorted && ref.
time >= previous;
326 if (is_sorted)
return task_by_increasing_shifted_start_min_;
328 task_by_increasing_shifted_start_min_.end());
330 return task_by_increasing_shifted_start_min_;
336 AddOtherReason(before);
337 AddOtherReason(after);
339 std::vector<IntegerVariable> vars;
342 const IntegerValue smax_before =
StartMax(before);
343 if (smax_before >= integer_trail_->
UpperBound(starts_[before])) {
352 vars.push_back(sizes_[before].
var);
357 const IntegerValue emin_after =
EndMin(after);
358 if (emin_after <= integer_trail_->
LowerBound(ends_[after])) {
360 vars.push_back(ends_[after].
var);
364 vars.push_back(starts_[after].
var);
367 vars.push_back(sizes_[after].
var);
372 const IntegerValue slack = emin_after - smax_before - 1;
374 slack, std::vector<IntegerValue>(vars.size(), IntegerValue(1)), vars,
379 CHECK(other_helper_ ==
nullptr);
380 return integer_trail_->
Enqueue(lit, literal_reason_, integer_reason_);
391 reason_for_presence_[t]) {
399 integer_reason_.push_back(
408 if (!integer_trail_->
Enqueue(lit, literal_reason_, integer_reason_)) {
416 bool SchedulingConstraintHelper::PushIntervalBound(
int t,
IntegerLiteral lit) {
420 UpdateCachedValues(t);
425 IntegerValue new_start_min) {
426 return PushIntervalBound(t, starts_[t].
GreaterOrEqual(new_start_min));
430 IntegerValue new_end_max) {
431 return PushIntervalBound(t, ends_[t].
LowerOrEqual(new_end_max));
441 literal_reason_.push_back(
Literal(reason_for_presence_[t]).Negated());
446 literal_reason_, integer_reason_);
457 literal_reason_.push_back(
Literal(reason_for_presence_[t]));
462 literal_reason_, integer_reason_);
468 return integer_trail_->
ReportConflict(literal_reason_, integer_reason_);
473 bool watch_start_max,
474 bool watch_end_max)
const {
475 const int num_tasks = starts_.size();
476 for (
int t = 0; t < num_tasks; ++t) {
480 if (watch_start_max) {
492 void SchedulingConstraintHelper::AddOtherReason(
int t) {
493 if (other_helper_ ==
nullptr || already_added_to_other_reasons_[t])
return;
494 already_added_to_other_reasons_[t] =
true;
499 void SchedulingConstraintHelper::ImportOtherReasons() {
500 if (other_helper_ !=
nullptr) ImportOtherReasons(*other_helper_);
503 void SchedulingConstraintHelper::ImportOtherReasons(
505 literal_reason_.insert(literal_reason_.end(),
506 other_helper.literal_reason_.begin(),
507 other_helper.literal_reason_.end());
508 integer_reason_.insert(integer_reason_.end(),
509 other_helper.integer_reason_.begin(),
510 other_helper.integer_reason_.end());
514 return absl::StrCat(
"t=", t,
" is_present=",
IsPresent(t),