16 LotSizingInstance instance,
17 LotSizingSolution solution,
18 double tolerance = 1.0e-6)
20 ArgumentNullException.ThrowIfNull(instance);
21 ArgumentNullException.ThrowIfNull(solution);
23 if (!
double.IsFinite(tolerance) ||
26 throw new ArgumentOutOfRangeException(
31 new List<MathematicalFeasibilityDiagnostic>();
35 foreach (ClosedLoopReturnStream stream
36 in instance.ClosedLoopReturnStreams)
38 ClosedLoopDecision[] decisions =
39 solution.ClosedLoopDecisions
42 candidate.ReturnStreamId ==
46 if (decisions.Length == 0)
53 $
"Closed-loop decision for return stream '{stream.Id}' is missing."));
58 if (decisions.Length > 1)
63 $
"Closed-loop return stream '{stream.Id}' has duplicate solution decisions."));
68 ClosedLoopDecision decision =
71 if (decision.PlanningHorizon !=
72 instance.PlanningHorizon)
77 $
"Closed-loop decision for stream '{stream.Id}' has an inconsistent planning horizon."));
83 period <= instance.PlanningHorizon;
87 decision.RecoveryInputs[period];
90 decision.DisposalQuantities[period];
93 decision.RecoveredOutputs[period];
98 stream.ReturnQuantity[period]) >
104 $
"Return conservation is violated for stream '{stream.Id}', period {period}."));
109 stream.RecoveryYield *
116 $
"Recovery-yield identity is violated for stream '{stream.Id}', period {period}."));
119 if (stream.RecoveryCapacity is not
null &&
121 stream.RecoveryCapacity[period] +
127 $
"Recovery capacity is violated for stream '{stream.Id}', period {period}."));
133 instance.ClosedLoopReturnStreams
139 foreach (ClosedLoopDecision decision
140 in solution.ClosedLoopDecisions)
142 if (!knownStreamIds.Contains(
143 decision.ReturnStreamId))
148 $
"Solution contains unknown closed-loop return stream '{decision.ReturnStreamId}'."));
158 FeasibilityStatus status =
160 ? FeasibilityStatus.Infeasible
162 ? FeasibilityStatus.PartiallyEvaluated
163 : FeasibilityStatus.Feasible;