43 const std::vector<IntervalVariable>& vars,
47 if (vars.empty())
return;
58 for (
int i = 0;
i < demands.size(); ++
i) {
59 if (intervals->MaxSize(vars[
i]) == 0)
continue;
62 builder.
AddTerm(demands[
i], IntegerValue(1));
63 builder.
AddTerm(capacity, IntegerValue(-1));
66 std::vector<Literal> enforcement_literals;
67 if (intervals->IsOptional(vars[
i])) {
68 enforcement_literals.push_back(intervals->PresenceLiteral(vars[
i]));
74 if (intervals->MinSize(vars[
i]) == 0) {
75 enforcement_literals.push_back(encoder->GetOrCreateAssociatedLiteral(
76 intervals->Size(vars[
i]).GreaterOrEqual(IntegerValue(1))));
79 if (enforcement_literals.empty()) {
86 if (vars.size() == 1)
return;
88 const SatParameters&
parameters = *(
model->GetOrCreate<SatParameters>());
92 if (
parameters.use_disjunctive_constraint_in_cumulative()) {
98 std::vector<IntervalVariable> in_disjunction;
100 const IntegerValue capa_max = integer_trail->UpperBound(capacity);
101 for (
int i = 0;
i < vars.size(); ++
i) {
102 const IntegerValue size_min = intervals->MinSize(vars[
i]);
103 if (size_min == 0)
continue;
104 const IntegerValue demand_min = integer_trail->LowerBound(demands[
i]);
105 if (2 * demand_min > capa_max) {
106 in_disjunction.push_back(vars[
i]);
107 min_of_demands = std::min(min_of_demands, demand_min);
112 if (!in_disjunction.empty()) {
113 IntervalVariable lift_var;
114 IntegerValue lift_size(0);
115 for (
int i = 0;
i < vars.size(); ++
i) {
116 const IntegerValue size_min = intervals->MinSize(vars[
i]);
117 if (size_min == 0)
continue;
118 const IntegerValue demand_min = integer_trail->LowerBound(demands[
i]);
119 if (2 * demand_min > capa_max)
continue;
120 if (min_of_demands + demand_min > capa_max && size_min > lift_size) {
122 lift_size = size_min;
126 in_disjunction.push_back(lift_var);
147 if (in_disjunction.size() == vars.size())
return;
150 if (helper ==
nullptr) {
151 helper = intervals->GetOrCreateHelper(vars);
154 intervals->GetOrCreateDemandHelper(helper, demands);
155 intervals->RegisterCumulative({capacity, helper, demands_helper});
171 if (
parameters.use_hard_precedences_in_cumulative()) {
181 std::vector<IntegerVariable> index_to_end_vars;
182 std::vector<int> index_to_task;
183 index_to_end_vars.clear();
184 for (
int t = 0; t < helper->
NumTasks(); ++t) {
189 index_to_end_vars.push_back(end_exp.
var);
190 index_to_task.push_back(t);
202 std::vector<FullIntegerPrecedence> full_precedences;
205 index_to_end_vars, &full_precedences);
208 const int size = data.indices.size();
209 if (
size <= 1)
continue;
211 const IntegerVariable
var = data.var;
212 std::vector<int> subtasks;
213 std::vector<IntegerValue> offsets;
214 IntegerValue sum_of_demand_max(0);
215 for (
int i = 0;
i <
size; ++
i) {
216 const int t = index_to_task[data.indices[
i]];
217 subtasks.push_back(t);
218 sum_of_demand_max += integer_trail->LevelZeroUpperBound(demands[t]);
224 offsets.push_back(data.offsets[
i] - end_exp.
constant);
226 if (sum_of_demand_max > integer_trail->LevelZeroLowerBound(capacity)) {
227 VLOG(2) <<
"Cumulative precedence constraint! var= " <<
var
228 <<
" #task: " << absl::StrJoin(subtasks,
",");
232 demands_helper,
model);
234 model->TakeOwnership(constraint);
245 model->TakeOwnership(time_tabling);
249 if (
parameters.use_overload_checker_in_cumulative()) {
252 if (
parameters.use_conservative_scale_overload_checker()) {
255 bool any_demand_greater_than_one =
false;
256 for (
int i = 0;
i < vars.size(); ++
i) {
257 const IntegerValue demand_min = integer_trail->LowerBound(demands[
i]);
258 if (demand_min > 1) {
259 any_demand_greater_than_one =
true;
263 if (any_demand_greater_than_one) {
272 if (
parameters.use_timetable_edge_finding_in_cumulative() &&
274 parameters.max_num_intervals_for_timetable_edge_finding()) {
278 model->TakeOwnership(time_table_edge_finding);
284 const std::vector<IntervalVariable>& vars,
288 if (vars.empty())
return;
291 CHECK(integer_trail->
IsFixed(capacity));
292 const Coefficient fixed_capacity(
295 const int num_tasks = vars.size();
300 std::vector<AffineExpression> start_exprs;
301 std::vector<AffineExpression> end_exprs;
302 std::vector<IntegerValue> fixed_demands;
304 for (
int t = 0; t < num_tasks; ++t) {
305 start_exprs.push_back(repository->Start(vars[t]));
306 end_exprs.push_back(repository->End(vars[t]));
307 CHECK(integer_trail->
IsFixed(demands[t]));
308 fixed_demands.push_back(integer_trail->
LowerBound(demands[t]));
314 for (
int t = 0; t < num_tasks; ++t) {
316 std::min(min_start, integer_trail->
LowerBound(start_exprs[t]));
317 max_end = std::max(max_end, integer_trail->
UpperBound(end_exprs[t]));
320 for (IntegerValue
time = min_start;
time < max_end; ++
time) {
321 std::vector<LiteralWithCoeff> literals_with_coeff;
322 for (
int t = 0; t < num_tasks; ++t) {
332 std::vector<Literal> consume_condition;
336 if (repository->IsOptional(vars[t])) {
337 consume_condition.push_back(repository->PresenceLiteral(vars[t]));
341 consume_condition.push_back(encoder->GetOrCreateAssociatedLiteral(
342 start_exprs[t].LowerOrEqual(IntegerValue(
time))));
343 consume_condition.push_back(encoder->GetOrCreateAssociatedLiteral(
344 end_exprs[t].GreaterOrEqual(IntegerValue(
time + 1))));
352 literals_with_coeff.push_back(
357 fixed_capacity, &literals_with_coeff);
366 const std::vector<IntervalVariable>& vars,
370 if (vars.empty())
return;
376 CHECK(integer_trail->IsFixed(capacity));
377 const IntegerValue fixed_capacity(
378 integer_trail->UpperBound(capacity).value());
380 std::vector<AffineExpression> times;
381 std::vector<AffineExpression> deltas;
382 std::vector<Literal> presences;
384 const int num_tasks = vars.size();
385 for (
int t = 0; t < num_tasks; ++t) {
386 CHECK(integer_trail->IsFixed(demands[t]));
387 times.push_back(repository->Start(vars[t]));
388 deltas.push_back(demands[t]);
389 times.push_back(repository->End(vars[t]));
390 deltas.push_back(demands[t].Negated());
391 if (repository->IsOptional(vars[t])) {
392 presences.push_back(repository->PresenceLiteral(vars[t]));
393 presences.push_back(repository->PresenceLiteral(vars[t]));
395 presences.push_back(encoder->GetTrueLiteral());
396 presences.push_back(encoder->GetTrueLiteral());