45 const std::vector<IntervalVariable>& vars,
48 return [=, demands = std::vector<AffineExpression>(
49 demands.begin(), demands.end())](
Model* model)
mutable {
52 auto* integer_trail = model->GetOrCreate<
IntegerTrail>();
57 sat_solver->NotifyThatModelIsUnsat();
59 if (demands.empty()) {
69 for (
int i = 0;
i < demands.size(); ++
i) {
70 if (intervals->MaxSize(vars[
i]) == 0)
continue;
73 builder.
AddTerm(demands[
i], IntegerValue(1));
74 builder.
AddTerm(capacity, IntegerValue(-1));
77 std::vector<Literal> enforcement_literals;
78 if (intervals->IsOptional(vars[
i])) {
79 enforcement_literals.push_back(intervals->PresenceLiteral(vars[
i]));
85 if (intervals->MinSize(vars[
i]) == 0) {
86 enforcement_literals.push_back(encoder->GetOrCreateAssociatedLiteral(
87 intervals->Size(vars[
i]).GreaterOrEqual(IntegerValue(1))));
90 if (enforcement_literals.empty()) {
97 if (vars.size() == 1)
return;
99 const SatParameters& parameters = *(model->GetOrCreate<SatParameters>());
103 if (parameters.use_disjunctive_constraint_in_cumulative()) {
109 std::vector<IntervalVariable> in_disjunction;
111 const IntegerValue capa_max = integer_trail->UpperBound(capacity);
112 for (
int i = 0;
i < vars.size(); ++
i) {
113 const IntegerValue size_min = intervals->MinSize(vars[
i]);
114 if (size_min == 0)
continue;
115 const IntegerValue demand_min = integer_trail->LowerBound(demands[
i]);
116 if (2 * demand_min > capa_max) {
117 in_disjunction.push_back(vars[
i]);
118 min_of_demands = std::min(min_of_demands, demand_min);
123 if (!in_disjunction.empty()) {
124 IntervalVariable lift_var;
125 IntegerValue lift_size(0);
126 for (
int i = 0;
i < vars.size(); ++
i) {
127 const IntegerValue size_min = intervals->MinSize(vars[
i]);
128 if (size_min == 0)
continue;
129 const IntegerValue demand_min = integer_trail->LowerBound(demands[
i]);
130 if (2 * demand_min > capa_max)
continue;
131 if (min_of_demands + demand_min > capa_max && size_min > lift_size) {
133 lift_size = size_min;
137 in_disjunction.push_back(lift_var);
157 if (in_disjunction.size() > 1)
AddDisjunctive(in_disjunction, model);
158 if (in_disjunction.size() == vars.size())
return;
161 if (helper ==
nullptr) {
162 helper = intervals->GetOrCreateHelper(vars);
165 intervals->GetOrCreateDemandHelper(helper, demands);
166 intervals->RegisterCumulative({capacity, helper, demands_helper});
182 if (parameters.use_hard_precedences_in_cumulative()) {
188 model->GetOrCreate<
SatSolver>()->NotifyThatModelIsUnsat();
192 std::vector<IntegerVariable> index_to_end_vars;
193 std::vector<int> index_to_task;
194 index_to_end_vars.clear();
195 for (
int t = 0; t < helper->
NumTasks(); ++t) {
200 index_to_end_vars.push_back(end_exp.
var);
201 index_to_task.push_back(t);
213 std::vector<FullIntegerPrecedence> full_precedences;
214 if (parameters.exploit_all_precedences()) {
216 index_to_end_vars, &full_precedences);
219 const int size = data.indices.size();
220 if (size <= 1)
continue;
222 const IntegerVariable var = data.var;
223 std::vector<int> subtasks;
224 std::vector<IntegerValue> offsets;
225 IntegerValue sum_of_demand_max(0);
226 for (
int i = 0;
i < size; ++
i) {
227 const int t = index_to_task[data.indices[
i]];
228 subtasks.push_back(t);
229 sum_of_demand_max += integer_trail->LevelZeroUpperBound(demands[t]);
235 offsets.push_back(data.offsets[
i] - end_exp.
constant);
237 if (sum_of_demand_max > integer_trail->LevelZeroLowerBound(capacity)) {
238 VLOG(2) <<
"Cumulative precedence constraint! var= " << var
239 <<
" #task: " << absl::StrJoin(subtasks,
",");
243 demands_helper, model);
245 model->TakeOwnership(constraint);
256 model->TakeOwnership(time_tabling);
260 if (parameters.use_overload_checker_in_cumulative()) {
263 if (parameters.use_conservative_scale_overload_checker()) {
266 bool any_demand_greater_than_one =
false;
267 for (
int i = 0;
i < vars.size(); ++
i) {
268 const IntegerValue demand_min = integer_trail->LowerBound(demands[
i]);
269 if (demand_min > 1) {
270 any_demand_greater_than_one =
true;
274 if (any_demand_greater_than_one) {
283 if (parameters.use_timetable_edge_finding_in_cumulative() &&
285 parameters.max_num_intervals_for_timetable_edge_finding()) {
289 model->TakeOwnership(time_table_edge_finding);
295 absl::Span<const IntervalVariable> vars,
298 return [=, vars = std::vector<IntervalVariable>(vars.begin(), vars.end()),
299 demands = std::vector<AffineExpression>(
300 demands.begin(), demands.end())](
Model* model) {
301 if (vars.empty())
return;
304 CHECK(integer_trail->
IsFixed(capacity));
305 const Coefficient fixed_capacity(
308 const int num_tasks = vars.size();
313 std::vector<AffineExpression> start_exprs;
314 std::vector<AffineExpression> end_exprs;
315 std::vector<IntegerValue> fixed_demands;
317 for (
int t = 0; t < num_tasks; ++t) {
318 start_exprs.push_back(repository->Start(vars[t]));
319 end_exprs.push_back(repository->End(vars[t]));
320 CHECK(integer_trail->
IsFixed(demands[t]));
321 fixed_demands.push_back(integer_trail->
LowerBound(demands[t]));
327 for (
int t = 0; t < num_tasks; ++t) {
329 std::min(min_start, integer_trail->
LowerBound(start_exprs[t]));
330 max_end = std::max(max_end, integer_trail->
UpperBound(end_exprs[t]));
333 for (IntegerValue time = min_start; time < max_end; ++time) {
334 std::vector<LiteralWithCoeff> literals_with_coeff;
335 for (
int t = 0; t < num_tasks; ++t) {
337 const IntegerValue start_min =
339 const IntegerValue end_max = integer_trail->
UpperBound(end_exprs[t]);
340 if (end_max <= time || time < start_min || fixed_demands[t] == 0) {
345 std::vector<Literal> consume_condition;
349 if (repository->IsOptional(vars[t])) {
350 consume_condition.push_back(repository->PresenceLiteral(vars[t]));
354 consume_condition.push_back(encoder->GetOrCreateAssociatedLiteral(
355 start_exprs[t].LowerOrEqual(IntegerValue(time))));
356 consume_condition.push_back(encoder->GetOrCreateAssociatedLiteral(
357 end_exprs[t].GreaterOrEqual(IntegerValue(time + 1))));
365 literals_with_coeff.push_back(
370 fixed_capacity, &literals_with_coeff);
379 absl::Span<const IntervalVariable> vars,
382 return [=, vars = std::vector<IntervalVariable>(vars.begin(), vars.end()),
383 demands = std::vector<AffineExpression>(
384 demands.begin(), demands.end())](
Model* model) {
385 if (vars.empty())
return;
387 auto* integer_trail = model->GetOrCreate<
IntegerTrail>();
391 CHECK(integer_trail->IsFixed(capacity));
392 const IntegerValue fixed_capacity(
393 integer_trail->UpperBound(capacity).value());
395 std::vector<AffineExpression> times;
396 std::vector<AffineExpression> deltas;
397 std::vector<Literal> presences;
399 const int num_tasks = vars.size();
400 for (
int t = 0; t < num_tasks; ++t) {
401 CHECK(integer_trail->IsFixed(demands[t]));
402 times.push_back(repository->Start(vars[t]));
403 deltas.push_back(demands[t]);
404 times.push_back(repository->End(vars[t]));
405 deltas.push_back(demands[t].Negated());
406 if (repository->IsOptional(vars[t])) {
407 presences.push_back(repository->PresenceLiteral(vars[t]));
408 presences.push_back(repository->PresenceLiteral(vars[t]));
410 presences.push_back(encoder->GetTrueLiteral());
411 presences.push_back(encoder->GetTrueLiteral());