Google OR-Tools v9.15
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
timetable.h
Go to the documentation of this file.
1// Copyright 2010-2025 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 ORTOOLS_SAT_TIMETABLE_H_
15#define ORTOOLS_SAT_TIMETABLE_H_
16
17#include <cstdint>
18#include <vector>
19
20#include "absl/types/span.h"
23#include "ortools/sat/integer.h"
25#include "ortools/sat/model.h"
29
30namespace operations_research {
31namespace sat {
32
33// Adds a reservoir constraint to the model. Note that to account for level not
34// containing zero at time zero, we might needs to create an artificial fixed
35// event.
36//
37// This instantiate one or more ReservoirTimeTabling class to perform the
38// propagation.
39void AddReservoirConstraint(absl::Span<const Literal> enforcement_literals,
40 absl::Span<const AffineExpression> times,
41 absl::Span<const AffineExpression> deltas,
42 absl::Span<const Literal> presences,
43 int64_t min_level, int64_t max_level, Model* model);
44
45// The piecewise constant function must be below the given capacity. The initial
46// function value is zero. Note that a negative capacity will thus be trivially
47// infeasible.
48//
49// Note that we take for the definition of the function at time t to be the sum
50// of all delta with time <= t. But because we check for the capacity over the
51// full horizon, we could have taken < t with no behavior change.
53 public:
54 ReservoirTimeTabling(absl::Span<const Literal> enforcement_literals,
55 absl::Span<const AffineExpression> times,
56 absl::Span<const AffineExpression> deltas,
57 absl::Span<const Literal> presences,
58 IntegerValue capacity, Model* model);
59
60 bool Propagate() final;
61
62 private:
63 // The rectangle will be ordered by start, and the end of each rectangle
64 // will be equal to the start of the next one. The height correspond to the
65 // one from start (inclusive) until the next one (exclusive).
66 struct ProfileRectangle {
67 ProfileRectangle() = default;
68 ProfileRectangle(IntegerValue start, IntegerValue height)
69 : start(start), height(height) {}
70
71 bool operator<(const ProfileRectangle& other) const {
72 return start < other.start;
73 }
74
75 /* const */ IntegerValue start = IntegerValue(0);
76 /* const */ IntegerValue height = IntegerValue(0);
77 };
78
79 // Builds the profile and increases the lower bound of the capacity
80 // variable accordingly.
81 bool BuildProfile();
82
83 // Explanation of the profile minimum value at time t, eventually ignoring the
84 // given event.
85 void FillReasonForProfileAtGivenTime(IntegerValue t,
86 int event_to_ignore = -1);
87
88 // Tries to tighten the min/max time of the given event depending on the sign
89 // of the delta associated with this event.
90 bool TryToIncreaseMin(int event);
91 bool TryToDecreaseMax(int event);
92
93 // Input.
94 std::vector<Literal> enforcement_literals_;
95 std::vector<AffineExpression> times_;
96 std::vector<AffineExpression> deltas_;
97 std::vector<Literal> presences_;
98 IntegerValue capacity_;
99
100 // Model class.
101 const VariablesAssignment& assignment_;
102 const IntegerTrail& integer_trail_;
103 EnforcementHelper& enforcement_helper_;
104 EnforcementId enforcement_id_;
105
106 // Temporary data.
107 std::vector<Literal> literal_reason_;
108 std::vector<IntegerLiteral> integer_reason_;
109 std::vector<ProfileRectangle> profile_;
110};
111
112// A strongly quadratic version of Time Tabling filtering. This propagator
113// is similar to the CumulativeTimeTable propagator of the constraint solver.
114//
115// TODO(user): Use SchedulingDemandHelper. In particular, if we know the task
116// is from a set of fixed alternatives, we might be able to push it more.
118 public:
121 SchedulingDemandHelper* demands, Model* model);
122
123 // This type is neither copyable nor movable.
126
127 bool Propagate() final;
128
129 void RegisterWith(GenericLiteralWatcher* watcher);
130
131 private:
132 // The rectangle will be ordered by start, and the end of each rectangle
133 // will be equal to the start of the next one. The height correspond to the
134 // one from start (inclusive) until the next one (exclusive).
135 struct ProfileRectangle {
136 /* const */ IntegerValue start;
137 /* const */ IntegerValue height;
138
139 ProfileRectangle(IntegerValue start, IntegerValue height)
140 : start(start), height(height) {}
141
142 bool operator<(const ProfileRectangle& other) const {
143 return start < other.start;
144 }
145 };
146
147 // Builds the profile and increases the lower bound of the capacity
148 // variable accordingly.
149 bool BuildProfile();
150
151 // Reverses the profile. This is needed to reuse a given profile to update
152 // both the start and end times.
153 void ReverseProfile();
154
155 // Tries to increase the minimum start time of each task according to the
156 // current profile. This function can be called after ReverseProfile() and
157 // ReverseVariables to update the maximum end time of each task.
158 bool SweepAllTasks();
159
160 // Tries to increase the minimum start time of task_id. This assumes tasks are
161 // processed by increasing start_min so that the starting profile_index only
162 // increase.
163 bool SweepTask(int task_id, IntegerValue initial_start_min,
164 IntegerValue conflict_height, int* profile_index);
165
166 // Updates the starting time of task_id to right and explain it. The reason is
167 // all the mandatory parts contained in [left, right).
168 bool UpdateStartingTime(int task_id, IntegerValue left, IntegerValue right);
169
170 // Increases the minimum capacity to new_min and explain it. The reason is all
171 // the mandatory parts that overlap time.
172 bool IncreaseCapacity(IntegerValue time, IntegerValue new_min);
173
174 // Explains the state of the profile in the time interval [left, right) that
175 // allow to push task_id. The reason is all the mandatory parts that overlap
176 // the interval. The current reason is not cleared when this method is called.
177 void AddProfileReason(int task_id, IntegerValue left, IntegerValue right,
178 IntegerValue capacity_threshold);
179
180 IntegerValue CapacityMin() const {
181 return integer_trail_->LowerBound(capacity_);
182 }
183
184 IntegerValue CapacityMax() const {
185 return integer_trail_->UpperBound(capacity_);
186 }
187
188 // Returns true if the tasks is present and has a mantatory part.
189 // This is only valid after BuildProfile() has been called.
190 bool IsInProfile(int t) const { return cached_demands_min_[t] > 0; }
191
192 // Number of tasks.
193 const int num_tasks_;
194
195 // Capacity of the resource.
196 const AffineExpression capacity_;
197
198 SchedulingConstraintHelper* helper_;
199 SchedulingDemandHelper* demands_;
200 IntegerTrail* integer_trail_;
201
202 // Optimistic profile of the resource consumption over time.
203 std::vector<ProfileRectangle> profile_;
204 IntegerValue profile_max_height_;
205
206 // Reversible set (with random access) of tasks to consider for building the
207 // profile. The set contains the tasks in the [0, num_profile_tasks_) prefix
208 // of profile_tasks_.
209 std::vector<int> profile_tasks_;
210 int num_profile_tasks_;
211
212 // Only task with mandatory part will have their demand cached.
213 // Others will have zero here.
214 std::vector<IntegerValue> cached_demands_min_;
215
216 // Statically computed.
217 // This allow to simplify the profile for common usage.
218 bool has_demand_equal_to_capacity_ = false;
219 IntegerValue initial_max_demand_;
220};
221
222} // namespace sat
223} // namespace operations_research
224
225#endif // ORTOOLS_SAT_TIMETABLE_H_
IntegerValue LowerBound(IntegerVariable i) const
Definition integer.h:1537
IntegerValue UpperBound(IntegerVariable i) const
Definition integer.h:1541
ReservoirTimeTabling(absl::Span< const Literal > enforcement_literals, absl::Span< const AffineExpression > times, absl::Span< const AffineExpression > deltas, absl::Span< const Literal > presences, IntegerValue capacity, Model *model)
Definition timetable.cc:63
void RegisterWith(GenericLiteralWatcher *watcher)
Definition timetable.cc:378
TimeTablingPerTask(const TimeTablingPerTask &)=delete
TimeTablingPerTask(AffineExpression capacity, SchedulingConstraintHelper *helper, SchedulingDemandHelper *demands, Model *model)
Definition timetable.cc:344
TimeTablingPerTask & operator=(const TimeTablingPerTask &)=delete
void AddReservoirConstraint(absl::Span< const Literal > enforcement_literals, absl::Span< const AffineExpression > times, absl::Span< const AffineExpression > deltas, absl::Span< const Literal > presences, int64_t min_level, int64_t max_level, Model *model)
Definition timetable.cc:33
OR-Tools root namespace.