LotSizingDataModel.Solution 2.0.1
Solution objects for production, setup, inventory and related decisions.
Loading...
Searching...
No Matches
LotSizingSolutionFactory.cs
Go to the documentation of this file.
1using System;
2using System.Linq;
3using LotSizingDataModel.Core;
4using LotSizingDataModel.Core.PhysicalModel;
5using LotSizingDataModel.Core.Validation;
8
10
11/// <summary>
12/// Creates lot-sizing solutions whose decision structure
13/// matches a supply-chain instance.
14/// </summary>
15/// <remarks>
16/// The created solution does not retain a reference to the
17/// supplied <see cref="SupplyChain"/> object.
18///
19/// Identifiers and warehouse references are copied into
20/// independent solution objects.
21/// </remarks>
22public static class LotSizingSolutionFactory
23{
24 /// <summary>
25 /// Creates a zero-initialized solution whose decision
26 /// structure matches the specified supply-chain instance.
27 /// </summary>
28 /// <param name="supplyChain">
29 /// Supply-chain instance used to create the decision
30 /// structure.
31 /// </param>
32 /// <param name="instanceIdentifier">
33 /// Identifier of the associated supply-chain instance.
34 /// </param>
35 /// <param name="name">
36 /// Optional human-readable solution name.
37 /// </param>
38 /// <param name="instanceFingerprint">
39 /// Optional fingerprint of the associated instance.
40 /// </param>
41 /// <param name="validateSupplyChain">
42 /// True to validate the supply-chain instance before
43 /// creating the solution; otherwise, false.
44 /// </param>
45 /// <returns>
46 /// A structurally complete, zero-initialized solution.
47 /// </returns>
48 /// <exception cref="ArgumentNullException">
49 /// Thrown when <paramref name="supplyChain"/> is null.
50 /// </exception>
51 /// <exception cref="ArgumentOutOfRangeException">
52 /// Thrown when the instance planning horizon is not
53 /// strictly positive.
54 /// </exception>
55 /// <exception cref="InvalidOperationException">
56 /// Thrown when the instance is invalid or contains an
57 /// unresolved transport-resource reference.
58 /// </exception>
60 SupplyChain supplyChain,
61 string instanceIdentifier = "",
62 string name = "",
63 string instanceFingerprint = "",
64 bool validateSupplyChain = true)
65 {
66 ArgumentNullException.ThrowIfNull(supplyChain);
67
68 if (supplyChain.PlanningHorizon <= 0)
69 {
70 throw new ArgumentOutOfRangeException(
71 nameof(supplyChain),
72 supplyChain.PlanningHorizon,
73 "The supply-chain planning horizon must be " +
74 "strictly positive.");
75 }
76
77 if (validateSupplyChain)
78 {
79 var validator =
80 new SupplyChainValidator();
81
82 validator.ThrowIfInvalid(
83 supplyChain);
84 }
85
86 var solution =
88 name: name ?? string.Empty,
89 instanceIdentifier:
90 instanceIdentifier ?? string.Empty,
91 planningHorizon:
92 supplyChain.PlanningHorizon)
93 {
94 InstanceFingerprint =
95 instanceFingerprint ?? string.Empty,
96
97 Completeness =
99 };
100
101 CreateProductionDecisions(
102 supplyChain,
103 solution);
104
105 CreateInventoryDecisions(
106 supplyChain,
107 solution);
108
109 CreateTransportDecisions(
110 supplyChain,
111 solution);
112
113 CreatePurchaseDecisions(
114 supplyChain,
115 solution);
116
117 CreateDistributionDecisions(
118 supplyChain,
119 solution);
120
121 CreateWorkCenterCapacityDecisions(
122 supplyChain,
123 solution);
124
125 CreateWarehouseCapacityDecisions(
126 supplyChain,
127 solution);
128
129 CreateTransportResourceCapacityDecisions(
130 supplyChain,
131 solution);
132
133 /*
134 * Every expected decision object has now been created.
135 * This means that the solution is structurally complete.
136 *
137 * It does not mean that the all-zero solution is feasible.
138 */
139 solution.Completeness =
140 SolutionCompleteness.Complete;
141
142 return solution;
143 }
144
145 private static void CreateProductionDecisions(
146 SupplyChain supplyChain,
147 LotSizingSolution solution)
148 {
149 foreach (var routing
150 in supplyChain.ProductionRoutings)
151 {
152 var decision =
154 routingId: routing.Id,
155 planningHorizon:
156 supplyChain.PlanningHorizon);
157
158 solution.AddProductionDecision(
159 decision);
160 }
161 }
162
163 private static void CreateInventoryDecisions(
164 SupplyChain supplyChain,
165 LotSizingSolution solution)
166 {
167 foreach (var inventory
168 in supplyChain.Inventories)
169 {
170 var decision =
172 itemId: inventory.ItemId,
173 warehouse:
174 CopyWarehouseReference(
175 inventory.Warehouse),
176 planningHorizon:
177 supplyChain.PlanningHorizon);
178
179 solution.AddInventoryDecision(
180 decision);
181 }
182 }
183
184 private static void CreateTransportDecisions(
185 SupplyChain supplyChain,
186 LotSizingSolution solution)
187 {
188 /*
189 * A transport characteristic identifies an allowed
190 * item-resource combination.
191 *
192 * The lanes of the transport resource identify
193 * the corresponding directed origin-destination pairs.
194 */
195 foreach (var characteristic
196 in supplyChain.TransportCharacteristics)
197 {
198 var transportResource =
199 supplyChain.TransportResources
200 .FirstOrDefault(
201 resource =>
202 resource.Id ==
203 characteristic
204 .TransportResourceId);
205
206 if (transportResource is null)
207 {
208 throw new InvalidOperationException(
209 $"Transport resource " +
210 $"{characteristic.TransportResourceId} " +
211 $"referenced by item " +
212 $"{characteristic.ItemId} does not exist.");
213 }
214
215 foreach (var lane
216 in supplyChain.GetTransportLanes(transportResource.Id))
217 {
218 var decision =
219 new TransportDecision(
220 itemId:
221 characteristic.ItemId,
222
223 transportResourceId:
224 characteristic
225 .TransportResourceId,
226
227 origin:
228 CopyWarehouseReference(
229 lane.Origin),
230
231 destination:
232 CopyWarehouseReference(
233 lane.Destination),
234
235 planningHorizon:
236 supplyChain.PlanningHorizon);
237
238 solution.AddTransportDecision(
239 decision);
240 }
241 }
242 }
243
244 private static void CreatePurchaseDecisions(
245 SupplyChain supplyChain,
246 LotSizingSolution solution)
247 {
248 foreach (var delivery
249 in supplyChain.SupplierDeliveries)
250 {
251 var decision =
252 new PurchaseDecision(
253 supplierId:
254 delivery.SupplierId,
255
256 itemId:
257 delivery.ItemId,
258
259 destinationWarehouse:
260 CopyWarehouseReference(
261 delivery.Warehouse),
262
263 planningHorizon:
264 supplyChain.PlanningHorizon);
265
266 solution.AddPurchaseDecision(
267 decision);
268 }
269 }
270
271 private static void CreateDistributionDecisions(
272 SupplyChain supplyChain,
273 LotSizingSolution solution)
274 {
275 foreach (var sourcing
276 in supplyChain
277 .DistributionCenterSourcings)
278 {
279 var decision =
280 new DistributionDecision(
281 distributionCenterId:
282 sourcing.DistributionCenterId,
283
284 itemId:
285 sourcing.ItemId,
286
287 warehouse:
288 CopyWarehouseReference(
289 sourcing.Warehouse),
290
291 planningHorizon:
292 supplyChain.PlanningHorizon);
293
295 decision);
296 }
297 }
298
299 private static void
300 CreateWorkCenterCapacityDecisions(
301 SupplyChain supplyChain,
302 LotSizingSolution solution)
303 {
304 foreach (var plant
305 in supplyChain.Plants)
306 {
307 foreach (var workCenter
308 in plant.WorkCenters)
309 {
310 var reference =
311 new WorkCenterReference
312 {
313 PlantId =
314 plant.Id,
315
316 WorkCenterId =
317 workCenter.Id
318 };
319
320 var decision =
321 new WorkCenterCapacityDecision(
322 workCenter: reference,
323 planningHorizon:
324 supplyChain.PlanningHorizon);
325
327 decision);
328 }
329 }
330 }
331
332 private static void
333 CreateWarehouseCapacityDecisions(
334 SupplyChain supplyChain,
335 LotSizingSolution solution)
336 {
337 /*
338 * Every plant owns one internal warehouse whose
339 * reference identifier is the plant identifier.
340 */
341 foreach (var plant
342 in supplyChain.Plants)
343 {
344 WarehouseReference reference =
345 WarehouseReference
346 .ForPlantWarehouse(
347 plant.Id);
348
349 var decision =
350 new WarehouseCapacityDecision(
351 warehouse: reference,
352 planningHorizon:
353 supplyChain.PlanningHorizon);
354
356 decision);
357 }
358
359 foreach (var warehouse
360 in supplyChain.StandaloneWarehouses)
361 {
362 WarehouseReference reference =
363 WarehouseReference
364 .ForStandaloneWarehouse(
365 warehouse.Id);
366
367 var decision =
368 new WarehouseCapacityDecision(
369 warehouse: reference,
370 planningHorizon:
371 supplyChain.PlanningHorizon);
372
374 decision);
375 }
376 }
377
378 private static void
379 CreateTransportResourceCapacityDecisions(
380 SupplyChain supplyChain,
381 LotSizingSolution solution)
382 {
383 foreach (var transportResource
384 in supplyChain.TransportResources)
385 {
386 var decision =
387 new TransportResourceCapacityDecision(
388 transportResourceId:
389 transportResource.Id,
390
391 planningHorizon:
392 supplyChain.PlanningHorizon);
393
394 solution
396 decision);
397 }
398 }
399
400 private static WarehouseReference
401 CopyWarehouseReference(
402 WarehouseReference source)
403 {
404 ArgumentNullException.ThrowIfNull(source);
405
406 return source.Kind switch
407 {
408 WarehouseReferenceKind
409 .StandaloneWarehouse =>
410 WarehouseReference
411 .ForStandaloneWarehouse(
412 source.ReferenceId),
413
414 WarehouseReferenceKind
415 .PlantWarehouse =>
416 WarehouseReference
417 .ForPlantWarehouse(
418 source.ReferenceId),
419
420 _ =>
421 throw new InvalidOperationException(
422 $"Unsupported warehouse-reference kind: " +
423 $"{source.Kind}.")
424 };
425 }
426}
Creates lot-sizing solutions whose decision structure matches a supply-chain instance.
static LotSizingSolution Create(SupplyChain supplyChain, string instanceIdentifier="", string name="", string instanceFingerprint="", bool validateSupplyChain=true)
Creates a zero-initialized solution whose decision structure matches the specified supply-chain insta...
Stores the inventory decisions associated with one item and one warehouse over the complete planning ...
Stores the production decisions associated with one production routing over the complete planning hor...
Represents one candidate solution for a lot-sizing supply-chain instance.
void AddPurchaseDecision(PurchaseDecision decision)
Adds a purchase decision to the solution.
void AddWarehouseCapacityDecision(WarehouseCapacityDecision decision)
Adds a warehouse-capacity decision to the solution.
void AddInventoryDecision(InventoryDecision decision)
Adds an inventory decision to the solution.
void AddTransportDecision(TransportDecision decision)
Adds a transport decision to the solution.
void AddWorkCenterCapacityDecision(WorkCenterCapacityDecision decision)
Adds a work-center capacity decision to the solution.
void AddDistributionDecision(DistributionDecision decision)
Adds a distribution decision to the solution.
void AddTransportResourceCapacityDecision(TransportResourceCapacityDecision decision)
Adds a transport-resource capacity decision to the solution.
void AddProductionDecision(ProductionDecision decision)
Adds a production decision to the solution.
SolutionCompleteness
Indicates whether a lot-sizing solution contains all decision values expected for its associated inst...
@ Unknown
The completeness of the solution has not been evaluated.