OR-Tools  9.6
scheduling_cuts.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_SCHEDULING_CUTS_H_
15 #define OR_TOOLS_SAT_SCHEDULING_CUTS_H_
16 
17 #include <functional>
18 #include <optional>
19 #include <string>
20 #include <utility>
21 #include <vector>
22 
23 #include "ortools/sat/cuts.h"
24 #include "ortools/sat/integer.h"
25 #include "ortools/sat/intervals.h"
26 
27 namespace operations_research {
28 namespace sat {
29 
30 // For a given set of intervals and demands, we compute the energy of
31 // each task and make sure their sum fits in the span of the intervals * its
32 // capacity.
33 //
34 // If an interval is optional, it contributes
35 // min_demand * min_size * presence_literal
36 // amount of total energy.
37 //
38 // If an interval is performed, we use the linear energy formulation (if
39 // defined, that is if different from a constant -1), or the McCormick
40 // relaxation of the product size * demand if not defined.
41 //
42 // The maximum energy is capacity * span of intervals at level 0.
44  SchedulingConstraintHelper* helper, SchedulingDemandHelper* demands_helper,
45  const AffineExpression& capacity,
46  const std::optional<AffineExpression>& makespan, Model* model);
47 
48 // For a given set of intervals and demands, we first compute the mandatory part
49 // of the interval as [start_max , end_min]. We use this to calculate mandatory
50 // demands for each start_max time points for eligible intervals.
51 // Since the sum of these mandatory demands must be smaller or equal to the
52 // capacity, we create a cut representing that.
53 //
54 // If an interval is optional, it contributes min_demand * presence_literal
55 // amount of demand to the mandatory demands sum. So the final cut is generated
56 // as follows:
57 // sum(demands of always present intervals)
58 // + sum(presence_literal * min_of_demand) <= capacity.
60  SchedulingConstraintHelper* helper, SchedulingDemandHelper* demands_helper,
61  const AffineExpression& capacity, Model* model);
62 
63 // Completion time cuts for the cumulative constraint. It is a simple relaxation
64 // where we replace a cumulative task with demand k and duration d by a
65 // no_overlap task with duration d * k / capacity_max.
67  SchedulingConstraintHelper* helper, SchedulingDemandHelper* demands_helper,
68  const AffineExpression& capacity, Model* model);
69 
70 // For a given set of intervals in a cumulative constraint, we detect violated
71 // mandatory precedences and create a cut for these.
73  SchedulingConstraintHelper* helper, SchedulingDemandHelper* demands_helper,
74  const AffineExpression& capacity, Model* model);
75 
76 // Completion time cuts for the no_overlap_2d constraint. It actually generates
77 // the completion time cumulative cuts in both axis.
79  const std::vector<IntervalVariable>& x_intervals,
80  const std::vector<IntervalVariable>& y_intervals, Model* model);
81 
82 // Energetic cuts for the no_overlap_2d constraint.
83 //
84 // For a given set of rectangles, we compute the area of each rectangle
85 // and make sure their sum is less than the area of the bounding interval.
86 //
87 // If an interval is optional, it contributes
88 // min_size_x * min_size_y * presence_literal
89 // amount of total area.
90 //
91 // If an interval is performed, we use the linear area formulation (if
92 // possible), or the McCormick relaxation of the size_x * size_y.
93 //
94 // The maximum area is the area of the bounding rectangle of each intervals
95 // at level 0.
97  const std::vector<IntervalVariable>& x_intervals,
98  const std::vector<IntervalVariable>& y_intervals, Model* model);
99 
100 // For a given set of intervals, we first compute the min and max of all
101 // intervals. Then we create a cut that indicates that all intervals must fit
102 // in that span.
103 //
104 // If an interval is optional, it contributes min_size * presence_literal
105 // amount of demand to the mandatory demands sum. So the final cut is generated
106 // as follows:
107 // sum(sizes of always present intervals)
108 // + sum(presence_literal * min_of_size) <= span of all intervals.
110  SchedulingConstraintHelper* helper,
111  const std::optional<AffineExpression>& makespan, Model* model);
112 
113 // For a given set of intervals in a no_overlap constraint, we detect violated
114 // mandatory precedences and create a cut for these.
116  SchedulingConstraintHelper* helper, Model* model);
117 
118 // For a given set of intervals in a no_overlap constraint, we detect violated
119 // area based cuts from Queyranne 93 [see note in the code] and create a cut for
120 // these.
122  SchedulingConstraintHelper* helper, Model* model);
123 
124 // Internal methods and data structures, useful for testing.
125 
126 // Base event type for scheduling cuts.
127 struct BaseEvent {
128  BaseEvent(int t, SchedulingConstraintHelper* x_helper);
129 
130  // Cache of the intervals bound on the x direction.
131  IntegerValue x_start_min;
132  IntegerValue x_start_max;
133  IntegerValue x_end_min;
134  IntegerValue x_end_max;
135  IntegerValue x_size_min;
136  // Useful for no_overlap_2d or cumulative.
137  IntegerValue y_min = IntegerValue(0);
138  IntegerValue y_max = IntegerValue(0);
139  IntegerValue y_size_min;
140 
141  // The energy min of this event.
142  IntegerValue energy_min;
143 
144  // If non empty, a decomposed view of the energy of this event.
145  // First value in each pair is x_size, second is y_size.
146  std::vector<LiteralValueValue> decomposed_energy;
147 };
148 
149 // Stores the event for a rectangle along the two axis x and y.
150 // For a no_overlap constraint, y is always of size 1 between 0 and 1.
151 // For a cumulative constraint, y is the demand that must be between 0 and
152 // capacity_max.
153 // For a no_overlap_2d constraint, y the other dimension of the rect.
154 struct CtEvent : BaseEvent {
155  CtEvent(int t, SchedulingConstraintHelper* x_helper);
156 
157  // The lp value of the end of the x interval.
159  double x_lp_end;
160 
161  // Indicates if the events used the optional energy information from the
162  // model.
163  bool use_energy = false;
164 
165  // Indicates if the cut is lifted, that is if it includes tasks that are not
166  // strictly contained in the current time window.
167  bool lifted = false;
168 
169  // If we know that the size on y is fixed, we can use some heuristic to
170  // compute the maximum subset sums under the capacity and use that instead
171  // of the full capacity.
172  bool y_size_is_fixed = false;
173 
174  std::string DebugString() const;
175 };
176 
177 // Computes the minimum sum of the end min and the minimum sum of the end min
178 // weighted by y_size_min of all events. It returns false if no permatutation is
179 // valid w.r.t. the range of x_start.
180 //
181 // Note that this is an exhaustive algorithm, so the number of events should be
182 // small, like <= 10. They should also starts in index order.
183 //
184 // Optim: If both sums are proven <= to the corresponding threshold, we abort.
187  : index(i),
191  y_size_min(e.y_size_min) {}
192  bool operator<(const PermutableEvent& o) const { return index < o.index; }
193 
194  int index; // for < to be used by std::next_permutation().
195  IntegerValue x_start_min;
196  IntegerValue x_start_max;
197  IntegerValue x_size_min;
198  IntegerValue y_size_min;
199 };
200 bool ComputeMinSumOfWeightedEndMins(std::vector<PermutableEvent>& events,
201  IntegerValue capacity_max,
202  IntegerValue& min_sum_of_end_mins,
203  IntegerValue& min_sum_of_weighted_end_mins,
204  IntegerValue unweighted_threshold,
205  IntegerValue weighted_threshold);
206 
207 } // namespace sat
208 } // namespace operations_research
209 
210 #endif // OR_TOOLS_SAT_SCHEDULING_CUTS_H_
GRBmodel * model
CutGenerator CreateCumulativeEnergyCutGenerator(SchedulingConstraintHelper *helper, SchedulingDemandHelper *demands_helper, const AffineExpression &capacity, const std::optional< AffineExpression > &makespan, Model *model)
bool ComputeMinSumOfWeightedEndMins(std::vector< PermutableEvent > &events, IntegerValue capacity_max, IntegerValue &min_sum_of_end_mins, IntegerValue &min_sum_of_weighted_end_mins, IntegerValue unweighted_threshold, IntegerValue weighted_threshold)
CutGenerator CreateNoOverlap2dEnergyCutGenerator(const std::vector< IntervalVariable > &x_intervals, const std::vector< IntervalVariable > &y_intervals, Model *model)
CutGenerator CreateNoOverlapCompletionTimeCutGenerator(SchedulingConstraintHelper *helper, Model *model)
CutGenerator CreateCumulativePrecedenceCutGenerator(SchedulingConstraintHelper *helper, SchedulingDemandHelper *demands_helper, const AffineExpression &capacity, Model *model)
CutGenerator CreateCumulativeCompletionTimeCutGenerator(SchedulingConstraintHelper *helper, SchedulingDemandHelper *demands_helper, const AffineExpression &capacity, Model *model)
CutGenerator CreateNoOverlap2dCompletionTimeCutGenerator(const std::vector< IntervalVariable > &x_intervals, const std::vector< IntervalVariable > &y_intervals, Model *model)
CutGenerator CreateCumulativeTimeTableCutGenerator(SchedulingConstraintHelper *helper, SchedulingDemandHelper *demands_helper, const AffineExpression &capacity, Model *model)
CutGenerator CreateNoOverlapEnergyCutGenerator(SchedulingConstraintHelper *helper, const std::optional< AffineExpression > &makespan, Model *model)
CutGenerator CreateNoOverlapPrecedenceCutGenerator(SchedulingConstraintHelper *helper, Model *model)
Collection of objects used to extend the Constraint Solver library.
int64_t capacity
std::vector< LiteralValueValue > decomposed_energy
BaseEvent(int t, SchedulingConstraintHelper *x_helper)
CtEvent(int t, SchedulingConstraintHelper *x_helper)
bool operator<(const PermutableEvent &o) const