LotSizingDataModel.Checker 2.0.1
Reusable validation engine for structural, mathematical and objective consistency checks.
Loading...
Searching...
No Matches
MathematicalModelSolveResultFeasibilityChecker.cs
Go to the documentation of this file.
1using LotSizingDataModel.Solution.Common;
2using LotSizingDataModel.Solver.Execution;
3using LotSizingDataModel.Solver.Modeling;
4
6
7/// <summary>
8/// Independently evaluates a mathematical solver result against
9/// the solver-independent model.
10/// </summary>
12{
14 MathematicalModel model,
15 MathematicalModelSolveResult solveResult,
16 double tolerance = 1.0e-6)
17 {
18 ArgumentNullException.ThrowIfNull(model);
19 ArgumentNullException.ThrowIfNull(solveResult);
20
21 if (!double.IsFinite(tolerance) ||
22 tolerance < 0.0)
23 {
24 throw new ArgumentOutOfRangeException(
25 nameof(tolerance));
26 }
27
28 model.EnsureValid();
29
30 var diagnostics =
31 new List<MathematicalFeasibilityDiagnostic>();
32
33 if (!solveResult.HasFeasibleSolution)
34 {
35 diagnostics.Add(
37 "LSDM-FEAS-SOL-000",
38 "Solver result does not claim a feasible incumbent; no candidate can be checked."));
39
41 FeasibilityStatus.NotEvaluated,
42 diagnostics);
43 }
44
45 var values =
46 new Dictionary<int, double>();
47
48 bool complete = true;
49
50 foreach (MathematicalVariable variable
51 in model.Variables)
52 {
53 MathematicalVariableValue? value =
54 solveResult.FindVariableValue(
55 variable.Id);
56
57 if (value is null)
58 {
59 complete = false;
60
61 diagnostics.Add(
63 "LSDM-FEAS-SOL-001",
64 $"Missing value for variable '{variable.Name}' ({variable.Id})."));
65
66 continue;
67 }
68
69 values[variable.Id] =
70 value.Value;
71
72 CheckVariableDomain(
73 variable,
74 value.Value,
75 tolerance,
76 diagnostics);
77 }
78
79 if (diagnostics.Any(
80 diagnostic =>
81 diagnostic.Code is
82 "LSDM-FEAS-SOL-002" or
83 "LSDM-FEAS-SOL-003"))
84 {
86 FeasibilityStatus.Infeasible,
87 diagnostics);
88 }
89
90 if (!complete)
91 {
93 FeasibilityStatus.PartiallyEvaluated,
94 diagnostics);
95 }
96
97 foreach (LinearConstraint constraint
98 in model.Constraints)
99 {
100 if (!constraint.IsEnabled)
101 {
102 continue;
103 }
104
105 double leftHandSide =
106 constraint.LeftHandSide.Constant;
107
108 foreach (LinearTerm term
109 in constraint.LeftHandSide.Terms)
110 {
111 leftHandSide +=
112 term.Coefficient *
113 values[term.VariableId];
114 }
115
116 bool satisfied =
117 constraint.Sense switch
118 {
119 MathematicalConstraintSense.LessThanOrEqual =>
120 leftHandSide <=
121 constraint.RightHandSide +
122 tolerance,
123
124 MathematicalConstraintSense.GreaterThanOrEqual =>
125 leftHandSide >=
126 constraint.RightHandSide -
127 tolerance,
128
129 MathematicalConstraintSense.Equal =>
130 Math.Abs(
131 leftHandSide -
132 constraint.RightHandSide) <=
133 tolerance,
134
135 _ =>
136 throw new NotSupportedException(
137 $"Constraint sense '{constraint.Sense}' is not supported by the checker.")
138 };
139
140 if (!satisfied)
141 {
142 diagnostics.Add(
144 "LSDM-FEAS-SOL-004",
145 $"Constraint '{constraint.Name}' ({constraint.Id}) is violated: lhs={leftHandSide:G17}, rhs={constraint.RightHandSide:G17}, sense={constraint.Sense}."));
146 }
147 }
148
150 diagnostics.Any(
151 diagnostic =>
152 diagnostic.Code ==
153 "LSDM-FEAS-SOL-004")
154 ? FeasibilityStatus.Infeasible
155 : FeasibilityStatus.Feasible,
156 diagnostics);
157 }
158
159 private static void CheckVariableDomain(
160 MathematicalVariable variable,
161 double value,
162 double tolerance,
163 ICollection<MathematicalFeasibilityDiagnostic> diagnostics)
164 {
165 if (!double.IsFinite(value) ||
166 value <
167 variable.LowerBound -
168 tolerance ||
169 value >
170 variable.UpperBound +
171 tolerance)
172 {
173 diagnostics.Add(
175 "LSDM-FEAS-SOL-002",
176 $"Variable '{variable.Name}' ({variable.Id}) violates its bounds."));
177
178 return;
179 }
180
181 bool integralViolation =
182 variable.VariableType switch
183 {
184 MathematicalVariableType.Integer or
185 MathematicalVariableType.SemiInteger =>
186 Math.Abs(
187 value -
188 Math.Round(
189 value,
190 MidpointRounding.AwayFromZero)) >
191 tolerance,
192
193 MathematicalVariableType.Binary =>
194 Math.Abs(value) > tolerance &&
195 Math.Abs(value - 1.0) > tolerance,
196
197 _ =>
198 false
199 };
200
201 if (integralViolation)
202 {
203 diagnostics.Add(
204 new MathematicalFeasibilityDiagnostic(
205 "LSDM-FEAS-SOL-003",
206 $"Variable '{variable.Name}' ({variable.Id}) violates its discrete domain."));
207 }
208 }
209}
Independently evaluates a mathematical solver result against the solver-independent model.
MathematicalFeasibilityCheckResult Check(MathematicalModel model, MathematicalModelSolveResult solveResult, double tolerance=1.0e-6)