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