OR-Tools  8.0
intervals.h
Go to the documentation of this file.
1 // Copyright 2010-2018 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 #ifndef OR_TOOLS_SAT_INTERVALS_H_
15 #define OR_TOOLS_SAT_INTERVALS_H_
16 
17 #include <functional>
18 #include <vector>
19 
20 #include "absl/types/span.h"
21 #include "ortools/base/int_type.h"
24 #include "ortools/base/logging.h"
25 #include "ortools/base/macros.h"
27 #include "ortools/sat/integer.h"
29 #include "ortools/sat/model.h"
32 #include "ortools/sat/sat_base.h"
33 #include "ortools/sat/sat_solver.h"
34 
35 namespace operations_research {
36 namespace sat {
37 
38 DEFINE_INT_TYPE(IntervalVariable, int32);
39 const IntervalVariable kNoIntervalVariable(-1);
40 
41 // This class maintains a set of intervals which correspond to three integer
42 // variables (start, end and size). It automatically registers with the
43 // PrecedencesPropagator the relation between the bounds of each interval and
44 // provides many helper functions to add precedences relation between intervals.
46  public:
48  : integer_trail_(model->GetOrCreate<IntegerTrail>()),
49  precedences_(model->GetOrCreate<PrecedencesPropagator>()) {}
50 
51  // Returns the current number of intervals in the repository.
52  // The interval will always be identified by an integer in [0, num_intervals).
53  int NumIntervals() const { return start_vars_.size(); }
54 
55  // Functions to add a new interval to the repository.
56  // - If size == kNoIntegerVariable, then the size is fixed to fixed_size.
57  // - If is_present != kNoLiteralIndex, then this is an optional interval.
58  IntervalVariable CreateInterval(IntegerVariable start, IntegerVariable end,
59  IntegerVariable size, IntegerValue fixed_size,
60  LiteralIndex is_present);
61 
62  // Returns whether or not a interval is optional and the associated literal.
63  bool IsOptional(IntervalVariable i) const {
64  return is_present_[i] != kNoLiteralIndex;
65  }
66  Literal IsPresentLiteral(IntervalVariable i) const {
67  return Literal(is_present_[i]);
68  }
69 
70  // The 3 integer variables associated to a interval.
71  // Fixed size intervals will have a kNoIntegerVariable as size.
72  //
73  // Note: For an optional interval, the start/end variables are propagated
74  // asssuming the interval is present. Because of that, these variables can
75  // cross each other or have an empty domain. If any of this happen, then the
76  // IsPresentLiteral() of this interval will be propagated to false.
77  IntegerVariable SizeVar(IntervalVariable i) const { return size_vars_[i]; }
78  IntegerVariable StartVar(IntervalVariable i) const { return start_vars_[i]; }
79  IntegerVariable EndVar(IntervalVariable i) const { return end_vars_[i]; }
80 
81  // Return the minimum size of the given IntervalVariable.
82  IntegerValue MinSize(IntervalVariable i) const {
83  const IntegerVariable size_var = size_vars_[i];
84  if (size_var == kNoIntegerVariable) return fixed_sizes_[i];
85  return integer_trail_->LowerBound(size_var);
86  }
87 
88  // Return the maximum size of the given IntervalVariable.
89  IntegerValue MaxSize(IntervalVariable i) const {
90  const IntegerVariable size_var = size_vars_[i];
91  if (size_var == kNoIntegerVariable) return fixed_sizes_[i];
92  return integer_trail_->UpperBound(size_var);
93  }
94 
95  // Utility function that returns a vector will all intervals.
96  std::vector<IntervalVariable> AllIntervals() const {
97  std::vector<IntervalVariable> result;
98  for (IntervalVariable i(0); i < NumIntervals(); ++i) {
99  result.push_back(i);
100  }
101  return result;
102  }
103 
104  private:
105  // External classes needed.
106  IntegerTrail* integer_trail_;
107  PrecedencesPropagator* precedences_;
108 
109  // Literal indicating if the tasks is executed. Tasks that are always executed
110  // will have a kNoLiteralIndex entry in this vector.
112 
113  // The integer variables for each tasks.
118 
119  DISALLOW_COPY_AND_ASSIGN(IntervalsRepository);
120 };
121 
122 // An helper struct to sort task by time. This is used by the
123 // SchedulingConstraintHelper but also by many scheduling propagators to sort
124 // tasks.
125 struct TaskTime {
127  IntegerValue time;
128  bool operator<(TaskTime other) const { return time < other.time; }
129  bool operator>(TaskTime other) const { return time > other.time; }
130 };
131 
132 // Helper class shared by the propagators that manage a given list of tasks.
133 //
134 // One of the main advantage of this class is that it allows to share the
135 // vectors of tasks sorted by various criteria between propagator for a faster
136 // code.
138  public:
139  // All the functions below refer to a task by its index t in the tasks
140  // vector given at construction.
141  SchedulingConstraintHelper(const std::vector<IntervalVariable>& tasks,
142  Model* model);
143 
144  // Temporary constructor.
145  // The class will not be usable until ResetFromSubset() is called.
146  //
147  // TODO(user): Remove this. It is a hack because the disjunctive class needs
148  // to fetch the maximum possible number of task at construction.
149  SchedulingConstraintHelper(int num_tasks, Model* model);
150 
151  // Resets the class to the same state as if it was constructed with
152  // the given subset of tasks from other.
154  absl::Span<const int> tasks);
155 
156  // Returns the number of task.
157  int NumTasks() const { return start_vars_.size(); }
158 
159  // Sets the time direction to either forward/backward. This will impact all
160  // the functions below.
161  void SetTimeDirection(bool is_forward);
162 
163  // Helpers for the current bounds on the current task time window.
164  // [(duration-min) ... (duration-min)]
165  // ^ ^ ^ ^
166  // start-min end-min start-max end-max
167  //
168  // Note that for tasks with variable durations, we don't necessarily have
169  // duration-min between the XXX-min and XXX-max value.
170  IntegerValue DurationMin(int t) const;
171  IntegerValue DurationMax(int t) const;
172  IntegerValue StartMin(int t) const;
173  IntegerValue StartMax(int t) const;
174  IntegerValue EndMin(int t) const;
175  IntegerValue EndMax(int t) const;
176 
177  // In the presense of tasks with a variable duration, we do not necessarily
178  // have start_min + duration_min = end_min, we can instead have a situation
179  // like:
180  // | |<- duration-min ->|
181  // ^ ^ ^
182  // start-min | end-min
183  // |
184  // We define the "shifted start min" to be the right most time such that
185  // we known that we must have min-duration "energy" to the right of it if the
186  // task is present. Using it in our scheduling propagators allows to propagate
187  // more in the presence of tasks with variable duration (or optional task
188  // where we also do not necessarily have start_min + duration_min = end_min.
189  //
190  // To explain this shifted start min, one must use the AddEnergyAfterReason().
191  IntegerValue ShiftedStartMin(int t) const;
192 
193  bool StartIsFixed(int t) const;
194  bool EndIsFixed(int t) const;
195 
196  // Returns true if the corresponding fact is known for sure. A normal task is
197  // always present. For optional task for which the presence is still unknown,
198  // both of these function will return false.
199  bool IsOptional(int t) const;
200  bool IsPresent(int t) const;
201  bool IsAbsent(int t) const;
202 
203  // Sorts and returns the tasks in corresponding order at the time of the call.
204  // Note that we do not mean strictly-increasing/strictly-decreasing, there
205  // will be duplicate time values in these vectors.
206  //
207  // TODO(user): we could merge the first loop of IncrementalSort() with the
208  // loop that fill TaskTime.time at each call.
209  const std::vector<TaskTime>& TaskByIncreasingStartMin();
210  const std::vector<TaskTime>& TaskByIncreasingEndMin();
211  const std::vector<TaskTime>& TaskByDecreasingStartMax();
212  const std::vector<TaskTime>& TaskByDecreasingEndMax();
213  const std::vector<TaskTime>& TaskByIncreasingShiftedStartMin();
214 
215  // Functions to clear and then set the current reason.
216  void ClearReason();
217  void AddPresenceReason(int t);
218  void AddDurationMinReason(int t);
219  void AddDurationMinReason(int t, IntegerValue lower_bound);
220  void AddStartMinReason(int t, IntegerValue lower_bound);
221  void AddStartMaxReason(int t, IntegerValue upper_bound);
222  void AddEndMinReason(int t, IntegerValue lower_bound);
223  void AddEndMaxReason(int t, IntegerValue upper_bound);
224  void AddEnergyAfterReason(int t, IntegerValue energy_min, IntegerValue time);
225 
226  // Adds the reason why task "before" must be before task "after".
227  // That is StartMax(before) < EndMin(after).
228  void AddReasonForBeingBefore(int before, int after);
229 
230  // It is also possible to directly manipulates the underlying reason vectors
231  // that will be used when pushing something.
232  std::vector<Literal>* MutableLiteralReason() { return &literal_reason_; }
233  std::vector<IntegerLiteral>* MutableIntegerReason() {
234  return &integer_reason_;
235  }
236 
237  // Push something using the current reason. Note that IncreaseStartMin() will
238  // also increase the end-min, and DecreaseEndMax() will also decrease the
239  // start-max.
240  //
241  // Important: IncreaseStartMin() and DecreaseEndMax() can be called on an
242  // optional interval whose presence is still unknown and push a bound
243  // conditionned on its presence. The functions will do the correct thing
244  // depending on whether or not the start_min/end_max are optional variables
245  // whose presence implies the interval presence.
246  ABSL_MUST_USE_RESULT bool IncreaseStartMin(int t, IntegerValue new_min_start);
247  ABSL_MUST_USE_RESULT bool DecreaseEndMax(int t, IntegerValue new_max_end);
248  ABSL_MUST_USE_RESULT bool PushTaskAbsence(int t);
249  ABSL_MUST_USE_RESULT bool PushIntegerLiteral(IntegerLiteral bound);
250  ABSL_MUST_USE_RESULT bool ReportConflict();
251  ABSL_MUST_USE_RESULT bool PushIntegerLiteralIfTaskPresent(
252  int t, IntegerLiteral bound);
253 
254  // Returns the underlying integer variables.
255  const std::vector<IntegerVariable>& StartVars() const { return start_vars_; }
256  const std::vector<IntegerVariable>& EndVars() const { return end_vars_; }
257  const std::vector<IntegerVariable>& DurationVars() const {
258  return duration_vars_;
259  }
260 
261  // Registers the given propagator id to be called if any of the tasks
262  // in this class change. Note that we do not watch duration max though.
263  void WatchAllTasks(int id, GenericLiteralWatcher* watcher,
264  bool watch_start_max = true,
265  bool watch_end_max = true) const;
266 
267  // Manages the other helper (used by the diffn constraint).
268  //
269  // For each interval appearing in a reason on this helper, another reason
270  // will be added. This other reason specifies that on the other helper, the
271  // corresponding interval overlaps 'event'.
273  IntegerValue event) {
274  CHECK(other_helper != nullptr);
275  other_helper_ = other_helper;
276  event_for_other_helper_ = event;
277  }
278 
279  void ClearOtherHelper() { other_helper_ = nullptr; }
280 
281  // Adds to this helper reason all the explanation of the other helper.
282  // This checks that other_helper_ is null.
283  //
284  // This is used in the 2D energetic reasoning in the diffn constraint.
285  void ImportOtherReasons(const SchedulingConstraintHelper& other_helper);
286 
287  private:
288  void InitSortedVectors();
289 
290  // Internal function for IncreaseStartMin()/DecreaseEndMax().
291  bool PushIntervalBound(int t, IntegerLiteral lit);
292 
293  // This will be called on any interval that is part of a reason or
294  // a bound push. Since the last call to ClearReason(), for each unique
295  // t, we will add once to other_helper_ the reason for t containing
296  // the point event_for_other_helper_.
297  void AddOtherReason(int t);
298 
299  // Import the reasons on the other helper into this helper.
300  void ImportOtherReasons();
301 
302  Trail* trail_;
303  IntegerTrail* integer_trail_;
304  PrecedencesPropagator* precedences_;
305 
306  // The current direction of time, true for forward, false for backward.
307  bool current_time_direction_ = true;
308 
309  // All the underlying variables of the tasks.
310  // The vectors are indexed by the task index t.
311  std::vector<IntegerVariable> start_vars_;
312  std::vector<IntegerVariable> end_vars_;
313  std::vector<IntegerVariable> duration_vars_;
314  std::vector<IntegerValue> fixed_durations_;
315  std::vector<LiteralIndex> reason_for_presence_;
316 
317  // The negation of the start/end variable so that SetTimeDirection()
318  // can do its job in O(1) instead of calling NegationOf() on each entry.
319  std::vector<IntegerVariable> minus_start_vars_;
320  std::vector<IntegerVariable> minus_end_vars_;
321 
322  // Sorted vectors returned by the TasksBy*() functions.
323  std::vector<TaskTime> task_by_increasing_start_min_;
324  std::vector<TaskTime> task_by_increasing_end_min_;
325  std::vector<TaskTime> task_by_decreasing_start_max_;
326  std::vector<TaskTime> task_by_decreasing_end_max_;
327 
328  std::vector<TaskTime> task_by_increasing_shifted_start_min_;
329  std::vector<TaskTime> task_by_negated_shifted_end_max_;
330  int64 shifted_start_min_timestamp_ = -1;
331  int64 negated_shifted_end_max_timestamp_ = -1;
332 
333  // Reason vectors.
334  std::vector<Literal> literal_reason_;
335  std::vector<IntegerLiteral> integer_reason_;
336 
337  // Optional 'slave' helper used in the diffn constraint.
338  SchedulingConstraintHelper* other_helper_ = nullptr;
339  IntegerValue event_for_other_helper_;
340  std::vector<bool> already_added_to_other_reasons_;
341 };
342 
343 // =============================================================================
344 // SchedulingConstraintHelper inlined functions.
345 // =============================================================================
346 
347 inline IntegerValue SchedulingConstraintHelper::DurationMin(int t) const {
348  return duration_vars_[t] == kNoIntegerVariable
349  ? fixed_durations_[t]
350  : integer_trail_->LowerBound(duration_vars_[t]);
351 }
352 
353 inline IntegerValue SchedulingConstraintHelper::DurationMax(int t) const {
354  return duration_vars_[t] == kNoIntegerVariable
355  ? fixed_durations_[t]
356  : integer_trail_->UpperBound(duration_vars_[t]);
357 }
358 
359 inline IntegerValue SchedulingConstraintHelper::StartMin(int t) const {
360  return integer_trail_->LowerBound(start_vars_[t]);
361 }
362 
363 inline IntegerValue SchedulingConstraintHelper::StartMax(int t) const {
364  return integer_trail_->UpperBound(start_vars_[t]);
365 }
366 
367 inline IntegerValue SchedulingConstraintHelper::EndMin(int t) const {
368  return integer_trail_->LowerBound(end_vars_[t]);
369 }
370 
371 inline IntegerValue SchedulingConstraintHelper::EndMax(int t) const {
372  return integer_trail_->UpperBound(end_vars_[t]);
373 }
374 
375 // for optional interval, we don't necessarily have start + duration = end.
376 inline IntegerValue SchedulingConstraintHelper::ShiftedStartMin(int t) const {
377  return std::max(StartMin(t), EndMin(t) - DurationMin(t));
378 }
379 
381  return StartMin(t) == StartMax(t);
382 }
383 
384 inline bool SchedulingConstraintHelper::EndIsFixed(int t) const {
385  return EndMin(t) == EndMax(t);
386 }
387 
388 inline bool SchedulingConstraintHelper::IsOptional(int t) const {
389  return reason_for_presence_[t] != kNoLiteralIndex;
390 }
391 
392 inline bool SchedulingConstraintHelper::IsPresent(int t) const {
393  if (reason_for_presence_[t] == kNoLiteralIndex) return true;
394  return trail_->Assignment().LiteralIsTrue(Literal(reason_for_presence_[t]));
395 }
396 
397 inline bool SchedulingConstraintHelper::IsAbsent(int t) const {
398  if (reason_for_presence_[t] == kNoLiteralIndex) return false;
399  return trail_->Assignment().LiteralIsFalse(Literal(reason_for_presence_[t]));
400 }
401 
403  integer_reason_.clear();
404  literal_reason_.clear();
405  if (other_helper_) {
406  other_helper_->ClearReason();
407  already_added_to_other_reasons_.assign(NumTasks(), false);
408  }
409 }
410 
412  DCHECK(IsPresent(t));
413  AddOtherReason(t);
414  if (reason_for_presence_[t] != kNoLiteralIndex) {
415  literal_reason_.push_back(Literal(reason_for_presence_[t]).Negated());
416  }
417 }
418 
420  AddOtherReason(t);
421  if (duration_vars_[t] != kNoIntegerVariable) {
422  integer_reason_.push_back(
423  integer_trail_->LowerBoundAsLiteral(duration_vars_[t]));
424  }
425 }
426 
428  int t, IntegerValue lower_bound) {
429  AddOtherReason(t);
430  if (duration_vars_[t] != kNoIntegerVariable) {
431  DCHECK_GE(DurationMin(t), lower_bound);
432  integer_reason_.push_back(
433  IntegerLiteral::GreaterOrEqual(duration_vars_[t], lower_bound));
434  }
435 }
436 
438  int t, IntegerValue lower_bound) {
439  DCHECK_GE(StartMin(t), lower_bound);
440  AddOtherReason(t);
441  integer_reason_.push_back(
442  IntegerLiteral::GreaterOrEqual(start_vars_[t], lower_bound));
443 }
444 
446  int t, IntegerValue upper_bound) {
447  DCHECK_LE(StartMax(t), upper_bound);
448  AddOtherReason(t);
449  integer_reason_.push_back(
450  IntegerLiteral::LowerOrEqual(start_vars_[t], upper_bound));
451 }
452 
454  int t, IntegerValue lower_bound) {
455  AddOtherReason(t);
456  if (EndMin(t) < lower_bound) {
457  // This might happen if we used for the end_min the max between end_min
458  // and start_min + duration_min. That is, the end_min assuming the task is
459  // present.
460  const IntegerValue duration_min = DurationMin(t);
461  if (duration_vars_[t] != kNoIntegerVariable) {
462  integer_reason_.push_back(
463  IntegerLiteral::GreaterOrEqual(duration_vars_[t], duration_min));
464  }
465  integer_reason_.push_back(IntegerLiteral::GreaterOrEqual(
466  start_vars_[t], lower_bound - duration_min));
467  return;
468  }
469  integer_reason_.push_back(
470  IntegerLiteral::GreaterOrEqual(end_vars_[t], lower_bound));
471 }
472 
474  int t, IntegerValue upper_bound) {
475  DCHECK_LE(EndMax(t), upper_bound);
476  AddOtherReason(t);
477  integer_reason_.push_back(
478  IntegerLiteral::LowerOrEqual(end_vars_[t], upper_bound));
479 }
480 
482  int t, IntegerValue energy_min, IntegerValue time) {
483  AddOtherReason(t);
484  if (StartMin(t) >= time) {
485  integer_reason_.push_back(
486  IntegerLiteral::GreaterOrEqual(start_vars_[t], time));
487  } else {
488  integer_reason_.push_back(
489  IntegerLiteral::GreaterOrEqual(end_vars_[t], time + energy_min));
490  }
491  if (duration_vars_[t] != kNoIntegerVariable) {
492  integer_reason_.push_back(
493  IntegerLiteral::GreaterOrEqual(duration_vars_[t], energy_min));
494  }
495 }
496 
497 // =============================================================================
498 // Model based functions.
499 // =============================================================================
500 
501 inline std::function<IntegerVariable(const Model&)> StartVar(
502  IntervalVariable v) {
503  return [=](const Model& model) {
504  return model.Get<IntervalsRepository>()->StartVar(v);
505  };
506 }
507 
508 inline std::function<IntegerVariable(const Model&)> EndVar(IntervalVariable v) {
509  return [=](const Model& model) {
510  return model.Get<IntervalsRepository>()->EndVar(v);
511  };
512 }
513 
514 inline std::function<IntegerVariable(const Model&)> SizeVar(
515  IntervalVariable v) {
516  return [=](const Model& model) {
517  return model.Get<IntervalsRepository>()->SizeVar(v);
518  };
519 }
520 
521 inline std::function<int64(const Model&)> MinSize(IntervalVariable v) {
522  return [=](const Model& model) {
523  return model.Get<IntervalsRepository>()->MinSize(v).value();
524  };
525 }
526 
527 inline std::function<int64(const Model&)> MaxSize(IntervalVariable v) {
528  return [=](const Model& model) {
529  return model.Get<IntervalsRepository>()->MaxSize(v).value();
530  };
531 }
532 
533 inline std::function<bool(const Model&)> IsOptional(IntervalVariable v) {
534  return [=](const Model& model) {
535  return model.Get<IntervalsRepository>()->IsOptional(v);
536  };
537 }
538 
539 inline std::function<Literal(const Model&)> IsPresentLiteral(
540  IntervalVariable v) {
541  return [=](const Model& model) {
542  return model.Get<IntervalsRepository>()->IsPresentLiteral(v);
543  };
544 }
545 
546 inline std::function<IntervalVariable(Model*)> NewInterval(int64 min_start,
547  int64 max_end,
548  int64 size) {
549  return [=](Model* model) {
550  return model->GetOrCreate<IntervalsRepository>()->CreateInterval(
551  model->Add(NewIntegerVariable(min_start, max_end)),
552  model->Add(NewIntegerVariable(min_start, max_end)), kNoIntegerVariable,
553  IntegerValue(size), kNoLiteralIndex);
554  };
555 }
556 
557 inline std::function<IntervalVariable(Model*)> NewInterval(
558  IntegerVariable start, IntegerVariable end, IntegerVariable size) {
559  return [=](Model* model) {
560  return model->GetOrCreate<IntervalsRepository>()->CreateInterval(
561  start, end, size, IntegerValue(0), kNoLiteralIndex);
562  };
563 }
564 
565 inline std::function<IntervalVariable(Model*)> NewIntervalWithVariableSize(
566  int64 min_start, int64 max_end, int64 min_size, int64 max_size) {
567  return [=](Model* model) {
568  return model->GetOrCreate<IntervalsRepository>()->CreateInterval(
569  model->Add(NewIntegerVariable(min_start, max_end)),
570  model->Add(NewIntegerVariable(min_start, max_end)),
571  model->Add(NewIntegerVariable(min_size, max_size)), IntegerValue(0),
573  };
574 }
575 
576 inline std::function<IntervalVariable(Model*)> NewOptionalInterval(
577  int64 min_start, int64 max_end, int64 size, Literal is_present) {
578  return [=](Model* model) {
579  return model->GetOrCreate<IntervalsRepository>()->CreateInterval(
580  model->Add(NewIntegerVariable(min_start, max_end)),
581  model->Add(NewIntegerVariable(min_start, max_end)), kNoIntegerVariable,
582  IntegerValue(size), is_present.Index());
583  };
584 }
585 
586 inline std::function<IntervalVariable(Model*)>
588  int64 size, Literal is_present) {
589  return [=](Model* model) {
590  // Note that we need to mark the optionality first.
591  const IntegerVariable start =
592  model->Add(NewIntegerVariable(min_start, max_end));
593  const IntegerVariable end =
594  model->Add(NewIntegerVariable(min_start, max_end));
595  auto* integer_trail = model->GetOrCreate<IntegerTrail>();
596  integer_trail->MarkIntegerVariableAsOptional(start, is_present);
597  integer_trail->MarkIntegerVariableAsOptional(end, is_present);
598  return model->GetOrCreate<IntervalsRepository>()->CreateInterval(
599  start, end, kNoIntegerVariable, IntegerValue(size), is_present.Index());
600  };
601 }
602 
603 inline std::function<IntervalVariable(Model*)> NewOptionalInterval(
604  IntegerVariable start, IntegerVariable end, IntegerVariable size,
605  Literal is_present) {
606  return [=](Model* model) {
607  return model->GetOrCreate<IntervalsRepository>()->CreateInterval(
608  start, end, size, IntegerValue(0), is_present.Index());
609  };
610 }
611 
612 inline std::function<IntervalVariable(Model*)>
614  int64 min_size, int64 max_size,
615  Literal is_present) {
616  return [=](Model* model) {
617  return model->GetOrCreate<IntervalsRepository>()->CreateInterval(
618  model->Add(NewIntegerVariable(min_start, max_end)),
619  model->Add(NewIntegerVariable(min_start, max_end)),
620  model->Add(NewIntegerVariable(min_size, max_size)), IntegerValue(0),
621  is_present.Index());
622  };
623 }
624 
625 // This requires that all the alternatives are optional tasks.
626 inline std::function<void(Model*)> IntervalWithAlternatives(
627  IntervalVariable master, const std::vector<IntervalVariable>& members) {
628  return [=](Model* model) {
629  IntervalsRepository* intervals = model->GetOrCreate<IntervalsRepository>();
630 
631  std::vector<Literal> presences;
632  std::vector<IntegerValue> durations;
633 
634  // Create an "exactly one executed" constraint on the alternatives.
635  std::vector<LiteralWithCoeff> sat_ct;
636  for (const IntervalVariable member : members) {
637  CHECK(intervals->IsOptional(member));
638  const Literal is_present = intervals->IsPresentLiteral(member);
639  sat_ct.push_back({is_present, Coefficient(1)});
640  model->Add(
641  Equality(model->Get(StartVar(master)), model->Get(StartVar(member))));
642  model->Add(
643  Equality(model->Get(EndVar(master)), model->Get(EndVar(member))));
644 
645  // TODO(user): IsOneOf() only work for members with fixed size.
646  // Generalize to an "int_var_element" constraint.
647  CHECK_EQ(intervals->SizeVar(member), kNoIntegerVariable);
648  presences.push_back(is_present);
649  durations.push_back(intervals->MinSize(member));
650  }
651  if (intervals->SizeVar(master) != kNoIntegerVariable) {
652  model->Add(IsOneOf(intervals->SizeVar(master), presences, durations));
653  }
654  model->Add(BooleanLinearConstraint(1, 1, &sat_ct));
655 
656  // Propagate from the candidate bounds to the master interval ones.
657  {
658  std::vector<IntegerVariable> starts;
659  starts.reserve(members.size());
660  for (const IntervalVariable member : members) {
661  starts.push_back(intervals->StartVar(member));
662  }
663  model->Add(
664  PartialIsOneOfVar(intervals->StartVar(master), starts, presences));
665  }
666  {
667  std::vector<IntegerVariable> ends;
668  ends.reserve(members.size());
669  for (const IntervalVariable member : members) {
670  ends.push_back(intervals->EndVar(member));
671  }
672  model->Add(PartialIsOneOfVar(intervals->EndVar(master), ends, presences));
673  }
674  };
675 }
676 
677 } // namespace sat
678 } // namespace operations_research
679 
680 #endif // OR_TOOLS_SAT_INTERVALS_H_
operations_research::sat::TaskTime::operator<
bool operator<(TaskTime other) const
Definition: intervals.h:128
operations_research::sat::Trail
Definition: sat_base.h:233
operations_research::sat::IntervalsRepository::EndVar
IntegerVariable EndVar(IntervalVariable i) const
Definition: intervals.h:79
operations_research::sat::VariablesAssignment::LiteralIsTrue
bool LiteralIsTrue(Literal literal) const
Definition: sat_base.h:150
operations_research::sat::IntervalsRepository::IsPresentLiteral
Literal IsPresentLiteral(IntervalVariable i) const
Definition: intervals.h:66
operations_research::sat::IntegerLiteral
Definition: integer.h:164
operations_research::sat::SchedulingConstraintHelper::AddDurationMinReason
void AddDurationMinReason(int t)
Definition: intervals.h:419
integral_types.h
operations_research::sat::IntegerLiteral::GreaterOrEqual
static IntegerLiteral GreaterOrEqual(IntegerVariable i, IntegerValue bound)
Definition: integer.h:1197
operations_research::sat::kNoIntegerVariable
const IntegerVariable kNoIntegerVariable(-1)
max
int64 max
Definition: alldiff_cst.cc:139
operations_research::sat::SchedulingConstraintHelper::IsAbsent
bool IsAbsent(int t) const
Definition: intervals.h:397
operations_research::sat::SchedulingConstraintHelper::EndMax
IntegerValue EndMax(int t) const
Definition: intervals.h:371
bound
int64 bound
Definition: routing_search.cc:972
operations_research::sat::SchedulingConstraintHelper::AddEndMaxReason
void AddEndMaxReason(int t, IntegerValue upper_bound)
Definition: intervals.h:473
operations_research::sat::kNoLiteralIndex
const LiteralIndex kNoLiteralIndex(-1)
operations_research::sat::SchedulingConstraintHelper::EndMin
IntegerValue EndMin(int t) const
Definition: intervals.h:367
operations_research::sat::IntegerTrail::UpperBound
IntegerValue UpperBound(IntegerVariable i) const
Definition: integer.h:1221
operations_research::sat::SizeVar
std::function< IntegerVariable(const Model &)> SizeVar(IntervalVariable v)
Definition: intervals.h:514
operations_research::sat::SchedulingConstraintHelper::AddReasonForBeingBefore
void AddReasonForBeingBefore(int before, int after)
Definition: intervals.cc:226
operations_research::sat::SchedulingConstraintHelper::DurationVars
const std::vector< IntegerVariable > & DurationVars() const
Definition: intervals.h:257
operations_research::sat::IsPresentLiteral
std::function< Literal(const Model &)> IsPresentLiteral(IntervalVariable v)
Definition: intervals.h:539
logging.h
operations_research::sat::StartVar
std::function< IntegerVariable(const Model &)> StartVar(IntervalVariable v)
Definition: intervals.h:501
operations_research::sat::SchedulingConstraintHelper::SetTimeDirection
void SetTimeDirection(bool is_forward)
Definition: intervals.cc:142
operations_research::sat::SchedulingConstraintHelper::TaskByIncreasingEndMin
const std::vector< TaskTime > & TaskByIncreasingEndMin()
Definition: intervals.cc:168
operations_research::sat::SchedulingConstraintHelper::ClearOtherHelper
void ClearOtherHelper()
Definition: intervals.h:279
operations_research::sat::SchedulingConstraintHelper
Definition: intervals.h:137
operations_research::sat::IntervalsRepository::SizeVar
IntegerVariable SizeVar(IntervalVariable i) const
Definition: intervals.h:77
model.h
operations_research::sat::IntervalsRepository::MaxSize
IntegerValue MaxSize(IntervalVariable i) const
Definition: intervals.h:89
macros.h
operations_research::sat::IntervalsRepository::IsOptional
bool IsOptional(IntervalVariable i) const
Definition: intervals.h:63
operations_research
The vehicle routing library lets one model and solve generic vehicle routing problems ranging from th...
Definition: dense_doubly_linked_list.h:21
operations_research::sat::TaskTime::time
IntegerValue time
Definition: intervals.h:127
operations_research::sat::SchedulingConstraintHelper::ClearReason
void ClearReason()
Definition: intervals.h:402
operations_research::sat::NewOptionalIntervalWithOptionalVariables
std::function< IntervalVariable(Model *)> NewOptionalIntervalWithOptionalVariables(int64 min_start, int64 max_end, int64 size, Literal is_present)
Definition: intervals.h:587
operations_research::sat::MinSize
std::function< int64(const Model &)> MinSize(IntervalVariable v)
Definition: intervals.h:521
operations_research::sat::SchedulingConstraintHelper::StartIsFixed
bool StartIsFixed(int t) const
Definition: intervals.h:380
operations_research::sat::IntegerTrail
Definition: integer.h:534
operations_research::sat::IntervalsRepository::StartVar
IntegerVariable StartVar(IntervalVariable i) const
Definition: intervals.h:78
operations_research::sat::TaskTime::operator>
bool operator>(TaskTime other) const
Definition: intervals.h:129
int64
int64_t int64
Definition: integral_types.h:34
gtl::ITIVector::size
size_type size() const
Definition: int_type_indexed_vector.h:146
sat_solver.h
operations_research::sat::SchedulingConstraintHelper::TaskByIncreasingStartMin
const std::vector< TaskTime > & TaskByIncreasingStartMin()
Definition: intervals.cc:156
operations_research::sat::Model
Class that owns everything related to a particular optimization model.
Definition: sat/model.h:38
sat_base.h
int32
int int32
Definition: integral_types.h:33
operations_research::sat::DEFINE_INT_TYPE
DEFINE_INT_TYPE(ClauseIndex, int)
pb_constraint.h
operations_research::sat::SchedulingConstraintHelper::DurationMax
IntegerValue DurationMax(int t) const
Definition: intervals.h:353
operations_research::sat::SchedulingConstraintHelper::TaskByDecreasingStartMax
const std::vector< TaskTime > & TaskByDecreasingStartMax()
Definition: intervals.cc:180
operations_research::sat::SchedulingConstraintHelper::NumTasks
int NumTasks() const
Definition: intervals.h:157
operations_research::sat::SchedulingConstraintHelper::StartVars
const std::vector< IntegerVariable > & StartVars() const
Definition: intervals.h:255
operations_research::sat::Literal
Definition: sat_base.h:64
operations_research::sat::SchedulingConstraintHelper::PushIntegerLiteralIfTaskPresent
ABSL_MUST_USE_RESULT bool PushIntegerLiteralIfTaskPresent(int t, IntegerLiteral bound)
Definition: intervals.cc:271
operations_research::sat::SchedulingConstraintHelper::TaskByDecreasingEndMax
const std::vector< TaskTime > & TaskByDecreasingEndMax()
Definition: intervals.cc:193
operations_research::sat::SchedulingConstraintHelper::StartMin
IntegerValue StartMin(int t) const
Definition: intervals.h:359
operations_research::sat::SchedulingConstraintHelper::EndIsFixed
bool EndIsFixed(int t) const
Definition: intervals.h:384
operations_research::sat::MaxSize
std::function< int64(const Model &)> MaxSize(IntervalVariable v)
Definition: intervals.h:527
operations_research::sat::BooleanLinearConstraint
std::function< void(Model *)> BooleanLinearConstraint(int64 lower_bound, int64 upper_bound, std::vector< LiteralWithCoeff > *cst)
Definition: sat_solver.h:832
operations_research::sat::GenericLiteralWatcher
Definition: integer.h:1056
operations_research::sat::SchedulingConstraintHelper::AddEndMinReason
void AddEndMinReason(int t, IntegerValue lower_bound)
Definition: intervals.h:453
operations_research::sat::SchedulingConstraintHelper::IsOptional
bool IsOptional(int t) const
Definition: intervals.h:388
operations_research::sat::IntervalWithAlternatives
std::function< void(Model *)> IntervalWithAlternatives(IntervalVariable master, const std::vector< IntervalVariable > &members)
Definition: intervals.h:626
operations_research::sat::SchedulingConstraintHelper::StartMax
IntegerValue StartMax(int t) const
Definition: intervals.h:363
int_type.h
operations_research::sat::NewOptionalIntervalWithVariableSize
std::function< IntervalVariable(Model *)> NewOptionalIntervalWithVariableSize(int64 min_start, int64 max_end, int64 min_size, int64 max_size, Literal is_present)
Definition: intervals.h:613
precedences.h
operations_research::sat::SchedulingConstraintHelper::WatchAllTasks
void WatchAllTasks(int id, GenericLiteralWatcher *watcher, bool watch_start_max=true, bool watch_end_max=true) const
Definition: intervals.cc:343
operations_research::sat::SchedulingConstraintHelper::MutableLiteralReason
std::vector< Literal > * MutableLiteralReason()
Definition: intervals.h:232
operations_research::sat::SchedulingConstraintHelper::EndVars
const std::vector< IntegerVariable > & EndVars() const
Definition: intervals.h:256
operations_research::sat::IsOneOf
std::function< void(Model *)> IsOneOf(IntegerVariable var, const std::vector< Literal > &selectors, const std::vector< IntegerValue > &values)
Definition: integer_expr.cc:792
integer_expr.h
operations_research::sat::NewIntegerVariable
std::function< IntegerVariable(Model *)> NewIntegerVariable()
Definition: integer.h:1321
operations_research::sat::SchedulingConstraintHelper::TaskByIncreasingShiftedStartMin
const std::vector< TaskTime > & TaskByIncreasingShiftedStartMin()
Definition: intervals.cc:205
int_type_indexed_vector.h
operations_research::sat::PartialIsOneOfVar
std::function< void(Model *)> PartialIsOneOfVar(IntegerVariable target_var, const std::vector< IntegerVariable > &vars, const std::vector< Literal > &selectors)
Definition: cp_constraints.h:159
operations_research::sat::Trail::Assignment
const VariablesAssignment & Assignment() const
Definition: sat_base.h:380
operations_research::sat::SchedulingConstraintHelper::IncreaseStartMin
ABSL_MUST_USE_RESULT bool IncreaseStartMin(int t, IntegerValue new_min_start)
Definition: intervals.cc:310
operations_research::sat::IntervalsRepository::MinSize
IntegerValue MinSize(IntervalVariable i) const
Definition: intervals.h:82
operations_research::sat::SchedulingConstraintHelper::PushTaskAbsence
ABSL_MUST_USE_RESULT bool PushTaskAbsence(int t)
Definition: intervals.cc:322
operations_research::sat::SchedulingConstraintHelper::IsPresent
bool IsPresent(int t) const
Definition: intervals.h:392
operations_research::sat::SchedulingConstraintHelper::AddStartMinReason
void AddStartMinReason(int t, IntegerValue lower_bound)
Definition: intervals.h:437
cp_constraints.h
operations_research::sat::IntegerTrail::LowerBoundAsLiteral
IntegerLiteral LowerBoundAsLiteral(IntegerVariable i) const
Definition: integer.h:1247
operations_research::sat::SchedulingConstraintHelper::ResetFromSubset
void ResetFromSubset(const SchedulingConstraintHelper &other, absl::Span< const int > tasks)
Definition: intervals.cc:96
operations_research::sat::SchedulingConstraintHelper::AddStartMaxReason
void AddStartMaxReason(int t, IntegerValue upper_bound)
Definition: intervals.h:445
operations_research::sat::NewInterval
std::function< IntervalVariable(Model *)> NewInterval(int64 min_start, int64 max_end, int64 size)
Definition: intervals.h:546
operations_research::sat::SchedulingConstraintHelper::PushIntegerLiteral
ABSL_MUST_USE_RESULT bool PushIntegerLiteral(IntegerLiteral bound)
Definition: intervals.cc:266
operations_research::sat::NewIntervalWithVariableSize
std::function< IntervalVariable(Model *)> NewIntervalWithVariableSize(int64 min_start, int64 max_end, int64 min_size, int64 max_size)
Definition: intervals.h:565
model
GRBmodel * model
Definition: gurobi_interface.cc:195
operations_research::sat::TaskTime::task_index
int task_index
Definition: intervals.h:126
operations_research::sat::SchedulingConstraintHelper::MutableIntegerReason
std::vector< IntegerLiteral > * MutableIntegerReason()
Definition: intervals.h:233
operations_research::sat::IntegerTrail::LowerBound
IntegerValue LowerBound(IntegerVariable i) const
Definition: integer.h:1217
operations_research::sat::IsOptional
std::function< bool(const Model &)> IsOptional(IntervalVariable v)
Definition: intervals.h:533
operations_research::sat::IntervalsRepository::AllIntervals
std::vector< IntervalVariable > AllIntervals() const
Definition: intervals.h:96
operations_research::sat::VariablesAssignment::LiteralIsFalse
bool LiteralIsFalse(Literal literal) const
Definition: sat_base.h:147
operations_research::sat::IntervalsRepository::NumIntervals
int NumIntervals() const
Definition: intervals.h:53
operations_research::sat::SchedulingConstraintHelper::ShiftedStartMin
IntegerValue ShiftedStartMin(int t) const
Definition: intervals.h:376
operations_research::sat::SchedulingConstraintHelper::AddEnergyAfterReason
void AddEnergyAfterReason(int t, IntegerValue energy_min, IntegerValue time)
Definition: intervals.h:481
operations_research::sat::IntervalsRepository::CreateInterval
IntervalVariable CreateInterval(IntegerVariable start, IntegerVariable end, IntegerVariable size, IntegerValue fixed_size, LiteralIndex is_present)
Definition: intervals.cc:23
operations_research::sat::IntegerLiteral::LowerOrEqual
static IntegerLiteral LowerOrEqual(IntegerVariable i, IntegerValue bound)
Definition: integer.h:1203
operations_research::sat::Equality
std::function< void(Model *)> Equality(IntegerVariable v, int64 value)
Definition: integer.h:1433
operations_research::sat::SchedulingConstraintHelper::ReportConflict
ABSL_MUST_USE_RESULT bool ReportConflict()
Definition: intervals.cc:338
gtl::ITIVector< IntervalVariable, LiteralIndex >
operations_research::sat::PrecedencesPropagator
Definition: precedences.h:51
operations_research::sat::IntervalsRepository
Definition: intervals.h:45
operations_research::sat::SchedulingConstraintHelper::SetOtherHelper
void SetOtherHelper(SchedulingConstraintHelper *other_helper, IntegerValue event)
Definition: intervals.h:272
operations_research::sat::SchedulingConstraintHelper::DurationMin
IntegerValue DurationMin(int t) const
Definition: intervals.h:347
operations_research::sat::SchedulingConstraintHelper::SchedulingConstraintHelper
SchedulingConstraintHelper(const std::vector< IntervalVariable > &tasks, Model *model)
Definition: intervals.cc:52
operations_research::sat::NewOptionalInterval
std::function< IntervalVariable(Model *)> NewOptionalInterval(int64 min_start, int64 max_end, int64 size, Literal is_present)
Definition: intervals.h:576
operations_research::sat::IntervalsRepository::IntervalsRepository
IntervalsRepository(Model *model)
Definition: intervals.h:47
operations_research::sat::SchedulingConstraintHelper::AddPresenceReason
void AddPresenceReason(int t)
Definition: intervals.h:411
operations_research::sat::Literal::Index
LiteralIndex Index() const
Definition: sat_base.h:84
integer.h
operations_research::sat::TaskTime
Definition: intervals.h:125
operations_research::sat::EndVar
std::function< IntegerVariable(const Model &)> EndVar(IntervalVariable v)
Definition: intervals.h:508
operations_research::sat::kNoIntervalVariable
const IntervalVariable kNoIntervalVariable(-1)
time
int64 time
Definition: resource.cc:1683
operations_research::sat::IntegerTrail::MarkIntegerVariableAsOptional
void MarkIntegerVariableAsOptional(IntegerVariable i, Literal is_considered)
Definition: integer.h:626
operations_research::sat::SchedulingConstraintHelper::DecreaseEndMax
ABSL_MUST_USE_RESULT bool DecreaseEndMax(int t, IntegerValue new_max_end)
Definition: intervals.cc:316