14#ifndef OR_TOOLS_SAT_SCHEDULING_HELPERS_H_
15#define OR_TOOLS_SAT_SCHEDULING_HELPERS_H_
24#include "absl/base/attributes.h"
25#include "absl/log/check.h"
26#include "absl/types/span.h"
72 return H::combine(std::move(h),
i.start,
i.end,
i.size,
i.is_present);
92 std::vector<AffineExpression> ends,
93 std::vector<AffineExpression> sizes,
94 std::vector<LiteralIndex> reason_for_presence,
142 IntegerValue
SizeMin(
int t)
const {
return cached_size_min_[t]; }
145 return integer_trail_->UpperBound(sizes_[t]);
147 IntegerValue
StartMin(
int t)
const {
return cached_start_min_[t]; }
148 IntegerValue
EndMin(
int t)
const {
return cached_end_min_[t]; }
149 IntegerValue
StartMax(
int t)
const {
return -cached_negated_start_max_[t]; }
150 IntegerValue
EndMax(
int t)
const {
return -cached_negated_end_max_[t]; }
155 return std::max(IntegerValue(0),
156 integer_trail_->LevelZeroLowerBound(sizes_[t]));
159 return integer_trail_->LevelZeroLowerBound(starts_[t]);
162 return integer_trail_->LevelZeroUpperBound(starts_[t]);
165 return integer_trail_->LevelZeroUpperBound(ends_[t]);
183 return cached_shifted_start_min_[t];
189 return -cached_negated_shifted_end_max_[t];
206 bool IsAbsent(LiteralIndex lit)
const;
211 int a,
int b,
bool add_reason_if_after =
false);
222 IntegerValue
GetMinOverlap(
int t, IntegerValue start, IntegerValue end)
const;
284 return &integer_reason_;
297 ABSL_MUST_USE_RESULT
bool IncreaseEndMin(
int t, IntegerValue value);
298 ABSL_MUST_USE_RESULT
bool DecreaseEndMax(
int t, IntegerValue value);
307 absl::Span<const AffineExpression>
Starts()
const {
return starts_; }
308 absl::Span<const AffineExpression>
Ends()
const {
return ends_; }
309 absl::Span<const AffineExpression>
Sizes()
const {
return sizes_; }
313 .start = starts_[index],
315 .size = sizes_[index],
317 ? std::optional<Literal>()
318 :
Literal(reason_for_presence_[index]))};
323 return Literal(reason_for_presence_[index]);
336 absl::Span<const int> map_to_other_helper,
337 IntegerValue event) {
338 CHECK(other_helper !=
nullptr);
339 other_helper_ = other_helper;
340 map_to_other_helper_ = map_to_other_helper;
341 event_for_other_helper_ = event;
360 return sat_solver_->CurrentDecisionLevel();
369 if (integer_trail_->
LowerBound(sizes_[t]) <= 0) {
372 return sizes_[t].Negated();
377 void AddGenericReason(
const AffineExpression& a, IntegerValue upper_bound,
378 const AffineExpression&
b,
const AffineExpression& c);
380 void InitSortedVectors();
381 ABSL_MUST_USE_RESULT
bool UpdateCachedValues(
int t);
384 bool PushIntervalBound(
int t, IntegerLiteral lit);
390 void AddOtherReason(
int t);
393 void ImportOtherReasons();
396 SatSolver* sat_solver_;
397 const VariablesAssignment& assignment_;
398 IntegerTrail* integer_trail_;
399 GenericLiteralWatcher* watcher_;
400 PrecedenceRelations* precedence_relations_;
403 bool current_time_direction_ =
true;
407 std::vector<AffineExpression> starts_;
408 std::vector<AffineExpression> ends_;
409 std::vector<AffineExpression> sizes_;
410 std::vector<LiteralIndex> reason_for_presence_;
414 std::vector<AffineExpression> minus_starts_;
415 std::vector<AffineExpression> minus_ends_;
418 int64_t saved_num_backtracks_ = 0;
427 const std::unique_ptr<IntegerValue[]> cached_size_min_;
428 std::unique_ptr<IntegerValue[]> cached_start_min_;
429 std::unique_ptr<IntegerValue[]> cached_end_min_;
430 std::unique_ptr<IntegerValue[]> cached_negated_start_max_;
431 std::unique_ptr<IntegerValue[]> cached_negated_end_max_;
432 std::unique_ptr<IntegerValue[]> cached_shifted_start_min_;
433 std::unique_ptr<IntegerValue[]> cached_negated_shifted_end_max_;
436 std::vector<TaskTime> task_by_increasing_start_min_;
437 std::vector<TaskTime> task_by_decreasing_end_max_;
439 bool recompute_by_start_max_ =
true;
440 bool recompute_by_end_min_ =
true;
441 std::vector<TaskTime> task_by_increasing_negated_start_max_;
442 std::vector<TaskTime> task_by_increasing_end_min_;
445 bool recompute_energy_profile_ =
true;
446 std::vector<ProfileEvent> energy_profile_;
450 std::vector<CachedTaskBounds> task_by_increasing_shifted_start_min_;
451 std::vector<CachedTaskBounds> task_by_negated_shifted_end_max_;
452 bool recompute_shifted_start_min_ =
true;
453 bool recompute_negated_shifted_end_max_ =
true;
457 bool recompute_all_cache_ =
true;
458 Bitset64<int> recompute_cache_;
461 std::vector<Literal> literal_reason_;
462 std::vector<IntegerLiteral> integer_reason_;
466 absl::Span<const int> map_to_other_helper_;
467 IntegerValue event_for_other_helper_;
468 std::vector<bool> already_added_to_other_reasons_;
471 std::vector<int> propagator_ids_;
495 return integer_trail_->LevelZeroLowerBound(demands_[t]);
500 const std::vector<AffineExpression>&
Demands()
const {
return demands_; }
525 IntegerValue
EnergyMin(
int t)
const {
return cached_energies_min_[t]; }
526 IntegerValue
EnergyMax(
int t)
const {
return cached_energies_max_[t]; }
535 IntegerValue window_end);
537 IntegerValue window_end);
548 return decomposed_energies_;
553 const std::vector<std::vector<LiteralValueValue>>& energies);
566 IntegerValue SimpleEnergyMin(
int t)
const;
567 IntegerValue SimpleEnergyMax(
int t)
const;
568 IntegerValue DecomposedEnergyMin(
int t)
const;
569 IntegerValue DecomposedEnergyMax(
int t)
const;
575 std::vector<AffineExpression> demands_;
579 std::vector<IntegerValue> cached_energies_min_;
580 std::vector<IntegerValue> cached_energies_max_;
581 std::vector<bool> energy_is_quadratic_;
585 std::vector<std::vector<LiteralValueValue>> decomposed_energies_;
593 IntegerValue start_min, IntegerValue start_max, IntegerValue end_min,
594 IntegerValue end_max, IntegerValue size_min, IntegerValue demand_min,
595 absl::Span<const LiteralValueValue> filtered_energy,
596 IntegerValue window_start, IntegerValue window_end);
603 return integer_trail_->
IsFixed(starts_[t]);
607 return integer_trail_->IsFixed(ends_[t]);
611 return integer_trail_->IsFixed(sizes_[t]);
616 DCHECK_LT(t, reason_for_presence_.size());
622 DCHECK_LT(t, reason_for_presence_.size());
623 const LiteralIndex lit = reason_for_presence_.data()[t];
625 return assignment_.LiteralIsTrue(
Literal(lit));
630 DCHECK_LT(t, reason_for_presence_.size());
631 const LiteralIndex lit = reason_for_presence_.data()[t];
633 return assignment_.LiteralIsFalse(
Literal(lit));
642 return assignment_.LiteralIsTrue(
Literal(lit));
647 return assignment_.LiteralIsFalse(
Literal(lit));
651 integer_reason_.clear();
652 literal_reason_.clear();
654 other_helper_->ClearReason();
655 already_added_to_other_reasons_.assign(
NumTasks(),
false);
663 literal_reason_.push_back(
Literal(reason_for_presence_[t]).Negated());
671 literal_reason_.push_back(
Literal(reason_for_presence_[t]));
679inline void SchedulingConstraintHelper::AddGenericReason(
682 if (integer_trail_->UpperBound(a) <= upper_bound) {
691 const IntegerValue slack = upper_bound - integer_trail_->UpperBound(
b) -
692 integer_trail_->UpperBound(c);
696 integer_reason_.push_back(c.LowerOrEqual(upper_bound -
b.constant));
698 integer_reason_.push_back(
b.LowerOrEqual(upper_bound - c.constant));
700 integer_trail_->AppendRelaxedLinearReason(
707 int t, IntegerValue lower_bound) {
710 if (lower_bound <= 0)
return;
711 AddGenericReason(sizes_[t].Negated(), -lower_bound, minus_ends_[t],
716 int t, IntegerValue upper_bound) {
719 AddGenericReason(sizes_[t], upper_bound, ends_[t], minus_starts_[t]);
723 int t, IntegerValue lower_bound) {
726 AddGenericReason(minus_starts_[t], -lower_bound, minus_ends_[t], sizes_[t]);
730 int t, IntegerValue upper_bound) {
733 AddGenericReason(starts_[t], upper_bound, ends_[t], NegatedSizeOrZero(t));
737 int t, IntegerValue lower_bound) {
740 AddGenericReason(minus_ends_[t], -lower_bound, minus_starts_[t],
741 NegatedSizeOrZero(t));
745 int t, IntegerValue upper_bound) {
748 AddGenericReason(ends_[t], upper_bound, starts_[t], sizes_[t]);
752 int t, IntegerValue upper_bound) {
757 int t, IntegerValue energy_min, IntegerValue time) {
767 int t, IntegerValue time_min, IntegerValue time_max) {
768 const IntegerValue energy_min =
SizeMin(t);
769 CHECK_LE(time_min + energy_min, time_max);
775 if (
EndMax(t) <= time_max) {
792 std::vector<IntegerVariable>* vars,
797 Model* model, std::vector<IntegerVariable>* vars);
IntegerValue LowerBound(IntegerVariable i) const
Returns the current lower/upper bound of the given integer variable.
bool IsFixed(IntegerVariable i) const
Checks if the variable is fixed.
Helper class to express a product as a linear constraint.
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 AddReasonForBeingBefore(int before, int after)
Produces a relaxed reason for StartMax(before) < EndMin(after).
IntervalDefinition GetIntervalDefinition(int index) const
void AddEnergyAfterReason(int t, IntegerValue energy_min, IntegerValue time)
void AddStartMaxReason(int t, IntegerValue upper_bound)
ABSL_MUST_USE_RESULT bool IncreaseEndMin(int t, IntegerValue value)
IntegerValue ShiftedStartMin(int t) const
void WatchAllTasks(int id)
std::vector< IntegerLiteral > * MutableIntegerReason()
void RegisterWith(GenericLiteralWatcher *watcher)
absl::Span< const TaskTime > TaskByIncreasingNegatedStartMax()
bool SizeIsFixed(int t) const
IntegerValue LevelZeroSizeMin(int t) const
void AddSizeMaxReason(int t, IntegerValue upper_bound)
IntegerValue StartMax(int t) const
bool PropagatePrecedence(int a, int b)
ABSL_MUST_USE_RESULT bool DecreaseEndMax(int t, IntegerValue value)
int NumTasks() const
Returns the number of task.
ABSL_MUST_USE_RESULT bool ReportConflict()
absl::Span< const AffineExpression > Sizes() const
ABSL_MUST_USE_RESULT bool PushLiteral(Literal l)
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
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
void ClearReason()
Functions to clear and then set the current reason.
bool InPropagationLoop() const
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()
absl::Span< const TaskTime > TaskByDecreasingEndMax()
ABSL_MUST_USE_RESULT bool SynchronizeAndSetTimeDirection(bool is_forward)
void SetOtherHelper(SchedulingConstraintHelper *other_helper, absl::Span< const int > map_to_other_helper, IntegerValue event)
ABSL_MUST_USE_RESULT bool PushTaskPresence(int t)
IntegerValue EndMax(int t) const
bool IsAbsent(int t) const
bool HasOtherHelper() const
IntegerValue EndMin(int t) const
bool IsOptional(int t) const
std::string TaskDebugString(int t) const
Returns a string with the current task bounds.
ABSL_MUST_USE_RESULT bool PushIntegerLiteral(IntegerLiteral lit)
void AddShiftedEndMaxReason(int t, IntegerValue upper_bound)
IntegerValue GetCurrentMinDistanceBetweenTasks(int a, int b, bool add_reason_if_after=false)
IntegerValue LevelZeroEndMax(int t) const
IntegerValue GetMinOverlap(int t, IntegerValue start, IntegerValue end) const
std::vector< Literal > * MutableLiteralReason()
void AddStartMinReason(int t, IntegerValue lower_bound)
void AddEnergyMinInIntervalReason(int t, IntegerValue min, IntegerValue max)
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)
Visible for testing.
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)
Returns the vector of the negated variables.
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
Cuts helpers.
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)
In SWIG mode, we don't want anything besides these top-level includes.
IntegerLiteral LowerOrEqual(IntegerValue bound) const
var * coeff + constant <= bound.
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<(TaskTime other) const
bool operator>(TaskTime other) const