ULSAlgorithms 1.1.0-g3e5595996d
High-performance exact and heuristic algorithms for uncapacitated lot sizing
Loading...
Searching...
No Matches
ShortestPathFormulationBuilder.cs
Go to the documentation of this file.
4
6
7/// <summary>
8/// Builds an acyclic regeneration-interval shortest-path formulation of ULS.
9/// </summary>
10/// <remarks>
11/// <para>
12/// A replenishment arc (t,j+1) represents one setup in period t serving all
13/// demand from t through j. Zero-demand periods may also be crossed by a
14/// zero-cost skip arc (t,t+1), which preserves correctness when demands contain
15/// zeros.
16/// </para>
17/// <para>
18/// Arc variables are continuous in [0,1]. The node-arc incidence matrix is a
19/// network matrix, so an extreme optimal flow is integral.
20/// </para>
21/// <para>
22/// This regeneration formulation requires the Wagner-Whitin/no-speculative-
23/// motive condition p[t] + h[t] &gt;= p[t+1]. The network interpretation follows
24/// Zangwill (1969), "A Backlogging Model and a Multi-Echelon Model of a Dynamic
25/// Economic Lot Size Production System—A Network Approach", Management Science
26/// 15(9), 506-527. Evans (1985), DOI 10.1016/0272-6963(85)90009-9, gives the
27/// classical efficient Wagner-Whitin recursion.
28/// </para>
29/// </remarks>
30public sealed class ShortestPathFormulationBuilder :
32{
33 /// <inheritdoc />
34 public string Name =>
35 "Regeneration-interval shortest-path formulation";
36
37 /// <inheritdoc />
39 UlsFormulationKind.ShortestPath;
40
41 /// <inheritdoc />
42 public bool IsApplicable(
43 UlsProblem problem)
44 {
45 ArgumentNullException.ThrowIfNull(problem);
46
48 .IsNoSpeculativeMotive(problem);
49 }
50
51 /// <inheritdoc />
53 UlsProblem problem)
54 {
55 ArgumentNullException.ThrowIfNull(problem);
56
57 if (!IsApplicable(problem))
58 {
59 throw new NotSupportedException(
60 "ShortestPathFormulationBuilder requires " +
61 "p[t] + h[t] >= p[t+1] for every adjacent period.");
62 }
63
64 int horizon =
65 problem.Horizon;
66
67 var model =
69
70 var arcs =
71 new Dictionary<(int From, int To), int>();
72
73 var outgoing =
74 new List<(int To, int Variable)>[horizon + 1];
75
76 var incoming =
77 new List<(int From, int Variable)>[horizon + 1];
78
79 for (int node = 0;
80 node <= horizon;
81 node++)
82 {
83 outgoing[node] = [];
84 incoming[node] = [];
85 }
86
87 for (int start = 0;
88 start < horizon;
89 start++)
90 {
91 if (problem.Demands[start] == 0.0)
92 {
93 AddArc(
94 start,
95 start + 1,
96 0.0,
97 $"skip[{start},{start + 1}]");
98 }
99
100 double segmentDemand = 0.0;
101
102 for (int end = start;
103 end < horizon;
104 end++)
105 {
106 segmentDemand =
108 segmentDemand,
109 problem.Demands[end],
110 "shortest-path segment demand");
111
112 if (segmentDemand == 0.0)
113 {
114 continue;
115 }
116
117 AddArc(
118 start,
119 end + 1,
121 problem,
122 start,
123 end),
124 $"z[{start},{end + 1}]");
125 }
126 }
127
128 for (int node = 0;
129 node <= horizon;
130 node++)
131 {
132 var flow =
133 new List<LinearTerm>(
134 outgoing[node].Count +
135 incoming[node].Count);
136
137 foreach ((int _, int variable) in outgoing[node])
138 {
139 flow.Add(
140 new LinearTerm(
141 variable,
142 1.0));
143 }
144
145 foreach ((int _, int variable) in incoming[node])
146 {
147 flow.Add(
148 new LinearTerm(
149 variable,
150 -1.0));
151 }
152
153 double rhs =
154 node == 0
155 ? 1.0
156 : node == horizon
157 ? -1.0
158 : 0.0;
159
160 model.AddConstraint(
161 $"flow[{node}]",
162 flow,
164 rhs);
165 }
166
167 return new UlsFormulation(
168 Kind,
169 "Regeneration network formulation; Zangwill (1969), Management " +
170 "Science 15(9), 506-527; Evans (1985), DOI " +
171 "10.1016/0272-6963(85)90009-9; classical formulation taxonomy in " +
172 "Brahimi et al. (2006), DOI 10.1016/j.ejor.2004.01.054.",
173 model.Build(
174 "ULS-Shortest-Path"),
176 arcs: arcs));
177
178 void AddArc(
179 int from,
180 int to,
181 double cost,
182 string name)
183 {
184 int variable =
185 model.AddVariable(
186 name,
187 LinearVariableType.Continuous,
188 0.0,
189 1.0);
190
191 arcs.Add(
192 (from, to),
193 variable);
194
195 outgoing[from].Add(
196 (to, variable));
197
198 incoming[to].Add(
199 (from, variable));
200
201 model.AddObjectiveTerm(
202 variable,
203 cost);
204 }
205 }
206}
static double RegenerationArcCost(UlsProblem problem, int start, int endInclusive)
static double AddFinite(double left, double right, string operation)
Builds an acyclic regeneration-interval shortest-path formulation of ULS.
bool IsApplicable(UlsProblem problem)
Tests whether the formulation is valid for the supplied costs.
UlsFormulation Build(UlsProblem problem)
Builds the portable formulation.
Solver-independent ULS mathematical formulation plus semantic variable map.
Maps semantic ULS decisions to solver-independent variable identifiers.
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 > Demands
Gets demand by period.
Definition UlsProblem.cs:92
Builds a solver-independent mathematical-programming formulation of ULS.
UlsFormulationKind
Identifies a mathematical-programming formulation of classical ULS.
LinearVariableType
Identifies the domain of a variable in a portable linear mathematical model.
LinearConstraintSense
Identifies the sense of a portable linear constraint.
Stores one coefficient of a portable linear expression.
Definition LinearTerm.cs:7