20 #include "absl/strings/str_join.h"
32 #include "ortools/sat/sat_parameters.pb.h"
42 const std::vector<IntervalVariable>& vars,
46 if (vars.empty())
return;
57 for (
int i = 0; i < demands.size(); ++i) {
58 if (intervals->MaxSize(vars[i]) == 0)
continue;
61 builder.
AddTerm(demands[i], IntegerValue(1));
65 std::vector<Literal> enforcement_literals;
66 if (intervals->IsOptional(vars[i])) {
67 enforcement_literals.push_back(intervals->PresenceLiteral(vars[i]));
73 if (intervals->MinSize(vars[i]) == 0) {
74 enforcement_literals.push_back(encoder->GetOrCreateAssociatedLiteral(
75 intervals->Size(vars[i]).GreaterOrEqual(IntegerValue(1))));
78 if (enforcement_literals.empty()) {
85 if (vars.size() == 1)
return;
87 const SatParameters&
parameters = *(
model->GetOrCreate<SatParameters>());
91 if (
parameters.use_disjunctive_constraint_in_cumulative()) {
97 std::vector<IntervalVariable> in_disjunction;
99 const IntegerValue capa_max = integer_trail->UpperBound(
capacity);
100 for (
int i = 0; i < vars.size(); ++i) {
101 const IntegerValue size_min = intervals->MinSize(vars[i]);
102 if (size_min == 0)
continue;
103 const IntegerValue demand_min = integer_trail->LowerBound(demands[i]);
104 if (2 * demand_min > capa_max) {
105 in_disjunction.push_back(vars[i]);
106 min_of_demands =
std::min(min_of_demands, demand_min);
111 if (!in_disjunction.empty()) {
112 IntervalVariable lift_var;
113 IntegerValue lift_size(0);
114 for (
int i = 0; i < vars.size(); ++i) {
115 const IntegerValue size_min = intervals->MinSize(vars[i]);
116 if (size_min == 0)
continue;
117 const IntegerValue demand_min = integer_trail->LowerBound(demands[i]);
118 if (2 * demand_min > capa_max)
continue;
119 if (min_of_demands + demand_min > capa_max && size_min > lift_size) {
121 lift_size = size_min;
125 in_disjunction.push_back(lift_var);
146 if (in_disjunction.size() == vars.size())
return;
149 if (helper ==
nullptr) {
150 helper = intervals->GetOrCreateHelper(vars);
154 model->TakeOwnership(demands_helper);
170 if (
parameters.use_hard_precedences_in_cumulative()) {
180 std::vector<IntegerVariable> index_to_end_vars;
181 std::vector<int> index_to_task;
182 index_to_end_vars.clear();
183 for (
int t = 0; t < helper->
NumTasks(); ++t) {
188 index_to_end_vars.push_back(end_exp.
var);
189 index_to_task.push_back(t);
201 std::vector<PrecedencesPropagator::FullIntegerPrecedence>
204 !
parameters.exploit_all_precedences(), index_to_end_vars,
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()) {
256 if (
parameters.use_timetable_edge_finding_in_cumulative()) {
260 model->TakeOwnership(time_table_edge_finding);
266 const std::vector<IntervalVariable>& vars,
270 if (vars.empty())
return;
277 const int num_tasks = vars.size();
282 std::vector<IntegerVariable> start_vars;
283 std::vector<IntegerVariable> end_vars;
284 std::vector<IntegerValue> fixed_demands;
286 for (
int t = 0; t < num_tasks; ++t) {
287 start_vars.push_back(intervals->StartVar(vars[t]));
288 end_vars.push_back(intervals->EndVar(vars[t]));
289 CHECK(integer_trail->
IsFixed(demands[t]));
290 fixed_demands.push_back(integer_trail->
LowerBound(demands[t]));
296 for (
int t = 0; t < num_tasks; ++t) {
301 for (IntegerValue
time = min_start;
time < max_end; ++
time) {
302 std::vector<LiteralWithCoeff> literals_with_coeff;
303 for (
int t = 0; t < num_tasks; ++t) {
312 std::vector<Literal> consume_condition;
316 if (intervals->IsOptional(vars[t])) {
317 consume_condition.push_back(intervals->PresenceLiteral(vars[t]));
321 consume_condition.push_back(encoder->GetOrCreateAssociatedLiteral(
323 consume_condition.push_back(encoder->GetOrCreateAssociatedLiteral(
325 IntegerValue(
time + 1))));
333 literals_with_coeff.push_back(
338 fixed_capacity, &literals_with_coeff);
347 const std::vector<IntervalVariable>& vars,
351 if (vars.empty())
return;
357 CHECK(integer_trail->IsFixed(
capacity));
358 const IntegerValue fixed_capacity(
359 integer_trail->UpperBound(
capacity).value());
361 std::vector<AffineExpression> times;
362 std::vector<AffineExpression> deltas;
363 std::vector<Literal> presences;
365 const int num_tasks = vars.size();
366 for (
int t = 0; t < num_tasks; ++t) {
367 CHECK(integer_trail->IsFixed(demands[t]));
368 times.push_back(intervals->StartVar(vars[t]));
369 deltas.push_back(demands[t]);
370 times.push_back(intervals->EndVar(vars[t]));
371 deltas.push_back(demands[t].Negated());
372 if (intervals->IsOptional(vars[t])) {
373 presences.push_back(intervals->PresenceLiteral(vars[t]));
374 presences.push_back(intervals->PresenceLiteral(vars[t]));
376 presences.push_back(encoder->GetTrueLiteral());
377 presences.push_back(encoder->GetTrueLiteral());
void RegisterWith(GenericLiteralWatcher *watcher)
bool IsFixed(IntegerVariable i) const
IntegerValue UpperBound(IntegerVariable i) const
IntegerValue LowerBound(IntegerVariable i) const
void AddTerm(IntegerVariable var, IntegerValue coeff)
Class that owns everything related to a particular optimization model.
bool AddLinearConstraint(bool use_lower_bound, Coefficient lower_bound, bool use_upper_bound, Coefficient upper_bound, std::vector< LiteralWithCoeff > *cst)
bool ModelIsUnsat() const
ABSL_MUST_USE_RESULT bool SynchronizeAndSetTimeDirection(bool is_forward)
const std::vector< AffineExpression > & Ends() const
void RegisterWith(GenericLiteralWatcher *watcher)
void RegisterWith(GenericLiteralWatcher *watcher)
std::tuple< int64_t, int64_t, const double > Coefficient
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
void AddCumulativeOverloadChecker(AffineExpression capacity, SchedulingConstraintHelper *helper, SchedulingDemandHelper *demands, Model *model)
std::function< void(Model *)> Disjunctive(const std::vector< IntervalVariable > &intervals)
std::function< BooleanVariable(Model *)> NewBooleanVariable()
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 *)> Cumulative(const std::vector< IntervalVariable > &vars, const std::vector< AffineExpression > &demands, AffineExpression capacity, SchedulingConstraintHelper *helper)
void AddReservoirConstraint(std::vector< AffineExpression > times, std::vector< AffineExpression > deltas, std::vector< Literal > presences, int64_t min_level, int64_t max_level, Model *model)
void LoadLinearConstraint(const ConstraintProto &ct, Model *m)
std::function< void(Model *)> ReifiedBoolAnd(const std::vector< Literal > &literals, Literal r)
std::function< void(Model *)> CumulativeTimeDecomposition(const std::vector< IntervalVariable > &vars, const std::vector< AffineExpression > &demands, AffineExpression capacity, SchedulingConstraintHelper *helper)
std::function< void(Model *)> CumulativeUsingReservoir(const std::vector< IntervalVariable > &vars, const std::vector< AffineExpression > &demands, AffineExpression capacity, SchedulingConstraintHelper *helper)
Collection of objects used to extend the Constraint Solver library.
static IntegerLiteral LowerOrEqual(IntegerVariable i, IntegerValue bound)
static IntegerLiteral GreaterOrEqual(IntegerVariable i, IntegerValue bound)
#define VLOG(verboselevel)