ULSAlgorithms 1.1.0-g3e5595996d
High-performance exact and heuristic algorithms for uncapacitated lot sizing
Loading...
Searching...
No Matches
WagnerWhitinClassicalSolver.cs
Go to the documentation of this file.
5
7
8/// <summary>
9/// Implements the classical Wagner-Whitin shortest-path dynamic program.
10/// </summary>
11/// <remarks>
12/// <para>
13/// This implementation deliberately materializes the complete triangular matrix
14/// of regeneration-interval costs before running the dynamic program. It is
15/// therefore useful as a transparent classical implementation and as a
16/// benchmarking baseline.
17/// </para>
18/// <para>
19/// Time complexity: <c>O(n^2)</c>.
20/// Space complexity: <c>O(n^2)</c>.
21/// </para>
22/// <para>
23/// Reference:
24/// H. M. Wagner and T. M. Whitin,
25/// "Dynamic Version of the Economic Lot Size Model",
26/// Management Science 5(1), 89-96, 1958.
27/// DOI: 10.1287/mnsc.5.1.89.
28/// </para>
29/// </remarks>
31{
32 /// <inheritdoc />
33 public string Name => "Wagner-Whitin classical";
34
35 /// <inheritdoc />
37
38 /// <inheritdoc />
40 UlsProblem problem,
41 CancellationToken cancellationToken = default)
42 {
43 ArgumentNullException.ThrowIfNull(problem);
44 cancellationToken.ThrowIfCancellationRequested();
45
46 var horizon = problem.Horizon;
47 var arcCosts = new double[checked(horizon * horizon)];
48
49 BuildArcCostMatrix(problem, arcCosts, cancellationToken);
50
51 var value = new double[horizon + 1];
52 var predecessor = new int[horizon + 1];
53
54 Array.Fill(value, double.PositiveInfinity);
55 Array.Fill(predecessor, -1);
56 value[0] = 0.0;
57
58 for (var end = 1; end <= horizon; end++)
59 {
60 cancellationToken.ThrowIfCancellationRequested();
61
62 var best = double.PositiveInfinity;
63 var bestStart = -1;
64
65 for (var start = 0; start < end; start++)
66 {
67 var arcCost = arcCosts[(start * horizon) + (end - 1)];
68 var candidate = value[start] + arcCost;
69
70 if (candidate < best)
71 {
72 best = candidate;
73 bestStart = start;
74 }
75 }
76
77 if (!double.IsFinite(best) || bestStart < 0)
78 {
79 throw new ArithmeticException(
80 $"No finite Wagner-Whitin value was obtained for horizon prefix {end}.");
81 }
82
83 value[end] = best;
84 predecessor[end] = bestStart;
85 }
86
88 problem,
89 predecessor,
90 Name,
91 cancellationToken);
92 }
93
94 private static void BuildArcCostMatrix(
95 UlsProblem problem,
96 Span<double> arcCosts,
97 CancellationToken cancellationToken)
98 {
99 var horizon = problem.Horizon;
100 var demands = problem.Demands;
101 var setupCosts = problem.SetupCosts;
102 var productionCosts = problem.UnitProductionCosts;
103 var holdingCosts = problem.HoldingCosts;
104
105 for (var start = 0; start < horizon; start++)
106 {
107 cancellationToken.ThrowIfCancellationRequested();
108
109 var deliveredUnitCost = productionCosts[start];
110 var batchCost = 0.0;
111 var cumulativeDemand = 0.0;
112
113 for (var end = start; end < horizon; end++)
114 {
115 cumulativeDemand += demands[end];
116
117 batchCost += demands[end] * deliveredUnitCost;
118
119 if (!double.IsFinite(batchCost))
120 {
121 throw new ArithmeticException(
122 "Numerical overflow while computing a Wagner-Whitin arc cost.");
123 }
124
125 arcCosts[(start * horizon) + end] =
126 cumulativeDemand > 0.0
127 ? setupCosts[start] + batchCost
128 : 0.0;
129
130 if (!double.IsFinite(arcCosts[(start * horizon) + end]))
131 {
132 throw new ArithmeticException(
133 "Numerical overflow while computing a Wagner-Whitin regeneration interval.");
134 }
135
136 if (end < horizon - 1)
137 {
138 deliveredUnitCost += holdingCosts[end];
139
140 if (!double.IsFinite(deliveredUnitCost))
141 {
142 throw new ArithmeticException(
143 "Numerical overflow while accumulating delivered unit cost.");
144 }
145 }
146 }
147 }
148 }
149}
Reconstructs a zero-inventory-order ULS solution from shortest-path predecessors.
static UlsSolveResult Build(UlsProblem problem, ReadOnlySpan< int > predecessor, string solverName, CancellationToken cancellationToken)
Implements the classical Wagner-Whitin shortest-path dynamic program.
string Name
Gets the stable human-readable name of the solver.
UlsSolveResult Solve(UlsProblem problem, CancellationToken cancellationToken=default)
Solves an uncapacitated lot-sizing problem.The solve result.
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.
Defines the common strategy contract implemented by every ULS solver.
Definition IUlsSolver.cs:14
UlsSolverKind
Identifies the broad family of a ULS solution strategy.