OR-Tools  9.6
intervals.h
Go to the documentation of this file.
1 // Copyright 2010-2022 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 <cstdint>
18 #include <functional>
19 #include <optional>
20 #include <string>
21 #include <vector>
22 
23 #include "absl/base/attributes.h"
24 #include "absl/strings/string_view.h"
26 #include "ortools/base/logging.h"
27 #include "ortools/base/macros.h"
30 #include "ortools/sat/integer.h"
32 #include "ortools/sat/model.h"
35 #include "ortools/sat/sat_base.h"
36 #include "ortools/sat/sat_solver.h"
37 #include "ortools/util/rev.h"
39 
40 namespace operations_research {
41 namespace sat {
42 
43 DEFINE_STRONG_INDEX_TYPE(IntervalVariable);
44 const IntervalVariable kNoIntervalVariable(-1);
45 
47 
48 // This class maintains a set of intervals which correspond to three integer
49 // variables (start, end and size). It automatically registers with the
50 // PrecedencesPropagator the relation between the bounds of each interval and
51 // provides many helper functions to add precedences relation between intervals.
53  public:
55  : model_(model),
56  assignment_(model->GetOrCreate<Trail>()->Assignment()),
57  integer_trail_(model->GetOrCreate<IntegerTrail>()) {}
58 
59  // Returns the current number of intervals in the repository.
60  // The interval will always be identified by an integer in [0, num_intervals).
61  int NumIntervals() const { return starts_.size(); }
62 
63  // Functions to add a new interval to the repository.
64  // If add_linear_relation is true, then we also link start, size and end.
65  //
66  // - If size == kNoIntegerVariable, then the size is fixed to fixed_size.
67  // - If is_present != kNoLiteralIndex, then this is an optional interval.
68  IntervalVariable CreateInterval(IntegerVariable start, IntegerVariable end,
69  IntegerVariable size, IntegerValue fixed_size,
70  LiteralIndex is_present);
72  AffineExpression size,
73  LiteralIndex is_present,
74  bool add_linear_relation);
75 
76  // Returns whether or not a interval is optional and the associated literal.
77  bool IsOptional(IntervalVariable i) const {
78  return is_present_[i] != kNoLiteralIndex;
79  }
80  Literal PresenceLiteral(IntervalVariable i) const {
81  return Literal(is_present_[i]);
82  }
83  bool IsPresent(IntervalVariable i) const {
84  if (!IsOptional(i)) return true;
85  return assignment_.LiteralIsTrue(PresenceLiteral(i));
86  }
87  bool IsAbsent(IntervalVariable i) const {
88  if (!IsOptional(i)) return false;
89  return assignment_.LiteralIsFalse(PresenceLiteral(i));
90  }
91 
92  // The 3 integer variables associated to a interval.
93  // Fixed size intervals will have a kNoIntegerVariable as size.
94  //
95  // Note: For an optional interval, the start/end variables are propagated
96  // asssuming the interval is present. Because of that, these variables can
97  // cross each other or have an empty domain. If any of this happen, then the
98  // PresenceLiteral() of this interval will be propagated to false.
99  AffineExpression Size(IntervalVariable i) const { return sizes_[i]; }
100  AffineExpression Start(IntervalVariable i) const { return starts_[i]; }
101  AffineExpression End(IntervalVariable i) const { return ends_[i]; }
102 
103  // Deprecated.
104  IntegerVariable SizeVar(IntervalVariable i) const {
105  if (sizes_[i].var != kNoIntegerVariable) {
106  CHECK_EQ(sizes_[i].coeff, 1);
107  CHECK_EQ(sizes_[i].constant, 0);
108  }
109  return sizes_[i].var;
110  }
111  IntegerVariable StartVar(IntervalVariable i) const {
112  if (starts_[i].var != kNoIntegerVariable) {
113  CHECK_EQ(starts_[i].coeff, 1);
114  CHECK_EQ(starts_[i].constant, 0);
115  }
116  return starts_[i].var;
117  }
118  IntegerVariable EndVar(IntervalVariable i) const {
119  if (ends_[i].var != kNoIntegerVariable) {
120  CHECK_EQ(ends_[i].coeff, 1);
121  CHECK_EQ(ends_[i].constant, 0);
122  }
123  return ends_[i].var;
124  }
125 
126  // Return the minimum size of the given IntervalVariable.
127  IntegerValue MinSize(IntervalVariable i) const {
128  return integer_trail_->LowerBound(sizes_[i]);
129  }
130 
131  // Return the maximum size of the given IntervalVariable.
132  IntegerValue MaxSize(IntervalVariable i) const {
133  return integer_trail_->UpperBound(sizes_[i]);
134  }
135 
136  // Utility function that returns a vector will all intervals.
137  std::vector<IntervalVariable> AllIntervals() const {
138  std::vector<IntervalVariable> result;
139  for (IntervalVariable i(0); i < NumIntervals(); ++i) {
140  result.push_back(i);
141  }
142  return result;
143  }
144 
145  // Returns a SchedulingConstraintHelper corresponding to the given variables.
146  // Note that the order of interval in the helper will be the same.
148  const std::vector<IntervalVariable>& variables);
149 
150  private:
151  // External classes needed.
152  Model* model_;
153  const VariablesAssignment& assignment_;
154  IntegerTrail* integer_trail_;
155 
156  // Literal indicating if the tasks is executed. Tasks that are always executed
157  // will have a kNoLiteralIndex entry in this vector.
159 
160  // The integer variables for each tasks.
164 
165  // We can share the helper for all the propagators that work on the same set
166  // of intervals.
167  absl::flat_hash_map<std::vector<IntervalVariable>,
169  helper_repository_;
170 
171  DISALLOW_COPY_AND_ASSIGN(IntervalsRepository);
172 };
173 
174 // An helper struct to sort task by time. This is used by the
175 // SchedulingConstraintHelper but also by many scheduling propagators to sort
176 // tasks.
177 struct TaskTime {
179  IntegerValue time;
180  bool operator<(TaskTime other) const { return time < other.time; }
181  bool operator>(TaskTime other) const { return time > other.time; }
182 };
183 
184 // Helper class shared by the propagators that manage a given list of tasks.
185 //
186 // One of the main advantage of this class is that it allows to share the
187 // vectors of tasks sorted by various criteria between propagator for a faster
188 // code.
191  public:
192  // All the functions below refer to a task by its index t in the tasks
193  // vector given at construction.
194  SchedulingConstraintHelper(const std::vector<IntervalVariable>& tasks,
195  Model* model);
196 
197  // Temporary constructor.
198  // The class will not be usable until ResetFromSubset() is called.
199  //
200  // TODO(user): Remove this. It is a hack because the disjunctive class needs
201  // to fetch the maximum possible number of task at construction.
202  SchedulingConstraintHelper(int num_tasks, Model* model);
203 
204  // This is a propagator so we can "cache" all the intervals relevant
205  // information. This gives good speedup. Note however that the info is stale
206  // except if a bound was pushed by this helper or if this was called. We run
207  // it at the highest priority, so that will mostly be the case at the
208  // beginning of each Propagate() call of the classes using this.
209  bool Propagate() final;
210  bool IncrementalPropagate(const std::vector<int>& watch_indices) final;
211  void RegisterWith(GenericLiteralWatcher* watcher);
212  void SetLevel(int level) final;
213 
214  // Resets the class to the same state as if it was constructed with
215  // the given subset of tasks from other.
216  ABSL_MUST_USE_RESULT bool ResetFromSubset(
217  const SchedulingConstraintHelper& other, absl::Span<const int> tasks);
218 
219  // Returns the number of task.
220  int NumTasks() const { return starts_.size(); }
221 
222  // Make sure the cached values are up to date. Also sets the time direction to
223  // either forward/backward. This will impact all the functions below. This
224  // MUST be called at the beginning of all Propagate() call that uses this
225  // helper.
226  void SetTimeDirection(bool is_forward);
227  ABSL_MUST_USE_RESULT bool SynchronizeAndSetTimeDirection(bool is_forward);
228 
229  // Helpers for the current bounds on the current task time window.
230  // [ (size-min) ... (size-min) ]
231  // ^ ^ ^ ^
232  // start-min end-min start-max end-max
233  //
234  // Note that for tasks with variable durations, we don't necessarily have
235  // duration-min between the XXX-min and XXX-max value.
236  //
237  // Remark: We use cached values for most of these function as this is faster.
238  // In practice, the cache will almost always be up to date, but not in corner
239  // cases where pushing the start of one task will change values for many
240  // others. This is fine as the new values will be picked up as we reach the
241  // propagation fixed point.
242  IntegerValue SizeMin(int t) const { return cached_size_min_[t]; }
243  IntegerValue SizeMax(int t) const {
244  // This one is "rare" so we don't cache it.
245  return integer_trail_->UpperBound(sizes_[t]);
246  }
247  IntegerValue StartMin(int t) const { return cached_start_min_[t]; }
248  IntegerValue EndMin(int t) const { return cached_end_min_[t]; }
249  IntegerValue StartMax(int t) const { return -cached_negated_start_max_[t]; }
250  IntegerValue EndMax(int t) const { return -cached_negated_end_max_[t]; }
251 
252  // In the presence of tasks with a variable size, we do not necessarily
253  // have start_min + size_min = end_min, we can instead have a situation
254  // like:
255  // | |<--- size-min --->|
256  // ^ ^ ^
257  // start-min | end-min
258  // |
259  // We define the "shifted start min" to be the right most time such that
260  // we known that we must have min-size "energy" to the right of it if the
261  // task is present. Using it in our scheduling propagators allows to propagate
262  // more in the presence of tasks with variable size (or optional task
263  // where we also do not necessarily have start_min + size_min = end_min.
264  //
265  // To explain this shifted start min, one must use the AddEnergyAfterReason().
266  IntegerValue ShiftedStartMin(int t) const {
267  return cached_shifted_start_min_[t];
268  }
269 
270  // As with ShiftedStartMin(), we can compute the shifted end max (that is
271  // start_max + size_min.
272  IntegerValue ShiftedEndMax(int t) const {
273  return -cached_negated_shifted_end_max_[t];
274  }
275 
276  bool StartIsFixed(int t) const;
277  bool EndIsFixed(int t) const;
278  bool SizeIsFixed(int t) const;
279 
280  // Returns true if the corresponding fact is known for sure. A normal task is
281  // always present. For optional task for which the presence is still unknown,
282  // both of these function will return false.
283  bool IsOptional(int t) const;
284  bool IsPresent(int t) const;
285  bool IsAbsent(int t) const;
286 
287  // Return the minimum overlap of interval i with the time window [start..end].
288  //
289  // Note: this is different from the mandatory part of an interval.
290  IntegerValue GetMinOverlap(int t, IntegerValue start, IntegerValue end) const;
291 
292  // Returns a string with the current task bounds.
293  std::string TaskDebugString(int t) const;
294 
295  // Sorts and returns the tasks in corresponding order at the time of the call.
296  // Note that we do not mean strictly-increasing/strictly-decreasing, there
297  // will be duplicate time values in these vectors.
298  //
299  // TODO(user): we could merge the first loop of IncrementalSort() with the
300  // loop that fill TaskTime.time at each call.
301  const std::vector<TaskTime>& TaskByIncreasingStartMin();
302  const std::vector<TaskTime>& TaskByIncreasingEndMin();
303  const std::vector<TaskTime>& TaskByDecreasingStartMax();
304  const std::vector<TaskTime>& TaskByDecreasingEndMax();
305  const std::vector<TaskTime>& TaskByIncreasingShiftedStartMin();
306 
307  // Returns a sorted vector where each task appear twice, the first occurrence
308  // is at size (end_min - size_min) and the second one at (end_min).
309  //
310  // This is quite usage specific.
311  struct ProfileEvent {
312  IntegerValue time;
313  int task;
314  bool is_first;
315 
316  bool operator<(const ProfileEvent& other) const {
317  if (time == other.time) {
318  if (task == other.task) return is_first > other.is_first;
319  return task < other.task;
320  }
321  return time < other.time;
322  }
323  };
324  const std::vector<ProfileEvent>& GetEnergyProfile();
325 
326  // Functions to clear and then set the current reason.
327  void ClearReason();
328  void AddPresenceReason(int t);
329  void AddAbsenceReason(int t);
330  void AddSizeMinReason(int t);
331  void AddSizeMinReason(int t, IntegerValue lower_bound);
332  void AddSizeMaxReason(int t, IntegerValue upper_bound);
333  void AddStartMinReason(int t, IntegerValue lower_bound);
334  void AddStartMaxReason(int t, IntegerValue upper_bound);
335  void AddEndMinReason(int t, IntegerValue lower_bound);
336  void AddEndMaxReason(int t, IntegerValue upper_bound);
337 
338  void AddEnergyAfterReason(int t, IntegerValue energy_min, IntegerValue time);
339  void AddEnergyMinInIntervalReason(int t, IntegerValue min, IntegerValue max);
340 
341  // Adds the reason why task "before" must be before task "after".
342  // That is StartMax(before) < EndMin(after).
343  void AddReasonForBeingBefore(int before, int after);
344 
345  // It is also possible to directly manipulates the underlying reason vectors
346  // that will be used when pushing something.
347  std::vector<Literal>* MutableLiteralReason() { return &literal_reason_; }
348  std::vector<IntegerLiteral>* MutableIntegerReason() {
349  return &integer_reason_;
350  }
351 
352  // Push something using the current reason. Note that IncreaseStartMin() will
353  // also increase the end-min, and DecreaseEndMax() will also decrease the
354  // start-max.
355  //
356  // Important: IncreaseStartMin() and DecreaseEndMax() can be called on an
357  // optional interval whose presence is still unknown and push a bound
358  // conditionned on its presence. The functions will do the correct thing
359  // depending on whether or not the start_min/end_max are optional variables
360  // whose presence implies the interval presence.
361  ABSL_MUST_USE_RESULT bool IncreaseStartMin(int t, IntegerValue value);
362  ABSL_MUST_USE_RESULT bool IncreaseEndMin(int t, IntegerValue value);
363  ABSL_MUST_USE_RESULT bool DecreaseEndMax(int t, IntegerValue value);
364  ABSL_MUST_USE_RESULT bool PushLiteral(Literal l);
365  ABSL_MUST_USE_RESULT bool PushTaskAbsence(int t);
366  ABSL_MUST_USE_RESULT bool PushTaskPresence(int t);
367  ABSL_MUST_USE_RESULT bool PushIntegerLiteral(IntegerLiteral lit);
368  ABSL_MUST_USE_RESULT bool ReportConflict();
369  ABSL_MUST_USE_RESULT bool PushIntegerLiteralIfTaskPresent(int t,
370  IntegerLiteral lit);
371 
372  // Returns the underlying affine expressions.
373  const std::vector<AffineExpression>& Starts() const { return starts_; }
374  const std::vector<AffineExpression>& Ends() const { return ends_; }
375  const std::vector<AffineExpression>& Sizes() const { return sizes_; }
377  DCHECK(IsOptional(index));
378  return Literal(reason_for_presence_[index]);
379  }
380 
381  // Registers the given propagator id to be called if any of the tasks
382  // in this class change. Note that we do not watch size max though.
383  void WatchAllTasks(int id, GenericLiteralWatcher* watcher,
384  bool watch_start_max = true,
385  bool watch_end_max = true) const;
386 
387  // Manages the other helper (used by the diffn constraint).
388  //
389  // For each interval appearing in a reason on this helper, another reason
390  // will be added. This other reason specifies that on the other helper, the
391  // corresponding interval overlaps 'event'.
393  absl::Span<const int> map_to_other_helper,
394  IntegerValue event) {
395  CHECK(other_helper != nullptr);
396  other_helper_ = other_helper;
397  map_to_other_helper_ = map_to_other_helper;
398  event_for_other_helper_ = event;
399  }
400 
401  void ClearOtherHelper() { other_helper_ = nullptr; }
402 
403  // Adds to this helper reason all the explanation of the other helper.
404  // This checks that other_helper_ is null.
405  //
406  // This is used in the 2D energetic reasoning in the diffn constraint.
407  void ImportOtherReasons(const SchedulingConstraintHelper& other_helper);
408 
409  // TODO(user): Change the propagation loop code so that we don't stop
410  // pushing in the middle of the propagation as more advanced propagator do
411  // not handle this correctly.
412  bool InPropagationLoop() const { return integer_trail_->InPropagationLoop(); }
413 
414  private:
415  // Generic reason for a <= upper_bound, given that a = b + c in case the
416  // current upper bound of a is not good enough.
417  void AddGenericReason(const AffineExpression& a, IntegerValue upper_bound,
418  const AffineExpression& b, const AffineExpression& c);
419 
420  void InitSortedVectors();
421  ABSL_MUST_USE_RESULT bool UpdateCachedValues(int t);
422 
423  // Internal function for IncreaseStartMin()/DecreaseEndMax().
424  bool PushIntervalBound(int t, IntegerLiteral lit);
425 
426  // This will be called on any interval that is part of a reason or
427  // a bound push. Since the last call to ClearReason(), for each unique
428  // t, we will add once to other_helper_ the reason for t containing
429  // the point event_for_other_helper_.
430  void AddOtherReason(int t);
431 
432  // Import the reasons on the other helper into this helper.
433  void ImportOtherReasons();
434 
435  Trail* trail_;
436  IntegerTrail* integer_trail_;
437  PrecedencesPropagator* precedences_;
438 
439  // The current direction of time, true for forward, false for backward.
440  bool current_time_direction_ = true;
441 
442  // All the underlying variables of the tasks.
443  // The vectors are indexed by the task index t.
444  std::vector<AffineExpression> starts_;
445  std::vector<AffineExpression> ends_;
446  std::vector<AffineExpression> sizes_;
447  std::vector<LiteralIndex> reason_for_presence_;
448 
449  // The negation of the start/end variable so that SetTimeDirection()
450  // can do its job in O(1) instead of calling NegationOf() on each entry.
451  std::vector<AffineExpression> minus_starts_;
452  std::vector<AffineExpression> minus_ends_;
453 
454  // This is used by SetLevel() to dected untrail.
455  int previous_level_ = 0;
456 
457  // The caches of all relevant interval values.
458  std::vector<IntegerValue> cached_size_min_;
459  std::vector<IntegerValue> cached_start_min_;
460  std::vector<IntegerValue> cached_end_min_;
461  std::vector<IntegerValue> cached_negated_start_max_;
462  std::vector<IntegerValue> cached_negated_end_max_;
463  std::vector<IntegerValue> cached_shifted_start_min_;
464  std::vector<IntegerValue> cached_negated_shifted_end_max_;
465 
466  // Sorted vectors returned by the TasksBy*() functions.
467  std::vector<TaskTime> task_by_increasing_start_min_;
468  std::vector<TaskTime> task_by_increasing_end_min_;
469  std::vector<TaskTime> task_by_decreasing_start_max_;
470  std::vector<TaskTime> task_by_decreasing_end_max_;
471 
472  // Sorted vector returned by GetEnergyProfile().
473  bool recompute_energy_profile_ = true;
474  std::vector<ProfileEvent> energy_profile_;
475 
476  // This one is the most commonly used, so we optimized a bit more its
477  // computation by detecting when there is nothing to do.
478  std::vector<TaskTime> task_by_increasing_shifted_start_min_;
479  std::vector<TaskTime> task_by_negated_shifted_end_max_;
480  bool recompute_shifted_start_min_ = true;
481  bool recompute_negated_shifted_end_max_ = true;
482 
483  // If recompute_cache_[t] is true, then we need to update all the cached
484  // value for the task t in SynchronizeAndSetTimeDirection().
485  bool recompute_all_cache_ = true;
486  std::vector<bool> recompute_cache_;
487 
488  // Reason vectors.
489  std::vector<Literal> literal_reason_;
490  std::vector<IntegerLiteral> integer_reason_;
491 
492  // Optional 'proxy' helper used in the diffn constraint.
493  SchedulingConstraintHelper* other_helper_ = nullptr;
494  absl::Span<const int> map_to_other_helper_;
495  IntegerValue event_for_other_helper_;
496  std::vector<bool> already_added_to_other_reasons_;
497 };
498 
499 // Helper class for cumulative constraint to wrap demands and expose concept
500 // like energy.
501 //
502 // In a cumulative constraint, an interval always has a size and a demand, but
503 // it can also have a set of "selector" literals each associated with a fixed
504 // size / fixed demands. This allows more precise energy estimation.
505 //
506 // TODO(user): Cache energy min and reason for the non O(1) cases.
508  public:
509  // Hack: this can be called with and empty demand vector as long as
510  // OverrideEnergies() is called to define the energies.
511  SchedulingDemandHelper(std::vector<AffineExpression> demands,
513 
514  // When defined, the interval will consume this much demand during its whole
515  // duration. Some propagator only relies on the "energy" and thus never uses
516  // this.
517  IntegerValue DemandMin(int t) const;
518  IntegerValue DemandMax(int t) const;
519  bool DemandIsFixed(int t) const;
520  void AddDemandMinReason(int t);
521  const std::vector<AffineExpression>& Demands() const { return demands_; }
522 
523  // Adds the linearized demand (either the affine demand expression, or the
524  // demand part of the decomposed energy if present) to the builder.
525  // It returns false and do not add any term to the builder.if any literal
526  // involved has no integer view.
527  ABSL_MUST_USE_RESULT bool AddLinearizedDemand(
528  int t, LinearConstraintBuilder* builder) const;
529 
530  // The "energy" is usually size * demand, but in some non-conventional usage
531  // it might have a more complex formula. In all case, the energy is assumed
532  // to be only consumed during the interval duration.
533  //
534  // IMPORTANT: One must call CacheAllEnergyValues() for the values to be
535  // updated. TODO(user): this is error prone, maybe we should revisit. But if
536  // there is many alternatives, we don't want to rescan the list more than a
537  // linear number of time per propagation.
538  //
539  // TODO(user): Add more complex EnergyMinBefore(time) once we also support
540  // expressing the interval as a set of alternatives.
541  //
542  // At level 0, it will filter false literals from decomposed energies.
543  void CacheAllEnergyValues();
544  IntegerValue EnergyMin(int t) const { return cached_energies_min_[t]; }
545  IntegerValue EnergyMax(int t) const { return cached_energies_max_[t]; }
546  bool EnergyIsQuadratic(int t) const { return energy_is_quadratic_[t]; }
547  void AddEnergyMinReason(int t);
548 
549  // Returns the energy min in [start, end].
550  //
551  // Note(user): These functions are not in O(1) if the decomposition is used,
552  // so we have to be careful in not calling them too often.
553  IntegerValue EnergyMinInWindow(int t, IntegerValue window_start,
554  IntegerValue window_end);
555  void AddEnergyMinInWindowReason(int t, IntegerValue window_start,
556  IntegerValue window_end);
557 
558  // Important: This might not do anything depending on the representation of
559  // the energy we have.
560  ABSL_MUST_USE_RESULT bool DecreaseEnergyMax(int t, IntegerValue value);
561 
562  // Different optional representation of the energy of an interval.
563  //
564  // Important: first value is size, second value is demand.
565  const std::vector<std::vector<LiteralValueValue>>& DecomposedEnergies()
566  const {
567  return decomposed_energies_;
568  }
569 
570  // Visible for testing.
572  const std::vector<LinearExpression>& energies);
574  const std::vector<std::vector<LiteralValueValue>>& energies);
575  // Returns the decomposed energy terms compatible with the current literal
576  // assignment. It must not be used to create reasons if not at level 0.
577  // It returns en empty vector if the decomposed energy is not available.
578  //
579  // Important: first value is size, second value is demand.
580  std::vector<LiteralValueValue> FilteredDecomposedEnergy(int index);
581 
582  private:
583  IntegerValue SimpleEnergyMin(int t) const;
584  IntegerValue LinearEnergyMin(int t) const;
585  IntegerValue SimpleEnergyMax(int t) const;
586  IntegerValue LinearEnergyMax(int t) const;
587  IntegerValue DecomposedEnergyMin(int t) const;
588  IntegerValue DecomposedEnergyMax(int t) const;
589 
590  IntegerTrail* integer_trail_;
591  SatSolver* sat_solver_; // To get the current propagation level.
592  const VariablesAssignment& assignment_;
593  std::vector<AffineExpression> demands_;
595 
596  // Cached value of the energies, as it can be a bit costly to compute.
597  std::vector<IntegerValue> cached_energies_min_;
598  std::vector<IntegerValue> cached_energies_max_;
599  std::vector<bool> energy_is_quadratic_;
600 
601  // A representation of the energies as a set of alternative.
602  // If subvector is empty, we don't have this representation.
603  std::vector<std::vector<LiteralValueValue>> decomposed_energies_;
604 
605  // A representation of the energies as a set of linear expression.
606  // If the optional is not set, we don't have this representation.
607  std::vector<std::optional<LinearExpression>> linearized_energies_;
608 };
609 
610 // =============================================================================
611 // Utilities
612 // =============================================================================
613 
614 IntegerValue ComputeEnergyMinInWindow(
615  IntegerValue start_min, IntegerValue start_max, IntegerValue end_min,
616  IntegerValue end_max, IntegerValue size_min, IntegerValue demand_min,
617  const std::vector<LiteralValueValue>& filtered_energy,
618  IntegerValue window_start, IntegerValue window_end);
619 
620 // =============================================================================
621 // SchedulingConstraintHelper inlined functions.
622 // =============================================================================
623 
625  return integer_trail_->IsFixed(starts_[t]);
626 }
627 
628 inline bool SchedulingConstraintHelper::EndIsFixed(int t) const {
629  return integer_trail_->IsFixed(ends_[t]);
630 }
631 
632 inline bool SchedulingConstraintHelper::SizeIsFixed(int t) const {
633  return integer_trail_->IsFixed(sizes_[t]);
634 }
635 
636 inline bool SchedulingConstraintHelper::IsOptional(int t) const {
637  return reason_for_presence_[t] != kNoLiteralIndex;
638 }
639 
640 inline bool SchedulingConstraintHelper::IsPresent(int t) const {
641  if (reason_for_presence_[t] == kNoLiteralIndex) return true;
642  return trail_->Assignment().LiteralIsTrue(Literal(reason_for_presence_[t]));
643 }
644 
645 inline bool SchedulingConstraintHelper::IsAbsent(int t) const {
646  if (reason_for_presence_[t] == kNoLiteralIndex) return false;
647  return trail_->Assignment().LiteralIsFalse(Literal(reason_for_presence_[t]));
648 }
649 
651  integer_reason_.clear();
652  literal_reason_.clear();
653  if (other_helper_) {
654  other_helper_->ClearReason();
655  already_added_to_other_reasons_.assign(NumTasks(), false);
656  }
657 }
658 
660  DCHECK(IsPresent(t));
661  AddOtherReason(t);
662  if (reason_for_presence_[t] != kNoLiteralIndex) {
663  literal_reason_.push_back(Literal(reason_for_presence_[t]).Negated());
664  }
665 }
666 
668  DCHECK(IsAbsent(t));
669  AddOtherReason(t);
670  if (reason_for_presence_[t] != kNoLiteralIndex) {
671  literal_reason_.push_back(Literal(reason_for_presence_[t]));
672  }
673 }
674 
676  AddSizeMinReason(t, SizeMin(t));
677 }
678 
679 inline void SchedulingConstraintHelper::AddGenericReason(
680  const AffineExpression& a, IntegerValue upper_bound,
681  const AffineExpression& b, const AffineExpression& c) {
682  if (integer_trail_->UpperBound(a) <= upper_bound) {
683  if (a.var != kNoIntegerVariable) {
684  integer_reason_.push_back(a.LowerOrEqual(upper_bound));
685  }
686  return;
687  }
688  CHECK_NE(a.var, kNoIntegerVariable);
689 
690  // Here we assume that the upper_bound on a comes from the bound on b + c.
691  const IntegerValue slack = upper_bound - integer_trail_->UpperBound(b) -
692  integer_trail_->UpperBound(c);
693  CHECK_GE(slack, 0);
694  if (b.var == kNoIntegerVariable && c.var == kNoIntegerVariable) return;
695  if (b.var == kNoIntegerVariable) {
696  integer_reason_.push_back(c.LowerOrEqual(upper_bound - b.constant));
697  } else if (c.var == kNoIntegerVariable) {
698  integer_reason_.push_back(b.LowerOrEqual(upper_bound - c.constant));
699  } else {
700  integer_trail_->AppendRelaxedLinearReason(
701  slack, {b.coeff, c.coeff}, {NegationOf(b.var), NegationOf(c.var)},
702  &integer_reason_);
703  }
704 }
705 
707  int t, IntegerValue lower_bound) {
708  AddOtherReason(t);
709  DCHECK(!IsAbsent(t));
710  if (lower_bound <= 0) return;
711  AddGenericReason(sizes_[t].Negated(), -lower_bound, minus_ends_[t],
712  starts_[t]);
713 }
714 
716  int t, IntegerValue upper_bound) {
717  AddOtherReason(t);
718  DCHECK(!IsAbsent(t));
719  AddGenericReason(sizes_[t], upper_bound, ends_[t], minus_starts_[t]);
720 }
721 
723  int t, IntegerValue lower_bound) {
724  AddOtherReason(t);
725  DCHECK(!IsAbsent(t));
726  AddGenericReason(minus_starts_[t], -lower_bound, minus_ends_[t], sizes_[t]);
727 }
728 
730  int t, IntegerValue upper_bound) {
731  AddOtherReason(t);
732  DCHECK(!IsAbsent(t));
733  AddGenericReason(starts_[t], upper_bound, ends_[t], sizes_[t].Negated());
734 }
735 
737  int t, IntegerValue lower_bound) {
738  AddOtherReason(t);
739  DCHECK(!IsAbsent(t));
740  AddGenericReason(minus_ends_[t], -lower_bound, minus_starts_[t],
741  sizes_[t].Negated());
742 }
743 
745  int t, IntegerValue upper_bound) {
746  AddOtherReason(t);
747  DCHECK(!IsAbsent(t));
748  AddGenericReason(ends_[t], upper_bound, starts_[t], sizes_[t]);
749 }
750 
752  int t, IntegerValue energy_min, IntegerValue time) {
753  if (StartMin(t) >= time) {
755  } else {
756  AddEndMinReason(t, time + energy_min);
757  }
758  AddSizeMinReason(t, energy_min);
759 }
760 
762  int t, IntegerValue time_min, IntegerValue time_max) {
763  const IntegerValue energy_min = SizeMin(t);
764  CHECK_LE(time_min + energy_min, time_max);
765  if (StartMin(t) >= time_min) {
766  AddStartMinReason(t, time_min);
767  } else {
768  AddEndMinReason(t, time_min + energy_min);
769  }
770  if (EndMax(t) <= time_max) {
771  AddEndMaxReason(t, time_max);
772  } else {
773  AddStartMaxReason(t, time_max - energy_min);
774  }
775  AddSizeMinReason(t, energy_min);
776 }
777 
778 // =============================================================================
779 // Model based functions.
780 // =============================================================================
781 
782 inline std::function<IntegerVariable(const Model&)> StartVar(
783  IntervalVariable v) {
784  return [=](const Model& model) {
785  return model.Get<IntervalsRepository>()->StartVar(v);
786  };
787 }
788 
789 inline std::function<IntegerVariable(const Model&)> EndVar(IntervalVariable v) {
790  return [=](const Model& model) {
791  return model.Get<IntervalsRepository>()->EndVar(v);
792  };
793 }
794 
795 inline std::function<IntegerVariable(const Model&)> SizeVar(
796  IntervalVariable v) {
797  return [=](const Model& model) {
798  return model.Get<IntervalsRepository>()->SizeVar(v);
799  };
800 }
801 
802 inline std::function<int64_t(const Model&)> MinSize(IntervalVariable v) {
803  return [=](const Model& model) {
804  return model.Get<IntervalsRepository>()->MinSize(v).value();
805  };
806 }
807 
808 inline std::function<int64_t(const Model&)> MaxSize(IntervalVariable v) {
809  return [=](const Model& model) {
810  return model.Get<IntervalsRepository>()->MaxSize(v).value();
811  };
812 }
813 
814 inline std::function<bool(const Model&)> IsOptional(IntervalVariable v) {
815  return [=](const Model& model) {
816  return model.Get<IntervalsRepository>()->IsOptional(v);
817  };
818 }
819 
820 inline std::function<Literal(const Model&)> IsPresentLiteral(
821  IntervalVariable v) {
822  return [=](const Model& model) {
823  return model.Get<IntervalsRepository>()->PresenceLiteral(v);
824  };
825 }
826 
827 inline std::function<IntervalVariable(Model*)> NewInterval(int64_t min_start,
828  int64_t max_end,
829  int64_t size) {
830  return [=](Model* model) {
831  return model->GetOrCreate<IntervalsRepository>()->CreateInterval(
832  model->Add(NewIntegerVariable(min_start, max_end)),
833  model->Add(NewIntegerVariable(min_start, max_end)), kNoIntegerVariable,
834  IntegerValue(size), kNoLiteralIndex);
835  };
836 }
837 
838 inline std::function<IntervalVariable(Model*)> NewInterval(
839  IntegerVariable start, IntegerVariable end, IntegerVariable size) {
840  return [=](Model* model) {
841  return model->GetOrCreate<IntervalsRepository>()->CreateInterval(
842  start, end, size, IntegerValue(0), kNoLiteralIndex);
843  };
844 }
845 
846 inline std::function<IntervalVariable(Model*)> NewIntervalWithVariableSize(
847  int64_t min_start, int64_t max_end, int64_t min_size, int64_t max_size) {
848  return [=](Model* model) {
849  return model->GetOrCreate<IntervalsRepository>()->CreateInterval(
850  model->Add(NewIntegerVariable(min_start, max_end)),
851  model->Add(NewIntegerVariable(min_start, max_end)),
852  model->Add(NewIntegerVariable(min_size, max_size)), IntegerValue(0),
854  };
855 }
856 
857 inline std::function<IntervalVariable(Model*)> NewOptionalInterval(
858  int64_t min_start, int64_t max_end, int64_t size, Literal is_present) {
859  return [=](Model* model) {
860  return model->GetOrCreate<IntervalsRepository>()->CreateInterval(
861  model->Add(NewIntegerVariable(min_start, max_end)),
862  model->Add(NewIntegerVariable(min_start, max_end)), kNoIntegerVariable,
863  IntegerValue(size), is_present.Index());
864  };
865 }
866 
867 inline std::function<IntervalVariable(Model*)>
868 NewOptionalIntervalWithOptionalVariables(int64_t min_start, int64_t max_end,
869  int64_t size, Literal is_present) {
870  return [=](Model* model) {
871  // Note that we need to mark the optionality first.
872  const IntegerVariable start =
873  model->Add(NewIntegerVariable(min_start, max_end));
874  const IntegerVariable end =
875  model->Add(NewIntegerVariable(min_start, max_end));
876  auto* integer_trail = model->GetOrCreate<IntegerTrail>();
877  integer_trail->MarkIntegerVariableAsOptional(start, is_present);
878  integer_trail->MarkIntegerVariableAsOptional(end, is_present);
879  return model->GetOrCreate<IntervalsRepository>()->CreateInterval(
880  start, end, kNoIntegerVariable, IntegerValue(size), is_present.Index());
881  };
882 }
883 
884 inline std::function<IntervalVariable(Model*)> NewOptionalInterval(
885  IntegerVariable start, IntegerVariable end, IntegerVariable size,
886  Literal is_present) {
887  return [=](Model* model) {
888  return model->GetOrCreate<IntervalsRepository>()->CreateInterval(
889  start, end, size, IntegerValue(0), is_present.Index());
890  };
891 }
892 
893 inline std::function<IntervalVariable(Model*)>
894 NewOptionalIntervalWithVariableSize(int64_t min_start, int64_t max_end,
895  int64_t min_size, int64_t max_size,
896  Literal is_present) {
897  return [=](Model* model) {
898  return model->GetOrCreate<IntervalsRepository>()->CreateInterval(
899  model->Add(NewIntegerVariable(min_start, max_end)),
900  model->Add(NewIntegerVariable(min_start, max_end)),
901  model->Add(NewIntegerVariable(min_size, max_size)), IntegerValue(0),
902  is_present.Index());
903  };
904 }
905 
906 // This requires that all the alternatives are optional tasks.
907 inline std::function<void(Model*)> IntervalWithAlternatives(
908  IntervalVariable parent, const std::vector<IntervalVariable>& members) {
909  return [=](Model* model) {
910  auto* integer_trail = model->GetOrCreate<IntegerTrail>();
911  auto* intervals = model->GetOrCreate<IntervalsRepository>();
912 
913  std::vector<Literal> presences;
914  std::vector<IntegerValue> sizes;
915 
916  // Create an "exactly one executed" constraint on the alternatives.
917  std::vector<LiteralWithCoeff> sat_ct;
918  for (const IntervalVariable member : members) {
919  CHECK(intervals->IsOptional(member));
920  const Literal is_present = intervals->PresenceLiteral(member);
921  sat_ct.push_back({is_present, Coefficient(1)});
922  model->Add(
923  Equality(model->Get(StartVar(parent)), model->Get(StartVar(member))));
924  model->Add(
925  Equality(model->Get(EndVar(parent)), model->Get(EndVar(member))));
926 
927  // TODO(user): IsOneOf() only work for members with fixed size.
928  // Generalize to an "int_var_element" constraint.
929  CHECK(integer_trail->IsFixed(intervals->Size(member)));
930  presences.push_back(is_present);
931  sizes.push_back(intervals->MinSize(member));
932  }
933  if (intervals->SizeVar(parent) != kNoIntegerVariable) {
934  model->Add(IsOneOf(intervals->SizeVar(parent), presences, sizes));
935  }
936  model->Add(BooleanLinearConstraint(1, 1, &sat_ct));
937 
938  // Propagate from the candidate bounds to the parent interval ones.
939  {
940  std::vector<IntegerVariable> starts;
941  starts.reserve(members.size());
942  for (const IntervalVariable member : members) {
943  starts.push_back(intervals->StartVar(member));
944  }
945  model->Add(
946  PartialIsOneOfVar(intervals->StartVar(parent), starts, presences));
947  }
948  {
949  std::vector<IntegerVariable> ends;
950  ends.reserve(members.size());
951  for (const IntervalVariable member : members) {
952  ends.push_back(intervals->EndVar(member));
953  }
954  model->Add(PartialIsOneOfVar(intervals->EndVar(parent), ends, presences));
955  }
956  };
957 }
958 
959 } // namespace sat
960 } // namespace operations_research
961 
962 #endif // OR_TOOLS_SAT_INTERVALS_H_
int64_t max
Definition: alldiff_cst.cc:140
int64_t min
Definition: alldiff_cst.cc:139
An Assignment is a variable -> domains mapping, used to report solutions to the user.
bool IsFixed(IntegerVariable i) const
Definition: integer.h:1565
IntegerValue UpperBound(IntegerVariable i) const
Definition: integer.h:1561
void MarkIntegerVariableAsOptional(IntegerVariable i, Literal is_considered)
Definition: integer.h:789
void AppendRelaxedLinearReason(IntegerValue slack, absl::Span< const IntegerValue > coeffs, absl::Span< const IntegerVariable > vars, std::vector< IntegerLiteral > *reason) const
Definition: integer.cc:1006
IntegerValue LowerBound(IntegerVariable i) const
Definition: integer.h:1557
bool IsOptional(IntegerVariable i) const
Definition: integer.h:772
IntegerVariable SizeVar(IntervalVariable i) const
Definition: intervals.h:104
AffineExpression End(IntervalVariable i) const
Definition: intervals.h:101
IntegerValue MaxSize(IntervalVariable i) const
Definition: intervals.h:132
AffineExpression Start(IntervalVariable i) const
Definition: intervals.h:100
Literal PresenceLiteral(IntervalVariable i) const
Definition: intervals.h:80
IntegerVariable StartVar(IntervalVariable i) const
Definition: intervals.h:111
IntegerValue MinSize(IntervalVariable i) const
Definition: intervals.h:127
IntegerVariable EndVar(IntervalVariable i) const
Definition: intervals.h:118
bool IsPresent(IntervalVariable i) const
Definition: intervals.h:83
AffineExpression Size(IntervalVariable i) const
Definition: intervals.h:99
std::vector< IntervalVariable > AllIntervals() const
Definition: intervals.h:137
bool IsAbsent(IntervalVariable i) const
Definition: intervals.h:87
bool IsOptional(IntervalVariable i) const
Definition: intervals.h:77
SchedulingConstraintHelper * GetOrCreateHelper(const std::vector< IntervalVariable > &variables)
Definition: intervals.cc:116
IntervalVariable CreateInterval(IntegerVariable start, IntegerVariable end, IntegerVariable size, IntegerValue fixed_size, LiteralIndex is_present)
Definition: intervals.cc:39
LiteralIndex Index() const
Definition: sat_base.h:90
Class that owns everything related to a particular optimization model.
Definition: sat/model.h:42
ABSL_MUST_USE_RESULT bool PushIntegerLiteral(IntegerLiteral lit)
Definition: intervals.cc:496
const std::vector< TaskTime > & TaskByDecreasingEndMax()
Definition: intervals.cc:386
ABSL_MUST_USE_RESULT bool PushTaskAbsence(int t)
Definition: intervals.cc:552
SchedulingConstraintHelper(const std::vector< IntervalVariable > &tasks, Model *model)
Definition: intervals.cc:80
ABSL_MUST_USE_RESULT bool IncreaseStartMin(int t, IntegerValue value)
Definition: intervals.cc:523
ABSL_MUST_USE_RESULT bool DecreaseEndMax(int t, IntegerValue value)
Definition: intervals.cc:539
const std::vector< TaskTime > & TaskByIncreasingStartMin()
Definition: intervals.cc:349
void AddStartMinReason(int t, IntegerValue lower_bound)
Definition: intervals.h:722
void WatchAllTasks(int id, GenericLiteralWatcher *watcher, bool watch_start_max=true, bool watch_end_max=true) const
Definition: intervals.cc:589
bool IncrementalPropagate(const std::vector< int > &watch_indices) final
Definition: intervals.cc:142
const std::vector< TaskTime > & TaskByIncreasingEndMin()
Definition: intervals.cc:361
ABSL_MUST_USE_RESULT bool IncreaseEndMin(int t, IntegerValue value)
Definition: intervals.cc:531
std::vector< IntegerLiteral > * MutableIntegerReason()
Definition: intervals.h:348
ABSL_MUST_USE_RESULT bool ResetFromSubset(const SchedulingConstraintHelper &other, absl::Span< const int > tasks)
Definition: intervals.cc:251
void AddEnergyAfterReason(int t, IntegerValue energy_min, IntegerValue time)
Definition: intervals.h:751
ABSL_MUST_USE_RESULT bool PushIntegerLiteralIfTaskPresent(int t, IntegerLiteral lit)
Definition: intervals.cc:501
void RegisterWith(GenericLiteralWatcher *watcher)
Definition: intervals.cc:161
void AddEndMinReason(int t, IntegerValue lower_bound)
Definition: intervals.h:736
IntegerValue GetMinOverlap(int t, IntegerValue start, IntegerValue end) const
Definition: intervals.cc:640
void AddSizeMaxReason(int t, IntegerValue upper_bound)
Definition: intervals.h:715
ABSL_MUST_USE_RESULT bool PushLiteral(Literal l)
Definition: intervals.cc:547
const std::vector< AffineExpression > & Starts() const
Definition: intervals.h:373
void SetOtherHelper(SchedulingConstraintHelper *other_helper, absl::Span< const int > map_to_other_helper, IntegerValue event)
Definition: intervals.h:392
const std::vector< ProfileEvent > & GetEnergyProfile()
Definition: intervals.cc:419
ABSL_MUST_USE_RESULT bool SynchronizeAndSetTimeDirection(bool is_forward)
Definition: intervals.cc:330
const std::vector< TaskTime > & TaskByDecreasingStartMax()
Definition: intervals.cc:373
ABSL_MUST_USE_RESULT bool PushTaskPresence(int t)
Definition: intervals.cc:568
void AddEndMaxReason(int t, IntegerValue upper_bound)
Definition: intervals.h:744
void AddEnergyMinInIntervalReason(int t, IntegerValue min, IntegerValue max)
Definition: intervals.h:761
const std::vector< TaskTime > & TaskByIncreasingShiftedStartMin()
Definition: intervals.cc:398
void AddReasonForBeingBefore(int before, int after)
Definition: intervals.cc:444
const std::vector< AffineExpression > & Sizes() const
Definition: intervals.h:375
void AddStartMaxReason(int t, IntegerValue upper_bound)
Definition: intervals.h:729
const std::vector< AffineExpression > & Ends() const
Definition: intervals.h:374
void OverrideLinearizedEnergies(const std::vector< LinearExpression > &energies)
Definition: intervals.cc:876
SchedulingDemandHelper(std::vector< AffineExpression > demands, SchedulingConstraintHelper *helper, Model *model)
Definition: intervals.cc:678
void AddEnergyMinInWindowReason(int t, IntegerValue window_start, IntegerValue window_end)
Definition: intervals.cc:924
ABSL_MUST_USE_RESULT bool AddLinearizedDemand(int t, LinearConstraintBuilder *builder) const
Definition: intervals.cc:858
const std::vector< std::vector< LiteralValueValue > > & DecomposedEnergies() const
Definition: intervals.h:565
std::vector< LiteralValueValue > FilteredDecomposedEnergy(int index)
Definition: intervals.cc:891
ABSL_MUST_USE_RESULT bool DecreaseEnergyMax(int t, IntegerValue value)
Definition: intervals.cc:792
const std::vector< AffineExpression > & Demands() const
Definition: intervals.h:521
void OverrideDecomposedEnergies(const std::vector< std::vector< LiteralValueValue >> &energies)
Definition: intervals.cc:908
IntegerValue EnergyMinInWindow(int t, IntegerValue window_start, IntegerValue window_end)
Definition: intervals.cc:914
const VariablesAssignment & Assignment() const
Definition: sat_base.h:402
bool LiteralIsTrue(Literal literal) const
Definition: sat_base.h:164
bool LiteralIsFalse(Literal literal) const
Definition: sat_base.h:161
int64_t b
int64_t a
int64_t value
IntVar * var
Definition: expr_array.cc:1874
GRBmodel * model
int index
std::tuple< int64_t, int64_t, const double > Coefficient
std::function< IntegerVariable(const Model &)> SizeVar(IntervalVariable v)
Definition: intervals.h:795
DEFINE_STRONG_INDEX_TYPE(ClauseIndex)
std::function< IntervalVariable(Model *)> NewInterval(int64_t min_start, int64_t max_end, int64_t size)
Definition: intervals.h:827
std::function< IntervalVariable(Model *)> NewOptionalIntervalWithVariableSize(int64_t min_start, int64_t max_end, int64_t min_size, int64_t max_size, Literal is_present)
Definition: intervals.h:894
std::function< Literal(const Model &)> IsPresentLiteral(IntervalVariable v)
Definition: intervals.h:820
const LiteralIndex kNoLiteralIndex(-1)
std::function< void(Model *)> PartialIsOneOfVar(IntegerVariable target_var, const std::vector< IntegerVariable > &vars, const std::vector< Literal > &selectors)
std::function< void(Model *)> IsOneOf(IntegerVariable var, const std::vector< Literal > &selectors, const std::vector< IntegerValue > &values)
const IntegerVariable kNoIntegerVariable(-1)
const IntervalVariable kNoIntervalVariable(-1)
std::function< IntegerVariable(const Model &)> EndVar(IntervalVariable v)
Definition: intervals.h:789
std::function< IntervalVariable(Model *)> NewIntervalWithVariableSize(int64_t min_start, int64_t max_end, int64_t min_size, int64_t max_size)
Definition: intervals.h:846
std::function< int64_t(const Model &)> MinSize(IntervalVariable v)
Definition: intervals.h:802
std::function< int64_t(const Model &)> MaxSize(IntervalVariable v)
Definition: intervals.h:808
std::function< bool(const Model &)> IsOptional(IntervalVariable v)
Definition: intervals.h:814
std::function< void(Model *)> BooleanLinearConstraint(int64_t lower_bound, int64_t upper_bound, std::vector< LiteralWithCoeff > *cst)
Definition: sat_solver.h:893
std::function< IntegerVariable(Model *)> NewIntegerVariable(int64_t lb, int64_t ub)
Definition: integer.h:1734
IntegerValue ComputeEnergyMinInWindow(IntegerValue start_min, IntegerValue start_max, IntegerValue end_min, IntegerValue end_max, IntegerValue size_min, IntegerValue demand_min, const std::vector< LiteralValueValue > &filtered_energy, IntegerValue window_start, IntegerValue window_end)
Definition: intervals.cc:647
std::function< IntegerVariable(const Model &)> StartVar(IntervalVariable v)
Definition: intervals.h:782
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
Definition: integer.cc:46
std::function< void(Model *)> Equality(IntegerVariable v, int64_t value)
Definition: integer.h:1832
std::function< void(Model *)> IntervalWithAlternatives(IntervalVariable parent, const std::vector< IntervalVariable > &members)
Definition: intervals.h:907
std::function< IntervalVariable(Model *)> NewOptionalInterval(int64_t min_start, int64_t max_end, int64_t size, Literal is_present)
Definition: intervals.h:857
std::function< IntervalVariable(Model *)> NewOptionalIntervalWithOptionalVariables(int64_t min_start, int64_t max_end, int64_t size, Literal is_present)
Definition: intervals.h:868
Collection of objects used to extend the Constraint Solver library.
int64_t time
Definition: resource.cc:1694
IntVar * upper_bound
Definition: routing.cc:1087
IntVar * lower_bound
Definition: routing.cc:1086
Rev< int64_t > start_max
Rev< int64_t > end_max
Rev< int64_t > start_min
Rev< int64_t > end_min
std::optional< int64_t > end
int64_t start
IntegerLiteral LowerOrEqual(IntegerValue bound) const
Definition: integer.h:1544
bool operator<(TaskTime other) const
Definition: intervals.h:180
bool operator>(TaskTime other) const
Definition: intervals.h:181