89 CancellationToken cancellationToken =
default)
91 cancellationToken.ThrowIfCancellationRequested();
102 catch (Exception exception)
104 return CreateFailureAvailability(
108 if (assembly is
null)
111 new SolverAvailabilityInfo(
113 SolverAvailabilityStatus.NotInstalled)
118 notInstalled.AddDiagnostic(
119 "The FICO Xpress Optimizer .NET assembly was not found. " +
120 "Define XPRESSDIR, make Optimizer.dll probeable, or set " +
121 $
"{XpressRuntimeLocator.ExplicitAssemblyEnvironmentVariable}.");
126 await RuntimeGate.WaitAsync(
143 new SolverAvailabilityInfo(
145 SolverAvailabilityStatus.Available)
151 available.AddDiagnostic(
152 $
"FICO Xpress Optimizer managed runtime loaded from " +
153 $
"'{resolvedPath}'.");
155 available.AddDiagnostic(
156 "XPRS.Init completed successfully, including native " +
157 "runtime/license initialization.");
166 catch (OperationCanceledException)
170 catch (Exception exception)
172 return CreateFailureAvailability(
173 Unwrap(exception).Message);
177 RuntimeGate.Release();
184 MathematicalModelSolveRequest request,
185 CancellationToken cancellationToken)
187 ArgumentNullException.ThrowIfNull(request);
188 ArgumentNullException.ThrowIfNull(request.Model);
190 request.Parameters.EnsureValid();
196 if (assembly is
null)
198 throw new InvalidOperationException(
199 "FICO Xpress MP is not available. Call solver discovery/" +
200 "availability before attempting to solve.");
203 string temporaryDirectory =
204 ExternalSolverResultUtilities.CreateTemporaryDirectory(
212 string solutionPath =
218 Stopwatch.StartNew();
220 await RuntimeGate.WaitAsync(
225 await PublishProgressAsync(
227 new SolverProgressSnapshot
229 Stage = SolverProgressStage.BuildingModel,
230 ElapsedSeconds = stopwatch.Elapsed.TotalSeconds,
231 Message =
"Writing the portable LP model for FICO Xpress."
235 new PortableLpModelWriter().Write(
239 if (request.Parameters.ExportModel)
241 ExternalSolverResultUtilities.ExportPortableModel(
243 request.Parameters.ExportModelPath);
260 SetActiveProblem(problem);
262 using CancellationTokenRegistration cancellationRegistration =
269 IReadOnlyList<string> parameterDiagnostics =
274 await PublishProgressAsync(
276 new SolverProgressSnapshot
278 Stage = ResolveOptimizationProgressStage(),
279 ElapsedSeconds = stopwatch.Elapsed.TotalSeconds,
280 Message =
"FICO Xpress optimization started."
289 CancellationToken.None);
296 IReadOnlyDictionary<int, double> values =
302 out
string mappingDiagnostic);
305 bool hasSolution = solution is not
null &&
306 values.Count == request.Model.VariableCount &&
307 !status.Contains(
"infeasible", StringComparison.OrdinalIgnoreCase) &&
308 !status.Contains(
"unbounded", StringComparison.OrdinalIgnoreCase);
311 values =
new Dictionary<int, double>();
315 new MathematicalModelSolveResult
320 !
string.IsNullOrWhiteSpace(_cachedVersion)
323 SolveDuration = stopwatch.Elapsed,
324 HasFeasibleSolution = hasSolution,
332 MapTerminationReason(
337 cancellationToken.IsCancellationRequested),
351 ExternalSolverResultUtilities.PopulateVariableValues(
356 PopulateObjectiveAndGap(
363 foreach (
string diagnostic
in parameterDiagnostics)
365 result.AddDiagnostic(diagnostic);
368 if (!
string.IsNullOrWhiteSpace(mappingDiagnostic))
370 result.AddDiagnostic(mappingDiagnostic);
373 result.AddDiagnostic(
374 string.IsNullOrWhiteSpace(status)
375 ?
"Xpress status was not exposed by the loaded API surface."
376 : $
"Xpress status: {status}.");
378 await PublishProgressAsync(
380 new SolverProgressSnapshot
382 Stage = SolverProgressStage.Completed,
383 ElapsedSeconds = stopwatch.Elapsed.TotalSeconds,
384 IncumbentObjective = result.ObjectiveValue,
385 BestBound = result.BestBound,
386 AbsoluteGap = result.AbsoluteGap,
387 RelativeGap = result.RelativeGap,
388 ExploredNodeCount = result.ExploredNodeCount,
389 IterationCount = result.IterationCount,
391 $
"FICO Xpress terminated with reason " +
392 $
"'{result.TerminationReason}'."
394 CancellationToken.None);
400 if (problem is not
null)
402 ClearActiveProblem(problem);
411 RuntimeGate.Release();
413 ExternalSolverResultUtilities.TryDeleteDirectory(