ULSAlgorithms 1.1.0-g3e5595996d
High-performance exact and heuristic algorithms for uncapacitated lot sizing
Loading...
Searching...
No Matches
HeuristicSolutionBuilder.cs
Go to the documentation of this file.
3
5
6/// <summary>
7/// Builds and validates a zero-backlogging heuristic solution from a set of
8/// replenishment cycles.
9/// </summary>
10internal static class HeuristicSolutionBuilder
11{
12 public static UlsSolveResult Build(
13 UlsProblem problem,
14 ReadOnlySpan<int> cycleEnds,
15 string solverName,
16 CancellationToken cancellationToken)
17 {
18 ArgumentNullException.ThrowIfNull(problem);
19
20 var horizon = problem.Horizon;
21
22 if (cycleEnds.Length < horizon)
23 {
24 throw new ArgumentException(
25 "The cycle-end vector is shorter than the problem horizon.",
26 nameof(cycleEnds));
27 }
28
29 var production = new double[horizon];
30 var inventory = new double[horizon];
31 var setup = new bool[horizon];
32
33 var demands = problem.Demands;
34
35 for (var start = 0; start < horizon; start++)
36 {
37 if ((start & 255) == 0)
38 {
39 cancellationToken.ThrowIfCancellationRequested();
40 }
41
42 var end = cycleEnds[start];
43
44 if (end < 0)
45 {
46 continue;
47 }
48
49 if (end < start || end >= horizon)
50 {
51 throw new InvalidOperationException(
52 $"Invalid replenishment cycle [{start}, {end}].");
53 }
54
55 var quantity = 0.0;
56
57 for (var period = start; period <= end; period++)
58 {
59 quantity += demands[period];
60
61 if (!double.IsFinite(quantity))
62 {
63 throw new ArithmeticException(
64 "Numerical overflow while accumulating a heuristic lot.");
65 }
66 }
67
68 if (quantity == 0.0)
69 {
70 continue;
71 }
72
73 if (production[start] != 0.0)
74 {
75 throw new InvalidOperationException(
76 $"More than one replenishment cycle starts in period {start}.");
77 }
78
79 production[start] = quantity;
80 setup[start] = true;
81 }
82
83 var setupCost = 0.0;
84 var productionCost = 0.0;
85 var holdingCost = 0.0;
86 var stock = 0.0;
87
88 var setupCosts = problem.SetupCosts;
89 var productionCosts = problem.UnitProductionCosts;
90 var holdingCosts = problem.HoldingCosts;
91
92 var tolerance =
93 1e-10 * Math.Max(1.0, problem.TotalDemand);
94
95 for (var period = 0; period < horizon; period++)
96 {
97 if ((period & 255) == 0)
98 {
99 cancellationToken.ThrowIfCancellationRequested();
100 }
101
102 stock += production[period] - demands[period];
103
104 if (stock < -tolerance)
105 {
106 throw new InvalidOperationException(
107 $"The heuristic plan backlogs demand in period {period}.");
108 }
109
110 if (Math.Abs(stock) <= tolerance)
111 {
112 stock = 0.0;
113 }
114
115 inventory[period] = stock;
116
117 if (setup[period])
118 {
119 setupCost = AddFinite(
120 setupCost,
121 setupCosts[period],
122 "heuristic setup cost");
123 }
124
125 productionCost = AddFinite(
126 productionCost,
127 MultiplyFinite(
128 production[period],
129 productionCosts[period],
130 "heuristic production cost"),
131 "heuristic production cost");
132
133 holdingCost = AddFinite(
134 holdingCost,
135 MultiplyFinite(
136 inventory[period],
137 holdingCosts[period],
138 "heuristic holding cost"),
139 "heuristic holding cost");
140 }
141
142 if (Math.Abs(stock) > tolerance)
143 {
144 throw new InvalidOperationException(
145 "The heuristic plan does not end with zero inventory.");
146 }
147
148 var solution = UlsSolution.FromOwnedBuffers(
149 production,
150 inventory,
151 setup,
152 setupCost,
153 productionCost,
154 holdingCost);
155
156 return new UlsSolveResult(
157 solverName,
158 UlsSolveStatus.Feasible,
159 solution,
160 "Heuristic solution; no optimality proof is claimed.");
161 }
162
163 private static double AddFinite(
164 double left,
165 double right,
166 string operation)
167 {
168 var value = left + right;
169
170 if (!double.IsFinite(value))
171 {
172 throw new ArithmeticException(
173 $"Numerical overflow while computing {operation}.");
174 }
175
176 return value;
177 }
178
179 private static double MultiplyFinite(
180 double left,
181 double right,
182 string operation)
183 {
184 var value = left * right;
185
186 if (!double.IsFinite(value))
187 {
188 throw new ArithmeticException(
189 $"Numerical overflow while computing {operation}.");
190 }
191
192 return value;
193 }
194}
Builds and validates a zero-backlogging heuristic solution from a set of replenishment cycles.
static UlsSolveResult Build(UlsProblem problem, ReadOnlySpan< int > cycleEnds, string solverName, CancellationToken cancellationToken)
Represents a validated classical uncapacitated lot-sizing problem.
Definition UlsProblem.cs:23
double TotalDemand
Gets the total demand over the complete planning horizon.
Definition UlsProblem.cs:87
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 a feasible production plan for a ULS problem.
Definition UlsSolution.cs:7
static UlsSolution FromOwnedBuffers(double[] productionQuantities, double[] endingInventories, bool[] setupDecisions, double setupCost, double productionCost, double holdingCost)
Creates a solution while transferring ownership of already allocated solver buffers.
Represents the outcome returned by a ULS solution strategy.
UlsSolveStatus
Describes the mathematical status of a ULS solve.