14#ifndef ORTOOLS_SAT_SCHEDULING_HELPERS_H_
15#define ORTOOLS_SAT_SCHEDULING_HELPERS_H_
26#include "absl/base/attributes.h"
27#include "absl/log/check.h"
28#include "absl/types/span.h"
77 return H::combine(std::move(h),
i.start,
i.end,
i.size,
i.is_present);
97 std::vector<AffineExpression> ends,
98 std::vector<AffineExpression> sizes,
99 std::vector<LiteralIndex> reason_for_presence,
120 absl::Span<const Literal> enforcement_literals);
156 IntegerValue
SizeMin(
int t)
const {
return cached_size_min_[t]; }
159 return integer_trail_->UpperBound(sizes_[t]);
161 IntegerValue
StartMin(
int t)
const {
return cached_start_min_[t]; }
162 IntegerValue
EndMin(
int t)
const {
return cached_end_min_[t]; }
163 IntegerValue
StartMax(
int t)
const {
return -cached_negated_start_max_[t]; }
164 IntegerValue
EndMax(
int t)
const {
return -cached_negated_end_max_[t]; }
169 return std::max(IntegerValue(0),
170 integer_trail_->LevelZeroLowerBound(sizes_[t]));
173 return integer_trail_->LevelZeroLowerBound(starts_[t]);
176 return integer_trail_->LevelZeroUpperBound(starts_[t]);
179 return integer_trail_->LevelZeroUpperBound(ends_[t]);
197 return cached_shifted_start_min_[t];
203 return -cached_negated_shifted_end_max_[t];
220 bool IsAbsent(LiteralIndex lit)
const;
240 IntegerValue
GetMinOverlap(
int t, IntegerValue start, IntegerValue
end)
const;
321 std::vector<Literal>* literal_reason);
333 ABSL_MUST_USE_RESULT
bool IncreaseEndMin(
int t, IntegerValue value);
334 ABSL_MUST_USE_RESULT
bool DecreaseEndMax(
int t, IntegerValue value);
348 absl::Span<const AffineExpression>
Starts()
const {
return starts_; }
349 absl::Span<const AffineExpression>
Ends()
const {
return ends_; }
350 absl::Span<const AffineExpression>
Sizes()
const {
return sizes_; }
354 .start = starts_[index],
356 .size = sizes_[index],
358 ? std::optional<Literal>()
359 :
Literal(reason_for_presence_[index]))};
364 return Literal(reason_for_presence_[index]);
384 std::function<
void(absl::Span<const int> items,
385 std::vector<Literal>* reason,
386 std::vector<IntegerLiteral>* integer_reason)>
387 extra_explanation_callback) {
388 used_items_for_reason_.ClearAndResize(
389 extra_explanation_callback ==
nullptr ? 0 : capacity_);
390 extra_explanation_callback_ = std::move(extra_explanation_callback);
399 return sat_solver_->CurrentDecisionLevel();
404 return integer_trail_->timestamp() + trail_->NumberOfEnqueues();
417 scratch_task_time_vector1_.ClearAndReserve(
NumTasks());
418 return scratch_task_time_vector1_;
421 scratch_task_time_vector2_.ClearAndReserve(
NumTasks());
422 return scratch_task_time_vector2_;
425 scratch_task_set_.ClearAndReserve(
NumTasks());
426 return scratch_task_set_;
435 if (integer_trail_->
LowerBound(sizes_[t]) <= 0) {
438 return sizes_[t].Negated();
443 void AddGenericReason(
const AffineExpression& a, IntegerValue upper_bound,
444 const AffineExpression&
b,
const AffineExpression& c);
446 void InitSortedVectors();
447 ABSL_MUST_USE_RESULT
bool UpdateCachedValues(
int t);
450 bool PushIntervalBound(
int t, IntegerLiteral lit);
454 void FlagItemAsUsedInReason(
int t);
456 void RunCallbackIfSet();
459 SatSolver* sat_solver_;
460 const VariablesAssignment& assignment_;
462 IntegerTrail* integer_trail_;
463 GenericLiteralWatcher* watcher_;
464 Linear2Bounds* linear2_bounds_;
465 RootLevelLinear2Bounds* root_level_lin2_bounds_;
466 EnforcementHelper& enforcement_helper_;
467 EnforcementId enforcement_id_;
469 FixedCapacityVector<TaskTime> scratch_task_time_vector1_;
470 FixedCapacityVector<TaskTime> scratch_task_time_vector2_;
471 FixedCapacityVector<TaskInfo> scratch_task_set_;
474 bool current_time_direction_ =
true;
478 std::vector<AffineExpression> starts_;
479 std::vector<AffineExpression> ends_;
480 std::vector<AffineExpression> sizes_;
481 std::vector<LiteralIndex> reason_for_presence_;
485 std::vector<AffineExpression> minus_starts_;
486 std::vector<AffineExpression> minus_ends_;
489 int64_t saved_num_backtracks_ = 0;
498 const std::unique_ptr<IntegerValue[]> cached_size_min_;
499 std::unique_ptr<IntegerValue[]> cached_start_min_;
500 std::unique_ptr<IntegerValue[]> cached_end_min_;
501 std::unique_ptr<IntegerValue[]> cached_negated_start_max_;
502 std::unique_ptr<IntegerValue[]> cached_negated_end_max_;
503 std::unique_ptr<IntegerValue[]> cached_shifted_start_min_;
504 std::unique_ptr<IntegerValue[]> cached_negated_shifted_end_max_;
507 std::vector<TaskTime> task_by_increasing_start_min_;
508 std::vector<TaskTime> task_by_decreasing_end_max_;
510 bool recompute_by_start_max_ =
true;
511 bool recompute_by_end_min_ =
true;
512 std::vector<TaskTime> task_by_increasing_negated_start_max_;
513 std::vector<TaskTime> task_by_increasing_end_min_;
516 bool recompute_energy_profile_ =
true;
517 std::vector<ProfileEvent> energy_profile_;
521 std::vector<CachedTaskBounds> task_by_increasing_shifted_start_min_;
522 std::vector<CachedTaskBounds> task_by_negated_shifted_end_max_;
523 bool recompute_shifted_start_min_ =
true;
524 bool recompute_negated_shifted_end_max_ =
true;
528 bool recompute_all_cache_ =
true;
529 Bitset64<int> recompute_cache_;
534 std::vector<int> non_fixed_intervals_;
537 std::vector<Literal> literal_reason_;
538 std::vector<IntegerLiteral> integer_reason_;
540 std::function<void(absl::Span<const int> items, std::vector<Literal>*,
541 std::vector<IntegerLiteral>*)>
542 extra_explanation_callback_ =
nullptr;
544 SparseBitset<int> used_items_for_reason_;
547 std::vector<int> propagator_ids_;
571 return integer_trail_->LevelZeroLowerBound(demands_[t]);
576 const std::vector<AffineExpression>&
Demands()
const {
return demands_; }
601 IntegerValue
EnergyMin(
int t)
const {
return cached_energies_min_[t]; }
602 IntegerValue
EnergyMax(
int t)
const {
return cached_energies_max_[t]; }
611 IntegerValue window_end);
613 IntegerValue window_end);
624 return decomposed_energies_;
629 const std::vector<std::vector<LiteralValueValue>>& energies);
642 IntegerValue SimpleEnergyMin(
int t)
const;
643 IntegerValue SimpleEnergyMax(
int t)
const;
644 IntegerValue DecomposedEnergyMin(
int t)
const;
645 IntegerValue DecomposedEnergyMax(
int t)
const;
651 std::vector<AffineExpression> demands_;
655 std::vector<IntegerValue> cached_energies_min_;
656 std::vector<IntegerValue> cached_energies_max_;
657 std::vector<bool> energy_is_quadratic_;
661 std::vector<std::vector<LiteralValueValue>> decomposed_energies_;
669 IntegerValue start_min, IntegerValue start_max, IntegerValue end_min,
670 IntegerValue end_max, IntegerValue size_min, IntegerValue demand_min,
671 absl::Span<const LiteralValueValue> filtered_energy,
672 IntegerValue window_start, IntegerValue window_end);
679 return integer_trail_->
IsFixed(starts_[t]);
683 return integer_trail_->IsFixed(ends_[t]);
687 return integer_trail_->IsFixed(sizes_[t]);
692 DCHECK_LT(t, reason_for_presence_.size());
698 DCHECK_LT(t, reason_for_presence_.size());
699 const LiteralIndex lit = reason_for_presence_.data()[t];
701 return assignment_.LiteralIsTrue(
Literal(lit));
706 DCHECK_LT(t, reason_for_presence_.size());
707 const LiteralIndex lit = reason_for_presence_.data()[t];
709 return assignment_.LiteralIsFalse(
Literal(lit));
718 return assignment_.LiteralIsTrue(
Literal(lit));
723 return assignment_.LiteralIsFalse(
Literal(lit));
727 integer_reason_.clear();
728 literal_reason_.clear();
729 enforcement_helper_.AddEnforcementReason(enforcement_id_, &literal_reason_);
730 used_items_for_reason_.ClearAndResize(capacity_);
735 FlagItemAsUsedInReason(t);
737 literal_reason_.push_back(
Literal(reason_for_presence_[t]).Negated());
743 FlagItemAsUsedInReason(t);
745 literal_reason_.push_back(
Literal(reason_for_presence_[t]));
753inline void SchedulingConstraintHelper::AddGenericReason(
756 if (integer_trail_->UpperBound(a) <= upper_bound) {
765 const IntegerValue slack = upper_bound - integer_trail_->UpperBound(
b) -
766 integer_trail_->UpperBound(c);
770 integer_reason_.push_back(c.LowerOrEqual(upper_bound -
b.constant));
772 integer_reason_.push_back(
b.LowerOrEqual(upper_bound - c.constant));
774 integer_trail_->AppendRelaxedLinearReason(
781 int t, IntegerValue lower_bound) {
782 FlagItemAsUsedInReason(t);
784 if (lower_bound <= 0)
return;
785 AddGenericReason(sizes_[t].Negated(), -lower_bound, minus_ends_[t],
790 int t, IntegerValue upper_bound) {
791 FlagItemAsUsedInReason(t);
793 AddGenericReason(sizes_[t], upper_bound, ends_[t], minus_starts_[t]);
797 int t, IntegerValue lower_bound) {
798 FlagItemAsUsedInReason(t);
800 AddGenericReason(minus_starts_[t], -lower_bound, minus_ends_[t], sizes_[t]);
804 int t, IntegerValue upper_bound) {
805 FlagItemAsUsedInReason(t);
807 AddGenericReason(starts_[t], upper_bound, ends_[t], NegatedSizeOrZero(t));
811 int t, IntegerValue lower_bound) {
812 FlagItemAsUsedInReason(t);
814 AddGenericReason(minus_ends_[t], -lower_bound, minus_starts_[t],
815 NegatedSizeOrZero(t));
819 int t, IntegerValue upper_bound) {
820 FlagItemAsUsedInReason(t);
822 AddGenericReason(ends_[t], upper_bound, starts_[t], sizes_[t]);
826 int t, IntegerValue upper_bound) {
831 int t, IntegerValue energy_min, IntegerValue time) {
841 int t, IntegerValue time_min, IntegerValue time_max) {
842 const IntegerValue energy_min =
SizeMin(t);
843 CHECK_LE(time_min + energy_min, time_max);
849 if (
EndMax(t) <= time_max) {
858 literal_reason_.push_back(l);
862 integer_reason_.push_back(l);
874 std::vector<IntegerVariable>* vars,
879 Model* model, std::vector<IntegerVariable>* vars);
IntegerValue LowerBound(IntegerVariable i) const
bool IsFixed(IntegerVariable i) const
PropagatorInterface()=default
void AddPresenceReason(int t)
IntegerValue ShiftedEndMax(int t) const
bool IncrementalPropagate(const std::vector< int > &watch_indices) final
absl::Span< const TaskTime > TaskByIncreasingStartMin()
void SetEnforcementId(EnforcementId id)
IntervalDefinition GetIntervalDefinition(int index) const
void AddEnergyAfterReason(int t, IntegerValue energy_min, IntegerValue time)
ABSL_MUST_USE_RESULT bool PushTaskOrderWhenPresent(int t_before, int t_after)
void SetExtraExplanationForItemCallback(std::function< void(absl::Span< const int > items, std::vector< Literal > *reason, std::vector< IntegerLiteral > *integer_reason)> extra_explanation_callback)
void AddStartMaxReason(int t, IntegerValue upper_bound)
ABSL_MUST_USE_RESULT bool IncreaseEndMin(int t, IntegerValue value)
IntegerValue ShiftedStartMin(int t) const
int64_t PropagationTimestamp() const
void WatchAllTasks(int id)
bool TaskIsBeforeOrIsOverlapping(int before, int after)
absl::Span< const TaskTime > TaskByIncreasingNegatedStartMax()
bool SizeIsFixed(int t) const
IntegerValue GetCurrentMinDistanceBetweenTasks(int a, int b)
IntegerValue LevelZeroSizeMin(int t) const
void AddSizeMaxReason(int t, IntegerValue upper_bound)
void AppendAndResetReason(std::vector< IntegerLiteral > *integer_reason, std::vector< Literal > *literal_reason)
IntegerValue StartMax(int t) const
ABSL_MUST_USE_RESULT bool DecreaseEndMax(int t, IntegerValue value)
ABSL_MUST_USE_RESULT bool ReportConflict()
absl::Span< const AffineExpression > Sizes() const
ABSL_MUST_USE_RESULT bool PushLiteral(Literal l)
FixedCapacityVector< TaskInfo > & GetScratchTaskSet()
const std::vector< ProfileEvent > & GetEnergyProfile()
ABSL_MUST_USE_RESULT bool PushTaskAbsence(int t)
bool IsPresent(int t) const
void SetTimeDirection(bool is_forward)
ABSL_MUST_USE_RESULT bool PushIntegerLiteralIfTaskPresent(int t, IntegerLiteral lit)
Literal PresenceLiteral(int index) const
void AddSizeMinReason(int t)
absl::Span< const AffineExpression > Starts() const
void AddEndMaxReason(int t, IntegerValue upper_bound)
absl::Span< const AffineExpression > Ends() const
void AddIntegerReason(IntegerLiteral l)
bool NotifyLevelZeroPrecedence(int a, int b)
ABSL_MUST_USE_RESULT bool ResetFromSubset(const SchedulingConstraintHelper &other, absl::Span< const int > tasks)
ABSL_MUST_USE_RESULT bool IncreaseStartMin(int t, IntegerValue value)
IntegerValue SizeMax(int t) const
void AddEndMinReason(int t, IntegerValue lower_bound)
IntegerValue StartMin(int t) const
bool InPropagationLoop() const
void AddReasonForUpperBoundLowerThan(LinearExpression2 expr, IntegerValue ub)
bool StartIsFixed(int t) const
SchedulingConstraintHelper(std::vector< AffineExpression > starts, std::vector< AffineExpression > ends, std::vector< AffineExpression > sizes, std::vector< LiteralIndex > reason_for_presence, Model *model)
IntegerValue SizeMin(int t) const
bool EndIsFixed(int t) const
IntegerValue LevelZeroStartMax(int t) const
absl::Span< const CachedTaskBounds > TaskByIncreasingShiftedStartMin()
void AddLiteralReason(Literal l)
absl::Span< const TaskTime > TaskByDecreasingEndMax()
ABSL_MUST_USE_RESULT bool SynchronizeAndSetTimeDirection(bool is_forward)
ABSL_MUST_USE_RESULT bool PushTaskPresence(int t)
void AddReasonForBeingBeforeAssumingNoOverlap(int before, int after)
IntegerValue EndMax(int t) const
bool IsAbsent(int t) const
IntegerValue EndMin(int t) const
bool IsOptional(int t) const
FixedCapacityVector< TaskTime > & GetScratchTaskTimeVector1()
std::string TaskDebugString(int t) const
ABSL_MUST_USE_RESULT bool PushIntegerLiteral(IntegerLiteral lit)
void AddShiftedEndMaxReason(int t, IntegerValue upper_bound)
IntegerValue LevelZeroEndMax(int t) const
IntegerValue GetMinOverlap(int t, IntegerValue start, IntegerValue end) const
void RegisterWith(GenericLiteralWatcher *watcher, absl::Span< const Literal > enforcement_literals)
void AddStartMinReason(int t, IntegerValue lower_bound)
absl::Span< const CachedTaskBounds > TaskByIncreasingNegatedShiftedEndMax()
void AddEnergyMinInIntervalReason(int t, IntegerValue min, IntegerValue max)
FixedCapacityVector< TaskTime > & GetScratchTaskTimeVector2()
void ImportReasonsFromOther(const SchedulingConstraintHelper &other_helper)
IntegerValue LevelZeroStartMin(int t) const
absl::Span< const TaskTime > TaskByIncreasingEndMin()
int CurrentDecisionLevel() const
void AddAbsenceReason(int t)
bool CurrentTimeIsForward() const
void AddDemandMinReason(int t)
std::vector< LiteralValueValue > FilteredDecomposedEnergy(int index)
bool DemandIsFixed(int t) const
bool CacheAllEnergyValues()
IntegerValue EnergyMinInWindow(int t, IntegerValue window_start, IntegerValue window_end)
IntegerValue LevelZeroDemandMin(int t) const
bool EnergyIsQuadratic(int t) const
const std::vector< std::vector< LiteralValueValue > > & DecomposedEnergies() const
IntegerValue EnergyMax(int t) const
void AddEnergyMinReason(int t)
void InitDecomposedEnergies()
void AddEnergyMinInWindowReason(int t, IntegerValue window_start, IntegerValue window_end)
IntegerValue DemandMax(int t) const
SchedulingDemandHelper(absl::Span< const AffineExpression > demands, SchedulingConstraintHelper *helper, Model *model)
void OverrideDecomposedEnergies(const std::vector< std::vector< LiteralValueValue > > &energies)
const std::vector< AffineExpression > & Demands() const
ABSL_MUST_USE_RESULT bool DecreaseEnergyMax(int t, IntegerValue value)
IntegerValue DemandMin(int t) const
ABSL_MUST_USE_RESULT bool AddLinearizedDemand(int t, LinearConstraintBuilder *builder) const
IntegerValue EnergyMin(int t) const
const LiteralIndex kNoLiteralIndex(-1)
std::vector< IntegerVariable > NegationOf(absl::Span< const IntegerVariable > vars)
const IntegerVariable kNoIntegerVariable(-1)
void AddIntegerVariableFromIntervals(const SchedulingConstraintHelper *helper, Model *model, std::vector< IntegerVariable > *vars, int mask)
void AppendVariablesFromCapacityAndDemands(const AffineExpression &capacity, SchedulingDemandHelper *demands_helper, Model *model, std::vector< IntegerVariable > *vars)
IntegerVariablesToAddMask
IntegerValue ComputeEnergyMinInWindow(IntegerValue start_min, IntegerValue start_max, IntegerValue end_min, IntegerValue end_max, IntegerValue size_min, IntegerValue demand_min, absl::Span< const LiteralValueValue > filtered_energy, IntegerValue window_start, IntegerValue window_end)
ClosedInterval::Iterator end(ClosedInterval interval)
IntegerLiteral LowerOrEqual(IntegerValue bound) const
bool operator>(CachedTaskBounds other) const
LiteralIndex presence_lit
bool operator<(CachedTaskBounds other) const
friend H AbslHashValue(H h, const IntervalDefinition &i)
std::optional< Literal > is_present
bool operator==(const IntervalDefinition &other) const
bool operator<(const ProfileEvent &other) const
bool operator<(TaskInfo other) const
bool operator<(TaskTime other) const
bool operator>(TaskTime other) const