Google OR-Tools v9.12
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-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 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"
26
27namespace operations_research {
28namespace 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.
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.
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.
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.
74 const AffineExpression& capacity, Model* model);
75
76// For a given set of intervals, we first compute the min and max of all
77// intervals. Then we create a cut that indicates that all intervals must fit
78// in that span.
79//
80// If an interval is optional, it contributes min_size * presence_literal
81// amount of demand to the mandatory demands sum. So the final cut is generated
82// as follows:
83// sum(sizes of always present intervals)
84// + sum(presence_literal * min_of_size) <= span of all intervals.
87 const std::optional<AffineExpression>& makespan, Model* model);
88
89// For a given set of intervals in a no_overlap constraint, we detect violated
90// mandatory precedences and create a cut for these.
92 SchedulingConstraintHelper* helper, Model* model);
93
94// For a given set of intervals in a no_overlap constraint, we detect violated
95// area based cuts from Queyranne 93 [see note in the code] and create a cut for
96// these.
98 SchedulingConstraintHelper* helper, Model* model);
99
100// Internal methods and data structures, useful for testing.
101
102// Base event type for scheduling cuts.
103struct BaseEvent {
104 BaseEvent(int t, SchedulingConstraintHelper* x_helper);
105
106 // Cache of the intervals bound on the x direction.
107 IntegerValue x_start_min;
108 IntegerValue x_start_max;
109 IntegerValue x_end_min;
110 IntegerValue x_end_max;
111 IntegerValue x_size_min;
112
113 // Cache of the bounds on the y direction.
114 IntegerValue y_size_min;
115
116 // The energy min of this event.
117 IntegerValue energy_min;
118
119 // If non empty, a decomposed view of the energy of this event.
120 // First value in each pair is x_size, second is y_size.
121 std::vector<LiteralValueValue> decomposed_energy;
122};
123
124// Stores the event for a rectangle along the two axis x and y.
125// For a no_overlap constraint, y is always of size 1 between 0 and 1.
126// For a cumulative constraint, y is the demand that must be between 0 and
127// capacity_max.
129 CtEvent(int t, SchedulingConstraintHelper* x_helper);
130
131 // The lp value of the end of the x interval.
133 double x_lp_end;
134
135 // Indicates if the events used the optional energy information from the
136 // model.
137 bool use_energy = false;
138
139 // Indicates if the cut is lifted, that is if it includes tasks that are not
140 // strictly contained in the current time window.
141 bool lifted = false;
142
143 // If we know that the size on y is fixed, we can use some heuristic to
144 // compute the maximum subset sums under the capacity and use that instead
145 // of the full capacity.
146 bool y_size_is_fixed = false;
147
148 std::string DebugString() const;
149};
150
151// Computes the minimum sum of the end min and the minimum sum of the end min
152// weighted by weight of all events. It returns false if no permutation is
153// valid w.r.t. the range of starts.
154//
155// Note that this is an exhaustive algorithm, so the number of events should be
156// small, like <= 10. They should also starts in index order.
157//
158// Optim: If both sums are proven <= to the corresponding threshold, we abort.
161 : index(i),
162 start_min(e.x_start_min),
163 start_max(e.x_start_max),
164 size(e.x_size_min),
165 demand(e.y_size_min),
166 weight(e.y_size_min) {}
167
168 bool operator<(const PermutableEvent& o) const { return index < o.index; }
169
170 int index; // for < to be used by std::next_permutation().
171 IntegerValue start_min;
172 IntegerValue start_max;
173 IntegerValue size;
174 IntegerValue demand;
175 IntegerValue weight;
176};
177bool ComputeMinSumOfWeightedEndMins(std::vector<PermutableEvent>& events,
178 IntegerValue capacity_max,
179 IntegerValue& min_sum_of_end_mins,
180 IntegerValue& min_sum_of_weighted_end_mins,
181 IntegerValue unweighted_threshold,
182 IntegerValue weighted_threshold);
183
184} // namespace sat
185} // namespace operations_research
186
187#endif // OR_TOOLS_SAT_SCHEDULING_CUTS_H_
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.
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