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