55 throw new ArgumentNullException(
61 MathematicalModel model,
62 LotSizingSolution solution,
65 ArgumentNullException.ThrowIfNull(model);
66 ArgumentNullException.ThrowIfNull(solution);
67 ArgumentNullException.ThrowIfNull(options);
79 AreVariableDomainsValid =
83 IsObjectiveConsistent =
105 LinearConstraint constraint
106 in model.Constraints)
108 if (options.IgnoreDisabledConstraints &&
109 !constraint.IsEnabled)
118 options.FeasibilityTolerance);
125 result.ViolatedConstraintCount++;
127 result.TotalConstraintViolation +=
130 result.MaximumConstraintViolation =
132 result.MaximumConstraintViolation,
136 CreateConstraintViolationIssue(
141 result.ViolatedConstraintCount == 0 &&
152 private static void AddProjectionIssues(
173 $
"Variable projection failed" +
174 $
"{FormatVariable(issue)}: " +
180 private static MathematicalConstraintCheckDetail EvaluateConstraint(
181 LinearConstraint constraint,
185 double leftHandSide =
186 constraint.LeftHandSide.Constant;
190 in constraint.LeftHandSide.Terms)
194 out
double variableValue))
196 throw new InvalidOperationException(
197 $
"No projected value exists for mathematical " +
198 $
"variable '{term.VariableId}' while evaluating " +
199 $
"constraint '{constraint.Name}'.");
207 if (!
double.IsFinite(leftHandSide))
209 throw new InvalidOperationException(
210 $
"Constraint '{constraint.Name}' evaluated to a " +
211 "non-finite left-hand-side value.");
218 constraint.RightHandSide);
220 return new MathematicalConstraintCheckDetail
229 string.IsNullOrWhiteSpace(
230 constraint.DomainKey)
232 : constraint.DomainKey,
241 constraint.RightHandSide,
247 violation <= tolerance
251 private static double ComputeViolation(
253 MathematicalConstraintSense sense,
254 double rightHandSide)
256 if (!
double.IsFinite(rightHandSide))
258 throw new InvalidOperationException(
259 "A mathematical constraint right-hand side must be finite.");
264 MathematicalConstraintSense.LessThanOrEqual =>
267 leftHandSide - rightHandSide),
269 MathematicalConstraintSense.Equal =>
271 leftHandSide - rightHandSide),
273 MathematicalConstraintSense.GreaterThanOrEqual =>
276 rightHandSide - leftHandSide),
279 throw new NotSupportedException(
280 $
"Mathematical constraint sense '{sense}' " +
281 "is not supported by the feasibility checker.")
285 private static SolutionCheckIssue CreateConstraintViolationIssue(
286 MathematicalConstraintCheckDetail detail)
288 return new SolutionCheckIssue
300 detail.ConstraintName,
303 detail.LeftHandSideValue,
306 detail.RightHandSideValue,
312 $
"Constraint '{detail.ConstraintName}' is violated. " +
313 $
"LHS={detail.LeftHandSideValue:G17}; " +
314 $
"sense={FormatSense(detail.Sense)}; " +
315 $
"RHS={detail.RightHandSideValue:G17}; " +
316 $
"violation={detail.Violation:G17}."
320 private static string FormatVariable(
321 MathematicalSolutionProjectionIssue issue)
324 !
string.IsNullOrWhiteSpace(
328 $
" for variable '{issue.VariableName}' " +
329 $
"(id={issue.VariableId.Value})";
335 $
" for variable id={issue.VariableId.Value}";
341 private static string FormatSense(
342 MathematicalConstraintSense sense)
346 MathematicalConstraintSense.LessThanOrEqual =>
349 MathematicalConstraintSense.Equal =>
352 MathematicalConstraintSense.GreaterThanOrEqual =>