20 ArgumentNullException.ThrowIfNull(problem);
22 if (cycleEnds.Length < problem.
Horizon)
24 throw new ArgumentException(
25 "The cycle-end buffer is shorter than the problem horizon.",
29 var previousStart = -1;
32 for (var period = 0; period < problem.
Horizon; period++)
34 if (cycleEnds[period] < period)
39 previousStart = lastStart;
43 if (previousStart < 0 || lastStart < 0)
48 var lastEnd = cycleEnds[lastStart];
50 if (lastEnd < lastStart ||
53 throw new InvalidOperationException(
54 $
"Invalid final replenishment cycle [{lastStart}, {lastEnd}].");
57 var lastQuantity = 0.0;
60 for (var period = lastStart; period <= lastEnd; period++)
62 lastQuantity += demands[period];
64 if (!
double.IsFinite(lastQuantity))
66 throw new ArithmeticException(
67 "Numerical overflow while evaluating the final-lot merge.");
71 if (lastQuantity <= 0.0)
81 var extraHoldingCost =
83 (lastStart - previousStart) *
86 if (!
double.IsFinite(extraHoldingCost))
88 throw new ArithmeticException(
89 "Numerical overflow while evaluating final-lot holding cost.");
98 Math.Abs(extraHoldingCost),
99 Math.Abs(setupSaving)));
101 var tolerance = 1.0e-12 * scale;
103 if (extraHoldingCost + tolerance >= setupSaving)
108 cycleEnds[previousStart] = lastEnd;
109 cycleEnds[lastStart] = -1;