64 ILotSizingSolverService solverService,
65 MathematicalModelFormulationRegistry formulationRegistry,
66 ScientificClassificationEngine classificationEngine,
67 ScientificFormulationSelectionService formulationSelectionService,
68 ScientificResolutionPlanner resolutionPlanner,
74 throw new ArgumentNullException(nameof(solverService));
76 _formulationRegistry =
77 formulationRegistry ??
78 throw new ArgumentNullException(nameof(formulationRegistry));
80 _classificationEngine =
81 classificationEngine ??
82 throw new ArgumentNullException(nameof(classificationEngine));
84 _formulationSelectionService =
85 formulationSelectionService ??
86 throw new ArgumentNullException(
87 nameof(formulationSelectionService));
91 throw new ArgumentNullException(nameof(resolutionPlanner));
93 _solutionVerificationService =
94 solutionVerificationService ??
95 throw new ArgumentNullException(
96 nameof(solutionVerificationService));
100 throw new ArgumentNullException(nameof(provenanceChecker));
103 public async ValueTask<ScientificSolvePipelineResult>
SolveAsync(
105 CancellationToken cancellationToken =
default)
107 ArgumentNullException.ThrowIfNull(request);
109 SolverRequest sourceRequest =
112 sourceRequest.EnsureValid();
114 ScientificClassificationResult classification =
115 _classificationEngine.Analyze(
116 sourceRequest.Instance!,
119 bool callerRequestedSpecificFormulation =
120 !
string.IsNullOrWhiteSpace(
121 sourceRequest.FormulationName);
123 ScientificFormulationSelectionResult selection =
124 _formulationSelectionService.Select(
126 _formulationRegistry,
127 requestedFormulationId:
128 sourceRequest.FormulationName ??
string.Empty,
130 !callerRequestedSpecificFormulation);
132 ScientificResolutionPlan resolutionPlan =
133 _resolutionPlanner.Create(
136 sourceRequest.PreferredSolver);
139 new List<ScientificSolvePipelineDiagnostic>();
142 classification.IsBlocked ||
143 !selection.IsSuccessful ||
144 selection.Formulation is
null ||
145 !resolutionPlan.IsReady ||
146 resolutionPlan.SelectedMethod is
null)
152 "scientificPreflight",
153 classification.IsBlocked
154 ?
"Scientific classification is blocked."
155 : !selection.IsSuccessful
156 ?
"No scientifically selectable mathematical " +
157 "formulation is available."
158 :
"No executable scientific resolution plan is " +
168 numericalVerification:
null,
169 provenanceVerification:
null,
174 !selection.Formulation.CanBuild(
175 sourceRequest.Instance!))
181 "scientificPreflight.formulation",
182 $
"Scientifically selected formulation " +
183 $
"'{selection.Formulation.FormulationId}' failed its " +
184 "technical CanBuild(instance) contract."));
193 numericalVerification:
null,
194 provenanceVerification:
null,
198 string selectedFormulationId =
199 selection.Formulation.FormulationId;
201 SolverRequest delegatedRequest =
204 selectedFormulationId);
208 !delegatedRequest.FormulationName.Equals(
209 selectedFormulationId,
210 StringComparison.OrdinalIgnoreCase))
212 throw new InvalidOperationException(
213 "Internal scientific solver-request pinning failed.");
216 SolverRunResult solverRun =
217 await _solverService.SolveAsync(
220 .ConfigureAwait(
false);
222 cancellationToken.ThrowIfCancellationRequested();
224 if (!solverRun.HasSolution)
229 solverRun.IsSuccessful
233 $
"Solver run completed with termination reason " +
234 $
"'{solverRun.TerminationReason}' and produced no " +
235 "normalized LotSizingSolution."));
244 numericalVerification:
null,
245 provenanceVerification:
null,
250 !solverRun.FormulationName.Equals(
251 selectedFormulationId,
252 StringComparison.OrdinalIgnoreCase))
258 "solverRun.formulationName",
259 $
"Scientific preflight selected formulation " +
260 $
"'{selectedFormulationId}', but the solver run reports " +
261 $
"'{solverRun.FormulationName}'."));
270 numericalVerification:
null,
271 provenanceVerification:
null,
276 resolutionPlan.SelectedMethod!.Method.RequiresMilpBackend &&
278 ScientificSolverBackendCatalog.Find(
279 solverRun.SolverKind) is not
280 ScientificSolverBackendDefinition actualBackend ||
281 !actualBackend.Supports(
282 resolutionPlan.SelectedMethod.Method)
289 "solverRun.solverKind",
290 $
"Solver backend '{solverRun.SolverKind}' is not " +
291 $
"compatible with scientific solution method " +
292 $
"'{resolutionPlan.SelectedMethod.Method.MethodId}'."));
301 numericalVerification:
null,
302 provenanceVerification:
null,
307 sourceRequest.PreferredSolver !=
309 solverRun.SolverKind !=
310 sourceRequest.PreferredSolver)
316 "solverRun.solverKind",
317 $
"Caller requested solver backend " +
318 $
"'{sourceRequest.PreferredSolver}', but the solver run " +
319 $
"reports '{solverRun.SolverKind}'."));
328 numericalVerification:
null,
329 provenanceVerification:
null,
333 LotSizingSolution solution =
336 SolutionScientificProvenance provenance;
341 ScientificSolutionProvenanceMapper.Apply(
344 resolutionPlan.SelectedMethod!.Method,
345 solverRun.SolverKind);
347 catch (Exception exception)
353 "solution.provenance",
354 "Scientific provenance capture failed: " +
364 numericalVerification:
null,
365 provenanceVerification:
null,
374 numericalVerification =
375 await _solutionVerificationService.VerifyAsync(
376 sourceRequest.Instance!,
380 .ConfigureAwait(
false);
382 if (!numericalVerification.
IsValid)
388 "solution.numericalVerification",
389 "The solver produced a normalized solution and " +
390 "scientific provenance was captured, but independent " +
391 "numerical solution verification did not validate all " +
392 "requested checks."));
401 provenanceVerification =
402 _provenanceChecker.Check(
403 sourceRequest.Instance!,
414 "solution.provenanceVerification",
415 $
"Scientific provenance verification returned " +
416 $
"'{provenanceVerification.Kind}'."));
420 if (diagnostics.Count == 0)
427 "Scientific preflight, solver execution, provenance " +
428 "capture and requested independent verifications " +
429 "completed coherently."));
439 numericalVerification,
440 provenanceVerification,