22 MathematicalModelSolverPluginBase
24 private readonly
object _nativeSyncRoot =
35 SolverCapability.LinearProgramming,
36 SolverCapability.MixedIntegerLinearProgramming,
37 SolverCapability.Interruption,
38 SolverCapability.LpExport,
39 SolverCapability.MpsExport,
40 SolverCapability.OptimalityGapReporting,
41 SolverCapability.SearchStatistics
90 "LotSizingDataModel.Solver.Cplex";
96 "LotSizingDataModel CPLEX Adapter";
114 public override ValueTask<SolverAvailabilityInfo>
116 CancellationToken cancellationToken =
default)
118 cancellationToken.ThrowIfCancellationRequested();
131 new SolverAvailabilityInfo(
133 SolverAvailabilityStatus.Available)
144 availability.InstallationPath =
147 availability.ManagedAssemblyPath =
148 installationDiscovery.Installation
149 .ManagedAssemblyDirectory;
151 availability.AddDiagnostic(
152 $
"Compatible CPLEX installation family " +
153 $
"'{installationDiscovery.Installation.Version}' " +
154 $
"was discovered from " +
155 $
"'{installationDiscovery.Installation.DiscoverySource}'.");
162 availability.AddDiagnostic(
166 availability.AddDiagnostic(
167 "The CPLEX managed and native runtime " +
168 "libraries were loaded successfully.");
170 return ValueTask.FromResult(
178 catch (Exception exception)
180 SolverAvailabilityStatus status =
181 installationDiscovery.IsFound
182 ? SolverAvailabilityStatus.LoadFailure
183 : SolverAvailabilityStatus.NotInstalled;
186 new SolverAvailabilityInfo(
196 availability.InstallationPath =
199 availability.ManagedAssemblyPath =
200 installationDiscovery.Installation
201 .ManagedAssemblyDirectory;
208 availability.AddDiagnostic(
212 availability.AddDiagnostic(
215 return ValueTask.FromResult(
223 protected override async ValueTask<MathematicalModelSolveResult>
225 MathematicalModelSolveRequest request,
226 CancellationToken cancellationToken)
228 ArgumentNullException.ThrowIfNull(request);
229 ArgumentNullException.ThrowIfNull(request.Model);
232 Stopwatch.StartNew();
234 await PublishProgressAsync(
236 new SolverProgressSnapshot
239 SolverProgressStage.BuildingModel,
242 stopwatch.Elapsed.TotalSeconds,
245 "Translating the generic mathematical model " +
246 "to IBM ILOG Concert."
254 translator.Translate(
271 var parameterMapper =
274 IReadOnlyList<string> parameterDiagnostics =
275 parameterMapper.Apply(
279 if (request.Parameters.ExportModel)
283 request.Parameters.ExportModelPath);
289 using CancellationTokenRegistration cancellationRegistration =
290 cancellationToken.Register(
297 await PublishProgressAsync(
299 new SolverProgressSnapshot
302 SolverProgressStage.Searching,
305 stopwatch.Elapsed.TotalSeconds,
308 "CPLEX optimization started."
315 CancellationToken.None);
326 cancellationToken.IsCancellationRequested);
328 foreach (
string diagnostic
in parameterDiagnostics)
330 result.AddDiagnostic(
334 await PublishProgressAsync(
336 new SolverProgressSnapshot
339 SolverProgressStage.Completed,
342 stopwatch.Elapsed.TotalSeconds,
345 result.ObjectiveValue,
357 result.ExploredNodeCount,
360 result.IterationCount,
363 $
"CPLEX terminated with reason " +
364 $
"'{result.TerminationReason}'."
366 CancellationToken.None);
397 lock (_nativeSyncRoot)
406 private static MathematicalModelSolveResult BuildResult(
407 MathematicalModel model,
411 TimeSpan solveDuration,
412 bool cancellationRequested)
415 new MathematicalModelSolveResult
429 HasFeasibleSolution =
434 cplex.GetStatus().ToString(),
436 StringComparison.OrdinalIgnoreCase),
439 MapTerminationReason(
440 cplex.GetStatus().ToString(),
441 cplex.GetCplexStatus().ToString(),
443 cancellationRequested),
454 result.ObjectiveValue =
457 foreach (MathematicalVariable variable
in model.Variables)
464 result.AddVariableValue(
465 new MathematicalVariableValue(
469 variable.DomainKey));
472 TryPopulateMipStatistics(
477 result.AddDiagnostic(
478 $
"CPLEX status: {cplex.GetStatus()}.");
480 result.AddDiagnostic(
481 $
"CPLEX detailed status: {cplex.GetCplexStatus()}.");
486 private static void TryPopulateMipStatistics(
487 MathematicalModelSolveResult result,
493 cplex.GetBestObjValue();
495 if (result.ObjectiveValue.HasValue &&
496 result.BestBound.HasValue)
500 result.ObjectiveValue.Value -
501 result.BestBound.Value);
504 result.AbsoluteGap.Value /
507 result.ObjectiveValue.Value));
517 private static SolverTerminationReason MapTerminationReason(
521 bool cancellationRequested)
523 if (cancellationRequested)
525 return SolverTerminationReason.UserInterrupted;
530 StringComparison.OrdinalIgnoreCase))
532 return SolverTerminationReason.Optimal;
537 StringComparison.OrdinalIgnoreCase))
539 return SolverTerminationReason.Infeasible;
544 StringComparison.OrdinalIgnoreCase))
546 return SolverTerminationReason.Unbounded;
550 "InfeasibleOrUnbounded",
551 StringComparison.OrdinalIgnoreCase))
553 return SolverTerminationReason.InfeasibleOrUnbounded;
556 if (subStatus.Contains(
558 StringComparison.OrdinalIgnoreCase))
560 return SolverTerminationReason.TimeLimit;
563 if (subStatus.Contains(
565 StringComparison.OrdinalIgnoreCase))
567 return SolverTerminationReason.NodeLimit;
570 if (subStatus.Contains(
572 StringComparison.OrdinalIgnoreCase))
574 return SolverTerminationReason.IterationLimit;
577 if (subStatus.Contains(
579 StringComparison.OrdinalIgnoreCase))
581 return SolverTerminationReason.SolutionLimit;
585 ? SolverTerminationReason.Feasible
586 : SolverTerminationReason.Unknown;
589 private static string ResolveExportPath(
590 string configuredPath)
592 if (
string.IsNullOrWhiteSpace(
595 return Path.GetFullPath(
596 "LotSizingModel.lp");
604 Path.GetDirectoryName(
607 if (!
string.IsNullOrWhiteSpace(
610 Directory.CreateDirectory(
617 private void SetActiveAborter(
620 lock (_nativeSyncRoot)
627 private void ClearActiveAborter(
630 lock (_nativeSyncRoot)