47 private readonly IMathematicalModelBuildService _modelBuildService;
48 private readonly MathematicalModelFormulationRegistry _formulationRegistry;
49 private readonly
string _formulationId;
63 _variableDomainChecker =
75 new MathematicalModelBuildService();
77 _formulationRegistry =
78 LotSizingFormulationRegistryFactory.CreateDefault();
113 IMathematicalModelBuildService modelBuildService,
114 MathematicalModelFormulationRegistry formulationRegistry,
115 string formulationId)
119 throw new ArgumentNullException(
120 nameof(structuralChecker));
122 _variableDomainChecker =
123 variableDomainChecker ??
124 throw new ArgumentNullException(
125 nameof(variableDomainChecker));
127 _feasibilityChecker =
128 feasibilityChecker ??
129 throw new ArgumentNullException(
130 nameof(feasibilityChecker));
134 throw new ArgumentNullException(
135 nameof(objectiveChecker));
139 throw new ArgumentNullException(
140 nameof(modelBuildService));
142 _formulationRegistry =
143 formulationRegistry ??
144 throw new ArgumentNullException(
145 nameof(formulationRegistry));
147 if (
string.IsNullOrWhiteSpace(
150 throw new ArgumentException(
151 "The mathematical formulation identifier cannot be empty.",
152 nameof(formulationId));
161 LotSizingInstance instance,
162 LotSizingSolution solution,
164 CancellationToken cancellationToken =
default)
166 return CheckCoreAsync(
169 mathematicalModel:
null,
176 LotSizingInstance instance,
177 LotSizingSolution solution,
178 MathematicalModel mathematicalModel,
180 CancellationToken cancellationToken =
default)
182 ArgumentNullException.ThrowIfNull(
185 return CheckCoreAsync(
193 private async Task<SolutionCheckResult> CheckCoreAsync(
194 LotSizingInstance instance,
195 LotSizingSolution solution,
196 MathematicalModel? mathematicalModel,
198 CancellationToken cancellationToken)
200 ArgumentNullException.ThrowIfNull(
203 ArgumentNullException.ThrowIfNull(
211 cancellationToken.ThrowIfCancellationRequested();
218 IsStructurallyValid =
220 AreVariableDomainsValid =
224 IsObjectiveConsistent =
231 _structuralChecker.Check(
236 MergeStructuralResult(
240 result.StructuralCheckCompleted =
249 if (!result.IsStructurallyValid &&
255 cancellationToken.ThrowIfCancellationRequested();
258 _variableDomainChecker.Check(
262 MergeVariableDomainResult(
266 result.VariableDomainCheckCompleted =
269 cancellationToken.ThrowIfCancellationRequested();
271 MathematicalModel? effectiveMathematicalModel =
274 if (effectiveMathematicalModel is
null)
276 effectiveMathematicalModel =
277 await BuildMathematicalModelAsync(
281 .ConfigureAwait(
false);
284 if (effectiveMathematicalModel is
null)
289 cancellationToken.ThrowIfCancellationRequested();
291 SolutionCheckResult feasibilityResult =
292 _feasibilityChecker.Check(
293 effectiveMathematicalModel,
297 MergeFeasibilityResult(
301 result.FeasibilityCheckCompleted =
310 if (HasProjectionFailure(
316 cancellationToken.ThrowIfCancellationRequested();
318 SolutionCheckResult objectiveResult =
319 _objectiveChecker.Check(
320 effectiveMathematicalModel,
324 MergeObjectiveResult(
328 result.ObjectiveCheckCompleted =
333 catch (OperationCanceledException)
334 when (cancellationToken.IsCancellationRequested)
338 catch (Exception exception)
346 result.IsObjectiveConsistent =
351 new SolutionCheckIssue
358 "Complete lot-sizing solution checking failed: " +
366 private async Task<MathematicalModel?> BuildMathematicalModelAsync(
367 LotSizingInstance instance,
368 SolutionCheckResult result,
369 CancellationToken cancellationToken)
372 new MathematicalModelBuildOptions
374 RequestedFormulationId =
378 ValidateGeneratedModel =
380 CloneGeneratedModel =
384 MathematicalModelBuildResult buildResult =
385 await _modelBuildService.BuildAsync(
387 _formulationRegistry,
390 .ConfigureAwait(
false);
392 if (buildResult.IsSuccessful &&
393 buildResult.Model is not
null)
395 return buildResult.Model;
398 string failureMessage =
399 string.IsNullOrWhiteSpace(
400 buildResult.FailureMessage)
401 ?
"The mathematical model required for solution checking " +
402 "could not be constructed."
403 : buildResult.FailureMessage;
406 new SolutionCheckIssue
413 "Mathematical model construction failed: " +
419 in buildResult.Diagnostics)
421 if (
string.IsNullOrWhiteSpace(
428 new SolutionCheckIssue
435 "Mathematical model diagnostic: " +
443 private static void MergeStructuralResult(
444 SolutionCheckResult source,
445 SolutionCheckResult target)
447 target.IsStructurallyValid =
455 private static void MergeVariableDomainResult(
456 SolutionCheckResult source,
457 SolutionCheckResult target)
459 target.AreVariableDomainsValid =
467 private static void MergeFeasibilityResult(
468 SolutionCheckResult source,
469 SolutionCheckResult target)
474 target.MaximumConstraintViolation =
477 target.TotalConstraintViolation =
480 target.ViolatedConstraintCount =
488 private static void MergeObjectiveResult(
489 SolutionCheckResult source,
490 SolutionCheckResult target)
492 target.IsObjectiveConsistent =
495 target.RecomputedObjectiveValue =
498 target.ReportedObjectiveValue =
501 target.ObjectiveDifference =
504 target.ObjectiveRelativeDifference =
507 target.ObjectiveComparisonTolerance =
515 private static void MergeIssues(
516 SolutionCheckResult source,
517 SolutionCheckResult target)
520 SolutionCheckIssue issue
528 private static bool HasProjectionFailure(
529 SolutionCheckResult feasibilityResult)
532 feasibilityResult.
Issues.Any(