12 IReadOnlyDictionary<int, double> values,
14 double feasibilityTolerance)
16 ArgumentNullException.ThrowIfNull(problem);
17 ArgumentNullException.ThrowIfNull(formulation);
18 ArgumentNullException.ThrowIfNull(values);
29 switch (formulation.
Kind)
39 feasibilityTolerance);
51 feasibilityTolerance);
63 feasibilityTolerance);
67 MapInventoryEliminated(
74 feasibilityTolerance);
78 throw new NotSupportedException(
79 $
"Unsupported ULS formulation kind '{formulation.Kind}'.");
82 ComputeCostComponents(
88 out
double productionCost,
89 out
double holdingCost);
100 private static void MapAggregate(
103 IReadOnlyDictionary<int, double> values,
107 double feasibilityTolerance)
120 feasibilityTolerance);
129 feasibilityTolerance);
140 private static void MapFacilityLocation(
143 IReadOnlyDictionary<int, double> values,
147 double zeroTolerance,
148 double feasibilityTolerance)
150 foreach (KeyValuePair<(
int First,
int Second),
int> entry in
158 $
"q[{entry.Key.First},{entry.Key.Second}]"),
159 feasibilityTolerance);
161 production[entry.Key.First] +=
169 if (Math.Abs(production[period]) <= zeroTolerance)
171 production[period] = 0.0;
182 ReconstructInventory(
187 feasibilityTolerance);
190 private static void MapInventoryEliminated(
192 UlsFormulation formulation,
193 IReadOnlyDictionary<int, double> values,
197 double feasibilityTolerance)
210 feasibilityTolerance);
220 ReconstructInventory(
224 zeroTolerance: feasibilityTolerance,
225 feasibilityTolerance);
228 private static void MapShortestPath(
230 UlsFormulation formulation,
231 IReadOnlyDictionary<int, double> values,
235 double zeroTolerance,
236 double feasibilityTolerance)
243 if (++steps > problem.
Horizon + 1)
245 throw new InvalidOperationException(
246 "The shortest-path solution contains an invalid cycle.");
250 formulation.Variables.Arcs
253 entry.Key.From == node)
263 $
"arc[{entry.Key.From},{entry.Key.To}]")
267 candidate.Value > zeroTolerance)
276 if (outgoing.Length == 0)
278 throw new InvalidOperationException(
279 $
"No positive outgoing shortest-path arc exists from node {node}.");
288 throw new InvalidOperationException(
289 $
"Invalid shortest-path arc ({node},{next}).");
292 double segmentDemand = 0.0;
294 for (
int demandPeriod = node;
302 if (segmentDemand > zeroTolerance)
313 ReconstructInventory(
318 feasibilityTolerance);
321 private static void ReconstructInventory(
325 double zeroTolerance,
326 double feasibilityTolerance)
328 double previous = 0.0;
339 if (Math.Abs(value) <= zeroTolerance)
347 feasibilityTolerance);
354 private static void ComputeCostComponents(
359 out
double setupCost,
360 out
double productionCost,
361 out
double holdingCost)
364 productionCost = 0.0;
386 if (!
double.IsFinite(setupCost) ||
387 !
double.IsFinite(productionCost) ||
388 !
double.IsFinite(holdingCost))
390 throw new ArithmeticException(
391 "A reconstructed ULS cost component is not finite.");
395 private static double GetValue(
396 IReadOnlyDictionary<int, int> semanticMap,
398 IReadOnlyDictionary<int, double> values,
401 if (!semanticMap.TryGetValue(
405 throw new InvalidOperationException(
406 $
"The formulation contains no {family} variable for period {period}.");
412 $
"{family}[{period}]");
415 private static double GetValue(
416 IReadOnlyDictionary<int, double> values,
420 if (!values.TryGetValue(
423 !
double.IsFinite(value))
425 throw new InvalidOperationException(
426 $
"No finite solver value exists for {description} " +
427 $
"(variable id {variableId}).");
433 private static bool GetBinaryDecision(
434 IReadOnlyDictionary<int, int> semanticMap,
436 IReadOnlyDictionary<int, double> values,
456 throw new InvalidOperationException(
457 $
"{family}[{period}] was not normalized to 0 or 1: {value:G17}.");
460 private static double CleanNonnegative(
462 double feasibilityTolerance)
464 if (!
double.IsFinite(value))
466 throw new InvalidOperationException(
467 "A reconstructed ULS decision is not finite.");
475 if (Math.Abs(value) <= feasibilityTolerance)
480 throw new InvalidOperationException(
481 $
"A reconstructed ULS decision is materially negative: {value:G17}.");