23#include "absl/container/flat_hash_map.h"
24#include "absl/log/check.h"
25#include "absl/meta/type_traits.h"
26#include "absl/strings/str_cat.h"
27#include "absl/types/span.h"
47 IntegerValue fixed_size,
48 LiteralIndex is_present) {
59 LiteralIndex is_present,
60 bool add_linear_relation) {
62 const IntervalVariable
i(starts_.size());
63 starts_.push_back(
start);
65 sizes_.push_back(
size);
68 std::vector<Literal> enforcement_literals;
70 enforcement_literals.push_back(
Literal(is_present));
73 if (add_linear_relation) {
86 IntervalVariable
a, IntervalVariable
b) {
87 if (disjunctive_precedences_.contains({a, b}))
return;
89 std::vector<Literal> enforcement_literals;
94 for (
const Literal l : enforcement_literals) {
99 enforcement_literals[new_size++] = l;
101 enforcement_literals.resize(new_size);
126 disjunctive_precedences_.insert({{
a,
b}, a_before_b});
127 disjunctive_precedences_.insert({{
b,
a}, a_before_b.
Negated()});
131 precedences_.insert({{end_a, start_b}, a_before_b});
132 precedences_.insert({{end_b, start_a}, a_before_b.
Negated()});
134 enforcement_literals.push_back(a_before_b);
136 enforcement_literals.pop_back();
138 enforcement_literals.push_back(a_before_b.
Negated());
140 enforcement_literals.pop_back();
144 for (
const Literal l : enforcement_literals) {
150 IntervalVariable
b) {
153 if (precedences_.contains({x, y}))
return false;
169 precedences_.insert({{
x,
y}, x_before_y});
179 IntervalVariable
a, IntervalVariable
b)
const {
182 const auto it = precedences_.find({
x,
y});
183 if (it != precedences_.end())
return it->second.Index();
191 const std::vector<IntervalVariable>& variables,
192 bool register_as_disjunctive_helper) {
193 const auto it = helper_repository_.find(variables);
194 if (it != helper_repository_.end())
return it->second;
198 helper_repository_[variables] = helper;
200 if (register_as_disjunctive_helper) {
201 disjunctive_helpers_.push_back(helper);
208 absl::Span<const AffineExpression> demands) {
209 const std::pair<SchedulingConstraintHelper*, std::vector<AffineExpression>>
211 std::vector<AffineExpression>(demands.begin(), demands.end())};
212 const auto it = demand_helper_repository_.find(key);
213 if (it != demand_helper_repository_.end())
return it->second;
218 demand_helper_repository_[key] = demand_helper;
219 return demand_helper;
223 for (
const auto& it : demand_helper_repository_) {
224 it.second->InitDecomposedEnergies();
229 const std::vector<IntervalVariable>& tasks,
Model*
model)
236 interval_variables_(tasks),
237 capacity_(tasks.
size()),
238 cached_size_min_(new IntegerValue[capacity_]),
239 cached_start_min_(new IntegerValue[capacity_]),
240 cached_end_min_(new IntegerValue[capacity_]),
241 cached_negated_start_max_(new IntegerValue[capacity_]),
242 cached_negated_end_max_(new IntegerValue[capacity_]),
243 cached_shifted_start_min_(new IntegerValue[capacity_]),
244 cached_negated_shifted_end_max_(new IntegerValue[capacity_]) {
248 minus_starts_.clear();
250 reason_for_presence_.clear();
253 for (
const IntervalVariable
i : tasks) {
254 if (repository->IsOptional(
i)) {
255 reason_for_presence_.push_back(repository->PresenceLiteral(
i).Index());
259 sizes_.push_back(repository->Size(
i));
260 starts_.push_back(repository->Start(
i));
261 ends_.push_back(repository->End(
i));
262 minus_starts_.push_back(repository->Start(
i).Negated());
263 minus_ends_.push_back(repository->End(
i).Negated());
280 capacity_(num_tasks),
281 cached_size_min_(new IntegerValue[capacity_]),
282 cached_start_min_(new IntegerValue[capacity_]),
283 cached_end_min_(new IntegerValue[capacity_]),
284 cached_negated_start_max_(new IntegerValue[capacity_]),
285 cached_negated_end_max_(new IntegerValue[capacity_]),
286 cached_shifted_start_min_(new IntegerValue[capacity_]),
287 cached_negated_shifted_end_max_(new IntegerValue[capacity_]) {
288 starts_.resize(num_tasks);
293 recompute_all_cache_ =
true;
299 const std::vector<int>& watch_indices) {
300 for (
const int t : watch_indices) recompute_cache_.
Set(t);
306 const int id = watcher->
Register(
this);
307 const int num_tasks = starts_.size();
308 for (
int t = 0; t < num_tasks; ++t) {
316bool SchedulingConstraintHelper::UpdateCachedValues(
int t) {
319 IntegerValue smin = integer_trail_->
LowerBound(starts_[t]);
320 IntegerValue smax = integer_trail_->
UpperBound(starts_[t]);
321 IntegerValue emin = integer_trail_->
LowerBound(ends_[t]);
322 IntegerValue emax = integer_trail_->
UpperBound(ends_[t]);
330 std::max(IntegerValue(0), integer_trail_->
LowerBound(sizes_[t]));
331 IntegerValue dmax = integer_trail_->
UpperBound(sizes_[t]);
339 if (smin + dmin - emax > 0) {
346 if (smax + dmax - emin < 0) {
360 smin = std::max(smin, emin - dmax);
361 smax = std::min(smax, emax - dmin);
362 dmin = std::max(dmin, emin - smax);
363 emin = std::max(emin, smin + dmin);
364 emax = std::min(emax, smax + dmax);
366 if (emin != cached_end_min_[t]) {
367 recompute_energy_profile_ =
true;
372 recompute_by_start_max_ =
true;
373 recompute_by_end_min_ =
true;
375 cached_start_min_[t] = smin;
376 cached_end_min_[t] = emin;
377 cached_negated_start_max_[t] = -smax;
378 cached_negated_end_max_[t] = -emax;
379 cached_size_min_[t] = dmin;
382 const IntegerValue new_shifted_start_min = emin - dmin;
383 if (new_shifted_start_min != cached_shifted_start_min_[t]) {
384 recompute_energy_profile_ =
true;
385 recompute_shifted_start_min_ =
true;
386 cached_shifted_start_min_[t] = new_shifted_start_min;
388 const IntegerValue new_negated_shifted_end_max = -(smax + dmin);
389 if (new_negated_shifted_end_max != cached_negated_shifted_end_max_[t]) {
390 recompute_negated_shifted_end_max_ =
true;
391 cached_negated_shifted_end_max_[t] = new_negated_shifted_end_max;
398 current_time_direction_ = other.current_time_direction_;
400 const int num_tasks = tasks.size();
401 interval_variables_.resize(num_tasks);
402 starts_.resize(num_tasks);
403 ends_.resize(num_tasks);
404 minus_ends_.resize(num_tasks);
405 minus_starts_.resize(num_tasks);
406 sizes_.resize(num_tasks);
407 reason_for_presence_.resize(num_tasks);
408 for (
int i = 0;
i < num_tasks; ++
i) {
409 const int t = tasks[
i];
410 interval_variables_[
i] = other.interval_variables_[t];
411 starts_[
i] = other.starts_[t];
412 ends_[
i] = other.ends_[t];
413 minus_ends_[
i] = other.minus_ends_[t];
414 minus_starts_[
i] = other.minus_starts_[t];
415 sizes_[
i] = other.sizes_[t];
416 reason_for_presence_[
i] = other.reason_for_presence_[t];
423void SchedulingConstraintHelper::InitSortedVectors() {
424 const int num_tasks = starts_.size();
426 recompute_all_cache_ =
true;
427 recompute_cache_.
Resize(num_tasks);
428 for (
int t = 0; t < num_tasks; ++t) {
429 recompute_cache_.
Set(t);
433 CHECK_LE(num_tasks, capacity_);
435 task_by_increasing_start_min_.resize(num_tasks);
436 task_by_increasing_end_min_.resize(num_tasks);
437 task_by_increasing_negated_start_max_.resize(num_tasks);
438 task_by_decreasing_end_max_.resize(num_tasks);
439 task_by_increasing_shifted_start_min_.resize(num_tasks);
440 task_by_negated_shifted_end_max_.resize(num_tasks);
441 for (
int t = 0; t < num_tasks; ++t) {
442 task_by_increasing_start_min_[t].task_index = t;
443 task_by_increasing_end_min_[t].task_index = t;
444 task_by_increasing_negated_start_max_[t].task_index = t;
445 task_by_decreasing_end_max_[t].task_index = t;
447 task_by_increasing_shifted_start_min_[t].task_index = t;
448 task_by_increasing_shifted_start_min_[t].presence_lit =
449 reason_for_presence_[t];
450 task_by_negated_shifted_end_max_[t].task_index = t;
451 task_by_negated_shifted_end_max_[t].presence_lit = reason_for_presence_[t];
454 recompute_by_start_max_ =
true;
455 recompute_by_end_min_ =
true;
456 recompute_energy_profile_ =
true;
457 recompute_shifted_start_min_ =
true;
458 recompute_negated_shifted_end_max_ =
true;
462 if (current_time_direction_ != is_forward) {
463 current_time_direction_ = is_forward;
465 std::swap(starts_, minus_ends_);
466 std::swap(ends_, minus_starts_);
468 std::swap(task_by_increasing_start_min_, task_by_decreasing_end_max_);
469 std::swap(task_by_increasing_end_min_,
470 task_by_increasing_negated_start_max_);
471 std::swap(recompute_by_end_min_, recompute_by_start_max_);
472 std::swap(task_by_increasing_shifted_start_min_,
473 task_by_negated_shifted_end_max_);
475 recompute_energy_profile_ =
true;
476 std::swap(cached_start_min_, cached_negated_end_max_);
477 std::swap(cached_end_min_, cached_negated_start_max_);
478 std::swap(cached_shifted_start_min_, cached_negated_shifted_end_max_);
479 std::swap(recompute_shifted_start_min_, recompute_negated_shifted_end_max_);
490 recompute_all_cache_ =
true;
494 if (recompute_all_cache_) {
495 for (
int t = 0; t < recompute_cache_.
size(); ++t) {
496 if (!UpdateCachedValues(t))
return false;
499 for (
const int t : recompute_cache_) {
500 if (!UpdateCachedValues(t))
return false;
504 recompute_all_cache_ =
false;
511 int a,
int b,
bool add_reason_if_after) {
521 const IntegerValue conditional_offset =
525 const IntegerValue offset = std::max(conditional_offset, known);
528 const IntegerValue
distance = offset - needed_offset;
529 if (add_reason_if_after &&
distance >= 0 && known < conditional_offset) {
532 literal_reason_.push_back(l.Negated());
549 if (after.
coeff != 1)
return true;
550 if (before.
coeff != 1)
return true;
554 if (precedence_relations_->
Add(before.
var, after.
var, offset)) {
561 {int64_t{1}, int64_t{-1}}, -offset.value(),
568absl::Span<const TaskTime>
570 for (
TaskTime& ref : task_by_increasing_start_min_) {
571 ref.time =
StartMin(ref.task_index);
574 task_by_increasing_start_min_.end());
575 return task_by_increasing_start_min_;
578absl::Span<const TaskTime>
580 if (!recompute_by_end_min_)
return task_by_increasing_end_min_;
581 for (
TaskTime& ref : task_by_increasing_end_min_) {
582 ref.time =
EndMin(ref.task_index);
585 task_by_increasing_end_min_.end());
586 recompute_by_end_min_ =
false;
587 return task_by_increasing_end_min_;
590absl::Span<const TaskTime>
592 if (!recompute_by_start_max_)
return task_by_increasing_negated_start_max_;
593 for (
TaskTime& ref : task_by_increasing_negated_start_max_) {
594 ref.time = cached_negated_start_max_[ref.task_index];
597 task_by_increasing_negated_start_max_.end());
598 recompute_by_start_max_ =
false;
599 return task_by_increasing_negated_start_max_;
602absl::Span<const TaskTime>
604 for (
TaskTime& ref : task_by_decreasing_end_max_) {
605 ref.time =
EndMax(ref.task_index);
608 task_by_decreasing_end_max_.end(), std::greater<TaskTime>());
609 return task_by_decreasing_end_max_;
612absl::Span<const CachedTaskBounds>
614 if (recompute_shifted_start_min_) {
615 recompute_shifted_start_min_ =
false;
616 bool is_sorted =
true;
620 is_sorted = is_sorted && ref.time >= previous;
623 if (is_sorted)
return task_by_increasing_shifted_start_min_;
625 task_by_increasing_shifted_start_min_.end());
627 return task_by_increasing_shifted_start_min_;
631const std::vector<SchedulingConstraintHelper::ProfileEvent>&
633 if (energy_profile_.empty()) {
635 for (
int t = 0; t < num_tasks; ++t) {
636 energy_profile_.push_back(
637 {cached_shifted_start_min_[t], t,
true});
638 energy_profile_.push_back({cached_end_min_[t], t,
false});
641 if (!recompute_energy_profile_)
return energy_profile_;
643 const int t = ref.task;
645 ref.time = cached_shifted_start_min_[t];
647 ref.time = cached_end_min_[t];
652 recompute_energy_profile_ =
false;
653 return energy_profile_;
659 AddOtherReason(before);
660 AddOtherReason(after);
664 std::vector<IntegerVariable> vars;
665 std::vector<IntegerValue> coeffs;
668 const IntegerValue smax_before =
StartMax(before);
669 if (smax_before >= integer_trail_->
UpperBound(starts_[before])) {
672 coeffs.push_back(starts_[before].coeff);
677 coeffs.push_back(ends_[before].coeff);
680 vars.push_back(sizes_[before].
var);
681 coeffs.push_back(sizes_[before].coeff);
686 const IntegerValue emin_after =
EndMin(after);
687 if (emin_after <= integer_trail_->
LowerBound(ends_[after])) {
689 vars.push_back(ends_[after].
var);
690 coeffs.push_back(ends_[after].coeff);
694 vars.push_back(starts_[after].
var);
695 coeffs.push_back(starts_[after].coeff);
698 vars.push_back(sizes_[after].
var);
699 coeffs.push_back(sizes_[after].coeff);
703 DCHECK_LT(smax_before, emin_after);
704 const IntegerValue slack = emin_after - smax_before - 1;
710 CHECK(other_helper_ ==
nullptr);
711 return integer_trail_->
Enqueue(
lit, literal_reason_, integer_reason_);
723 return integer_trail_->
Enqueue(
lit, literal_reason_, integer_reason_);
731 if (!UpdateCachedValues(t))
return false;
732 recompute_cache_.
Clear(t);
761 integer_trail_->
EnqueueLiteral(l, literal_reason_, integer_reason_);
772 literal_reason_.push_back(
Literal(reason_for_presence_[t]).Negated());
777 literal_reason_, integer_reason_);
788 literal_reason_.push_back(
Literal(reason_for_presence_[t]));
793 literal_reason_, integer_reason_);
799 return integer_trail_->
ReportConflict(literal_reason_, integer_reason_);
805 const int num_tasks = starts_.size();
806 for (
int t = 0; t < num_tasks; ++t) {
815 if (watch_max_side) {
816 propagator_ids_.push_back(
id);
821 for (
int t = 0; t < num_tasks; ++t) {
828void SchedulingConstraintHelper::AddOtherReason(
int t) {
829 if (other_helper_ ==
nullptr || already_added_to_other_reasons_[t])
return;
830 already_added_to_other_reasons_[t] =
true;
831 const int mapped_t = map_to_other_helper_[t];
836void SchedulingConstraintHelper::ImportOtherReasons() {
837 if (other_helper_ !=
nullptr) ImportOtherReasons(*other_helper_);
840void SchedulingConstraintHelper::ImportOtherReasons(
842 literal_reason_.insert(literal_reason_.end(),
843 other_helper.literal_reason_.begin(),
844 other_helper.literal_reason_.end());
845 integer_reason_.insert(integer_reason_.end(),
846 other_helper.integer_reason_.begin(),
847 other_helper.integer_reason_.end());
851 return absl::StrCat(
"t=", t,
" is_present=",
IsPresent(t),
" size=[",
860 IntegerValue
end)
const {
867 IntegerValue
end_max, IntegerValue size_min, IntegerValue demand_min,
868 absl::Span<const LiteralValueValue> filtered_energy,
869 IntegerValue window_start, IntegerValue window_end) {
870 if (window_end <= window_start)
return IntegerValue(0);
873 if (
end_min <= window_start)
return IntegerValue(0);
874 if (
start_max >= window_end)
return IntegerValue(0);
875 const IntegerValue window_size = window_end - window_start;
876 const IntegerValue simple_energy_min =
878 size_min, window_size});
879 if (filtered_energy.empty())
return simple_energy_min;
882 for (
const auto [
lit, fixed_size, fixed_demand] : filtered_energy) {
884 const IntegerValue alt_start_max =
886 const IntegerValue energy_min =
888 std::min({alt_end_min - window_start, window_end - alt_start_max,
889 fixed_size, window_size});
890 result = std::min(result, energy_min);
893 return std::max(simple_energy_min, result);
897 absl::Span<const AffineExpression> demands,
903 demands_(demands.begin(), demands.
end()),
905 const int num_tasks = helper->
NumTasks();
906 linearized_energies_.resize(num_tasks);
907 decomposed_energies_.resize(num_tasks);
910 energy_is_quadratic_.resize(num_tasks,
false);
919 const int num_tasks = helper_->
NumTasks();
920 if (demands_.size() != num_tasks)
return;
921 for (
int t = 0; t < num_tasks; ++t) {
928IntegerValue SchedulingDemandHelper::SimpleEnergyMin(
int t)
const {
933IntegerValue SchedulingDemandHelper::LinearEnergyMin(
int t)
const {
935 return linearized_energies_[t]->Min(*integer_trail_);
938IntegerValue SchedulingDemandHelper::DecomposedEnergyMin(
int t)
const {
941 for (
const auto [
lit, fixed_size, fixed_demand] : decomposed_energies_[t]) {
943 return fixed_size * fixed_demand;
946 result = std::min(result, fixed_size * fixed_demand);
952IntegerValue SchedulingDemandHelper::SimpleEnergyMax(
int t)
const {
957IntegerValue SchedulingDemandHelper::LinearEnergyMax(
int t)
const {
959 return linearized_energies_[t]->Max(*integer_trail_);
962IntegerValue SchedulingDemandHelper::DecomposedEnergyMax(
int t)
const {
965 for (
const auto [
lit, fixed_size, fixed_demand] : decomposed_energies_[t]) {
967 return fixed_size * fixed_demand;
970 result = std::max(result, fixed_size * fixed_demand);
977 const int num_tasks = cached_energies_min_.size();
979 for (
int t = 0; t < num_tasks; ++t) {
981 if (is_at_level_zero) {
983 for (
int i = 0;
i < decomposed_energies_[t].size(); ++
i) {
987 decomposed_energies_[t][new_size++] = decomposed_energies_[t][
i];
989 decomposed_energies_[t].resize(new_size);
992 cached_energies_min_[t] = std::max(
993 {SimpleEnergyMin(t), LinearEnergyMin(t), DecomposedEnergyMin(t)});
995 energy_is_quadratic_[t] =
996 decomposed_energies_[t].empty() && !demands_.empty() &&
998 cached_energies_max_[t] = std::min(
999 {SimpleEnergyMax(t), LinearEnergyMax(t), DecomposedEnergyMax(t)});
1005 DCHECK_LT(t, demands_.size());
1006 return integer_trail_->
LowerBound(demands_[t]);
1010 DCHECK_LT(t, demands_.size());
1011 return integer_trail_->
UpperBound(demands_[t]);
1015 return integer_trail_->
IsFixed(demands_[t]);
1025 }
else if (!decomposed_energies_[t].empty()) {
1026 for (
const auto [
lit, fixed_size, fixed_demand] : decomposed_energies_[t]) {
1027 if (fixed_size * fixed_demand >
value) {
1033 }
else if (linearized_energies_[t].has_value() &&
1034 linearized_energies_[t]->vars.size() == 1) {
1043 VLOG(3) <<
"Cumulative energy missed propagation";
1049 DCHECK_LT(t, demands_.size());
1057 IntegerValue min_demand) {
1058 DCHECK_LT(t, demands_.size());
1067 const IntegerValue
value = cached_energies_min_[t];
1068 if (DecomposedEnergyMin(t) >=
value) {
1070 const int old_size = reason->size();
1071 for (
const auto [
lit, fixed_size, fixed_demand] : decomposed_energies_[t]) {
1073 reason->resize(old_size);
1074 reason->push_back(
lit.Negated());
1076 }
else if (fixed_size * fixed_demand <
value &&
1078 reason->push_back(
lit);
1081 }
else if (SimpleEnergyMin(t) >=
value) {
1085 DCHECK_GE(LinearEnergyMin(t),
value);
1086 for (
const IntegerVariable
var : linearized_energies_[t]->vars) {
1096 if (!decomposed_energies_[t].empty()) {
1098 if (!builder->
AddLiteralTerm(entry.literal, entry.right_value)) {
1103 builder->
AddTerm(demands_[t], IntegerValue(1));
1105 }
else if (!helper_->
IsAbsent(t)) {
1112 absl::Span<const LinearExpression> energies) {
1113 const int num_tasks = energies.size();
1114 DCHECK_EQ(num_tasks, helper_->
NumTasks());
1115 linearized_energies_.resize(num_tasks);
1116 for (
int t = 0; t < num_tasks; ++t) {
1117 linearized_energies_[t] = energies[t];
1119 for (
const IntegerValue coeff : linearized_energies_[t]->coeffs) {
1120 DCHECK_GE(coeff, 0);
1128 if (decomposed_energies_[
index].empty())
return {};
1131 return decomposed_energies_[
index];
1135 std::vector<LiteralValueValue> result;
1136 for (
const auto& e : decomposed_energies_[
index]) {
1138 result.push_back(e);
1144 const std::vector<std::vector<LiteralValueValue>>& energies) {
1145 DCHECK_EQ(energies.size(), helper_->
NumTasks());
1146 decomposed_energies_ = energies;
1150 int t, IntegerValue window_start, IntegerValue window_end) {
1160 int t, IntegerValue window_start, IntegerValue window_end) {
1161 const IntegerValue actual_energy_min =
1163 if (actual_energy_min == 0)
return;
1169 const IntegerValue min_overlap =
1171 const IntegerValue simple_energy_min =
DemandMin(t) * min_overlap;
1172 if (simple_energy_min == actual_energy_min) {
1183 DCHECK(!decomposed_energies_[t].empty());
1190 const int old_size = literal_reason->size();
1192 DCHECK(!decomposed_energies_[t].empty());
1193 for (
const auto [
lit, fixed_size, fixed_demand] : decomposed_energies_[t]) {
1196 literal_reason->resize(old_size);
1197 literal_reason->push_back(
lit.Negated());
1203 const IntegerValue energy_min =
1205 std::min({alt_em - window_start, window_end - alt_sm, fixed_size});
1206 if (energy_min >= actual_energy_min)
continue;
1207 literal_reason->push_back(
lit);
1214 std::vector<IntegerVariable>* vars) {
1216 for (
int t = 0; t < helper->
NumTasks(); ++t) {
1218 vars->push_back(helper->
Starts()[t].var);
1221 vars->push_back(helper->
Sizes()[t].var);
1224 vars->push_back(helper->
Ends()[t].var);
1233 vars->push_back(view);
1240 Model*
model, std::vector<IntegerVariable>* vars) {
1243 if (!integer_trail->IsFixed(demand_expr)) {
1244 vars->push_back(demand_expr.var);
1249 for (
const auto& lit_val_val : product) {
1254 vars->push_back(view);
1258 if (!integer_trail->IsFixed(capacity)) {
1259 vars->push_back(capacity.
var);
void ClearAll()
Sets all bits to 0.
IndexType size() const
Returns how many bits this Bitset64 can hold.
void Clear(IndexType i)
Sets the bit at position i to 0.
void Resize(IndexType size)
void Set(IndexType i)
Sets the bit at position i to 1.
bool AddBinaryClause(Literal a, Literal b)
void WatchLiteral(Literal l, int id, int watch_index=-1)
void WatchLowerBound(IntegerVariable var, int id, int watch_index=-1)
void SetPropagatorPriority(int id, int priority)
void WatchIntegerVariable(IntegerVariable i, int id, int watch_index=-1)
int Register(PropagatorInterface *propagator)
Registers a propagator and returns its unique ids.
void CallOnNextPropagate(int id)
Add the given propagator to its queue.
ABSL_MUST_USE_RESULT bool LiteralOrNegationHasView(Literal lit, IntegerVariable *view=nullptr, bool *view_is_direct=nullptr) const
ABSL_MUST_USE_RESULT bool ConditionalEnqueue(Literal lit, IntegerLiteral i_lit, std::vector< Literal > *literal_reason, std::vector< IntegerLiteral > *integer_reason)
IntegerValue LowerBound(IntegerVariable i) const
Returns the current lower/upper bound of the given integer variable.
IntegerValue UpperBound(IntegerVariable i) const
IntegerLiteral LowerBoundAsLiteral(IntegerVariable i) const
bool ReportConflict(absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
void AppendRelaxedLinearReason(IntegerValue slack, absl::Span< const IntegerValue > coeffs, absl::Span< const IntegerVariable > vars, std::vector< IntegerLiteral > *reason) const
Same as above but take in IntegerVariables instead of IntegerLiterals.
bool IsFixed(IntegerVariable i) const
Checks if the variable is fixed.
IntegerValue LevelZeroUpperBound(IntegerVariable var) const
void EnqueueLiteral(Literal literal, absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
IntegerValue LevelZeroLowerBound(IntegerVariable var) const
Returns globally valid lower/upper bound on the given integer variable.
ABSL_MUST_USE_RESULT bool Enqueue(IntegerLiteral i_lit)
SchedulingDemandHelper * GetOrCreateDemandHelper(SchedulingConstraintHelper *helper, absl::Span< const AffineExpression > demands)
AffineExpression Start(IntervalVariable i) const
AffineExpression Size(IntervalVariable i) const
AffineExpression End(IntervalVariable i) const
void InitAllDecomposedEnergies()
Calls InitDecomposedEnergies on all SchedulingDemandHelper created.
Literal PresenceLiteral(IntervalVariable i) const
void CreateDisjunctivePrecedenceLiteral(IntervalVariable a, IntervalVariable b)
LiteralIndex GetPrecedenceLiteral(IntervalVariable a, IntervalVariable b) const
bool CreatePrecedenceLiteral(IntervalVariable a, IntervalVariable b)
bool IsOptional(IntervalVariable i) const
Returns whether or not a interval is optional and the associated literal.
IntervalVariable CreateInterval(IntegerVariable start, IntegerVariable end, IntegerVariable size, IntegerValue fixed_size, LiteralIndex is_present)
SchedulingConstraintHelper * GetOrCreateHelper(const std::vector< IntervalVariable > &variables, bool register_as_disjunctive_helper=false)
ABSL_MUST_USE_RESULT bool AddLiteralTerm(Literal lit, IntegerValue coeff=IntegerValue(1))
void AddTerm(IntegerVariable var, IntegerValue coeff)
bool Add(IntegerVariable tail, IntegerVariable head, IntegerValue offset)
IntegerValue GetConditionalOffset(IntegerVariable a, IntegerVariable b) const
absl::Span< const Literal > GetConditionalEnforcements(IntegerVariable a, IntegerVariable b) const
Helper class to express a product as a linear constraint.
std::vector< LiteralValueValue > TryToDecompose(const AffineExpression &left, const AffineExpression &right)
BooleanVariable NewBooleanVariable()
bool ModelIsUnsat() const
int64_t num_backtracks() const
int CurrentDecisionLevel() const
bool IncrementalPropagate(const std::vector< int > &watch_indices) final
absl::Span< const TaskTime > TaskByIncreasingStartMin()
void WatchAllTasks(int id, bool watch_max_side=true)
void AddReasonForBeingBefore(int before, int after)
Produces a relaxed reason for StartMax(before) < EndMin(after).
void AddStartMaxReason(int t, IntegerValue upper_bound)
ABSL_MUST_USE_RESULT bool IncreaseEndMin(int t, IntegerValue value)
IntegerValue ShiftedStartMin(int t) const
std::vector< IntegerLiteral > * MutableIntegerReason()
void RegisterWith(GenericLiteralWatcher *watcher)
absl::Span< const TaskTime > TaskByIncreasingNegatedStartMax()
bool SizeIsFixed(int t) const
SchedulingConstraintHelper(const std::vector< IntervalVariable > &tasks, Model *model)
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.
IntegerValue SizeMin(int t) const
absl::Span< const CachedTaskBounds > TaskByIncreasingShiftedStartMin()
absl::Span< const TaskTime > TaskByDecreasingEndMax()
ABSL_MUST_USE_RESULT bool SynchronizeAndSetTimeDirection(bool is_forward)
ABSL_MUST_USE_RESULT bool PushTaskPresence(int t)
IntegerValue EndMax(int t) const
bool IsAbsent(int t) 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 ImportOtherReasons(const SchedulingConstraintHelper &other_helper)
IntegerValue GetCurrentMinDistanceBetweenTasks(int a, int b, bool add_reason_if_after=false)
IntegerValue GetMinOverlap(int t, IntegerValue start, IntegerValue end) const
std::vector< Literal > * MutableLiteralReason()
void AddStartMinReason(int t, IntegerValue lower_bound)
absl::Span< const TaskTime > TaskByIncreasingEndMin()
void AddDemandMinReason(int t)
std::vector< LiteralValueValue > FilteredDecomposedEnergy(int index)
bool DemandIsFixed(int t) const
IntegerValue EnergyMinInWindow(int t, IntegerValue window_start, IntegerValue window_end)
const std::vector< std::vector< LiteralValueValue > > & DecomposedEnergies() const
void OverrideLinearizedEnergies(absl::Span< const LinearExpression > energies)
Visible for testing.
void AddEnergyMinReason(int t)
void InitDecomposedEnergies()
void AddEnergyMinInWindowReason(int t, IntegerValue window_start, IntegerValue window_end)
IntegerValue DemandMax(int t) const
void CacheAllEnergyValues()
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
int CurrentDecisionLevel() const
bool LiteralIsFalse(Literal literal) const
bool LiteralIsTrue(Literal literal) const
void push_back(const value_type &val)
std::function< IntegerVariable(Model *)> NewIntegerVariableFromLiteral(Literal lit)
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
const LiteralIndex kNoLiteralIndex(-1)
std::function< int64_t(const Model &)> LowerBound(IntegerVariable v)
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
Returns the vector of the negated variables.
std::function< void(Model *)> LowerOrEqual(IntegerVariable v, int64_t ub)
void LoadConditionalLinearConstraint(const absl::Span< const Literal > enforcement_literals, const LinearConstraint &cst, Model *model)
LinearConstraint version.
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue.value())
const IntegerVariable kNoIntegerVariable(-1)
void AddConditionalAffinePrecedence(const absl::Span< const Literal > enforcement_literals, AffineExpression left, AffineExpression right, Model *model)
void AppendVariablesFromCapacityAndDemands(const AffineExpression &capacity, SchedulingDemandHelper *demands_helper, Model *model, std::vector< IntegerVariable > *vars)
void AddWeightedSumLowerOrEqual(absl::Span< const Literal > enforcement_literals, absl::Span< const IntegerVariable > vars, absl::Span< const int64_t > coefficients, int64_t upper_bound, Model *model)
enforcement_literals => sum <= upper_bound
std::function< void(Model *)> GreaterOrEqual(IntegerVariable v, int64_t lb)
void AddIntegerVariableFromIntervals(SchedulingConstraintHelper *helper, Model *model, std::vector< IntegerVariable > *vars)
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.
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
var * coeff + constant <= bound.
std::vector< IntegerVariable > vars
std::vector< IntegerValue > coeffs