1using System.Diagnostics;
2using LotSizingDataModel.Core.DecisionModel.Objectives;
28 private readonly IReadOnlyList<SolverAvailabilityInfo> _availabilityInformation;
35 IEnumerable<SolverAvailabilityInfo> availabilityInformation)
42 solverAdapterRegistry,
43 availabilityInformation,
55 IEnumerable<SolverAvailabilityInfo> availabilityInformation,
59 ArgumentNullException.ThrowIfNull(modelBuildService);
60 ArgumentNullException.ThrowIfNull(solverExecutionService);
61 ArgumentNullException.ThrowIfNull(solutionMappingService);
62 ArgumentNullException.ThrowIfNull(formulationRegistry);
63 ArgumentNullException.ThrowIfNull(solverAdapterRegistry);
64 ArgumentNullException.ThrowIfNull(availabilityInformation);
65 ArgumentNullException.ThrowIfNull(solverSelectionOptions);
66 ArgumentNullException.ThrowIfNull(mappingOptions);
68 _modelBuildService = modelBuildService;
69 _solverExecutionService = solverExecutionService;
70 _solutionMappingService = solutionMappingService;
71 _formulationRegistry = formulationRegistry;
72 _solverAdapterRegistry = solverAdapterRegistry;
73 _availabilityInformation = availabilityInformation.ToArray();
74 _solverSelectionOptions = solverSelectionOptions;
75 _mappingOptions = mappingOptions;
80 CancellationToken cancellationToken =
default)
82 ArgumentNullException.ThrowIfNull(request);
85 DateTime startedAtUtc = DateTime.UtcNow;
86 var stopwatch = Stopwatch.StartNew();
93 RequestedFormulationId =
94 request.FormulationName ??
string.Empty,
96 string.IsNullOrWhiteSpace(
98 ValidateGeneratedModel =
true,
99 CloneGeneratedModel =
false
103 await _modelBuildService.BuildAsync(
105 _formulationRegistry,
110 buildResult.
Model is
null)
128 IReadOnlyList<ExecutableObjectiveCriterion> criteria =
133 ObjectiveAggregationMode aggregationMode =
134 request.
Instance!.SupplyChain.ObjectivePolicy?
136 ObjectiveAggregationMode.Single;
140 var stageDiagnostics =
new List<string>();
142 if (aggregationMode ==
143 ObjectiveAggregationMode.WeightedSum)
151 await SolveModelAsync(
166 "WeightedSum solve did not produce a feasible solution.",
170 stageDiagnostics.Add(
171 $
"WeightedSum solved with {criteria.Count} explicit criteria.");
173 else if (aggregationMode ==
174 ObjectiveAggregationMode.Lexicographic)
177 new List<(ExecutableObjectiveCriterion Criterion, double Value)>();
194 await SolveModelAsync(
200 if (!currentSolve.HasFeasibleSolution ||
201 !currentSolve.IsOptimal ||
202 !currentSolve.ObjectiveValue.HasValue)
210 currentSolve.TerminationReason,
211 $
"Lexicographic stage {stageIndex} ({criterion.Kind}) must be proven optimal before the next stage.",
212 currentSolve.Diagnostics);
216 currentSolve.ObjectiveValue.Value;
221 stageDiagnostics.Add(
222 $
"Lexicographic stage {stageIndex}: kind={criterion.Kind}; value={value:R}; tolerance={criterion.AbsoluteTolerance:R}; solver={currentSolve.SolverName} {currentSolve.SolverVersion}.");
225 if (currentModel is
null ||
226 currentSolve is
null)
228 throw new InvalidOperationException(
229 "Lexicographic execution produced no stage.");
232 finalModel = currentModel;
233 finalSolve = currentSolve;
247 await SolveModelAsync(
262 $
"Single objective '{criterion.Kind}' did not produce a feasible solution.",
268 await _solutionMappingService.MapAsync(
284 foreach (
string diagnostic
in buildResult.Diagnostics)
286 result.AddDiagnostic(diagnostic);
289 foreach (
string diagnostic
in stageDiagnostics)
291 result.AddDiagnostic(diagnostic);
294 if (mappingResult.IsSuccessful &&
295 mappingResult.Solution is not
null)
303 result.RecomputedObjectiveValue =
306 result.ObjectiveDifference =
309 result.ObjectiveVerificationStatus =
312 foreach (
string diagnostic
in objectiveCheck.Diagnostics)
314 result.AddDiagnostic(diagnostic);
320 catch (OperationCanceledException)
329 "The multiobjective solve workflow was cancelled.",
332 catch (Exception exception)
342 new[] { exception.ToString() });
348 _solverExecutionService.RequestStop();
351 private async ValueTask<MathematicalModelSolveResult> SolveModelAsync(
353 string formulationId,
355 CancellationToken cancellationToken)
357 var mathematicalRequest =
361 RunName = request.RunName ??
string.Empty,
362 FormulationId = formulationId,
363 Parameters = request.Parameters
368 mathematicalRequest.ProgressObservers.Add(observer);
373 return await _solverExecutionService.SolveAsync(
376 _solverAdapterRegistry,
377 _availabilityInformation,
378 _solverSelectionOptions,
382 private static SolverRunResult Failure(
383 SolverRequest request,
384 DateTime startedAtUtc,
388 IEnumerable<string>? diagnostics)
393 RunName = request.RunName ??
string.Empty,
396 request.FormulationName ??
string.Empty,
397 StartedAtUtc = startedAtUtc,
398 CompletedAtUtc = startedAtUtc + elapsed,
399 ElapsedSeconds = elapsed.TotalSeconds,
400 TerminationReason = reason,
405 if (!
string.IsNullOrWhiteSpace(message))
407 result.AddDiagnostic(message);
410 if (diagnostics is not
null)
412 foreach (
string diagnostic
in diagnostics)
414 result.AddDiagnostic(diagnostic);
Stores solver adapters that were loaded successfully and provides lookup services by adapter identifi...
Configures how a solver adapter is selected when automatic solver selection is requested.
Stores the result of objective-value post-processing.
ObjectiveVerificationStatus Status
Gets or sets the verification status.
double? AbsoluteDifference
Gets or sets the absolute difference between the two objective values.
double? RecomputedObjectiveValue
Gets or sets the objective value recomputed from normalized mathematical-variable values.
Recomputes the objective from the exact normalized numerical representation used by the business solu...
static MathematicalObjectiveRecalculationResult Recalculate(MathematicalModel model, MathematicalModelSolveResult solveResult, MathematicalSolutionMappingOptions mappingOptions)
Recomputes and verifies the objective value.
Adds complete-period OPEX coverage and optional cash-flow constraints to a built economic mathematica...
static FinancialExecutionModelContext Decorate(LotSizingInstance instance, MathematicalModel source)
Describes a request to solve an already built, solver-independent mathematical model.
void EnsureValid()
Validates the mathematical-model solve request.
Stores the solver result for a solver-independent mathematical model.
SolverTerminationReason TerminationReason
Gets or sets the termination reason.
bool HasFeasibleSolution
Gets or sets a value indicating whether the solver produced at least one feasible solution.
List< string > Diagnostics
Gets diagnostic messages produced while solving.
Selects a compatible mathematical-model solver adapter and executes an already built solver-independe...
Creates the public solver-run result from the generic mathematical-model result and the normalized so...
static SolverRunResult Create(MathematicalModelSolveResult solveResult, MathematicalSolutionMappingResult mappingResult, DateTime startedAtUtc, TimeSpan elapsed)
Creates a normalized solver-run result.
async ValueTask< SolverRunResult > SolveAsync(SolverRequest request, CancellationToken cancellationToken=default)
Solves a lot-sizing instance described by the supplied request.
void RequestStop()
Requests interruption of the currently running solve operation, when supported by the selected solver...
MultiObjectiveLotSizingSolverService(IMathematicalModelBuildService modelBuildService, IMathematicalModelSolverExecutionService solverExecutionService, IMathematicalSolutionMappingService solutionMappingService, MathematicalModelFormulationRegistry formulationRegistry, SolverAdapterRegistry solverAdapterRegistry, IEnumerable< SolverAvailabilityInfo > availabilityInformation, SolverSelectionOptions solverSelectionOptions, MathematicalSolutionMappingOptions mappingOptions)
MultiObjectiveLotSizingSolverService(MathematicalModelFormulationRegistry formulationRegistry, SolverAdapterRegistry solverAdapterRegistry, IEnumerable< SolverAvailabilityInfo > availabilityInformation)
Resolves executable objective criteria and constructs weighted/lexicographic mathematical models.
static IReadOnlyList< ExecutableObjectiveCriterion > ResolveCriteria(LotSizingInstance instance, FinancialExecutionModelContext context)
static MathematicalModel CreateLexicographicStageModel(FinancialExecutionModelContext context, ExecutableObjectiveCriterion criterion, IEnumerable<(ExecutableObjectiveCriterion Criterion, double Value)> preserved)
static MathematicalModel CreateWeightedSumModel(FinancialExecutionModelContext context, IReadOnlyList< ExecutableObjectiveCriterion > criteria)
Describes a request to solve a lot-sizing instance.
string FormulationName
Gets or sets the formulation name to use.
void EnsureValid()
Validates the solver request.
IList< ISolverProgressObserver > ProgressObservers
Gets the progress observers attached to this request.
SolverKind PreferredSolver
Gets or sets the preferred solver.
LotSizingInstance? Instance
Gets or sets the lot-sizing instance to solve.
Represents the normalized result of a solver execution.
Creates preconfigured mathematical decision-mapper registries for the standard lot-sizing solution mo...
Defines the options used when mapping a mathematical solver result back to a normalized lot-sizing so...
Describes the result of mapping a mathematical solver result back to a normalized lot-sizing solution...
Maps a generic mathematical solver result to a normalized lot-sizing solution and reports mapping dia...
Represents a solver-independent mathematical optimization model.
Defines the high-level service used to solve a complete lot-sizing instance from a normalized solver ...
Defines a service that selects a compatible solver adapter and executes an already built solver-indep...
Defines a service that maps a generic mathematical solver result to a normalized lot-sizing solution.
SolverTerminationReason
Describes why a solver execution terminated.
SolverKind
Identifies a supported mathematical optimization solver.