46 const std::vector<Literal>& enforcement_literals,
47 const std::vector<IntervalVariable>& vars,
50 return [=, demands = std::vector<AffineExpression>(
51 demands.begin(), demands.end())](
Model* model)
mutable {
54 auto* integer_trail = model->GetOrCreate<
IntegerTrail>();
58 if (enforcement_literals.empty()) {
60 sat_solver->NotifyThatModelIsUnsat();
64 builder.
AddTerm(capacity, IntegerValue(1));
68 if (demands.empty()) {
78 for (
int i = 0;
i < demands.size(); ++
i) {
79 if (intervals->MaxSize(vars[
i]) == 0)
continue;
82 builder.
AddTerm(demands[
i], IntegerValue(1));
83 builder.
AddTerm(capacity, IntegerValue(-1));
86 std::vector<Literal> task_enforcement_literals = enforcement_literals;
87 if (intervals->IsOptional(vars[
i])) {
88 task_enforcement_literals.push_back(
89 intervals->PresenceLiteral(vars[
i]));
95 if (intervals->MinSize(vars[
i]) <= 0) {
96 task_enforcement_literals.push_back(
97 encoder->GetOrCreateAssociatedLiteral(
98 intervals->Size(vars[
i]).GreaterOrEqual(IntegerValue(1))));
101 if (task_enforcement_literals.empty()) {
108 if (vars.size() == 1)
return;
120 std::vector<IntervalVariable> in_disjunction;
122 const IntegerValue capa_max = integer_trail->UpperBound(capacity);
123 for (
int i = 0;
i < vars.size(); ++
i) {
124 const IntegerValue size_min = intervals->MinSize(vars[
i]);
125 if (size_min == 0)
continue;
126 const IntegerValue demand_min = integer_trail->LowerBound(demands[
i]);
127 if (2 * demand_min > capa_max) {
128 in_disjunction.push_back(vars[
i]);
129 min_of_demands = std::min(min_of_demands, demand_min);
134 if (!in_disjunction.empty()) {
135 IntervalVariable lift_var;
136 IntegerValue lift_size(0);
137 for (
int i = 0;
i < vars.size(); ++
i) {
138 const IntegerValue size_min = intervals->MinSize(vars[
i]);
139 if (size_min == 0)
continue;
140 const IntegerValue demand_min = integer_trail->LowerBound(demands[
i]);
141 if (2 * demand_min > capa_max)
continue;
142 if (min_of_demands + demand_min > capa_max && size_min > lift_size) {
144 lift_size = size_min;
148 in_disjunction.push_back(lift_var);
168 if (in_disjunction.size() > 1)
170 if (in_disjunction.size() == vars.size())
return;
173 if (helper ==
nullptr) {
174 helper = intervals->GetOrCreateHelper(enforcement_literals, vars);
177 intervals->GetOrCreateDemandHelper(helper, demands);
178 intervals->RegisterCumulative({capacity, helper, demands_helper});
200 model->GetOrCreate<
SatSolver>()->NotifyThatModelIsUnsat();
204 std::vector<IntegerVariable> index_to_end_vars;
205 std::vector<int> index_to_task;
206 index_to_end_vars.clear();
207 for (
int t = 0; t < helper->
NumTasks(); ++t) {
212 index_to_end_vars.push_back(end_exp.
var);
213 index_to_task.push_back(t);
225 std::vector<FullIntegerPrecedence> full_precedences;
228 ->ComputeFullPrecedences(index_to_end_vars, &full_precedences);
231 const int size = data.indices.size();
232 if (size <= 1)
continue;
234 const IntegerVariable var = data.var;
235 std::vector<int> subtasks;
236 std::vector<IntegerValue> offsets;
237 IntegerValue sum_of_demand_max(0);
238 for (
int i = 0;
i < size; ++
i) {
239 const int t = index_to_task[data.indices[
i]];
240 subtasks.push_back(t);
241 sum_of_demand_max += integer_trail->LevelZeroUpperBound(demands[t]);
247 offsets.push_back(data.offsets[
i] - end_exp.
constant);
249 if (sum_of_demand_max > integer_trail->LevelZeroLowerBound(capacity)) {
250 VLOG(2) <<
"Cumulative precedence constraint! var= " << var
251 <<
" #task: " << absl::StrJoin(subtasks,
",");
255 demands_helper, model);
257 model->TakeOwnership(constraint);
268 model->TakeOwnership(time_tabling);
278 bool any_demand_greater_than_one =
false;
279 for (
int i = 0;
i < vars.size(); ++
i) {
280 const IntegerValue demand_min = integer_trail->LowerBound(demands[
i]);
281 if (demand_min > 1) {
282 any_demand_greater_than_one =
true;
286 if (any_demand_greater_than_one) {
301 model->TakeOwnership(time_table_edge_finding);
307 absl::Span<const Literal> enforcement_literals,
308 absl::Span<const IntervalVariable> vars,
311 CHECK(enforcement_literals.empty());
312 return [=, vars = std::vector<IntervalVariable>(vars.begin(), vars.end()),
313 demands = std::vector<AffineExpression>(
314 demands.begin(), demands.end())](
Model* model) {
315 if (vars.empty())
return;
318 CHECK(integer_trail->
IsFixed(capacity));
319 const Coefficient fixed_capacity(
322 const int num_tasks = vars.size();
327 std::vector<AffineExpression> start_exprs;
328 std::vector<AffineExpression> end_exprs;
329 std::vector<IntegerValue> fixed_demands;
331 for (
int t = 0; t < num_tasks; ++t) {
332 start_exprs.push_back(repository->Start(vars[t]));
333 end_exprs.push_back(repository->End(vars[t]));
334 CHECK(integer_trail->
IsFixed(demands[t]));
335 fixed_demands.push_back(integer_trail->
LowerBound(demands[t]));
341 for (
int t = 0; t < num_tasks; ++t) {
343 std::min(min_start, integer_trail->
LowerBound(start_exprs[t]));
344 max_end = std::max(max_end, integer_trail->
UpperBound(end_exprs[t]));
347 for (IntegerValue time = min_start; time < max_end; ++time) {
348 std::vector<LiteralWithCoeff> literals_with_coeff;
349 for (
int t = 0; t < num_tasks; ++t) {
351 const IntegerValue start_min =
353 const IntegerValue end_max = integer_trail->
UpperBound(end_exprs[t]);
354 if (end_max <= time || time < start_min || fixed_demands[t] == 0) {
359 std::vector<Literal> consume_condition;
363 if (repository->IsOptional(vars[t])) {
364 consume_condition.push_back(repository->PresenceLiteral(vars[t]));
368 consume_condition.push_back(encoder->GetOrCreateAssociatedLiteral(
369 start_exprs[t].LowerOrEqual(IntegerValue(time))));
370 consume_condition.push_back(encoder->GetOrCreateAssociatedLiteral(
371 end_exprs[t].GreaterOrEqual(IntegerValue(time + 1))));
379 literals_with_coeff.push_back(
384 fixed_capacity, &literals_with_coeff);
393 absl::Span<const Literal> enforcement_literals,
394 absl::Span<const IntervalVariable> vars,
397 return [=, vars = std::vector<IntervalVariable>(vars.begin(), vars.end()),
398 demands = std::vector<AffineExpression>(
399 demands.begin(), demands.end())](
Model* model) {
400 if (vars.empty())
return;
402 auto* integer_trail = model->GetOrCreate<
IntegerTrail>();
406 CHECK(integer_trail->IsFixed(capacity));
407 const IntegerValue fixed_capacity(
408 integer_trail->UpperBound(capacity).value());
410 std::vector<AffineExpression> times;
411 std::vector<AffineExpression> deltas;
412 std::vector<Literal> presences;
414 const int num_tasks = vars.size();
415 for (
int t = 0; t < num_tasks; ++t) {
416 CHECK(integer_trail->IsFixed(demands[t]));
417 times.push_back(repository->Start(vars[t]));
418 deltas.push_back(demands[t]);
419 times.push_back(repository->End(vars[t]));
420 deltas.push_back(demands[t].Negated());
421 if (repository->IsOptional(vars[t])) {
422 presences.push_back(repository->PresenceLiteral(vars[t]));
423 presences.push_back(repository->PresenceLiteral(vars[t]));
425 presences.push_back(encoder->GetTrueLiteral());
426 presences.push_back(encoder->GetTrueLiteral());
430 fixed_capacity.value(), model);