LotSizingDataModel.Solver 2.0.1
Solver-independent modeling, execution, monitoring and adapter infrastructure.
Loading...
Searching...
No Matches
SolverRuntimeBuilder.cs
Go to the documentation of this file.
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Threading;
5using System.Threading.Tasks;
8
10
11/// <summary>
12/// Discovers solver infrastructure, loads adapter plugins, and
13/// validates loaded adapters against their native solver
14/// runtimes.
15/// </summary>
16public sealed class SolverRuntimeBuilder
17{
18 private readonly ISolverDiscoveryService
19 _discoveryService;
20
21 private readonly SolverAdapterLoader
22 _adapterLoader;
23
24 /// <summary>
25 /// Initializes a solver-runtime builder with default
26 /// discovery and adapter-loading services.
27 /// </summary>
29 : this(
32 {
33 }
34
35 /// <summary>
36 /// Initializes a solver-runtime builder with the supplied
37 /// discovery service and the default adapter loader.
38 /// </summary>
39 /// <param name="discoveryService">
40 /// Service responsible for solver discovery.
41 /// </param>
42 /// <exception cref="ArgumentNullException">
43 /// Thrown when <paramref name="discoveryService"/> is
44 /// <see langword="null"/>.
45 /// </exception>
47 ISolverDiscoveryService discoveryService)
48 : this(
49 discoveryService,
51 {
52 }
53
54 /// <summary>
55 /// Initializes a solver-runtime builder with explicit
56 /// dependencies.
57 /// </summary>
58 /// <param name="discoveryService">
59 /// Service responsible for solver discovery.
60 /// </param>
61 /// <param name="adapterLoader">
62 /// Loader used to instantiate discovered adapter plugins.
63 /// </param>
64 /// <exception cref="ArgumentNullException">
65 /// Thrown when a dependency is <see langword="null"/>.
66 /// </exception>
68 ISolverDiscoveryService discoveryService,
69 SolverAdapterLoader adapterLoader)
70 {
71 ArgumentNullException.ThrowIfNull(
72 discoveryService);
73
74 ArgumentNullException.ThrowIfNull(
75 adapterLoader);
76
77 _discoveryService =
78 discoveryService;
79
80 _adapterLoader =
81 adapterLoader;
82 }
83
84 /// <summary>
85 /// Discovers solver infrastructure, loads adapters, and
86 /// performs adapter-level native availability validation.
87 /// </summary>
88 /// <param name="options">
89 /// Solver-discovery options.
90 /// </param>
91 /// <param name="cancellationToken">
92 /// Token used to cancel discovery and validation.
93 /// </param>
94 /// <returns>
95 /// Complete solver-runtime build result.
96 /// </returns>
97 public async ValueTask<SolverRuntimeBuildResult> BuildAsync(
99 CancellationToken cancellationToken = default)
100 {
101 ArgumentNullException.ThrowIfNull(
102 options);
103
104 options.EnsureValid();
105
106 var buildResult =
108
109 try
110 {
111 cancellationToken.ThrowIfCancellationRequested();
112
113 SolverDiscoveryResult discoveryResult =
114 await _discoveryService.DiscoverAsync(
115 options,
116 cancellationToken);
117
118 buildResult.DiscoveryResult =
119 discoveryResult;
120
121 buildResult.AddDiagnostics(
122 discoveryResult.Diagnostics);
123
124 var registry =
126
127 var validatedAvailability =
128 discoveryResult.AvailabilityInformation
129 .ToDictionary(
130 item =>
131 item.SolverKind,
132 item =>
133 item);
134
135 foreach (
136 SolverAdapterDescriptor descriptor
137 in discoveryResult.AdapterDescriptors)
138 {
139 cancellationToken.ThrowIfCancellationRequested();
140
141 SolverAdapterLoadResult loadResult =
142 _adapterLoader.Load(
143 descriptor);
144
145 buildResult.AddAdapterLoadResult(
146 loadResult);
147
148 buildResult.AddDiagnostics(
149 loadResult.Diagnostics);
150
151 if (!loadResult.IsLoaded ||
152 loadResult.Adapter is null)
153 {
154 buildResult.AddDiagnostic(
155 $"Solver adapter '{descriptor.AdapterId}' " +
156 $"was not loaded. Status: " +
157 $"{loadResult.Status}.");
158
159 continue;
160 }
161
162 ISolverAdapter adapter =
163 loadResult.Adapter;
164
165 SolverAvailabilityInfo availability;
166
167 try
168 {
169 availability =
170 await adapter.CheckAvailabilityAsync(
171 cancellationToken);
172
173 if (availability.SolverKind !=
174 adapter.SolverKind)
175 {
176 buildResult.AddDiagnostic(
177 $"Adapter '{adapter.AdapterId}' returned " +
178 $"availability for {availability.SolverKind} " +
179 $"instead of {adapter.SolverKind}. The " +
180 "availability record was normalized.");
181
182 availability.SolverKind =
183 adapter.SolverKind;
184 }
185
186 validatedAvailability[
187 adapter.SolverKind] =
188 availability;
189
190 buildResult.AddDiagnostics(
191 availability.Diagnostics);
192
193 if (!availability.IsUsable)
194 {
195 buildResult.AddDiagnostic(
196 $"Solver adapter '{adapter.AdapterId}' was " +
197 $"loaded, but native solver " +
198 $"'{adapter.SolverName}' is not usable. " +
199 $"Status: {availability.Status}.");
200
201 continue;
202 }
203 }
204 catch (OperationCanceledException)
205 {
206 throw;
207 }
208 catch (Exception exception)
209 {
210 availability =
212 adapter.SolverKind,
213 SolverAvailabilityStatus.LoadFailure)
214 {
215 SolverName =
216 adapter.SolverName,
217
218 SolverVersion =
219 adapter.SolverVersion
220 };
221
222 availability.AddDiagnostic(
223 $"Adapter-level availability validation " +
224 $"failed: {exception.Message}");
225
226 validatedAvailability[
227 adapter.SolverKind] =
228 availability;
229
230 buildResult.AddDiagnostic(
231 $"Solver adapter '{adapter.AdapterId}' could " +
232 "not validate its native solver runtime.");
233
234 continue;
235 }
236
237 if (!registry.TryRegister(
238 loadResult))
239 {
240 buildResult.AddDiagnostic(
241 $"Solver adapter '{adapter.AdapterId}' was " +
242 "loaded and validated but could not be " +
243 "registered, most likely because another " +
244 "adapter with the same identifier is already " +
245 "registered.");
246
247 continue;
248 }
249
250 buildResult.AddDiagnostic(
251 $"Solver adapter '{adapter.AdapterId}' for " +
252 $"{adapter.SolverKind} was loaded, validated, " +
253 "and registered successfully.");
254 }
255
256 SolverAvailabilityInfo[] finalAvailability =
257 GetConcreteSolverKinds()
258 .Select(
259 solverKind =>
260 validatedAvailability.TryGetValue(
261 solverKind,
262 out SolverAvailabilityInfo? info)
263 ? info
265 solverKind,
266 SolverAvailabilityStatus.NotInstalled))
267 .ToArray();
268
269 buildResult.RuntimeContext =
271 registry,
272 finalAvailability);
273
274 if (registry.Count == 0)
275 {
276 buildResult.AddDiagnostic(
277 "No usable solver adapter was registered.");
278 }
279
280 if (!buildResult.RuntimeContext.CanSolve)
281 {
282 buildResult.AddDiagnostic(
283 "The current runtime cannot solve a model " +
284 "because no loaded and validated adapter " +
285 "matches a usable native solver.");
286 }
287
288 return buildResult;
289 }
290 catch (OperationCanceledException)
291 {
292 buildResult.AddDiagnostic(
293 "Solver-runtime construction was cancelled.");
294
295 return buildResult;
296 }
297 catch (Exception exception)
298 {
299 buildResult.AddDiagnostic(
300 $"Solver-runtime construction failed: " +
301 $"{exception.Message}");
302
303 buildResult.AddDiagnostic(
304 exception.ToString());
305
306 return buildResult;
307 }
308 }
309
310 /// <summary>
311 /// Returns every concrete solver kind supported by the
312 /// generic runtime.
313 /// </summary>
314 private static IReadOnlyList<SolverKind>
315 GetConcreteSolverKinds()
316 {
317 return
318 [
319 SolverKind.Cplex,
320 SolverKind.Gurobi,
321 SolverKind.Xpress,
323 ];
324 }
325}
Describes a solver adapter without loading or executing its native optimization engine.
Represents the result of attempting to load a solver adapter plugin.
ISolverAdapter? Adapter
Gets or sets the loaded adapter instance.
List< string > Diagnostics
Gets the diagnostics produced during adapter loading.
bool IsLoaded
Gets a value indicating whether the adapter was loaded successfully.
Describes the availability and detected installation details of a mathematical optimization solver.
void AddDiagnostic(string message)
Adds a diagnostic message.
List< string > Diagnostics
Gets the diagnostic messages produced during solver discovery and validation.
bool IsUsable
Gets or sets a value indicating whether the solver can currently be used.
Provides the default solver discovery implementation used by the generic solver infrastructure.
Loads solver adapter plugins from managed assemblies.
Stores solver adapters that were loaded successfully and provides lookup services by adapter identifi...
Configures how solver adapter plugins and native solver installations are discovered on the current c...
void EnsureValid()
Validates the solver-discovery options.
Represents the complete result of solver and adapter discovery on the current computer.
List< string > Diagnostics
Gets the diagnostics produced during discovery.
Represents the result of building the solver runtime from discovery information and dynamically loade...
SolverRuntimeBuilder(ISolverDiscoveryService discoveryService, SolverAdapterLoader adapterLoader)
Initializes a solver-runtime builder with explicit dependencies.
async ValueTask< SolverRuntimeBuildResult > BuildAsync(SolverDiscoveryOptions options, CancellationToken cancellationToken=default)
Discovers solver infrastructure, loads adapters, and performs adapter-level native availability valid...
SolverRuntimeBuilder(ISolverDiscoveryService discoveryService)
Initializes a solver-runtime builder with the supplied discovery service and the default adapter load...
SolverRuntimeBuilder()
Initializes a solver-runtime builder with default discovery and adapter-loading services.
Represents the solver runtime infrastructure available to the application after adapter discovery and...
ValueTask< SolverAvailabilityInfo > CheckAvailabilityAsync(CancellationToken cancellationToken=default)
Checks whether the solver is installed, loadable, and licensed when a license is required.
string SolverName
Gets the display name of the solver.
SolverKind SolverKind
Gets the solver kind implemented by this adapter.
Defines the metadata and capabilities exposed by a solver adapter plugin.
Defines a service that discovers solver adapter plugins and native solver installations on the curren...
SolverKind
Identifies a supported mathematical optimization solver.
Definition SolverKind.cs:12
@ CoinOrCbc
COIN-OR CBC mixed-integer programming solver.
Definition SolverKind.cs:42
SolverAvailabilityStatus
Describes the availability state of a solver adapter on the current computer.