ULSAlgorithms 1.1.0-g3e5595996d
High-performance exact and heuristic algorithms for uncapacitated lot sizing
Loading...
Searching...
No Matches
GurobiLinearModelExecutor.cs
Go to the documentation of this file.
1using System.Diagnostics;
3
5
6/// <summary>
7/// Executes portable LP/MILP models through the official gurobi_cl executable.
8/// </summary>
9public sealed class GurobiLinearModelExecutor :
11{
12 private readonly ExternalSolverProcessRunner _runner =
13 new();
14
15 /// <inheritdoc />
17 SolverKind.Gurobi;
18
19 /// <inheritdoc />
20 public async ValueTask<LinearModelSolveResult> SolveAsync(
21 LinearModel model,
22 SolverSelectionResult selection,
24 CancellationToken cancellationToken = default)
25 {
26 ArgumentNullException.ThrowIfNull(model);
27 ArgumentNullException.ThrowIfNull(selection);
28 ArgumentNullException.ThrowIfNull(options);
29
30 if (selection.SelectedSolver != SolverKind.Gurobi ||
31 selection.Availability is null)
32 {
33 throw new ArgumentException(
34 "The supplied selection does not target Gurobi.",
35 nameof(selection));
36 }
37
38 string executable =
40
41 if (string.IsNullOrWhiteSpace(executable) ||
42 !File.Exists(executable))
43 {
44 return Failure(
45 model,
46 selection,
47 "The selected Gurobi executable is no longer available.");
48 }
49
50 string artifacts =
53 options);
54
55 var stopwatch =
56 Stopwatch.StartNew();
57
58 try
59 {
60 string modelPath =
61 Path.Combine(
62 artifacts,
63 "model.lp");
64
65 string solutionPath =
66 Path.Combine(
67 artifacts,
68 "solution.sol");
69
71 model,
72 modelPath);
73
75 modelPath,
76 options);
77
79 await _runner.RunAsync(
80 executable,
81 [
82 $"ResultFile={solutionPath}",
83 modelPath
84 ],
85 artifacts,
86 standardInput: null,
87 cancellationToken);
88
89 stopwatch.Stop();
90
91 string output =
92 process.CombinedOutput;
93
94 bool solutionExists =
95 File.Exists(solutionPath);
96
97 IReadOnlyDictionary<int, double> values =
99 solutionPath);
100
102 MapStatus(
103 output,
104 solutionExists,
105 process.ExitCode);
106
108 model,
109 selection,
110 options,
111 status,
112 values,
113 solutionExists,
114 stopwatch.Elapsed,
116 [
117 $"gurobi_cl exit code: {process.ExitCode}.",
119 ],
120 artifacts);
121 }
122 catch (OperationCanceledException)
123 {
124 stopwatch.Stop();
125
126 return new LinearModelSolveResult(
127 model.Name,
128 LinearModelSolveStatus.Cancelled,
129 new SolverExecutionInfo(selection),
130 null,
131 null,
132 stopwatch.Elapsed,
133 "Cancelled",
134 ["Gurobi execution was cancelled by the caller."],
135 options.KeepTemporaryFiles
136 ? artifacts
137 : string.Empty);
138 }
139 catch (Exception exception)
140 {
141 stopwatch.Stop();
142
143 return new LinearModelSolveResult(
144 model.Name,
146 new SolverExecutionInfo(selection),
147 null,
148 null,
149 stopwatch.Elapsed,
150 exception.GetType().Name,
151 [exception.Message],
152 options.KeepTemporaryFiles
153 ? artifacts
154 : string.Empty);
155 }
156 finally
157 {
159 artifacts,
160 options);
161 }
162 }
163
164 private static LinearModelSolveStatus MapStatus(
165 string output,
166 bool solutionExists,
167 int exitCode)
168 {
169 if (output.Contains(
170 "infeasible or unbounded",
171 StringComparison.OrdinalIgnoreCase))
172 {
173 return LinearModelSolveStatus.InfeasibleOrUnbounded;
174 }
175
176 if (output.Contains(
177 "model is infeasible",
178 StringComparison.OrdinalIgnoreCase))
179 {
180 return LinearModelSolveStatus.Infeasible;
181 }
182
183 if (output.Contains(
184 "model is unbounded",
185 StringComparison.OrdinalIgnoreCase))
186 {
187 return LinearModelSolveStatus.Unbounded;
188 }
189
190 if (output.Contains(
191 "optimal solution found",
192 StringComparison.OrdinalIgnoreCase) ||
193 output.Contains(
194 "optimal objective",
195 StringComparison.OrdinalIgnoreCase))
196 {
197 return LinearModelSolveStatus.Optimal;
198 }
199
200 if (solutionExists)
201 {
202 return LinearModelSolveStatus.Feasible;
203 }
204
205 return exitCode == 0
206 ? LinearModelSolveStatus.Unknown
207 : LinearModelSolveStatus.Failed;
208 }
209
210 private static LinearModelSolveResult Failure(
211 LinearModel model,
212 SolverSelectionResult selection,
213 string diagnostic)
214 {
215 return new LinearModelSolveResult(
216 model.Name,
218 new SolverExecutionInfo(selection),
219 null,
220 null,
221 TimeSpan.Zero,
222 "Executable unavailable",
223 [diagnostic]);
224 }
225}
Runs a solver command-line process with cancellation and captured output.
Configures one solver-backed execution of a portable linear model.
bool KeepTemporaryFiles
Gets or sets whether temporary model/solution/log artifacts are retained.
Result of executing a solver-independent linear or mixed-integer model.
Parses solver text solutions using portable variable names v_<id>.
static IReadOnlyDictionary< int, double > ParseFile(string path)
Parses a text solution file.
Writes a conservative LP representation understood by all four supported execution backends.
void Write(LinearModel model, string path)
Writes the supplied model to an LP file.
Executes portable LP/MILP models through the official gurobi_cl executable.
SolverKind SolverKind
Gets the concrete solver implemented by this executor.
async ValueTask< LinearModelSolveResult > SolveAsync(LinearModel model, SolverSelectionResult selection, LinearModelSolveOptions options, CancellationToken cancellationToken=default)
Executes one portable model using an already selected solver.
static LinearModelSolveResult BuildSolutionResult(LinearModel model, SolverSelectionResult selection, LinearModelSolveOptions options, LinearModelSolveStatus proposedStatus, IReadOnlyDictionary< int, double > returnedValues, bool hasCandidateSolution, TimeSpan duration, string nativeStatus, IEnumerable< string > diagnostics, string artifactDirectory)
static string CreateArtifactDirectory(SolverKind solverKind, LinearModelSolveOptions options)
static void DeleteArtifactsUnlessRetained(string directory, LinearModelSolveOptions options)
static void ExportModelIfRequested(string generatedModelPath, LinearModelSolveOptions options)
Immutable solver-independent linear or mixed-integer linear model.
Definition LinearModel.cs:7
string NativeLibraryPath
Gets the native library or executable path, when applicable.
Serializable-style immutable snapshot of the solver selected for one solver-backed ULS execution.
Describes the outcome of optimization-solver selection.
SolverKind SelectedSolver
Gets the selected solver kind, or Unknown when none was selected.
SolverAvailabilityInfo? Availability
Gets machine-availability information for the selected solver.
Executes the portable LinearModel with one concrete solver.
LinearModelSolveStatus
Describes the termination state of a solver-backed portable linear model.
record ExternalSolverProcessResult(int ExitCode, string StandardOutput, string StandardError)