ULSAlgorithms 1.1.0-g3e5595996d
High-performance exact and heuristic algorithms for uncapacitated lot sizing
Loading...
Searching...
No Matches
WagnerWhitinLsCutSeparator.cs
Go to the documentation of this file.
5
7
8/// <summary>
9/// Separates the O(T^2) Wagner-Whitin specialization of the classical ULS
10/// (l,S) inequalities.
11/// </summary>
12/// <remarks>
13/// <para>
14/// Under Wagner-Whitin costs, the relevant prefix-S inequalities can be written
15/// equivalently as
16///
17/// I[k-1] + sum(j=k..l) d[j,l] y[j] >= d[k,l],
18///
19/// for 0 &lt;= k &lt;= l, with zero initial inventory.
20/// </para>
21/// <para>
22/// In the canonical (l,S) representation this corresponds to
23/// S = {0,...,k-1}. All (k,l) candidates are evaluated in O(T^2) time using
24/// cumulative production and backward weighted-setup sums.
25/// </para>
26/// <para>
27/// Scientific source: Y. Pochet, L.A. Wolsey,
28/// "Polyhedra for lot-sizing with Wagner-Whitin costs",
29/// Mathematical Programming 67 (1994), 297-323,
30/// DOI 10.1007/BF01582225.
31/// </para>
32/// </remarks>
33public sealed class WagnerWhitinLsCutSeparator :
35{
36 /// <inheritdoc />
37 public string Name =>
38 "Wagner-Whitin (l,S) separator";
39
40 /// <inheritdoc />
42 CutSeparationMethod.WagnerWhitin;
43
44 /// <inheritdoc />
45 public bool IsApplicable(
46 UlsProblem problem)
47 {
48 ArgumentNullException.ThrowIfNull(problem);
49
51 problem);
52 }
53
54 /// <inheritdoc />
55 public IReadOnlyList<LsSeparatedCut> Separate(
56 UlsProblem problem,
57 UlsFormulation formulation,
58 IReadOnlyDictionary<int, double> variableValues)
59 {
60 ArgumentNullException.ThrowIfNull(problem);
61 ArgumentNullException.ThrowIfNull(formulation);
62 ArgumentNullException.ThrowIfNull(variableValues);
63
64 if (!IsApplicable(problem))
65 {
66 throw new NotSupportedException(
67 "The Wagner-Whitin separator requires " +
68 "p[t] + h[t] >= p[t+1] for every adjacent period.");
69 }
70
72 formulation);
73
74 double[] cumulativeDemand =
76 problem);
77
78 var x =
79 new double[problem.Horizon];
80
81 var y =
82 new double[problem.Horizon];
83
84 for (int period = 0;
85 period < problem.Horizon;
86 period++)
87 {
88 x[period] =
90 formulation.Variables.Production,
91 period,
92 variableValues,
93 "production");
94
95 y[period] =
97 formulation.Variables.Setup,
98 period,
99 variableValues,
100 "setup");
101 }
102
103 var prefixProduction =
104 new double[problem.Horizon + 1];
105
106 for (int period = 0;
107 period < problem.Horizon;
108 period++)
109 {
110 prefixProduction[period + 1] =
111 prefixProduction[period] +
112 x[period];
113 }
114
115 var cuts =
116 new List<LsSeparatedCut>(
117 problem.Horizon *
118 (problem.Horizon + 1) /
119 2);
120
121 var suffixWeightedSetup =
122 new double[problem.Horizon + 1];
123
124 for (int l = 0;
125 l < problem.Horizon;
126 l++)
127 {
128 double rhs =
129 cumulativeDemand[l];
130
131 if (rhs == 0.0)
132 {
133 continue;
134 }
135
136 suffixWeightedSetup[l + 1] =
137 0.0;
138
139 for (int period = l;
140 period >= 0;
141 period--)
142 {
143 double demandToL =
145 cumulativeDemand,
146 period,
147 l);
148
149 suffixWeightedSetup[period] =
150 suffixWeightedSetup[period + 1] +
151 demandToL *
152 y[period];
153 }
154
155 for (int k = 0;
156 k <= l;
157 k++)
158 {
159 double lhs =
160 prefixProduction[k] +
161 suffixWeightedSetup[k];
162
163 double violation =
164 rhs - lhs;
165
166 var s =
167 Enumerable
168 .Range(
169 0,
170 k)
171 .ToArray();
172
173 var coefficients =
174 new List<CutCoefficient>(
175 l + 1);
176
177 for (int period = 0;
178 period < k;
179 period++)
180 {
181 coefficients.Add(
182 new CutCoefficient(
184 formulation,
185 formulation.Variables.Production,
186 period,
187 "production"),
188 1.0));
189 }
190
191 for (int period = k;
192 period <= l;
193 period++)
194 {
195 double demandToL =
197 cumulativeDemand,
198 period,
199 l);
200
201 if (demandToL == 0.0)
202 {
203 continue;
204 }
205
206 coefficients.Add(
207 new CutCoefficient(
209 formulation,
210 formulation.Variables.Setup,
211 period,
212 "setup"),
213 demandToL));
214 }
215
216 if (coefficients.Count == 0)
217 {
218 continue;
219 }
220
221 var definition =
222 new LsCutDefinition(
223 l,
224 s,
225 coefficients,
226 LinearConstraintSense.GreaterOrEqual,
227 rhs);
228
229 cuts.Add(
230 new LsSeparatedCut(
231 definition,
232 violation,
234 violation,
235 coefficients)));
236 }
237 }
238
239 return cuts;
240 }
241}
Solver-independent definition of one ULS (l,S) inequality.
static void RequireAggregateVariables(UlsFormulation formulation)
static string GetVariableName(UlsFormulation formulation, IReadOnlyDictionary< int, int > semanticMap, int period, string family)
static double GetSemanticValue(IReadOnlyDictionary< int, int > semanticMap, int period, IReadOnlyDictionary< int, double > values, string family)
static double Efficacy(double violation, IEnumerable< CutCoefficient > coefficients)
static double IntervalDemand(double[] cumulativeDemand, int first, int last)
One candidate (l,S) inequality produced by a separation procedure.
Separates the O(T^2) Wagner-Whitin specialization of the classical ULS (l,S) inequalities.
bool IsApplicable(UlsProblem problem)
Tests whether the separator is applicable to the problem.
IReadOnlyList< LsSeparatedCut > Separate(UlsProblem problem, UlsFormulation formulation, IReadOnlyDictionary< int, double > variableValues)
Generates the separator's candidate inequalities at one LP point.
CutSeparationMethod Method
Gets the traceability method identifier.
Solver-independent ULS mathematical formulation plus semantic variable map.
UlsFormulationVariableMap Variables
Gets semantic variable mappings.
IReadOnlyDictionary< int, int > Setup
Gets setup-variable ids by period.
IReadOnlyDictionary< int, int > Production
Gets production-variable ids by period.
Represents a validated classical uncapacitated lot-sizing problem.
Definition UlsProblem.cs:23
int Horizon
Gets the number of planning periods.
Definition UlsProblem.cs:82
Separates classical ULS (l,S) inequalities from a fractional aggregate lot-sizing solution.
LinearConstraintSense
Identifies the sense of a generated linear inequality.
CutSeparationMethod
Identifies the separation procedure that generated a cut.
Stores one nonzero coefficient of a generated linear inequality.