21 #include "absl/strings/str_cat.h"
22 #include "absl/types/span.h"
42 IntegerValue fixed_size,
43 LiteralIndex is_present) {
54 LiteralIndex is_present,
55 bool add_linear_relation) {
57 const IntervalVariable i(starts_.size());
58 starts_.push_back(
start);
60 sizes_.push_back(size);
63 std::vector<Literal> enforcement_literals;
65 enforcement_literals.push_back(
Literal(is_present));
68 if (add_linear_relation) {
81 const std::vector<IntervalVariable>& tasks,
Model*
model)
88 minus_starts_.clear();
90 reason_for_presence_.clear();
93 for (
const IntervalVariable i : tasks) {
94 if (repository->IsOptional(i)) {
95 reason_for_presence_.push_back(repository->PresenceLiteral(i).Index());
99 sizes_.push_back(repository->Size(i));
100 starts_.push_back(repository->Start(i));
101 ends_.push_back(repository->End(i));
102 minus_starts_.push_back(repository->Start(i).Negated());
103 minus_ends_.push_back(repository->End(i).Negated());
117 const std::vector<IntervalVariable>& variables) {
118 const auto it = helper_repository_.find(variables);
119 if (it != helper_repository_.end())
return it->second;
123 helper_repository_[variables] = helper;
133 starts_.resize(num_tasks);
138 recompute_all_cache_ =
true;
143 const std::vector<int>& watch_indices) {
144 for (
const int t : watch_indices) recompute_cache_[t] =
true;
155 if (level < previous_level_) {
156 recompute_all_cache_ =
true;
158 previous_level_ = level;
162 const int id = watcher->
Register(
this);
163 const int num_tasks = starts_.size();
164 for (
int t = 0; t < num_tasks; ++t) {
176 bool SchedulingConstraintHelper::UpdateCachedValues(
int t) {
177 recompute_cache_[t] =
false;
180 IntegerValue smin = integer_trail_->
LowerBound(starts_[t]);
181 IntegerValue smax = integer_trail_->
UpperBound(starts_[t]);
182 IntegerValue emin = integer_trail_->
LowerBound(ends_[t]);
183 IntegerValue emax = integer_trail_->
UpperBound(ends_[t]);
192 IntegerValue dmax = integer_trail_->
UpperBound(sizes_[t]);
199 if (smin + dmin - emax > 0) {
206 if (smax + dmax - emin < 0) {
226 if (emin != cached_end_min_[t]) {
227 recompute_energy_profile_ =
true;
230 cached_start_min_[t] = smin;
231 cached_end_min_[t] = emin;
232 cached_negated_start_max_[t] = -smax;
233 cached_negated_end_max_[t] = -emax;
234 cached_size_min_[t] = dmin;
237 const IntegerValue new_shifted_start_min =
EndMin(t) - dmin;
238 if (new_shifted_start_min != cached_shifted_start_min_[t]) {
239 recompute_energy_profile_ =
true;
240 recompute_shifted_start_min_ =
true;
241 cached_shifted_start_min_[t] = new_shifted_start_min;
243 const IntegerValue new_negated_shifted_end_max = -(
StartMax(t) + dmin);
244 if (new_negated_shifted_end_max != cached_negated_shifted_end_max_[t]) {
245 recompute_negated_shifted_end_max_ =
true;
246 cached_negated_shifted_end_max_[t] = new_negated_shifted_end_max;
253 current_time_direction_ = other.current_time_direction_;
255 const int num_tasks = tasks.size();
256 starts_.resize(num_tasks);
257 ends_.resize(num_tasks);
258 minus_ends_.resize(num_tasks);
259 minus_starts_.resize(num_tasks);
260 sizes_.resize(num_tasks);
261 reason_for_presence_.resize(num_tasks);
262 for (
int i = 0; i < num_tasks; ++i) {
263 const int t = tasks[i];
264 starts_[i] = other.starts_[t];
265 ends_[i] = other.ends_[t];
266 minus_ends_[i] = other.minus_ends_[t];
267 minus_starts_[i] = other.minus_starts_[t];
268 sizes_[i] = other.sizes_[t];
269 reason_for_presence_[i] = other.reason_for_presence_[t];
276 void SchedulingConstraintHelper::InitSortedVectors() {
277 const int num_tasks = starts_.size();
279 recompute_all_cache_ =
true;
280 recompute_cache_.resize(num_tasks,
true);
282 cached_shifted_start_min_.resize(num_tasks);
283 cached_negated_shifted_end_max_.resize(num_tasks);
284 cached_size_min_.resize(num_tasks);
285 cached_start_min_.resize(num_tasks);
286 cached_end_min_.resize(num_tasks);
287 cached_negated_start_max_.resize(num_tasks);
288 cached_negated_end_max_.resize(num_tasks);
290 task_by_increasing_start_min_.resize(num_tasks);
291 task_by_increasing_end_min_.resize(num_tasks);
292 task_by_decreasing_start_max_.resize(num_tasks);
293 task_by_decreasing_end_max_.resize(num_tasks);
294 task_by_increasing_shifted_start_min_.resize(num_tasks);
295 task_by_negated_shifted_end_max_.resize(num_tasks);
296 for (
int t = 0; t < num_tasks; ++t) {
297 task_by_increasing_start_min_[t].task_index = t;
298 task_by_increasing_end_min_[t].task_index = t;
299 task_by_decreasing_start_max_[t].task_index = t;
300 task_by_decreasing_end_max_[t].task_index = t;
301 task_by_increasing_shifted_start_min_[t].task_index = t;
302 task_by_negated_shifted_end_max_[t].task_index = t;
305 recompute_energy_profile_ =
true;
306 recompute_shifted_start_min_ =
true;
307 recompute_negated_shifted_end_max_ =
true;
311 if (current_time_direction_ != is_forward) {
312 current_time_direction_ = is_forward;
317 std::swap(task_by_increasing_start_min_, task_by_decreasing_end_max_);
318 std::swap(task_by_increasing_end_min_, task_by_decreasing_start_max_);
319 std::swap(task_by_increasing_shifted_start_min_,
320 task_by_negated_shifted_end_max_);
322 recompute_energy_profile_ =
true;
323 std::swap(cached_start_min_, cached_negated_end_max_);
324 std::swap(cached_end_min_, cached_negated_start_max_);
325 std::swap(cached_shifted_start_min_, cached_negated_shifted_end_max_);
326 std::swap(recompute_shifted_start_min_, recompute_negated_shifted_end_max_);
333 if (recompute_all_cache_) {
334 for (
int t = 0; t < recompute_cache_.size(); ++t) {
335 if (!UpdateCachedValues(t))
return false;
338 for (
int t = 0; t < recompute_cache_.size(); ++t) {
339 if (recompute_cache_[t]) {
340 if (!UpdateCachedValues(t))
return false;
344 recompute_all_cache_ =
false;
348 const std::vector<TaskTime>&
351 for (
int i = 0; i < num_tasks; ++i) {
352 TaskTime& ref = task_by_increasing_start_min_[i];
356 task_by_increasing_start_min_.end());
357 return task_by_increasing_start_min_;
360 const std::vector<TaskTime>&
363 for (
int i = 0; i < num_tasks; ++i) {
364 TaskTime& ref = task_by_increasing_end_min_[i];
368 task_by_increasing_end_min_.end());
369 return task_by_increasing_end_min_;
372 const std::vector<TaskTime>&
375 for (
int i = 0; i < num_tasks; ++i) {
376 TaskTime& ref = task_by_decreasing_start_max_[i];
380 task_by_decreasing_start_max_.end(),
381 std::greater<TaskTime>());
382 return task_by_decreasing_start_max_;
385 const std::vector<TaskTime>&
388 for (
int i = 0; i < num_tasks; ++i) {
389 TaskTime& ref = task_by_decreasing_end_max_[i];
393 task_by_decreasing_end_max_.end(), std::greater<TaskTime>());
394 return task_by_decreasing_end_max_;
397 const std::vector<TaskTime>&
399 if (recompute_shifted_start_min_) {
400 recompute_shifted_start_min_ =
false;
402 bool is_sorted =
true;
404 for (
int i = 0; i < num_tasks; ++i) {
405 TaskTime& ref = task_by_increasing_shifted_start_min_[i];
407 is_sorted = is_sorted && ref.
time >= previous;
410 if (is_sorted)
return task_by_increasing_shifted_start_min_;
412 task_by_increasing_shifted_start_min_.end());
414 return task_by_increasing_shifted_start_min_;
418 const std::vector<SchedulingConstraintHelper::ProfileEvent>&
420 if (energy_profile_.empty()) {
422 for (
int t = 0; t < num_tasks; ++t) {
423 energy_profile_.push_back(
424 {cached_shifted_start_min_[t], t,
true});
425 energy_profile_.push_back({cached_end_min_[t], t,
false});
428 if (!recompute_energy_profile_)
return energy_profile_;
430 const int t = ref.task;
432 ref.time = cached_shifted_start_min_[t];
434 ref.time = cached_end_min_[t];
439 recompute_energy_profile_ =
false;
440 return energy_profile_;
446 AddOtherReason(before);
447 AddOtherReason(after);
451 std::vector<IntegerVariable> vars;
452 std::vector<IntegerValue> coeffs;
455 const IntegerValue smax_before =
StartMax(before);
456 if (smax_before >= integer_trail_->
UpperBound(starts_[before])) {
459 coeffs.push_back(starts_[before].coeff);
464 coeffs.push_back(ends_[before].coeff);
467 vars.push_back(sizes_[before].
var);
468 coeffs.push_back(sizes_[before].coeff);
473 const IntegerValue emin_after =
EndMin(after);
474 if (emin_after <= integer_trail_->
LowerBound(ends_[after])) {
476 vars.push_back(ends_[after].
var);
477 coeffs.push_back(ends_[after].coeff);
481 vars.push_back(starts_[after].
var);
482 coeffs.push_back(starts_[after].coeff);
485 vars.push_back(sizes_[after].
var);
486 coeffs.push_back(sizes_[after].coeff);
490 DCHECK_LT(smax_before, emin_after);
491 const IntegerValue slack = emin_after - smax_before - 1;
497 CHECK(other_helper_ ==
nullptr);
498 return integer_trail_->
Enqueue(lit, literal_reason_, integer_reason_);
510 return integer_trail_->
Enqueue(lit, literal_reason_, integer_reason_);
515 bool SchedulingConstraintHelper::PushIntervalBound(
int t,
IntegerLiteral lit) {
519 if (!UpdateCachedValues(t))
return false;
548 integer_trail_->
EnqueueLiteral(l, literal_reason_, integer_reason_);
559 literal_reason_.push_back(
Literal(reason_for_presence_[t]).Negated());
564 literal_reason_, integer_reason_);
575 literal_reason_.push_back(
Literal(reason_for_presence_[t]));
580 literal_reason_, integer_reason_);
586 return integer_trail_->
ReportConflict(literal_reason_, integer_reason_);
591 bool watch_start_max,
592 bool watch_end_max)
const {
593 const int num_tasks = starts_.size();
594 for (
int t = 0; t < num_tasks; ++t) {
598 if (watch_start_max) {
610 void SchedulingConstraintHelper::AddOtherReason(
int t) {
611 if (other_helper_ ==
nullptr || already_added_to_other_reasons_[t])
return;
612 already_added_to_other_reasons_[t] =
true;
613 const int mapped_t = map_to_other_helper_[t];
618 void SchedulingConstraintHelper::ImportOtherReasons() {
619 if (other_helper_ !=
nullptr) ImportOtherReasons(*other_helper_);
622 void SchedulingConstraintHelper::ImportOtherReasons(
624 literal_reason_.insert(literal_reason_.end(),
625 other_helper.literal_reason_.begin(),
626 other_helper.literal_reason_.end());
627 integer_reason_.insert(integer_reason_.end(),
628 other_helper.integer_reason_.begin(),
629 other_helper.integer_reason_.end());
633 return absl::StrCat(
"t=", t,
" is_present=",
IsPresent(t),
" size=[",
642 IntegerValue
end)
const {
649 IntegerValue
end_max, IntegerValue size_min, IntegerValue demand_min,
650 const std::vector<LiteralValueValue>& filtered_energy,
651 IntegerValue window_start, IntegerValue window_end) {
652 if (window_end <= window_start)
return IntegerValue(0);
655 if (
end_min <= window_start)
return IntegerValue(0);
656 if (
start_max >= window_end)
return IntegerValue(0);
657 const IntegerValue window_size = window_end - window_start;
658 const IntegerValue simple_energy_min =
660 size_min, window_size});
661 if (filtered_energy.empty())
return simple_energy_min;
664 for (
const auto [lit, fixed_size, fixed_demand] : filtered_energy) {
666 const IntegerValue alt_start_max =
668 const IntegerValue energy_min =
670 std::min({alt_end_min - window_start, window_end - alt_start_max,
671 fixed_size, window_size});
672 result =
std::min(result, energy_min);
675 return std::max(simple_energy_min, result);
684 demands_(std::move(demands)),
686 const int num_tasks = helper->
NumTasks();
687 linearized_energies_.resize(num_tasks);
688 decomposed_energies_.resize(num_tasks);
691 energy_is_quadratic_.resize(num_tasks,
false);
694 if (demands_.size() != num_tasks)
return;
695 for (
int t = 0; t < num_tasks; ++t) {
702 IntegerValue SchedulingDemandHelper::SimpleEnergyMin(
int t)
const {
707 IntegerValue SchedulingDemandHelper::LinearEnergyMin(
int t)
const {
709 return linearized_energies_[t]->Min(*integer_trail_);
712 IntegerValue SchedulingDemandHelper::DecomposedEnergyMin(
int t)
const {
715 for (
const auto [lit, fixed_size, fixed_demand] : decomposed_energies_[t]) {
717 return fixed_size * fixed_demand;
720 result =
std::min(result, fixed_size * fixed_demand);
726 IntegerValue SchedulingDemandHelper::SimpleEnergyMax(
int t)
const {
731 IntegerValue SchedulingDemandHelper::LinearEnergyMax(
int t)
const {
733 return linearized_energies_[t]->Max(*integer_trail_);
736 IntegerValue SchedulingDemandHelper::DecomposedEnergyMax(
int t)
const {
739 for (
const auto [lit, fixed_size, fixed_demand] : decomposed_energies_[t]) {
741 return fixed_size * fixed_demand;
744 result =
std::max(result, fixed_size * fixed_demand);
751 const int num_tasks = cached_energies_min_.size();
753 for (
int t = 0; t < num_tasks; ++t) {
755 if (is_at_level_zero) {
757 for (
int i = 0; i < decomposed_energies_[t].size(); ++i) {
758 if (assignment_.
LiteralIsFalse(decomposed_energies_[t][i].literal)) {
761 decomposed_energies_[t][new_size++] = decomposed_energies_[t][i];
763 decomposed_energies_[t].resize(new_size);
767 {SimpleEnergyMin(t), LinearEnergyMin(t), DecomposedEnergyMin(t)});
769 energy_is_quadratic_[t] =
770 decomposed_energies_[t].empty() && !demands_.empty() &&
773 {SimpleEnergyMax(t), LinearEnergyMax(t), DecomposedEnergyMax(t)});
779 DCHECK_LT(t, demands_.size());
780 return integer_trail_->
LowerBound(demands_[t]);
784 DCHECK_LT(t, demands_.size());
785 return integer_trail_->
UpperBound(demands_[t]);
789 return integer_trail_->
IsFixed(demands_[t]);
799 }
else if (!decomposed_energies_[t].empty()) {
800 for (
const auto [lit, fixed_size, fixed_demand] : decomposed_energies_[t]) {
801 if (fixed_size * fixed_demand >
value) {
807 }
else if (linearized_energies_[t].has_value() &&
808 linearized_energies_[t]->vars.size() == 1) {
817 VLOG(3) <<
"Cumulative energy missed propagation";
823 DCHECK_LT(t, demands_.size());
832 const IntegerValue
value = cached_energies_min_[t];
833 if (DecomposedEnergyMin(t) >=
value) {
835 const int old_size = reason->size();
836 for (
const auto [lit, fixed_size, fixed_demand] : decomposed_energies_[t]) {
838 reason->resize(old_size);
839 reason->push_back(lit.
Negated());
841 }
else if (fixed_size * fixed_demand <
value &&
843 reason->push_back(lit);
846 }
else if (SimpleEnergyMin(t) >=
value) {
850 DCHECK_GE(LinearEnergyMin(t),
value);
851 for (
const IntegerVariable
var : linearized_energies_[t]->vars) {
861 if (!decomposed_energies_[t].empty()) {
868 builder->
AddTerm(demands_[t], IntegerValue(1));
877 const std::vector<LinearExpression>& energies) {
878 const int num_tasks = energies.size();
879 DCHECK_EQ(num_tasks, helper_->
NumTasks());
880 linearized_energies_.resize(num_tasks);
881 for (
int t = 0; t < num_tasks; ++t) {
882 linearized_energies_[t] = energies[t];
884 for (
const IntegerValue coeff : linearized_energies_[t]->coeffs) {
893 if (decomposed_energies_[
index].empty())
return {};
896 return decomposed_energies_[
index];
900 std::vector<LiteralValueValue> result;
901 for (
const auto& e : decomposed_energies_[
index]) {
909 const std::vector<std::vector<LiteralValueValue>>& energies) {
910 DCHECK_EQ(energies.size(), helper_->
NumTasks());
911 decomposed_energies_ = energies;
915 int t, IntegerValue window_start, IntegerValue window_end) {
925 int t, IntegerValue window_start, IntegerValue window_end) {
926 const IntegerValue actual_energy_min =
928 if (actual_energy_min == 0)
return;
934 const IntegerValue min_overlap =
936 const IntegerValue simple_energy_min =
DemandMin(t) * min_overlap;
937 if (simple_energy_min == actual_energy_min) {
948 DCHECK(!decomposed_energies_[t].empty());
955 const int old_size = literal_reason->size();
957 DCHECK(!decomposed_energies_[t].empty());
958 for (
const auto [lit, fixed_size, fixed_demand] : decomposed_energies_[t]) {
961 literal_reason->resize(old_size);
962 literal_reason->push_back(lit.
Negated());
968 const IntegerValue energy_min =
970 std::min({alt_em - window_start, window_end - alt_sm, fixed_size});
971 if (energy_min >= actual_energy_min)
continue;
972 literal_reason->push_back(lit);
void push_back(const value_type &x)
An Assignment is a variable -> domains mapping, used to report solutions to the user.
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 IsFixed(IntegerVariable i) const
IntegerLiteral LowerBoundAsLiteral(IntegerVariable i) const
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
SchedulingConstraintHelper * GetOrCreateHelper(const std::vector< IntervalVariable > &variables)
IntervalVariable CreateInterval(IntegerVariable start, IntegerVariable end, IntegerVariable size, IntegerValue fixed_size, LiteralIndex is_present)
ABSL_MUST_USE_RESULT bool AddLiteralTerm(Literal lit, IntegerValue coeff=IntegerValue(1))
void AddTerm(IntegerVariable var, IntegerValue coeff)
Class that owns everything related to a particular optimization model.
T * TakeOwnership(T *t)
Gives ownership of a pointer to this model.
bool PropagateOutgoingArcs(IntegerVariable var)
int CurrentDecisionLevel() const
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
std::vector< Literal > * MutableLiteralReason()
ABSL_MUST_USE_RESULT bool PushTaskAbsence(int t)
SchedulingConstraintHelper(const std::vector< IntervalVariable > &tasks, Model *model)
ABSL_MUST_USE_RESULT bool IncreaseStartMin(int t, IntegerValue value)
ABSL_MUST_USE_RESULT bool DecreaseEndMax(int t, IntegerValue value)
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 IncreaseEndMin(int t, IntegerValue value)
std::vector< IntegerLiteral > * MutableIntegerReason()
ABSL_MUST_USE_RESULT bool ResetFromSubset(const SchedulingConstraintHelper &other, absl::Span< const int > tasks)
bool IsPresent(int t) const
bool SizeIsFixed(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)
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()
ABSL_MUST_USE_RESULT bool PushLiteral(Literal l)
void ImportOtherReasons(const SchedulingConstraintHelper &other_helper)
bool IsOptional(int t) const
const std::vector< ProfileEvent > & GetEnergyProfile()
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)
const std::vector< AffineExpression > & Sizes() const
void AddStartMaxReason(int t, IntegerValue upper_bound)
void SetTimeDirection(bool is_forward)
IntegerValue SizeMax(int t) const
IntegerValue SizeMin(int t) const
void OverrideLinearizedEnergies(const std::vector< LinearExpression > &energies)
SchedulingDemandHelper(std::vector< AffineExpression > demands, SchedulingConstraintHelper *helper, Model *model)
bool DemandIsFixed(int t) const
void AddEnergyMinInWindowReason(int t, IntegerValue window_start, IntegerValue window_end)
ABSL_MUST_USE_RESULT bool AddLinearizedDemand(int t, LinearConstraintBuilder *builder) const
IntegerValue DemandMax(int t) const
std::vector< LiteralValueValue > FilteredDecomposedEnergy(int index)
IntegerValue EnergyMin(int t) const
void CacheAllEnergyValues()
void AddDemandMinReason(int t)
ABSL_MUST_USE_RESULT bool DecreaseEnergyMax(int t, IntegerValue value)
void OverrideDecomposedEnergies(const std::vector< std::vector< LiteralValueValue >> &energies)
IntegerValue DemandMin(int t) const
IntegerValue EnergyMinInWindow(int t, IntegerValue window_start, IntegerValue window_end)
void AddEnergyMinReason(int t)
bool LiteralIsTrue(Literal literal) const
bool LiteralIsFalse(Literal literal) const
void swap(IdMap< K, V > &a, IdMap< K, V > &b)
std::function< void(Model *)> GreaterOrEqual(IntegerVariable v, int64_t lb)
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
const LiteralIndex kNoLiteralIndex(-1)
void LoadConditionalLinearConstraint(const absl::Span< const Literal > enforcement_literals, const LinearConstraint &cst, Model *model)
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue.value())
const IntegerVariable kNoIntegerVariable(-1)
std::function< void(Model *)> LowerOrEqual(IntegerVariable v, int64_t ub)
IntegerValue ComputeEnergyMinInWindow(IntegerValue start_min, IntegerValue start_max, IntegerValue end_min, IntegerValue end_max, IntegerValue size_min, IntegerValue demand_min, const std::vector< LiteralValueValue > &filtered_energy, IntegerValue window_start, IntegerValue window_end)
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
std::vector< LiteralValueValue > TryToDecomposeProduct(const AffineExpression &left, const AffineExpression &right, Model *model)
std::function< int64_t(const Model &)> LowerBound(IntegerVariable v)
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
IntegerLiteral LowerOrEqual(IntegerValue bound) const
IntegerLiteral Negated() const
std::vector< IntegerValue > coeffs
std::vector< IntegerVariable > vars
#define VLOG(verboselevel)