29 IntegerValue fixed_size,
30 LiteralIndex is_present) {
41 LiteralIndex is_present,
42 bool add_linear_relation) {
44 const IntervalVariable i(starts_.size());
45 starts_.push_back(start);
47 sizes_.push_back(size);
50 std::vector<Literal> enforcement_literals;
52 enforcement_literals.push_back(
Literal(is_present));
55 if (add_linear_relation) {
68 const std::vector<IntervalVariable>& tasks,
Model*
model)
75 minus_starts_.clear();
77 reason_for_presence_.clear();
80 for (
const IntervalVariable i : tasks) {
81 if (repository->IsOptional(i)) {
82 reason_for_presence_.push_back(repository->PresenceLiteral(i).Index());
86 sizes_.push_back(repository->Size(i));
87 starts_.push_back(repository->Start(i));
88 ends_.push_back(repository->End(i));
89 minus_starts_.push_back(repository->Start(i).Negated());
90 minus_ends_.push_back(repository->End(i).Negated());
105 starts_.resize(num_tasks);
110 recompute_all_cache_ =
true;
115 const std::vector<int>& watch_indices) {
116 for (
const int t : watch_indices) recompute_cache_[t] =
true;
127 if (level < previous_level_) {
128 recompute_all_cache_ =
true;
130 previous_level_ = level;
134 const int id = watcher->
Register(
this);
135 const int num_tasks = starts_.size();
136 for (
int t = 0; t < num_tasks; ++t) {
148 bool SchedulingConstraintHelper::UpdateCachedValues(
int t) {
149 recompute_cache_[t] =
false;
152 IntegerValue smin = integer_trail_->
LowerBound(starts_[t]);
153 IntegerValue smax = integer_trail_->
UpperBound(starts_[t]);
154 IntegerValue emin = integer_trail_->
LowerBound(ends_[t]);
155 IntegerValue emax = integer_trail_->
UpperBound(ends_[t]);
164 IntegerValue dmax = integer_trail_->
UpperBound(sizes_[t]);
171 if (smin + dmin - emax > 0) {
178 if (smax + dmax - emin < 0) {
198 cached_start_min_[t] = smin;
199 cached_end_min_[t] = emin;
200 cached_negated_start_max_[t] = -smax;
201 cached_negated_end_max_[t] = -emax;
202 cached_size_min_[t] = dmin;
205 const IntegerValue new_shifted_start_min =
EndMin(t) - dmin;
206 if (new_shifted_start_min != cached_shifted_start_min_[t]) {
207 recompute_shifted_start_min_ =
true;
208 cached_shifted_start_min_[t] = new_shifted_start_min;
210 const IntegerValue new_negated_shifted_end_max = -(
StartMax(t) + dmin);
211 if (new_negated_shifted_end_max != cached_negated_shifted_end_max_[t]) {
212 recompute_negated_shifted_end_max_ =
true;
213 cached_negated_shifted_end_max_[t] = new_negated_shifted_end_max;
220 current_time_direction_ = other.current_time_direction_;
222 const int num_tasks = tasks.size();
223 starts_.resize(num_tasks);
224 ends_.resize(num_tasks);
225 minus_ends_.resize(num_tasks);
226 minus_starts_.resize(num_tasks);
227 sizes_.resize(num_tasks);
228 reason_for_presence_.resize(num_tasks);
229 for (
int i = 0; i < num_tasks; ++i) {
230 const int t = tasks[i];
231 starts_[i] = other.starts_[t];
232 ends_[i] = other.ends_[t];
233 minus_ends_[i] = other.minus_ends_[t];
234 minus_starts_[i] = other.minus_starts_[t];
235 sizes_[i] = other.sizes_[t];
236 reason_for_presence_[i] = other.reason_for_presence_[t];
243 void SchedulingConstraintHelper::InitSortedVectors() {
244 const int num_tasks = starts_.size();
246 recompute_all_cache_ =
true;
247 recompute_cache_.resize(num_tasks,
true);
249 cached_shifted_start_min_.resize(num_tasks);
250 cached_negated_shifted_end_max_.resize(num_tasks);
251 cached_size_min_.resize(num_tasks);
252 cached_start_min_.resize(num_tasks);
253 cached_end_min_.resize(num_tasks);
254 cached_negated_start_max_.resize(num_tasks);
255 cached_negated_end_max_.resize(num_tasks);
257 task_by_increasing_start_min_.resize(num_tasks);
258 task_by_increasing_end_min_.resize(num_tasks);
259 task_by_decreasing_start_max_.resize(num_tasks);
260 task_by_decreasing_end_max_.resize(num_tasks);
261 task_by_increasing_shifted_start_min_.resize(num_tasks);
262 task_by_negated_shifted_end_max_.resize(num_tasks);
263 for (
int t = 0; t < num_tasks; ++t) {
264 task_by_increasing_start_min_[t].task_index = t;
265 task_by_increasing_end_min_[t].task_index = t;
266 task_by_decreasing_start_max_[t].task_index = t;
267 task_by_decreasing_end_max_[t].task_index = t;
268 task_by_increasing_shifted_start_min_[t].task_index = t;
269 task_by_negated_shifted_end_max_[t].task_index = t;
272 recompute_shifted_start_min_ =
true;
273 recompute_negated_shifted_end_max_ =
true;
277 if (current_time_direction_ != is_forward) {
278 current_time_direction_ = is_forward;
283 std::swap(task_by_increasing_start_min_, task_by_decreasing_end_max_);
284 std::swap(task_by_increasing_end_min_, task_by_decreasing_start_max_);
285 std::swap(task_by_increasing_shifted_start_min_,
286 task_by_negated_shifted_end_max_);
288 std::swap(cached_start_min_, cached_negated_end_max_);
289 std::swap(cached_end_min_, cached_negated_start_max_);
290 std::swap(cached_shifted_start_min_, cached_negated_shifted_end_max_);
291 std::swap(recompute_shifted_start_min_, recompute_negated_shifted_end_max_);
298 if (recompute_all_cache_) {
299 for (
int t = 0; t < recompute_cache_.size(); ++t) {
300 if (!UpdateCachedValues(t))
return false;
303 for (
int t = 0; t < recompute_cache_.size(); ++t) {
304 if (recompute_cache_[t])
305 if (!UpdateCachedValues(t))
return false;
308 recompute_all_cache_ =
false;
312 const std::vector<TaskTime>&
315 for (
int i = 0; i < num_tasks; ++i) {
316 TaskTime& ref = task_by_increasing_start_min_[i];
320 task_by_increasing_start_min_.end());
321 return task_by_increasing_start_min_;
324 const std::vector<TaskTime>&
327 for (
int i = 0; i < num_tasks; ++i) {
328 TaskTime& ref = task_by_increasing_end_min_[i];
332 task_by_increasing_end_min_.end());
333 return task_by_increasing_end_min_;
336 const std::vector<TaskTime>&
339 for (
int i = 0; i < num_tasks; ++i) {
340 TaskTime& ref = task_by_decreasing_start_max_[i];
344 task_by_decreasing_start_max_.end(),
345 std::greater<TaskTime>());
346 return task_by_decreasing_start_max_;
349 const std::vector<TaskTime>&
352 for (
int i = 0; i < num_tasks; ++i) {
353 TaskTime& ref = task_by_decreasing_end_max_[i];
357 task_by_decreasing_end_max_.end(), std::greater<TaskTime>());
358 return task_by_decreasing_end_max_;
361 const std::vector<TaskTime>&
363 if (recompute_shifted_start_min_) {
364 recompute_shifted_start_min_ =
false;
366 bool is_sorted =
true;
368 for (
int i = 0; i < num_tasks; ++i) {
369 TaskTime& ref = task_by_increasing_shifted_start_min_[i];
371 is_sorted = is_sorted && ref.
time >= previous;
374 if (is_sorted)
return task_by_increasing_shifted_start_min_;
376 task_by_increasing_shifted_start_min_.end());
378 return task_by_increasing_shifted_start_min_;
384 AddOtherReason(before);
385 AddOtherReason(after);
387 std::vector<IntegerVariable> vars;
390 const IntegerValue smax_before =
StartMax(before);
391 if (smax_before >= integer_trail_->
UpperBound(starts_[before])) {
400 vars.push_back(sizes_[before].
var);
405 const IntegerValue emin_after =
EndMin(after);
406 if (emin_after <= integer_trail_->
LowerBound(ends_[after])) {
408 vars.push_back(ends_[after].
var);
412 vars.push_back(starts_[after].
var);
415 vars.push_back(sizes_[after].
var);
420 const IntegerValue slack = emin_after - smax_before - 1;
422 slack, std::vector<IntegerValue>(vars.size(), IntegerValue(1)), vars,
427 CHECK(other_helper_ ==
nullptr);
428 return integer_trail_->
Enqueue(lit, literal_reason_, integer_reason_);
440 return integer_trail_->
Enqueue(lit, literal_reason_, integer_reason_);
445 bool SchedulingConstraintHelper::PushIntervalBound(
int t,
IntegerLiteral lit) {
449 if (!UpdateCachedValues(t))
return false;
454 IntegerValue new_start_min) {
459 return PushIntervalBound(t, starts_[t].
GreaterOrEqual(new_start_min));
463 IntegerValue new_end_max) {
468 return PushIntervalBound(t, ends_[t].
LowerOrEqual(new_end_max));
478 literal_reason_.push_back(
Literal(reason_for_presence_[t]).Negated());
483 literal_reason_, integer_reason_);
494 literal_reason_.push_back(
Literal(reason_for_presence_[t]));
499 literal_reason_, integer_reason_);
505 return integer_trail_->
ReportConflict(literal_reason_, integer_reason_);
510 bool watch_start_max,
511 bool watch_end_max)
const {
512 const int num_tasks = starts_.size();
513 for (
int t = 0; t < num_tasks; ++t) {
517 if (watch_start_max) {
529 void SchedulingConstraintHelper::AddOtherReason(
int t) {
530 if (other_helper_ ==
nullptr || already_added_to_other_reasons_[t])
return;
531 already_added_to_other_reasons_[t] =
true;
532 const int mapped_t = map_to_other_helper_[t];
537 void SchedulingConstraintHelper::ImportOtherReasons() {
538 if (other_helper_ !=
nullptr) ImportOtherReasons(*other_helper_);
541 void SchedulingConstraintHelper::ImportOtherReasons(
543 literal_reason_.insert(literal_reason_.end(),
544 other_helper.literal_reason_.begin(),
545 other_helper.literal_reason_.end());
546 integer_reason_.insert(integer_reason_.end(),
547 other_helper.integer_reason_.begin(),
548 other_helper.integer_reason_.end());
552 return absl::StrCat(
"t=", t,
" is_present=",
IsPresent(t),
" size=[",
561 IntegerValue end)
const {
SchedulingConstraintHelper(const std::vector< IntervalVariable > &tasks, Model *model)
IntegerValue SizeMin(int t) const
void AddEndMaxReason(int t, IntegerValue upper_bound)
ABSL_MUST_USE_RESULT bool PushIntegerLiteralIfTaskPresent(int t, IntegerLiteral lit)
void AddStartMinReason(int t, IntegerValue lower_bound)
void IncrementalSort(int max_comparisons, Iterator begin, Iterator end, Compare comp=Compare{}, bool is_stable=false)
IntegerValue StartMax(int t) const
ABSL_MUST_USE_RESULT bool SynchronizeAndSetTimeDirection(bool is_forward)
bool IsAbsent(int t) const
ABSL_MUST_USE_RESULT bool PushIntegerLiteral(IntegerLiteral lit)
Class that owns everything related to a particular optimization model.
const std::vector< TaskTime > & TaskByDecreasingEndMax()
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue)
void AppendRelaxedLinearReason(IntegerValue slack, absl::Span< const IntegerValue > coeffs, absl::Span< const IntegerVariable > vars, std::vector< IntegerLiteral > *reason) const
std::string TaskDebugString(int t) const
IntegerValue SizeMax(int t) const
bool ReportConflict(absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
AffineExpression Size(IntervalVariable i) const
IntegerValue LowerBound(IntegerVariable i) const
void swap(IdMap< K, V > &a, IdMap< K, V > &b)
ABSL_MUST_USE_RESULT bool PushTaskPresence(int t)
void AddReasonForBeingBefore(int before, int after)
bool IsPresent(int t) const
void WatchAllTasks(int id, GenericLiteralWatcher *watcher, bool watch_start_max=true, bool watch_end_max=true) const
const std::vector< TaskTime > & TaskByIncreasingShiftedStartMin()
void ImportOtherReasons(const SchedulingConstraintHelper &other_helper)
void AddTerm(IntegerVariable var, IntegerValue coeff)
ABSL_MUST_USE_RESULT bool IncreaseStartMin(int t, IntegerValue new_start_min)
void AddStartMaxReason(int t, IntegerValue upper_bound)
bool IncrementalPropagate(const std::vector< int > &watch_indices) final
void AddEndMinReason(int t, IntegerValue lower_bound)
ABSL_MUST_USE_RESULT bool Enqueue(IntegerLiteral i_lit, absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
std::function< void(Model *)> LowerOrEqual(IntegerVariable v, int64_t ub)
bool PropagateOutgoingArcs(IntegerVariable var)
void WatchLowerBound(IntegerVariable var, int id, int watch_index=-1)
ABSL_MUST_USE_RESULT bool DecreaseEndMax(int t, IntegerValue new_end_max)
AffineExpression End(IntervalVariable i) const
#define DCHECK_NE(val1, val2)
ABSL_MUST_USE_RESULT bool PushTaskAbsence(int t)
std::function< void(Model *)> GreaterOrEqual(IntegerVariable v, int64_t lb)
void SetPropagatorPriority(int id, int priority)
void push_back(const value_type &x)
void EnqueueLiteral(Literal literal, absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
IntegerValue StartMin(int t) const
void WatchLiteral(Literal l, int id, int watch_index=-1)
void SetLevel(int level) final
#define CHECK_EQ(val1, val2)
ABSL_MUST_USE_RESULT bool ConditionalEnqueue(Literal lit, IntegerLiteral i_lit, std::vector< Literal > *literal_reason, std::vector< IntegerLiteral > *integer_reason)
IntervalVariable CreateInterval(IntegerVariable start, IntegerVariable end, IntegerVariable size, IntegerValue fixed_size, LiteralIndex is_present)
bool IsOptional(int t) const
IntegerValue EndMin(int t) const
ABSL_MUST_USE_RESULT bool ReportConflict()
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
IntegerValue GetMinOverlap(int t, IntegerValue start, IntegerValue end) const
IntegerValue EndMax(int t) const
#define DCHECK(condition)
void RegisterReversibleClass(ReversibleInterface *rev)
std::function< int64_t(const Model &)> LowerBound(IntegerVariable v)
const std::vector< TaskTime > & TaskByIncreasingStartMin()
void WatchIntegerVariable(IntegerVariable i, int id, int watch_index=-1)
int Register(PropagatorInterface *propagator)
IntegerValue UpperBound(IntegerVariable i) const
Collection of objects used to extend the Constraint Solver library.
const IntegerVariable kNoIntegerVariable(-1)
void WatchUpperBound(IntegerVariable var, int id, int watch_index=-1)
IntegerValue ShiftedStartMin(int t) const
void SetTimeDirection(bool is_forward)
const LiteralIndex kNoLiteralIndex(-1)
AffineExpression Start(IntervalVariable i) const
ABSL_MUST_USE_RESULT bool ResetFromSubset(const SchedulingConstraintHelper &other, absl::Span< const int > tasks)
const std::vector< TaskTime > & TaskByIncreasingEndMin()
void AddSizeMinReason(int t)
Literal PresenceLiteral(int index) const
const std::vector< TaskTime > & TaskByDecreasingStartMax()
void LoadConditionalLinearConstraint(const absl::Span< const Literal > enforcement_literals, const LinearConstraint &cst, Model *model)
void RegisterWith(GenericLiteralWatcher *watcher)
void AddSizeMaxReason(int t, IntegerValue upper_bound)
#define DCHECK_LT(val1, val2)