ULSAlgorithms 1.1.0-g3e5595996d
High-performance exact and heuristic algorithms for uncapacitated lot sizing
Loading...
Searching...
No Matches
LeastUnitCostSolver.cs
Go to the documentation of this file.
1using System.Buffers;
6
8
9/// <summary>
10/// Implements the classical Least Unit Cost (LUC) heuristic.
11/// </summary>
12/// <remarks>
13/// LUC is analogous to Silver-Meal but divides setup-plus-holding cost by the
14/// number of units in the candidate lot rather than by the number of periods.
15/// The lot is extended until relevant cost per unit first increases.
16/// </remarks>
17public sealed class LeastUnitCostSolver : IUlsSolver
18{
19 public string Name => "Least Unit Cost";
20
21 public UlsSolverKind Kind => UlsSolverKind.Heuristic;
22
23 public static bool IsApplicable(UlsProblem problem) =>
25
27 UlsProblem problem,
28 CancellationToken cancellationToken = default)
29 {
30 ArgumentNullException.ThrowIfNull(problem);
31 cancellationToken.ThrowIfCancellationRequested();
33
34 var horizon = problem.Horizon;
35 var buffer = ArrayPool<int>.Shared.Rent(horizon);
36
37 try
38 {
39 var cycleEnds = buffer.AsSpan(0, horizon);
40 cycleEnds.Fill(-1);
41
42 var demands = problem.Demands;
43 var setupCost = problem.SetupCosts[0];
44 var holdingCost =
45 horizon > 1 ? problem.HoldingCosts[0] : 0.0;
46
47 var start =
49
50 while (start < horizon)
51 {
52 cancellationToken.ThrowIfCancellationRequested();
53
54 var bestEnd = start;
55 var quantity = demands[start];
56 var accumulatedHolding = 0.0;
57 var previousUnitCost = setupCost / quantity;
58
59 for (var end = start + 1; end < horizon; end++)
60 {
61 accumulatedHolding +=
62 holdingCost *
63 (end - start) *
64 demands[end];
65
66 quantity += demands[end];
67
68 var unitCost =
69 (setupCost + accumulatedHolding) /
70 quantity;
71
72 if (unitCost > previousUnitCost)
73 {
74 break;
75 }
76
77 previousUnitCost = unitCost;
78 bestEnd = end;
79 }
80
81 cycleEnds[start] = bestEnd;
82
84 demands,
85 bestEnd + 1);
86 }
87
89 problem,
90 cycleEnds,
91 Name,
92 cancellationToken);
93 }
94 finally
95 {
96 ArrayPool<int>.Shared.Return(buffer, clearArray: false);
97 }
98 }
99}
Shared applicability checks for classical stationary-cost lot-sizing heuristics.
static void ThrowIfNotStationary(UlsProblem problem, string solverName)
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 the classical Least Unit Cost (LUC) heuristic.
string Name
Gets the stable human-readable name of the solver.
UlsSolverKind Kind
Gets the broad family of the solver.
static bool IsApplicable(UlsProblem problem)
UlsSolveResult Solve(UlsProblem problem, CancellationToken cancellationToken=default)
Solves an uncapacitated lot-sizing problem.
Represents a validated classical uncapacitated lot-sizing problem.
Definition UlsProblem.cs:23
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.