Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
intervals.h
Go to the documentation of this file.
1// Copyright 2010-2024 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 <memory>
20#include <optional>
21#include <string>
22#include <utility>
23#include <vector>
24
25#include "absl/base/attributes.h"
26#include "absl/container/flat_hash_map.h"
27#include "absl/log/check.h"
28#include "absl/strings/string_view.h"
29#include "absl/types/span.h"
33#include "ortools/sat/integer.h"
36#include "ortools/sat/model.h"
41#include "ortools/util/rev.h"
43
44namespace operations_research {
45namespace sat {
46
47DEFINE_STRONG_INDEX_TYPE(IntervalVariable);
48const IntervalVariable kNoIntervalVariable(-1);
49
52
53// This class maintains a set of intervals which correspond to three integer
54// variables (start, end and size). It automatically registers with the
55// PrecedencesPropagator the relation between the bounds of each interval and
56// provides many helper functions to add precedences relation between intervals.
58 public:
60 : model_(model),
61 assignment_(model->GetOrCreate<Trail>()->Assignment()),
62 sat_solver_(model->GetOrCreate<SatSolver>()),
63 implications_(model->GetOrCreate<BinaryImplicationGraph>()),
64 integer_trail_(model->GetOrCreate<IntegerTrail>()) {}
65
66 // This type is neither copyable nor movable.
69
70 // Returns the current number of intervals in the repository.
71 // The interval will always be identified by an integer in [0, num_intervals).
72 int NumIntervals() const { return starts_.size(); }
73
74 // Functions to add a new interval to the repository.
75 // If add_linear_relation is true, then we also link start, size and end.
76 //
77 // - If size == kNoIntegerVariable, then the size is fixed to fixed_size.
78 // - If is_present != kNoLiteralIndex, then this is an optional interval.
79 IntervalVariable CreateInterval(IntegerVariable start, IntegerVariable end,
80 IntegerVariable size, IntegerValue fixed_size,
81 LiteralIndex is_present);
84 LiteralIndex is_present = kNoLiteralIndex,
85 bool add_linear_relation = false);
86
87 // Returns whether or not a interval is optional and the associated literal.
88 bool IsOptional(IntervalVariable i) const {
89 return is_present_[i] != kNoLiteralIndex;
90 }
91 Literal PresenceLiteral(IntervalVariable i) const {
92 return Literal(is_present_[i]);
93 }
94 bool IsPresent(IntervalVariable i) const {
95 if (!IsOptional(i)) return true;
96 return assignment_.LiteralIsTrue(PresenceLiteral(i));
97 }
98 bool IsAbsent(IntervalVariable i) const {
99 if (!IsOptional(i)) return false;
100 return assignment_.LiteralIsFalse(PresenceLiteral(i));
101 }
102
103 // The 3 integer variables associated to a interval.
104 // Fixed size intervals will have a kNoIntegerVariable as size.
105 //
106 // Note: For an optional interval, the start/end variables are propagated
107 // assuming the interval is present. Because of that, these variables can
108 // cross each other or have an empty domain. If any of this happen, then the
109 // PresenceLiteral() of this interval will be propagated to false.
110 AffineExpression Size(IntervalVariable i) const { return sizes_[i]; }
111 AffineExpression Start(IntervalVariable i) const { return starts_[i]; }
112 AffineExpression End(IntervalVariable i) const { return ends_[i]; }
113
114 // Return the minimum size of the given IntervalVariable.
115 IntegerValue MinSize(IntervalVariable i) const {
116 return integer_trail_->LowerBound(sizes_[i]);
117 }
118
119 // Return the maximum size of the given IntervalVariable.
120 IntegerValue MaxSize(IntervalVariable i) const {
121 return integer_trail_->UpperBound(sizes_[i]);
122 }
123
124 // Utility function that returns a vector will all intervals.
125 std::vector<IntervalVariable> AllIntervals() const {
126 std::vector<IntervalVariable> result;
127 for (IntervalVariable i(0); i < NumIntervals(); ++i) {
128 result.push_back(i);
129 }
130 return result;
131 }
132
133 // Returns a SchedulingConstraintHelper corresponding to the given variables.
134 // Note that the order of interval in the helper will be the same.
135 //
136 // It is possible to indicate that this correspond to a disjunctive constraint
137 // by setting the Boolean to true. This is used by our scheduling heuristic
138 // based on precedences.
140 const std::vector<IntervalVariable>& variables,
141 bool register_as_disjunctive_helper = false);
142
143 // Returns a SchedulingDemandHelper corresponding to the given helper and
144 // demands. Note that the order of interval in the helper and the order of
145 // demands must be the compatible.
148 absl::Span<const AffineExpression> demands);
149
150 // Calls InitDecomposedEnergies on all SchedulingDemandHelper created.
152
153 // Assuming a and b cannot overlap if they are present, this create a new
154 // literal such that:
155 // - literal & presences => a is before b.
156 // - not(literal) & presences => b is before a.
157 // - not present => literal @ true for disallowing multiple solutions.
158 //
159 // If such literal already exists this returns it.
160 void CreateDisjunctivePrecedenceLiteral(IntervalVariable a,
161 IntervalVariable b);
162
163 // Creates a literal l <=> start_b >= end_a.
164 // Returns true if such literal is "non-trivial" and was created.
165 // Note that this ignore the optionality of a or b, it just creates a literal
166 // comparing the two affine expression.
167 bool CreatePrecedenceLiteral(IntervalVariable a, IntervalVariable b);
168
169 // Returns a literal l <=> start_b >= end_a if it exist or kNoLiteralIndex
170 // otherwise. This could be the one created by
171 // CreateDisjunctivePrecedenceLiteral() or CreatePrecedenceLiteral().
172 LiteralIndex GetPrecedenceLiteral(IntervalVariable a,
173 IntervalVariable b) const;
174
175 const std::vector<SchedulingConstraintHelper*>& AllDisjunctiveHelpers()
176 const {
177 return disjunctive_helpers_;
178 }
179
180 // We register cumulative at load time so that our search heuristic can loop
181 // over all cumulative constraints easily.
188 cumulative_helpers_.push_back(helper);
189 }
190 const std::vector<CumulativeHelper>& AllCumulativeHelpers() const {
191 return cumulative_helpers_;
192 }
193
194 private:
195 // External classes needed.
196 Model* model_;
197 const VariablesAssignment& assignment_;
198 SatSolver* sat_solver_;
199 BinaryImplicationGraph* implications_;
200 IntegerTrail* integer_trail_;
201
202 // Literal indicating if the tasks is executed. Tasks that are always executed
203 // will have a kNoLiteralIndex entry in this vector.
205
206 // The integer variables for each tasks.
210
211 // We can share the helper for all the propagators that work on the same set
212 // of intervals.
213 absl::flat_hash_map<std::vector<IntervalVariable>,
215 helper_repository_;
216 absl::flat_hash_map<
217 std::pair<SchedulingConstraintHelper*, std::vector<AffineExpression>>,
219 demand_helper_repository_;
220
221 // Disjunctive and normal precedences.
222 //
223 // Note that for normal precedences, we use directly the affine expression so
224 // that if many intervals share the same start, we don't re-create Booleans
225 // for no reason.
226 absl::flat_hash_map<std::pair<IntervalVariable, IntervalVariable>, Literal>
227 disjunctive_precedences_;
228 absl::flat_hash_map<std::pair<AffineExpression, AffineExpression>, Literal>
229 precedences_;
230
231 // Disjunctive/Cumulative helpers_.
232 std::vector<SchedulingConstraintHelper*> disjunctive_helpers_;
233 std::vector<CumulativeHelper> cumulative_helpers_;
234};
235
236// An helper struct to sort task by time. This is used by the
237// SchedulingConstraintHelper but also by many scheduling propagators to sort
238// tasks.
239struct TaskTime {
241 IntegerValue time;
242 bool operator<(TaskTime other) const { return time < other.time; }
243 bool operator>(TaskTime other) const { return time > other.time; }
244};
245
246// We have some free space in TaskTime.
247// We stick the presence_lit to save an indirection in some algo.
248//
249// TODO(user): Experiment caching more value. In particular
250// TaskByIncreasingShiftedStartMin() could tie break task for better heuristics?
253 LiteralIndex presence_lit;
254 IntegerValue time;
255 bool operator<(CachedTaskBounds other) const { return time < other.time; }
256 bool operator>(CachedTaskBounds other) const { return time > other.time; }
257};
258
259// Helper class shared by the propagators that manage a given list of tasks.
260//
261// One of the main advantage of this class is that it allows to share the
262// vectors of tasks sorted by various criteria between propagator for a faster
263// code.
265 public:
266 // All the functions below refer to a task by its index t in the tasks
267 // vector given at construction.
268 SchedulingConstraintHelper(const std::vector<IntervalVariable>& tasks,
269 Model* model);
270
271 // Temporary constructor.
272 // The class will not be usable until ResetFromSubset() is called.
273 //
274 // TODO(user): Remove this. It is a hack because the disjunctive class needs
275 // to fetch the maximum possible number of task at construction.
276 SchedulingConstraintHelper(int num_tasks, Model* model);
277
278 // This is a propagator so we can "cache" all the intervals relevant
279 // information. This gives good speedup. Note however that the info is stale
280 // except if a bound was pushed by this helper or if this was called. We run
281 // it at the highest priority, so that will mostly be the case at the
282 // beginning of each Propagate() call of the classes using this.
283 bool Propagate() final;
284 bool IncrementalPropagate(const std::vector<int>& watch_indices) final;
285 void RegisterWith(GenericLiteralWatcher* watcher);
286
287 // Resets the class to the same state as if it was constructed with
288 // the given subset of tasks from other.
289 ABSL_MUST_USE_RESULT bool ResetFromSubset(
290 const SchedulingConstraintHelper& other, absl::Span<const int> tasks);
291
292 // Returns the number of task.
293 int NumTasks() const { return starts_.size(); }
294
295 // Make sure the cached values are up to date. Also sets the time direction to
296 // either forward/backward. This will impact all the functions below. This
297 // MUST be called at the beginning of all Propagate() call that uses this
298 // helper.
299 void SetTimeDirection(bool is_forward);
300 bool CurrentTimeIsForward() const { return current_time_direction_; }
301 ABSL_MUST_USE_RESULT bool SynchronizeAndSetTimeDirection(bool is_forward);
302
303 // Helpers for the current bounds on the current task time window.
304 // [ (size-min) ... (size-min) ]
305 // ^ ^ ^ ^
306 // start-min end-min start-max end-max
307 //
308 // Note that for tasks with variable durations, we don't necessarily have
309 // duration-min between the XXX-min and XXX-max value.
310 //
311 // Remark: We use cached values for most of these function as this is faster.
312 // In practice, the cache will almost always be up to date, but not in corner
313 // cases where pushing the start of one task will change values for many
314 // others. This is fine as the new values will be picked up as we reach the
315 // propagation fixed point.
316 IntegerValue SizeMin(int t) const { return cached_size_min_[t]; }
317 IntegerValue SizeMax(int t) const {
318 // This one is "rare" so we don't cache it.
319 return integer_trail_->UpperBound(sizes_[t]);
320 }
321 IntegerValue StartMin(int t) const { return cached_start_min_[t]; }
322 IntegerValue EndMin(int t) const { return cached_end_min_[t]; }
323 IntegerValue StartMax(int t) const { return -cached_negated_start_max_[t]; }
324 IntegerValue EndMax(int t) const { return -cached_negated_end_max_[t]; }
325
326 IntegerValue LevelZeroStartMin(int t) const {
327 return integer_trail_->LevelZeroLowerBound(starts_[t]);
328 }
329 IntegerValue LevelZeroStartMax(int t) const {
330 return integer_trail_->LevelZeroUpperBound(starts_[t]);
331 }
332 IntegerValue LevelZeroEndMax(int t) const {
333 return integer_trail_->LevelZeroUpperBound(ends_[t]);
334 }
335
336 // In the presence of tasks with a variable size, we do not necessarily
337 // have start_min + size_min = end_min, we can instead have a situation
338 // like:
339 // | |<--- size-min --->|
340 // ^ ^ ^
341 // start-min | end-min
342 // |
343 // We define the "shifted start min" to be the right most time such that
344 // we known that we must have min-size "energy" to the right of it if the
345 // task is present. Using it in our scheduling propagators allows to propagate
346 // more in the presence of tasks with variable size (or optional task
347 // where we also do not necessarily have start_min + size_min = end_min.
348 //
349 // To explain this shifted start min, one must use the AddEnergyAfterReason().
350 IntegerValue ShiftedStartMin(int t) const {
351 return cached_shifted_start_min_[t];
352 }
353
354 // As with ShiftedStartMin(), we can compute the shifted end max (that is
355 // start_max + size_min.
356 IntegerValue ShiftedEndMax(int t) const {
357 return -cached_negated_shifted_end_max_[t];
358 }
359
360 bool StartIsFixed(int t) const;
361 bool EndIsFixed(int t) const;
362 bool SizeIsFixed(int t) const;
363
364 // Returns true if the corresponding fact is known for sure. A normal task is
365 // always present. For optional task for which the presence is still unknown,
366 // both of these function will return false.
367 bool IsOptional(int t) const;
368 bool IsPresent(int t) const;
369 bool IsAbsent(int t) const;
370
371 // Same if one already have the presence LiteralIndex of a task.
372 bool IsOptional(LiteralIndex lit) const;
373 bool IsPresent(LiteralIndex lit) const;
374 bool IsAbsent(LiteralIndex lit) const;
375
376 // Return a value so that End(a) + dist <= Start(b).
377 // Returns kMinInterValue if we don't have any such relation.
379 int a, int b, bool add_reason_if_after = false);
380
381 // We detected a precedence between two tasks.
382 // If we are at level zero, we might want to add the constraint.
383 // If we are at positive level, we might want to propagate the associated
384 // precedence literal if it exists.
385 bool PropagatePrecedence(int a, int b);
386
387 // Return the minimum overlap of interval i with the time window [start..end].
388 //
389 // Note: this is different from the mandatory part of an interval.
390 IntegerValue GetMinOverlap(int t, IntegerValue start, IntegerValue end) const;
391
392 // Returns a string with the current task bounds.
393 std::string TaskDebugString(int t) const;
394
395 // Sorts and returns the tasks in corresponding order at the time of the call.
396 // Note that we do not mean strictly-increasing/strictly-decreasing, there
397 // will be duplicate time values in these vectors.
398 //
399 // TODO(user): we could merge the first loop of IncrementalSort() with the
400 // loop that fill TaskTime.time at each call.
401 absl::Span<const TaskTime> TaskByIncreasingStartMin();
402 absl::Span<const TaskTime> TaskByDecreasingEndMax();
403
404 absl::Span<const TaskTime> TaskByIncreasingNegatedStartMax();
405 absl::Span<const TaskTime> TaskByIncreasingEndMin();
406
407 absl::Span<const CachedTaskBounds> TaskByIncreasingShiftedStartMin();
408
409 // Returns a sorted vector where each task appear twice, the first occurrence
410 // is at size (end_min - size_min) and the second one at (end_min).
411 //
412 // This is quite usage specific.
414 IntegerValue time;
415 int task;
417
418 bool operator<(const ProfileEvent& other) const {
419 if (time == other.time) {
420 if (task == other.task) return is_first > other.is_first;
421 return task < other.task;
422 }
423 return time < other.time;
424 }
425 };
426 const std::vector<ProfileEvent>& GetEnergyProfile();
427
428 // Functions to clear and then set the current reason.
429 void ClearReason();
430 void AddPresenceReason(int t);
431 void AddAbsenceReason(int t);
432 void AddSizeMinReason(int t);
433 void AddSizeMinReason(int t, IntegerValue lower_bound);
434 void AddSizeMaxReason(int t, IntegerValue upper_bound);
435 void AddStartMinReason(int t, IntegerValue lower_bound);
436 void AddStartMaxReason(int t, IntegerValue upper_bound);
437 void AddEndMinReason(int t, IntegerValue lower_bound);
438 void AddEndMaxReason(int t, IntegerValue upper_bound);
439 void AddShiftedEndMaxReason(int t, IntegerValue upper_bound);
440
441 void AddEnergyAfterReason(int t, IntegerValue energy_min, IntegerValue time);
442 void AddEnergyMinInIntervalReason(int t, IntegerValue min, IntegerValue max);
443
444 // Adds the reason why task "before" must be before task "after".
445 // That is StartMax(before) < EndMin(after).
446 void AddReasonForBeingBefore(int before, int after);
447
448 // It is also possible to directly manipulates the underlying reason vectors
449 // that will be used when pushing something.
450 std::vector<Literal>* MutableLiteralReason() { return &literal_reason_; }
451 std::vector<IntegerLiteral>* MutableIntegerReason() {
452 return &integer_reason_;
453 }
454
455 // Push something using the current reason. Note that IncreaseStartMin() will
456 // also increase the end-min, and DecreaseEndMax() will also decrease the
457 // start-max.
458 //
459 // Important: IncreaseStartMin() and DecreaseEndMax() can be called on an
460 // optional interval whose presence is still unknown and push a bound
461 // conditioned on its presence. The functions will do the correct thing
462 // depending on whether or not the start_min/end_max are optional variables
463 // whose presence implies the interval presence.
464 ABSL_MUST_USE_RESULT bool IncreaseStartMin(int t, IntegerValue value);
465 ABSL_MUST_USE_RESULT bool IncreaseEndMin(int t, IntegerValue value);
466 ABSL_MUST_USE_RESULT bool DecreaseEndMax(int t, IntegerValue value);
467 ABSL_MUST_USE_RESULT bool PushLiteral(Literal l);
468 ABSL_MUST_USE_RESULT bool PushTaskAbsence(int t);
469 ABSL_MUST_USE_RESULT bool PushTaskPresence(int t);
470 ABSL_MUST_USE_RESULT bool PushIntegerLiteral(IntegerLiteral lit);
471 ABSL_MUST_USE_RESULT bool ReportConflict();
472 ABSL_MUST_USE_RESULT bool PushIntegerLiteralIfTaskPresent(int t,
474
475 // Returns the underlying affine expressions.
476 absl::Span<const IntervalVariable> IntervalVariables() const {
477 return interval_variables_;
478 }
479 absl::Span<const AffineExpression> Starts() const { return starts_; }
480 absl::Span<const AffineExpression> Ends() const { return ends_; }
481 absl::Span<const AffineExpression> Sizes() const { return sizes_; }
482
484 DCHECK(IsOptional(index));
485 return Literal(reason_for_presence_[index]);
486 }
487
488 // Registers the given propagator id to be called if any of the tasks
489 // in this class change. Note that we do not watch size max though.
490 void WatchAllTasks(int id, bool watch_max_side = true);
491
492 // Manages the other helper (used by the diffn constraint).
493 //
494 // For each interval appearing in a reason on this helper, another reason
495 // will be added. This other reason specifies that on the other helper, the
496 // corresponding interval overlaps 'event'.
498 absl::Span<const int> map_to_other_helper,
499 IntegerValue event) {
500 CHECK(other_helper != nullptr);
501 other_helper_ = other_helper;
502 map_to_other_helper_ = map_to_other_helper;
503 event_for_other_helper_ = event;
504 }
505
506 bool HasOtherHelper() const { return other_helper_ != nullptr; }
507
508 void ClearOtherHelper() { other_helper_ = nullptr; }
509
510 // Adds to this helper reason all the explanation of the other helper.
511 // This checks that other_helper_ is null.
512 //
513 // This is used in the 2D energetic reasoning in the diffn constraint.
514 void ImportOtherReasons(const SchedulingConstraintHelper& other_helper);
515
516 // TODO(user): Change the propagation loop code so that we don't stop
517 // pushing in the middle of the propagation as more advanced propagator do
518 // not handle this correctly.
519 bool InPropagationLoop() const { return integer_trail_->InPropagationLoop(); }
520
521 int CurrentDecisionLevel() const { return trail_->CurrentDecisionLevel(); }
522
523 private:
524 // Generic reason for a <= upper_bound, given that a = b + c in case the
525 // current upper bound of a is not good enough.
526 void AddGenericReason(const AffineExpression& a, IntegerValue upper_bound,
527 const AffineExpression& b, const AffineExpression& c);
528
529 void InitSortedVectors();
530 ABSL_MUST_USE_RESULT bool UpdateCachedValues(int t);
531
532 // Internal function for IncreaseStartMin()/DecreaseEndMax().
533 bool PushIntervalBound(int t, IntegerLiteral lit);
534
535 // This will be called on any interval that is part of a reason or
536 // a bound push. Since the last call to ClearReason(), for each unique
537 // t, we will add once to other_helper_ the reason for t containing
538 // the point event_for_other_helper_.
539 void AddOtherReason(int t);
540
541 // Import the reasons on the other helper into this helper.
542 void ImportOtherReasons();
543
544 Model* model_;
545 Trail* trail_;
546 SatSolver* sat_solver_;
547 IntegerTrail* integer_trail_;
548 GenericLiteralWatcher* watcher_;
549 PrecedenceRelations* precedence_relations_;
550
551 // The current direction of time, true for forward, false for backward.
552 bool current_time_direction_ = true;
553
554 // All the underlying variables of the tasks.
555 // The vectors are indexed by the task index t.
556 std::vector<IntervalVariable> interval_variables_;
557 std::vector<AffineExpression> starts_;
558 std::vector<AffineExpression> ends_;
559 std::vector<AffineExpression> sizes_;
560 std::vector<LiteralIndex> reason_for_presence_;
561
562 // The negation of the start/end variable so that SetTimeDirection()
563 // can do its job in O(1) instead of calling NegationOf() on each entry.
564 std::vector<AffineExpression> minus_starts_;
565 std::vector<AffineExpression> minus_ends_;
566
567 // This is used to detect when we need to invalidate the cache.
568 int64_t saved_num_backtracks_ = 0;
569
570 // The caches of all relevant interval values.
571 // These are initially of size capacity and never resized.
572 //
573 // TODO(user): Because of std::swap() in SetTimeDirection, we cannot mark
574 // most of them as "const" and as a result we loose some performance since
575 // the address need to be re-fetched on most access.
576 const int capacity_;
577 const std::unique_ptr<IntegerValue[]> cached_size_min_;
578 std::unique_ptr<IntegerValue[]> cached_start_min_;
579 std::unique_ptr<IntegerValue[]> cached_end_min_;
580 std::unique_ptr<IntegerValue[]> cached_negated_start_max_;
581 std::unique_ptr<IntegerValue[]> cached_negated_end_max_;
582 std::unique_ptr<IntegerValue[]> cached_shifted_start_min_;
583 std::unique_ptr<IntegerValue[]> cached_negated_shifted_end_max_;
584
585 // Sorted vectors returned by the TasksBy*() functions.
586 std::vector<TaskTime> task_by_increasing_start_min_;
587 std::vector<TaskTime> task_by_decreasing_end_max_;
588
589 bool recompute_by_start_max_ = true;
590 bool recompute_by_end_min_ = true;
591 std::vector<TaskTime> task_by_increasing_negated_start_max_;
592 std::vector<TaskTime> task_by_increasing_end_min_;
593
594 // Sorted vector returned by GetEnergyProfile().
595 bool recompute_energy_profile_ = true;
596 std::vector<ProfileEvent> energy_profile_;
597
598 // This one is the most commonly used, so we optimized a bit more its
599 // computation by detecting when there is nothing to do.
600 std::vector<CachedTaskBounds> task_by_increasing_shifted_start_min_;
601 std::vector<CachedTaskBounds> task_by_negated_shifted_end_max_;
602 bool recompute_shifted_start_min_ = true;
603 bool recompute_negated_shifted_end_max_ = true;
604
605 // If recompute_cache_[t] is true, then we need to update all the cached
606 // value for the task t in SynchronizeAndSetTimeDirection().
607 bool recompute_all_cache_ = true;
608 Bitset64<int> recompute_cache_;
609
610 // Reason vectors.
611 std::vector<Literal> literal_reason_;
612 std::vector<IntegerLiteral> integer_reason_;
613
614 // Optional 'proxy' helper used in the diffn constraint.
615 SchedulingConstraintHelper* other_helper_ = nullptr;
616 absl::Span<const int> map_to_other_helper_;
617 IntegerValue event_for_other_helper_;
618 std::vector<bool> already_added_to_other_reasons_;
619
620 // List of watcher to "wake-up" each time one of the task bounds changes.
621 std::vector<int> propagator_ids_;
622};
623
624// Helper class for cumulative constraint to wrap demands and expose concept
625// like energy.
626//
627// In a cumulative constraint, an interval always has a size and a demand, but
628// it can also have a set of "selector" literals each associated with a fixed
629// size / fixed demands. This allows more precise energy estimation.
630//
631// TODO(user): Cache energy min and reason for the non O(1) cases.
633 public:
634 // Hack: this can be called with and empty demand vector as long as
635 // OverrideEnergies() is called to define the energies.
636 SchedulingDemandHelper(absl::Span<const AffineExpression> demands,
638
639 // When defined, the interval will consume this much demand during its whole
640 // duration. Some propagator only relies on the "energy" and thus never uses
641 // this.
642 IntegerValue DemandMin(int t) const;
643 IntegerValue DemandMax(int t) const;
644 IntegerValue LevelZeroDemandMin(int t) const {
645 return integer_trail_->LevelZeroLowerBound(demands_[t]);
646 }
647 bool DemandIsFixed(int t) const;
648 void AddDemandMinReason(int t);
649 void AddDemandMinReason(int t, IntegerValue min_demand);
650 const std::vector<AffineExpression>& Demands() const { return demands_; }
651
652 // Adds the linearized demand (either the affine demand expression, or the
653 // demand part of the decomposed energy if present) to the builder.
654 // It returns false and do not add any term to the builder.if any literal
655 // involved has no integer view.
656 ABSL_MUST_USE_RESULT bool AddLinearizedDemand(
657 int t, LinearConstraintBuilder* builder) const;
658
659 // The "energy" is usually size * demand, but in some non-conventional usage
660 // it might have a more complex formula. In all case, the energy is assumed
661 // to be only consumed during the interval duration.
662 //
663 // IMPORTANT: One must call CacheAllEnergyValues() for the values to be
664 // updated. TODO(user): this is error prone, maybe we should revisit. But if
665 // there is many alternatives, we don't want to rescan the list more than a
666 // linear number of time per propagation.
667 //
668 // TODO(user): Add more complex EnergyMinBefore(time) once we also support
669 // expressing the interval as a set of alternatives.
670 //
671 // At level 0, it will filter false literals from decomposed energies.
673 IntegerValue EnergyMin(int t) const { return cached_energies_min_[t]; }
674 IntegerValue EnergyMax(int t) const { return cached_energies_max_[t]; }
675 bool EnergyIsQuadratic(int t) const { return energy_is_quadratic_[t]; }
676 void AddEnergyMinReason(int t);
677
678 // Returns the energy min in [start, end].
679 //
680 // Note(user): These functions are not in O(1) if the decomposition is used,
681 // so we have to be careful in not calling them too often.
682 IntegerValue EnergyMinInWindow(int t, IntegerValue window_start,
683 IntegerValue window_end);
684 void AddEnergyMinInWindowReason(int t, IntegerValue window_start,
685 IntegerValue window_end);
686
687 // Important: This might not do anything depending on the representation of
688 // the energy we have.
689 ABSL_MUST_USE_RESULT bool DecreaseEnergyMax(int t, IntegerValue value);
690
691 // Different optional representation of the energy of an interval.
692 //
693 // Important: first value is size, second value is demand.
694 const std::vector<std::vector<LiteralValueValue>>& DecomposedEnergies()
695 const {
696 return decomposed_energies_;
697 }
698
699 // Visible for testing.
700 void OverrideLinearizedEnergies(absl::Span<const LinearExpression> energies);
702 const std::vector<std::vector<LiteralValueValue>>& energies);
703 // Returns the decomposed energy terms compatible with the current literal
704 // assignment. It must not be used to create reasons if not at level 0.
705 // It returns en empty vector if the decomposed energy is not available.
706 //
707 // Important: first value is size, second value is demand.
708 std::vector<LiteralValueValue> FilteredDecomposedEnergy(int index);
709
710 // Init all decomposed energies. It needs probing to be finished. This happens
711 // after the creation of the helper.
713
714 private:
715 IntegerValue SimpleEnergyMin(int t) const;
716 IntegerValue LinearEnergyMin(int t) const;
717 IntegerValue SimpleEnergyMax(int t) const;
718 IntegerValue LinearEnergyMax(int t) const;
719 IntegerValue DecomposedEnergyMin(int t) const;
720 IntegerValue DecomposedEnergyMax(int t) const;
721
722 IntegerTrail* integer_trail_;
723 ProductDecomposer* product_decomposer_;
724 SatSolver* sat_solver_; // To get the current propagation level.
725 const VariablesAssignment& assignment_;
726 std::vector<AffineExpression> demands_;
728
729 // Cached value of the energies, as it can be a bit costly to compute.
730 std::vector<IntegerValue> cached_energies_min_;
731 std::vector<IntegerValue> cached_energies_max_;
732 std::vector<bool> energy_is_quadratic_;
733
734 // A representation of the energies as a set of alternative.
735 // If subvector is empty, we don't have this representation.
736 std::vector<std::vector<LiteralValueValue>> decomposed_energies_;
737
738 // A representation of the energies as a set of linear expression.
739 // If the optional is not set, we don't have this representation.
740 std::vector<std::optional<LinearExpression>> linearized_energies_;
741};
742
743// =============================================================================
744// Utilities
745// =============================================================================
746
747IntegerValue ComputeEnergyMinInWindow(
748 IntegerValue start_min, IntegerValue start_max, IntegerValue end_min,
749 IntegerValue end_max, IntegerValue size_min, IntegerValue demand_min,
750 absl::Span<const LiteralValueValue> filtered_energy,
751 IntegerValue window_start, IntegerValue window_end);
752
753// =============================================================================
754// SchedulingConstraintHelper inlined functions.
755// =============================================================================
756
757inline bool SchedulingConstraintHelper::StartIsFixed(int t) const {
758 return integer_trail_->IsFixed(starts_[t]);
759}
760
762 return integer_trail_->IsFixed(ends_[t]);
763}
764
766 return integer_trail_->IsFixed(sizes_[t]);
767}
768
770 return reason_for_presence_[t] != kNoLiteralIndex;
771}
772
774 if (reason_for_presence_[t] == kNoLiteralIndex) return true;
775 return trail_->Assignment().LiteralIsTrue(Literal(reason_for_presence_[t]));
776}
778inline bool SchedulingConstraintHelper::IsAbsent(int t) const {
779 if (reason_for_presence_[t] == kNoLiteralIndex) return false;
780 return trail_->Assignment().LiteralIsFalse(Literal(reason_for_presence_[t]));
781}
783inline bool SchedulingConstraintHelper::IsOptional(LiteralIndex lit) const {
784 return lit != kNoLiteralIndex;
785}
786
787inline bool SchedulingConstraintHelper::IsPresent(LiteralIndex lit) const {
788 if (lit == kNoLiteralIndex) return true;
789 return trail_->Assignment().LiteralIsTrue(Literal(lit));
790}
792inline bool SchedulingConstraintHelper::IsAbsent(LiteralIndex lit) const {
793 if (lit == kNoLiteralIndex) return false;
794 return trail_->Assignment().LiteralIsFalse(Literal(lit));
795}
798 integer_reason_.clear();
799 literal_reason_.clear();
800 if (other_helper_) {
801 other_helper_->ClearReason();
802 already_added_to_other_reasons_.assign(NumTasks(), false);
803 }
804}
805
807 DCHECK(IsPresent(t));
808 AddOtherReason(t);
809 if (reason_for_presence_[t] != kNoLiteralIndex) {
810 literal_reason_.push_back(Literal(reason_for_presence_[t]).Negated());
811 }
812}
813
815 DCHECK(IsAbsent(t));
816 AddOtherReason(t);
817 if (reason_for_presence_[t] != kNoLiteralIndex) {
818 literal_reason_.push_back(Literal(reason_for_presence_[t]));
819 }
820}
821
824}
825
826inline void SchedulingConstraintHelper::AddGenericReason(
827 const AffineExpression& a, IntegerValue upper_bound,
828 const AffineExpression& b, const AffineExpression& c) {
829 if (integer_trail_->UpperBound(a) <= upper_bound) {
830 if (a.var != kNoIntegerVariable) {
831 integer_reason_.push_back(a.LowerOrEqual(upper_bound));
832 }
833 return;
834 }
835 CHECK_NE(a.var, kNoIntegerVariable);
836
837 // Here we assume that the upper_bound on a comes from the bound on b + c.
838 const IntegerValue slack = upper_bound - integer_trail_->UpperBound(b) -
839 integer_trail_->UpperBound(c);
840 CHECK_GE(slack, 0);
841 if (b.var == kNoIntegerVariable && c.var == kNoIntegerVariable) return;
842 if (b.var == kNoIntegerVariable) {
843 integer_reason_.push_back(c.LowerOrEqual(upper_bound - b.constant));
844 } else if (c.var == kNoIntegerVariable) {
845 integer_reason_.push_back(b.LowerOrEqual(upper_bound - c.constant));
846 } else {
847 integer_trail_->AppendRelaxedLinearReason(
848 slack, {b.coeff, c.coeff}, {NegationOf(b.var), NegationOf(c.var)},
849 &integer_reason_);
850 }
851}
852
854 int t, IntegerValue lower_bound) {
855 AddOtherReason(t);
856 DCHECK(!IsAbsent(t));
857 if (lower_bound <= 0) return;
858 AddGenericReason(sizes_[t].Negated(), -lower_bound, minus_ends_[t],
859 starts_[t]);
860}
861
863 int t, IntegerValue upper_bound) {
864 AddOtherReason(t);
865 DCHECK(!IsAbsent(t));
866 AddGenericReason(sizes_[t], upper_bound, ends_[t], minus_starts_[t]);
867}
868
870 int t, IntegerValue lower_bound) {
871 AddOtherReason(t);
872 DCHECK(!IsAbsent(t));
873 AddGenericReason(minus_starts_[t], -lower_bound, minus_ends_[t], sizes_[t]);
874}
875
877 int t, IntegerValue upper_bound) {
878 AddOtherReason(t);
879 DCHECK(!IsAbsent(t));
880 AddGenericReason(starts_[t], upper_bound, ends_[t], sizes_[t].Negated());
881}
882
884 int t, IntegerValue lower_bound) {
885 AddOtherReason(t);
886 DCHECK(!IsAbsent(t));
887 AddGenericReason(minus_ends_[t], -lower_bound, minus_starts_[t],
888 sizes_[t].Negated());
889}
890
892 int t, IntegerValue upper_bound) {
893 AddOtherReason(t);
894 DCHECK(!IsAbsent(t));
895 AddGenericReason(ends_[t], upper_bound, starts_[t], sizes_[t]);
896}
897
899 int t, IntegerValue upper_bound) {
901}
904 int t, IntegerValue energy_min, IntegerValue time) {
905 if (StartMin(t) >= time) {
907 } else {
908 AddEndMinReason(t, time + energy_min);
909 }
910 AddSizeMinReason(t, energy_min);
911}
912
914 int t, IntegerValue time_min, IntegerValue time_max) {
915 const IntegerValue energy_min = SizeMin(t);
916 CHECK_LE(time_min + energy_min, time_max);
917 if (StartMin(t) >= time_min) {
918 AddStartMinReason(t, time_min);
919 } else {
920 AddEndMinReason(t, time_min + energy_min);
921 }
922 if (EndMax(t) <= time_max) {
923 AddEndMaxReason(t, time_max);
924 } else {
925 AddStartMaxReason(t, time_max - energy_min);
926 }
927 AddSizeMinReason(t, energy_min);
928}
929
930// =============================================================================
931// Model based functions.
932// =============================================================================
933
934inline std::function<int64_t(const Model&)> MinSize(IntervalVariable v) {
935 return [=](const Model& model) {
936 return model.Get<IntervalsRepository>()->MinSize(v).value();
937 };
938}
939
940inline std::function<int64_t(const Model&)> MaxSize(IntervalVariable v) {
941 return [=](const Model& model) {
942 return model.Get<IntervalsRepository>()->MaxSize(v).value();
943 };
944}
945
946inline std::function<bool(const Model&)> IsOptional(IntervalVariable v) {
947 return [=](const Model& model) {
948 return model.Get<IntervalsRepository>()->IsOptional(v);
949 };
950}
951
952inline std::function<Literal(const Model&)> IsPresentLiteral(
953 IntervalVariable v) {
954 return [=](const Model& model) {
955 return model.Get<IntervalsRepository>()->PresenceLiteral(v);
956 };
957}
959inline std::function<IntervalVariable(Model*)> NewInterval(int64_t min_start,
960 int64_t max_end,
961 int64_t size) {
962 return [=](Model* model) {
963 CHECK_LE(min_start + size, max_end);
964 const IntegerVariable start =
965 model->Add(NewIntegerVariable(min_start, max_end - size));
966 return model->GetOrCreate<IntervalsRepository>()->CreateInterval(
968 AffineExpression(start, IntegerValue(1), IntegerValue(size)),
969 AffineExpression(IntegerValue(size)), kNoLiteralIndex,
970 /*add_linear_relation=*/false);
971 };
972}
973
974inline std::function<IntervalVariable(Model*)> NewInterval(
975 IntegerVariable start, IntegerVariable end, IntegerVariable size) {
976 return [=](Model* model) {
977 return model->GetOrCreate<IntervalsRepository>()->CreateInterval(
978 start, end, size, IntegerValue(0), kNoLiteralIndex);
979 };
981
982inline std::function<IntervalVariable(Model*)> NewIntervalWithVariableSize(
983 int64_t min_start, int64_t max_end, int64_t min_size, int64_t max_size) {
984 return [=](Model* model) {
985 return model->GetOrCreate<IntervalsRepository>()->CreateInterval(
986 model->Add(NewIntegerVariable(min_start, max_end)),
987 model->Add(NewIntegerVariable(min_start, max_end)),
988 model->Add(NewIntegerVariable(min_size, max_size)), IntegerValue(0),
990 };
991}
992
993// Note that this should only be used in tests.
994inline std::function<IntervalVariable(Model*)> NewOptionalInterval(
995 int64_t min_start, int64_t max_end, int64_t size, Literal is_present) {
996 return [=](Model* model) {
997 CHECK_LE(min_start + size, max_end);
998 const IntegerVariable start =
999 model->Add(NewIntegerVariable(min_start, max_end - size));
1000 const IntervalVariable interval =
1001 model->GetOrCreate<IntervalsRepository>()->CreateInterval(
1003 AffineExpression(start, IntegerValue(1), IntegerValue(size)),
1004 AffineExpression(IntegerValue(size)), is_present.Index(),
1005 /*add_linear_relation=*/false);
1006
1007 // To not have too many solutions during enumeration, we force the
1008 // start at its min value for absent interval.
1009 model->Add(Implication({is_present.Negated()},
1010 IntegerLiteral::LowerOrEqual(start, min_start)));
1011 return interval;
1012 };
1013}
1014
1015inline std::function<IntervalVariable(Model*)> NewOptionalInterval(
1016 IntegerVariable start, IntegerVariable end, IntegerVariable size,
1017 Literal is_present) {
1018 return [=](Model* model) {
1019 return model->GetOrCreate<IntervalsRepository>()->CreateInterval(
1020 start, end, size, IntegerValue(0), is_present.Index());
1022}
1023
1024inline std::function<IntervalVariable(Model*)>
1025NewOptionalIntervalWithVariableSize(int64_t min_start, int64_t max_end,
1026 int64_t min_size, int64_t max_size,
1027 Literal is_present) {
1028 return [=](Model* model) {
1029 return model->GetOrCreate<IntervalsRepository>()->CreateInterval(
1030 model->Add(NewIntegerVariable(min_start, max_end)),
1031 model->Add(NewIntegerVariable(min_start, max_end)),
1032 model->Add(NewIntegerVariable(min_size, max_size)), IntegerValue(0),
1033 is_present.Index());
1034 };
1035}
1036
1037// Cuts helpers.
1038void AddIntegerVariableFromIntervals(SchedulingConstraintHelper* helper,
1039 Model* model,
1040 std::vector<IntegerVariable>* vars);
1041
1043 const AffineExpression& capacity, SchedulingDemandHelper* demands_helper,
1044 Model* model, std::vector<IntegerVariable>* vars);
1045
1046} // namespace sat
1047} // namespace operations_research
1048
1049#endif // OR_TOOLS_SAT_INTERVALS_H_
IntegerValue size
int64_t max
int64_t min
IntegerValue LowerBound(IntegerVariable i) const
Returns the current lower/upper bound of the given integer variable.
Definition integer.h:1717
IntegerValue UpperBound(IntegerVariable i) const
Definition integer.h:1721
void AppendRelaxedLinearReason(IntegerValue slack, absl::Span< const IntegerValue > coeffs, absl::Span< const IntegerVariable > vars, std::vector< IntegerLiteral > *reason) const
Same as above but take in IntegerVariables instead of IntegerLiterals.
Definition integer.cc:1047
bool IsFixed(IntegerVariable i) const
Checks if the variable is fixed.
Definition integer.h:1725
IntegerValue LevelZeroUpperBound(IntegerVariable var) const
Definition integer.h:1817
IntegerValue LevelZeroLowerBound(IntegerVariable var) const
Returns globally valid lower/upper bound on the given integer variable.
Definition integer.h:1812
IntervalsRepository(const IntervalsRepository &)=delete
This type is neither copyable nor movable.
SchedulingDemandHelper * GetOrCreateDemandHelper(SchedulingConstraintHelper *helper, absl::Span< const AffineExpression > demands)
Definition intervals.cc:206
AffineExpression Start(IntervalVariable i) const
Definition intervals.h:111
AffineExpression Size(IntervalVariable i) const
Definition intervals.h:110
AffineExpression End(IntervalVariable i) const
Definition intervals.h:112
bool IsAbsent(IntervalVariable i) const
Definition intervals.h:98
const std::vector< CumulativeHelper > & AllCumulativeHelpers() const
Definition intervals.h:190
void InitAllDecomposedEnergies()
Calls InitDecomposedEnergies on all SchedulingDemandHelper created.
Definition intervals.cc:222
Literal PresenceLiteral(IntervalVariable i) const
Definition intervals.h:91
void CreateDisjunctivePrecedenceLiteral(IntervalVariable a, IntervalVariable b)
Definition intervals.cc:85
LiteralIndex GetPrecedenceLiteral(IntervalVariable a, IntervalVariable b) const
Definition intervals.cc:178
bool CreatePrecedenceLiteral(IntervalVariable a, IntervalVariable b)
Definition intervals.cc:149
const std::vector< SchedulingConstraintHelper * > & AllDisjunctiveHelpers() const
Definition intervals.h:175
bool IsOptional(IntervalVariable i) const
Returns whether or not a interval is optional and the associated literal.
Definition intervals.h:88
void RegisterCumulative(CumulativeHelper helper)
Definition intervals.h:187
IntervalVariable CreateInterval(IntegerVariable start, IntegerVariable end, IntegerVariable size, IntegerValue fixed_size, LiteralIndex is_present)
Definition intervals.cc:44
IntegerValue MaxSize(IntervalVariable i) const
Return the maximum size of the given IntervalVariable.
Definition intervals.h:120
IntegerValue MinSize(IntervalVariable i) const
Return the minimum size of the given IntervalVariable.
Definition intervals.h:115
SchedulingConstraintHelper * GetOrCreateHelper(const std::vector< IntervalVariable > &variables, bool register_as_disjunctive_helper=false)
Definition intervals.cc:190
IntervalsRepository & operator=(const IntervalsRepository &)=delete
std::vector< IntervalVariable > AllIntervals() const
Utility function that returns a vector will all intervals.
Definition intervals.h:125
bool IsPresent(IntervalVariable i) const
Definition intervals.h:94
Helper class to express a product as a linear constraint.
Base class for CP like propagators.
Definition integer.h:1414
bool IncrementalPropagate(const std::vector< int > &watch_indices) final
Definition intervals.cc:298
absl::Span< const TaskTime > TaskByIncreasingStartMin()
Definition intervals.cc:569
void WatchAllTasks(int id, bool watch_max_side=true)
Definition intervals.cc:802
void AddReasonForBeingBefore(int before, int after)
Produces a relaxed reason for StartMax(before) < EndMin(after).
Definition intervals.cc:657
void AddEnergyAfterReason(int t, IntegerValue energy_min, IntegerValue time)
Definition intervals.h:907
void AddStartMaxReason(int t, IntegerValue upper_bound)
Definition intervals.h:880
ABSL_MUST_USE_RESULT bool IncreaseEndMin(int t, IntegerValue value)
Definition intervals.cc:744
std::vector< IntegerLiteral > * MutableIntegerReason()
Definition intervals.h:451
void RegisterWith(GenericLiteralWatcher *watcher)
Definition intervals.cc:305
absl::Span< const TaskTime > TaskByIncreasingNegatedStartMax()
Definition intervals.cc:591
SchedulingConstraintHelper(const std::vector< IntervalVariable > &tasks, Model *model)
Definition intervals.cc:228
void AddSizeMaxReason(int t, IntegerValue upper_bound)
Definition intervals.h:866
ABSL_MUST_USE_RESULT bool DecreaseEndMax(int t, IntegerValue value)
Definition intervals.cc:752
int NumTasks() const
Returns the number of task.
Definition intervals.h:293
absl::Span< const AffineExpression > Sizes() const
Definition intervals.h:481
ABSL_MUST_USE_RESULT bool PushLiteral(Literal l)
Definition intervals.cc:760
const std::vector< ProfileEvent > & GetEnergyProfile()
Definition intervals.cc:632
ABSL_MUST_USE_RESULT bool PushTaskAbsence(int t)
Definition intervals.cc:765
ABSL_MUST_USE_RESULT bool PushIntegerLiteralIfTaskPresent(int t, IntegerLiteral lit)
Definition intervals.cc:714
absl::Span< const AffineExpression > Starts() const
Definition intervals.h:479
void AddEndMaxReason(int t, IntegerValue upper_bound)
Definition intervals.h:895
absl::Span< const AffineExpression > Ends() const
Definition intervals.h:480
ABSL_MUST_USE_RESULT bool ResetFromSubset(const SchedulingConstraintHelper &other, absl::Span< const int > tasks)
Definition intervals.cc:396
ABSL_MUST_USE_RESULT bool IncreaseStartMin(int t, IntegerValue value)
Definition intervals.cc:736
void AddEndMinReason(int t, IntegerValue lower_bound)
Definition intervals.h:887
void ClearReason()
Functions to clear and then set the current reason.
Definition intervals.h:801
absl::Span< const CachedTaskBounds > TaskByIncreasingShiftedStartMin()
Definition intervals.cc:613
absl::Span< const TaskTime > TaskByDecreasingEndMax()
Definition intervals.cc:603
ABSL_MUST_USE_RESULT bool SynchronizeAndSetTimeDirection(bool is_forward)
Definition intervals.cc:483
void SetOtherHelper(SchedulingConstraintHelper *other_helper, absl::Span< const int > map_to_other_helper, IntegerValue event)
Definition intervals.h:497
ABSL_MUST_USE_RESULT bool PushTaskPresence(int t)
Definition intervals.cc:781
std::string TaskDebugString(int t) const
Returns a string with the current task bounds.
Definition intervals.cc:850
ABSL_MUST_USE_RESULT bool PushIntegerLiteral(IntegerLiteral lit)
Definition intervals.cc:709
void AddShiftedEndMaxReason(int t, IntegerValue upper_bound)
Definition intervals.h:902
absl::Span< const IntervalVariable > IntervalVariables() const
Returns the underlying affine expressions.
Definition intervals.h:476
IntegerValue GetCurrentMinDistanceBetweenTasks(int a, int b, bool add_reason_if_after=false)
Definition intervals.cc:510
IntegerValue GetMinOverlap(int t, IntegerValue start, IntegerValue end) const
Definition intervals.cc:858
void AddStartMinReason(int t, IntegerValue lower_bound)
Definition intervals.h:873
void AddEnergyMinInIntervalReason(int t, IntegerValue min, IntegerValue max)
Definition intervals.h:917
absl::Span< const TaskTime > TaskByIncreasingEndMin()
Definition intervals.cc:579
std::vector< LiteralValueValue > FilteredDecomposedEnergy(int index)
IntegerValue EnergyMinInWindow(int t, IntegerValue window_start, IntegerValue window_end)
const std::vector< std::vector< LiteralValueValue > > & DecomposedEnergies() const
Definition intervals.h:694
void OverrideLinearizedEnergies(absl::Span< const LinearExpression > energies)
Visible for testing.
void AddEnergyMinInWindowReason(int t, IntegerValue window_start, IntegerValue window_end)
SchedulingDemandHelper(absl::Span< const AffineExpression > demands, SchedulingConstraintHelper *helper, Model *model)
Definition intervals.cc:896
void OverrideDecomposedEnergies(const std::vector< std::vector< LiteralValueValue > > &energies)
const std::vector< AffineExpression > & Demands() const
Definition intervals.h:650
ABSL_MUST_USE_RESULT bool DecreaseEnergyMax(int t, IntegerValue value)
ABSL_MUST_USE_RESULT bool AddLinearizedDemand(int t, LinearConstraintBuilder *builder) const
const VariablesAssignment & Assignment() const
Definition sat_base.h:462
bool LiteralIsFalse(Literal literal) const
Definition sat_base.h:185
bool LiteralIsTrue(Literal literal) const
Definition sat_base.h:188
int64_t a
Definition table.cc:44
int64_t value
double upper_bound
double lower_bound
GRBmodel * model
int lit
int index
std::function< int64_t(const Model &)> MaxSize(IntervalVariable v)
Definition intervals.h:946
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:1031
std::function< Literal(const Model &)> IsPresentLiteral(IntervalVariable v)
Definition intervals.h:958
const LiteralIndex kNoLiteralIndex(-1)
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
Returns the vector of the negated variables.
Definition integer.cc:51
std::function< IntervalVariable(Model *)> NewIntervalWithVariableSize(int64_t min_start, int64_t max_end, int64_t min_size, int64_t max_size)
Definition intervals.h:988
std::function< IntervalVariable(Model *)> NewInterval(int64_t min_start, int64_t max_end, int64_t size)
Definition intervals.h:965
const IntegerVariable kNoIntegerVariable(-1)
std::function< void(Model *)> Implication(absl::Span< const Literal > enforcement_literals, IntegerLiteral i)
Definition integer.h:2025
const IntervalVariable kNoIntervalVariable(-1)
std::function< IntervalVariable(Model *)> NewOptionalInterval(int64_t min_start, int64_t max_end, int64_t size, Literal is_present)
Definition intervals.h:1000
void AppendVariablesFromCapacityAndDemands(const AffineExpression &capacity, SchedulingDemandHelper *demands_helper, Model *model, std::vector< IntegerVariable > *vars)
std::function< IntegerVariable(Model *)> NewIntegerVariable(int64_t lb, int64_t ub)
Definition integer.h:1907
std::function< int64_t(const Model &)> MinSize(IntervalVariable v)
Definition intervals.h:940
void AddIntegerVariableFromIntervals(SchedulingConstraintHelper *helper, Model *model, std::vector< IntegerVariable > *vars)
Cuts helpers.
std::function< bool(const Model &)> IsOptional(IntervalVariable v)
Definition intervals.h:952
IntegerValue ComputeEnergyMinInWindow(IntegerValue start_min, IntegerValue start_max, IntegerValue end_min, IntegerValue end_max, IntegerValue size_min, IntegerValue demand_min, absl::Span< const LiteralValueValue > filtered_energy, IntegerValue window_start, IntegerValue window_end)
Definition intervals.cc:865
In SWIG mode, we don't want anything besides these top-level includes.
int64_t time
Definition resource.cc:1708
IntervalVar * interval
Definition resource.cc:101
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
#define DEFINE_STRONG_INDEX_TYPE(index_type_name)
bool operator>(CachedTaskBounds other) const
Definition intervals.h:256
bool operator<(CachedTaskBounds other) const
Definition intervals.h:255
static IntegerLiteral LowerOrEqual(IntegerVariable i, IntegerValue bound)
Definition integer.h:1673
bool operator<(TaskTime other) const
Definition intervals.h:242
bool operator>(TaskTime other) const
Definition intervals.h:243