34 "McLaren Order Moment";
50 ArgumentNullException.ThrowIfNull(problem);
54 "McLaren Order Moment");
67 if (holdingCost == 0.0)
69 return double.PositiveInfinity;
72 double averageDemand =
80 if (denominator == 0.0)
82 return double.PositiveInfinity;
90 if (
double.IsPositiveInfinity(ratio))
92 return double.PositiveInfinity;
95 if (!
double.IsFinite(ratio) ||
98 throw new ArithmeticException(
99 "Non-finite EOQ-derived ratio while computing the Order Moment Target.");
102 double timeBetweenOrders =
105 double truncatedTimeBetweenOrders =
106 Math.Floor(timeBetweenOrders);
108 double integerMoment =
109 truncatedTimeBetweenOrders *
110 (truncatedTimeBetweenOrders - 1.0) /
113 double fractionalMoment =
115 truncatedTimeBetweenOrders) *
116 truncatedTimeBetweenOrders;
123 if (!
double.IsFinite(target))
125 return double.PositiveInfinity;
133 CancellationToken cancellationToken =
default)
135 ArgumentNullException.ThrowIfNull(problem);
136 cancellationToken.ThrowIfCancellationRequested();
144 ArrayPool<int>.Shared.Rent(horizon);
148 Span<int> cycleEnds =
149 buffer.AsSpan(0, horizon);
153 ReadOnlySpan<double> demands =
161 if (start >= horizon)
175 if (holdingCost == 0.0)
193 while (start < horizon)
195 cancellationToken.ThrowIfCancellationRequested();
197 double partPeriods = 0.0;
198 int selectedEnd = start;
201 for (
int candidate = start + 1;
205 if ((candidate & 255) == 0)
207 cancellationToken.ThrowIfCancellationRequested();
215 selectedEnd = candidate;
219 double candidatePartPeriods =
221 (candidate - start) *
224 if (!
double.IsFinite(candidatePartPeriods))
226 throw new ArithmeticException(
227 "Numerical overflow while accumulating MOM part-periods.");
231 candidatePartPeriods,
235 candidatePartPeriods;
243 double marginalHolding =
245 (candidate - start) *
248 if (!
double.IsFinite(marginalHolding))
250 throw new ArithmeticException(
251 "Numerical overflow while evaluating the MOM marginal test.");
296 ArrayPool<int>.Shared.Return(
302 private static bool StrictlyBelow(
306 if (
double.IsPositiveInfinity(target))
323 private static bool LessOrEqual(
Shared applicability checks for classical stationary-cost lot-sizing heuristics.
static void ThrowIfNotStationary(UlsProblem problem, string solverName)
static bool HasStationaryRelevantCosts(UlsProblem problem)
static int FindNextPositiveDemand(ReadOnlySpan< double > demands, int start)
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)
Implements McLaren's Order Moment (MOM) lot-sizing heuristic.
UlsSolveResult Solve(UlsProblem problem, CancellationToken cancellationToken=default)
Solves an uncapacitated lot-sizing problem.
UlsSolverKind Kind
Gets the broad family of the solver.
string Name
Gets the stable human-readable name of the solver.
static bool IsApplicable(UlsProblem problem)
static double GetOrderMomentTarget(UlsProblem problem)
Computes the Order Moment Target for the supplied stationary-cost problem.
Represents a validated classical uncapacitated lot-sizing problem.
double TotalDemand
Gets the total demand over the complete planning horizon.
int Horizon
Gets the number of planning periods.
ReadOnlySpan< double > HoldingCosts
Gets end-of-period unit holding costs by period.
ReadOnlySpan< double > Demands
Gets demand by period.
ReadOnlySpan< double > SetupCosts
Gets fixed setup costs by period.
Represents the outcome returned by a ULS solution strategy.
Defines the common strategy contract implemented by every ULS solver.
UlsSolverKind
Identifies the broad family of a ULS solution strategy.