ULSAlgorithms 1.1.0-g3e5595996d
High-performance exact and heuristic algorithms for uncapacitated lot sizing
Loading...
Searching...
No Matches
FedergruenTzurLinearCore.cs
Go to the documentation of this file.
1using System.Buffers;
5
7
8/// <summary>
9/// Shared allocation-conscious forward recurrence for the two Federgruen-Tzur
10/// linear-time specializations.
11/// </summary>
12internal static class FedergruenTzurLinearCore
13{
14 private const int CancellationCheckMask = 255;
15
17 UlsProblem problem,
18 string solverName,
19 CancellationToken cancellationToken)
20 {
21 return Solve(
22 problem,
23 solverName,
24 FedergruenTzurLinearMode.NoSpeculativeMotive,
25 cancellationToken);
26 }
27
29 UlsProblem problem,
30 string solverName,
31 CancellationToken cancellationToken)
32 {
33 return Solve(
34 problem,
35 solverName,
36 FedergruenTzurLinearMode.NondecreasingSetupCosts,
37 cancellationToken);
38 }
39
40 private static UlsSolveResult Solve(
41 UlsProblem problem,
42 string solverName,
43 FedergruenTzurLinearMode mode,
44 CancellationToken cancellationToken)
45 {
46 var horizon = problem.Horizon;
47
48 var valueBuffer = ArrayPool<double>.Shared.Rent(horizon + 1);
49 var predecessorBuffer = ArrayPool<int>.Shared.Rent(horizon + 1);
50
51 try
52 {
53 var value = valueBuffer.AsSpan(0, horizon + 1);
54 var predecessor = predecessorBuffer.AsSpan(0, horizon + 1);
55
56 value[0] = 0.0;
57 predecessor[0] = -1;
58
59 var demands = problem.Demands;
60 var setupCosts = problem.SetupCosts;
61 var productionCosts = problem.UnitProductionCosts;
62 var holdingCosts = problem.HoldingCosts;
63
64 var cumulativeDemand = 0.0;
65 var cumulativeHoldingBefore = 0.0;
66 var firstPeriodHoldingCost = 0.0;
67
68 using var candidates =
70
71 for (var period = 0; period < horizon; period++)
72 {
73 if ((period & CancellationCheckMask) == 0)
74 {
75 cancellationToken.ThrowIfCancellationRequested();
76 }
77
78 var previousCumulativeDemand = cumulativeDemand;
79
80 cumulativeDemand = AddFinite(
81 cumulativeDemand,
82 demands[period],
83 "cumulative demand");
84
85 firstPeriodHoldingCost = AddFinite(
86 firstPeriodHoldingCost,
87 MultiplyFinite(
88 demands[period],
89 cumulativeHoldingBefore,
90 "first-period-order holding-cost transform"),
91 "first-period-order holding-cost transform");
92
93 // Federgruen-Tzur:
94 // C(i) = c_i - H(i-1).
95 var transformedVariableCost =
96 productionCosts[period] -
97 cumulativeHoldingBefore;
98
99 EnsureFinite(
100 transformedVariableCost,
101 "transformed variable production cost");
102
103 var intercept = value[period];
104
105 intercept = AddFinite(
106 intercept,
107 setupCosts[period],
108 "candidate intercept");
109
110 intercept = AddFinite(
111 intercept,
112 -firstPeriodHoldingCost,
113 "candidate intercept");
114
115 intercept = AddFinite(
116 intercept,
117 MultiplyFinite(
118 cumulativeDemand,
119 cumulativeHoldingBefore,
120 "candidate intercept"),
121 "candidate intercept");
122
123 intercept = AddFinite(
124 intercept,
125 -MultiplyFinite(
126 productionCosts[period],
127 previousCumulativeDemand,
128 "candidate intercept"),
129 "candidate intercept");
130
131 var shouldInsert = candidates.IsEmpty;
132
133 if (!shouldInsert)
134 {
135 shouldInsert =
136 mode == FedergruenTzurLinearMode.NoSpeculativeMotive ||
137 transformedVariableCost < candidates.LastSlope;
138 }
139
140 if (shouldInsert)
141 {
142 candidates.AddMonotone(
143 period,
144 transformedVariableCost,
145 intercept);
146 }
147
148 var bestPeriod =
149 candidates.GetBestAndDiscardPast(
150 cumulativeDemand);
151
152 var bestLineValue = AddFinite(
153 candidates.BestIntercept,
154 MultiplyFinite(
155 candidates.BestSlope,
156 cumulativeDemand,
157 "candidate line evaluation"),
158 "candidate line evaluation");
159
160 var orderValue = AddFinite(
161 firstPeriodHoldingCost,
162 bestLineValue,
163 "forward dynamic-programming value");
164
165 if (demands[period] == 0.0 &&
166 value[period] <= orderValue)
167 {
168 value[period + 1] = value[period];
169 predecessor[period + 1] = period;
170 }
171 else
172 {
173 value[period + 1] = orderValue;
174 predecessor[period + 1] = bestPeriod;
175 }
176
177 cumulativeHoldingBefore = AddFinite(
178 cumulativeHoldingBefore,
179 holdingCosts[period],
180 "cumulative holding cost");
181 }
182
183 cancellationToken.ThrowIfCancellationRequested();
184
185 return ZeroInventoryOrderSolutionBuilder.Build(
186 problem,
187 predecessor,
188 solverName,
189 cancellationToken);
190 }
191 finally
192 {
193 ArrayPool<double>.Shared.Return(
194 valueBuffer,
195 clearArray: false);
196
197 ArrayPool<int>.Shared.Return(
198 predecessorBuffer,
199 clearArray: false);
200 }
201 }
202
203 private static double AddFinite(
204 double left,
205 double right,
206 string operation)
207 {
208 var value = left + right;
209 EnsureFinite(value, operation);
210 return value;
211 }
212
213 private static double MultiplyFinite(
214 double left,
215 double right,
216 string operation)
217 {
218 var value = left * right;
219 EnsureFinite(value, operation);
220 return value;
221 }
222
223 private static void EnsureFinite(
224 double value,
225 string operation)
226 {
227 if (!double.IsFinite(value))
228 {
229 throw new ArithmeticException(
230 $"Numerical overflow while computing {operation}.");
231 }
232 }
233
234 private enum FedergruenTzurLinearMode
235 {
236 NoSpeculativeMotive,
237 NondecreasingSetupCosts
238 }
239}
Array-backed monotone candidate deque used by the two linear-time Federgruen-Tzur specializations.
Shared allocation-conscious forward recurrence for the two Federgruen-Tzur linear-time specialization...
static UlsSolveResult SolveNoSpeculativeMotive(UlsProblem problem, string solverName, CancellationToken cancellationToken)
static UlsSolveResult SolveNondecreasingSetupCosts(UlsProblem problem, string solverName, CancellationToken cancellationToken)
Represents a validated classical uncapacitated lot-sizing problem.
Definition UlsProblem.cs:23
ReadOnlySpan< double > UnitProductionCosts
Gets unit production costs by period.
int Horizon
Gets the number of planning periods.
Definition UlsProblem.cs:82
ReadOnlySpan< double > HoldingCosts
Gets end-of-period unit holding costs by period.
ReadOnlySpan< double > Demands
Gets demand by period.
Definition UlsProblem.cs:92
ReadOnlySpan< double > SetupCosts
Gets fixed setup costs by period.
Definition UlsProblem.cs:97
Represents the outcome returned by a ULS solution strategy.