21#include "absl/strings/str_cat.h"
22#include "absl/types/span.h"
41 IntegerValue fixed_size,
42 LiteralIndex is_present) {
53 LiteralIndex is_present,
54 bool add_linear_relation) {
56 const IntervalVariable i(starts_.size());
57 starts_.push_back(
start);
59 sizes_.push_back(size);
62 std::vector<Literal> enforcement_literals;
64 enforcement_literals.push_back(
Literal(is_present));
67 if (add_linear_relation) {
80 const std::vector<IntervalVariable>& tasks,
Model*
model)
87 minus_starts_.clear();
89 reason_for_presence_.clear();
92 for (
const IntervalVariable i : tasks) {
93 if (repository->IsOptional(i)) {
94 reason_for_presence_.push_back(repository->PresenceLiteral(i).Index());
98 sizes_.push_back(repository->Size(i));
99 starts_.push_back(repository->Start(i));
100 ends_.push_back(repository->End(i));
101 minus_starts_.push_back(repository->Start(i).Negated());
102 minus_ends_.push_back(repository->End(i).Negated());
117 starts_.resize(num_tasks);
122 recompute_all_cache_ =
true;
127 const std::vector<int>& watch_indices) {
128 for (
const int t : watch_indices) recompute_cache_[t] =
true;
139 if (level < previous_level_) {
140 recompute_all_cache_ =
true;
142 previous_level_ = level;
146 const int id = watcher->
Register(
this);
147 const int num_tasks = starts_.size();
148 for (
int t = 0; t < num_tasks; ++t) {
160bool SchedulingConstraintHelper::UpdateCachedValues(
int t) {
161 recompute_cache_[t] =
false;
164 IntegerValue smin = integer_trail_->
LowerBound(starts_[t]);
165 IntegerValue smax = integer_trail_->
UpperBound(starts_[t]);
166 IntegerValue emin = integer_trail_->
LowerBound(ends_[t]);
167 IntegerValue emax = integer_trail_->
UpperBound(ends_[t]);
176 IntegerValue dmax = integer_trail_->
UpperBound(sizes_[t]);
183 if (smin + dmin - emax > 0) {
190 if (smax + dmax - emin < 0) {
210 cached_start_min_[t] = smin;
211 cached_end_min_[t] = emin;
212 cached_negated_start_max_[t] = -smax;
213 cached_negated_end_max_[t] = -emax;
214 cached_size_min_[t] = dmin;
217 const IntegerValue new_shifted_start_min =
EndMin(t) - dmin;
218 if (new_shifted_start_min != cached_shifted_start_min_[t]) {
219 recompute_shifted_start_min_ =
true;
220 cached_shifted_start_min_[t] = new_shifted_start_min;
222 const IntegerValue new_negated_shifted_end_max = -(
StartMax(t) + dmin);
223 if (new_negated_shifted_end_max != cached_negated_shifted_end_max_[t]) {
224 recompute_negated_shifted_end_max_ =
true;
225 cached_negated_shifted_end_max_[t] = new_negated_shifted_end_max;
232 current_time_direction_ = other.current_time_direction_;
234 const int num_tasks = tasks.size();
235 starts_.resize(num_tasks);
236 ends_.resize(num_tasks);
237 minus_ends_.resize(num_tasks);
238 minus_starts_.resize(num_tasks);
239 sizes_.resize(num_tasks);
240 reason_for_presence_.resize(num_tasks);
241 for (
int i = 0; i < num_tasks; ++i) {
242 const int t = tasks[i];
243 starts_[i] = other.starts_[t];
244 ends_[i] = other.ends_[t];
245 minus_ends_[i] = other.minus_ends_[t];
246 minus_starts_[i] = other.minus_starts_[t];
247 sizes_[i] = other.sizes_[t];
248 reason_for_presence_[i] = other.reason_for_presence_[t];
255void SchedulingConstraintHelper::InitSortedVectors() {
256 const int num_tasks = starts_.size();
258 recompute_all_cache_ =
true;
259 recompute_cache_.resize(num_tasks,
true);
261 cached_shifted_start_min_.resize(num_tasks);
262 cached_negated_shifted_end_max_.resize(num_tasks);
263 cached_size_min_.resize(num_tasks);
264 cached_start_min_.resize(num_tasks);
265 cached_end_min_.resize(num_tasks);
266 cached_negated_start_max_.resize(num_tasks);
267 cached_negated_end_max_.resize(num_tasks);
269 task_by_increasing_start_min_.resize(num_tasks);
270 task_by_increasing_end_min_.resize(num_tasks);
271 task_by_decreasing_start_max_.resize(num_tasks);
272 task_by_decreasing_end_max_.resize(num_tasks);
273 task_by_increasing_shifted_start_min_.resize(num_tasks);
274 task_by_negated_shifted_end_max_.resize(num_tasks);
275 for (
int t = 0; t < num_tasks; ++t) {
276 task_by_increasing_start_min_[t].task_index = t;
277 task_by_increasing_end_min_[t].task_index = t;
278 task_by_decreasing_start_max_[t].task_index = t;
279 task_by_decreasing_end_max_[t].task_index = t;
280 task_by_increasing_shifted_start_min_[t].task_index = t;
281 task_by_negated_shifted_end_max_[t].task_index = t;
284 recompute_shifted_start_min_ =
true;
285 recompute_negated_shifted_end_max_ =
true;
289 if (current_time_direction_ != is_forward) {
290 current_time_direction_ = is_forward;
295 std::swap(task_by_increasing_start_min_, task_by_decreasing_end_max_);
296 std::swap(task_by_increasing_end_min_, task_by_decreasing_start_max_);
297 std::swap(task_by_increasing_shifted_start_min_,
298 task_by_negated_shifted_end_max_);
300 std::swap(cached_start_min_, cached_negated_end_max_);
301 std::swap(cached_end_min_, cached_negated_start_max_);
302 std::swap(cached_shifted_start_min_, cached_negated_shifted_end_max_);
303 std::swap(recompute_shifted_start_min_, recompute_negated_shifted_end_max_);
310 if (recompute_all_cache_) {
311 for (
int t = 0; t < recompute_cache_.size(); ++t) {
312 if (!UpdateCachedValues(t))
return false;
315 for (
int t = 0; t < recompute_cache_.size(); ++t) {
316 if (recompute_cache_[t])
317 if (!UpdateCachedValues(t))
return false;
320 recompute_all_cache_ =
false;
324const std::vector<TaskTime>&
327 for (
int i = 0; i < num_tasks; ++i) {
328 TaskTime& ref = task_by_increasing_start_min_[i];
332 task_by_increasing_start_min_.end());
333 return task_by_increasing_start_min_;
336const std::vector<TaskTime>&
339 for (
int i = 0; i < num_tasks; ++i) {
340 TaskTime& ref = task_by_increasing_end_min_[i];
344 task_by_increasing_end_min_.end());
345 return task_by_increasing_end_min_;
348const std::vector<TaskTime>&
351 for (
int i = 0; i < num_tasks; ++i) {
352 TaskTime& ref = task_by_decreasing_start_max_[i];
356 task_by_decreasing_start_max_.end(),
357 std::greater<TaskTime>());
358 return task_by_decreasing_start_max_;
361const std::vector<TaskTime>&
364 for (
int i = 0; i < num_tasks; ++i) {
365 TaskTime& ref = task_by_decreasing_end_max_[i];
369 task_by_decreasing_end_max_.end(), std::greater<TaskTime>());
370 return task_by_decreasing_end_max_;
373const std::vector<TaskTime>&
375 if (recompute_shifted_start_min_) {
376 recompute_shifted_start_min_ =
false;
378 bool is_sorted =
true;
380 for (
int i = 0; i < num_tasks; ++i) {
381 TaskTime& ref = task_by_increasing_shifted_start_min_[i];
383 is_sorted = is_sorted && ref.
time >= previous;
386 if (is_sorted)
return task_by_increasing_shifted_start_min_;
388 task_by_increasing_shifted_start_min_.end());
390 return task_by_increasing_shifted_start_min_;
396 AddOtherReason(before);
397 AddOtherReason(after);
399 std::vector<IntegerVariable> vars;
402 const IntegerValue smax_before =
StartMax(before);
403 if (smax_before >= integer_trail_->
UpperBound(starts_[before])) {
412 vars.push_back(sizes_[before].
var);
417 const IntegerValue emin_after =
EndMin(after);
418 if (emin_after <= integer_trail_->
LowerBound(ends_[after])) {
420 vars.push_back(ends_[after].
var);
424 vars.push_back(starts_[after].
var);
427 vars.push_back(sizes_[after].
var);
432 const IntegerValue slack = emin_after - smax_before - 1;
434 slack, std::vector<IntegerValue>(vars.size(), IntegerValue(1)), vars,
439 CHECK(other_helper_ ==
nullptr);
440 return integer_trail_->
Enqueue(lit, literal_reason_, integer_reason_);
452 return integer_trail_->
Enqueue(lit, literal_reason_, integer_reason_);
457bool SchedulingConstraintHelper::PushIntervalBound(
int t,
IntegerLiteral lit) {
461 if (!UpdateCachedValues(t))
return false;
466 IntegerValue new_start_min) {
471 return PushIntervalBound(t, starts_[t].
GreaterOrEqual(new_start_min));
475 IntegerValue new_end_max) {
480 return PushIntervalBound(t, ends_[t].
LowerOrEqual(new_end_max));
490 literal_reason_.push_back(
Literal(reason_for_presence_[t]).Negated());
495 literal_reason_, integer_reason_);
506 literal_reason_.push_back(
Literal(reason_for_presence_[t]));
511 literal_reason_, integer_reason_);
517 return integer_trail_->
ReportConflict(literal_reason_, integer_reason_);
522 bool watch_start_max,
523 bool watch_end_max)
const {
524 const int num_tasks = starts_.size();
525 for (
int t = 0; t < num_tasks; ++t) {
529 if (watch_start_max) {
541void SchedulingConstraintHelper::AddOtherReason(
int t) {
542 if (other_helper_ ==
nullptr || already_added_to_other_reasons_[t])
return;
543 already_added_to_other_reasons_[t] =
true;
544 const int mapped_t = map_to_other_helper_[t];
549void SchedulingConstraintHelper::ImportOtherReasons() {
550 if (other_helper_ !=
nullptr) ImportOtherReasons(*other_helper_);
553void SchedulingConstraintHelper::ImportOtherReasons(
555 literal_reason_.insert(literal_reason_.end(),
556 other_helper.literal_reason_.begin(),
557 other_helper.literal_reason_.end());
558 integer_reason_.insert(integer_reason_.end(),
559 other_helper.integer_reason_.begin(),
560 other_helper.integer_reason_.end());
564 return absl::StrCat(
"t=", t,
" is_present=",
IsPresent(t),
" size=[",
573 IntegerValue
end)
const {
#define DCHECK_NE(val1, val2)
#define CHECK_EQ(val1, val2)
#define DCHECK_LT(val1, val2)
#define DCHECK(condition)
void push_back(const value_type &x)
void WatchLiteral(Literal l, int id, int watch_index=-1)
void WatchLowerBound(IntegerVariable var, int id, int watch_index=-1)
void WatchIntegerVariable(IntegerVariable i, 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)
ABSL_MUST_USE_RESULT bool Enqueue(IntegerLiteral i_lit, absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
bool ReportConflict(absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
void EnqueueLiteral(Literal literal, absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
IntegerValue UpperBound(IntegerVariable i) const
void AppendRelaxedLinearReason(IntegerValue slack, absl::Span< const IntegerValue > coeffs, absl::Span< const IntegerVariable > vars, std::vector< IntegerLiteral > *reason) const
IntegerValue LowerBound(IntegerVariable i) const
ABSL_MUST_USE_RESULT bool ConditionalEnqueue(Literal lit, IntegerLiteral i_lit, std::vector< Literal > *literal_reason, std::vector< IntegerLiteral > *integer_reason)
void RegisterReversibleClass(ReversibleInterface *rev)
AffineExpression End(IntervalVariable i) const
AffineExpression Start(IntervalVariable i) const
AffineExpression Size(IntervalVariable i) const
IntervalVariable CreateInterval(IntegerVariable start, IntegerVariable end, IntegerVariable size, IntegerValue fixed_size, LiteralIndex is_present)
void AddTerm(IntegerVariable var, IntegerValue coeff)
Class that owns everything related to a particular optimization model.
bool PropagateOutgoingArcs(IntegerVariable var)
IntegerValue ShiftedStartMin(int t) const
IntegerValue EndMin(int t) const
ABSL_MUST_USE_RESULT bool PushIntegerLiteral(IntegerLiteral lit)
const std::vector< TaskTime > & TaskByDecreasingEndMax()
void SetLevel(int level) final
ABSL_MUST_USE_RESULT bool PushTaskAbsence(int t)
SchedulingConstraintHelper(const std::vector< IntervalVariable > &tasks, Model *model)
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
bool IncrementalPropagate(const std::vector< int > &watch_indices) final
const std::vector< TaskTime > & TaskByIncreasingEndMin()
ABSL_MUST_USE_RESULT bool ResetFromSubset(const SchedulingConstraintHelper &other, absl::Span< const int > tasks)
bool IsPresent(int t) const
ABSL_MUST_USE_RESULT bool PushIntegerLiteralIfTaskPresent(int t, IntegerLiteral lit)
void RegisterWith(GenericLiteralWatcher *watcher)
std::string TaskDebugString(int t) const
void AddEndMinReason(int t, IntegerValue lower_bound)
ABSL_MUST_USE_RESULT bool IncreaseStartMin(int t, IntegerValue new_start_min)
IntegerValue GetMinOverlap(int t, IntegerValue start, IntegerValue end) const
bool IsAbsent(int t) const
void AddSizeMaxReason(int t, IntegerValue upper_bound)
IntegerValue EndMax(int t) const
ABSL_MUST_USE_RESULT bool ReportConflict()
void ImportOtherReasons(const SchedulingConstraintHelper &other_helper)
bool IsOptional(int t) const
ABSL_MUST_USE_RESULT bool SynchronizeAndSetTimeDirection(bool is_forward)
IntegerValue StartMin(int t) const
const std::vector< TaskTime > & TaskByDecreasingStartMax()
ABSL_MUST_USE_RESULT bool PushTaskPresence(int t)
Literal PresenceLiteral(int index) const
void AddEndMaxReason(int t, IntegerValue upper_bound)
IntegerValue StartMax(int t) const
const std::vector< TaskTime > & TaskByIncreasingShiftedStartMin()
void AddReasonForBeingBefore(int before, int after)
void AddStartMaxReason(int t, IntegerValue upper_bound)
void SetTimeDirection(bool is_forward)
ABSL_MUST_USE_RESULT bool DecreaseEndMax(int t, IntegerValue new_end_max)
IntegerValue SizeMax(int t) const
IntegerValue SizeMin(int t) const
void swap(IdMap< K, V > &a, IdMap< K, V > &b)
const LiteralIndex kNoLiteralIndex(-1)
std::function< int64_t(const Model &)> LowerBound(IntegerVariable v)
std::function< void(Model *)> LowerOrEqual(IntegerVariable v, int64_t ub)
void LoadConditionalLinearConstraint(const absl::Span< const Literal > enforcement_literals, const LinearConstraint &cst, Model *model)
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue.value())
const IntegerVariable kNoIntegerVariable(-1)
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
std::function< void(Model *)> GreaterOrEqual(IntegerVariable v, int64_t lb)
Collection of objects used to extend the Constraint Solver library.
void IncrementalSort(int max_comparisons, Iterator begin, Iterator end, Compare comp=Compare{}, bool is_stable=false)
std::optional< int64_t > end