LotSizingDataModel.Solver 2.0.1
Solver-independent modeling, execution, monitoring and adapter infrastructure.
Loading...
Searching...
No Matches
SolverSelectionService.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/// Selects a usable solver adapter according to the requested
13/// solver kind, adapter capabilities, availability information,
14/// and configured priority.
15/// </summary>
16public sealed class SolverSelectionService
17{
18 /// <summary>
19 /// Initializes a new solver-selection service.
20 /// </summary>
22 {
23 }
24
25 /// <summary>
26 /// Selects a solver adapter.
27 /// </summary>
28 /// <param name="requestedSolver">
29 /// Solver requested by the caller.
30 /// </param>
31 /// <param name="registry">
32 /// Registry containing loaded solver adapters.
33 /// </param>
34 /// <param name="availabilityInformation">
35 /// Availability information associated with detected
36 /// solvers.
37 /// </param>
38 /// <param name="options">
39 /// Solver-selection options.
40 /// </param>
41 /// <param name="cancellationToken">
42 /// Token used to cancel availability checks.
43 /// </param>
44 /// <returns>
45 /// Solver-selection result.
46 /// </returns>
47 /// <exception cref="ArgumentNullException">
48 /// Thrown when <paramref name="registry"/>,
49 /// <paramref name="availabilityInformation"/>, or
50 /// <paramref name="options"/> is
51 /// <see langword="null"/>.
52 /// </exception>
53 public async ValueTask<SolverSelectionResult> SelectAsync(
54 SolverKind requestedSolver,
55 SolverAdapterRegistry registry,
56 IEnumerable<SolverAvailabilityInfo>
57 availabilityInformation,
59 CancellationToken cancellationToken = default)
60 {
61 ArgumentNullException.ThrowIfNull(
62 registry);
63
64 ArgumentNullException.ThrowIfNull(
65 availabilityInformation);
66
67 ArgumentNullException.ThrowIfNull(
68 options);
69
70 options.EnsureValid();
71
72 var result =
74 {
75 RequestedSolver =
76 requestedSolver
77 };
78
79 if (requestedSolver ==
80 SolverKind.Unknown)
81 {
82 result.AddDiagnostic(
83 "The requested solver cannot be Unknown.");
84
85 return result;
86 }
87
88 Dictionary<SolverKind, SolverAvailabilityInfo>
89 availabilityBySolver =
90 availabilityInformation
91 .Where(
92 information =>
93 information is not null)
94 .GroupBy(
95 information =>
96 information.SolverKind)
97 .ToDictionary(
98 group =>
99 group.Key,
100 group =>
101 group.First());
102
103 IReadOnlyList<SolverKind> solverOrder =
104 BuildSolverOrder(
105 requestedSolver,
106 options);
107
108 foreach (
109 SolverKind solverKind
110 in solverOrder)
111 {
112 cancellationToken.ThrowIfCancellationRequested();
113
114 IReadOnlyList<ISolverAdapter> adapters =
115 registry.FindBySolverKind(
116 solverKind);
117
118 if (adapters.Count == 0)
119 {
120 result.AddDiagnostic(
121 $"No loaded adapter is registered for " +
122 $"solver '{solverKind}'.");
123
124 if (requestedSolver !=
125 SolverKind.Automatic &&
126 options.RequireExactSolverKind)
127 {
128 return result;
129 }
130
131 continue;
132 }
133
134 SolverAvailabilityInfo? availability =
135 availabilityBySolver.TryGetValue(
136 solverKind,
138 discoveredAvailability)
139 ? discoveredAvailability
140 : null;
141
142 foreach (
143 ISolverAdapter adapter
144 in adapters)
145 {
146 cancellationToken.ThrowIfCancellationRequested();
147
148 if (!SupportsRequiredCapabilities(
149 adapter,
150 options.RequiredCapabilities))
151 {
152 result.AddDiagnostic(
153 $"Adapter '{adapter.AdapterName}' does " +
154 "not support all required " +
155 "capabilities.");
156
157 continue;
158 }
159
160 SolverAvailabilityInfo effectiveAvailability =
161 availability ??
162 await adapter.CheckAvailabilityAsync(
163 cancellationToken);
164
165 if (!IsAvailabilityAccepted(
166 effectiveAvailability,
167 options))
168 {
169 result.AddDiagnostic(
170 $"Adapter '{adapter.AdapterName}' is " +
171 $"not usable. Availability status: " +
172 $"'{effectiveAvailability.Status}'.");
173
174 continue;
175 }
176
177 result.SetSelection(
178 adapter,
179 effectiveAvailability);
180
181 result.AddDiagnostic(
182 $"Adapter '{adapter.AdapterName}' was " +
183 $"selected for solver '{solverKind}'.");
184
185 return result;
186 }
187
188 if (requestedSolver !=
189 SolverKind.Automatic &&
190 options.RequireExactSolverKind)
191 {
192 return result;
193 }
194 }
195
196 result.AddDiagnostic(
197 "No suitable solver adapter could be selected.");
198
199 return result;
200 }
201
202 private static IReadOnlyList<SolverKind>
203 BuildSolverOrder(
204 SolverKind requestedSolver,
206 {
207 if (requestedSolver ==
208 SolverKind.Automatic)
209 {
210 return options.SolverPriority.ToArray();
211 }
212
213 if (options.RequireExactSolverKind)
214 {
215 return new[]
216 {
217 requestedSolver
218 };
219 }
220
221 var solverOrder =
222 new List<SolverKind>
223 {
224 requestedSolver
225 };
226
227 foreach (
228 SolverKind solverKind
229 in options.SolverPriority)
230 {
231 if (!solverOrder.Contains(
232 solverKind))
233 {
234 solverOrder.Add(
235 solverKind);
236 }
237 }
238
239 return solverOrder;
240 }
241
242 private static bool SupportsRequiredCapabilities(
243 ISolverAdapter adapter,
244 IEnumerable<SolverCapability>
245 requiredCapabilities)
246 {
247 foreach (
248 SolverCapability capability
249 in requiredCapabilities)
250 {
251 if (!adapter.SupportsCapability(
252 capability))
253 {
254 return false;
255 }
256 }
257
258 return true;
259 }
260
261 private static bool IsAvailabilityAccepted(
262 SolverAvailabilityInfo availability,
263 SolverSelectionOptions options)
264 {
265 if (availability.Status ==
266 SolverAvailabilityStatus.Available)
267 {
268 return true;
269 }
270
271 return
272 options.AllowLimitedAvailability &&
273 availability.Status ==
275 .AvailableWithLimitations;
276 }
277}
Describes the availability and detected installation details of a mathematical optimization solver.
SolverAvailabilityStatus Status
Gets or sets the detected availability status.
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.
bool RequireExactSolverKind
Gets or sets whether a preferred concrete solver must be used without falling back to another solver.
void EnsureValid()
Validates the solver-selection options.
List< SolverKind > SolverPriority
Gets the solver priority used during automatic selection.
Represents the result of selecting a solver adapter for a solve request.
async ValueTask< SolverSelectionResult > SelectAsync(SolverKind requestedSolver, SolverAdapterRegistry registry, IEnumerable< SolverAvailabilityInfo > availabilityInformation, SolverSelectionOptions options, CancellationToken cancellationToken=default)
Selects a solver adapter.
SolverSelectionService()
Initializes a new solver-selection service.
ValueTask< SolverAvailabilityInfo > CheckAvailabilityAsync(CancellationToken cancellationToken=default)
Checks whether the solver is installed, loadable, and licensed when a license is required.
Defines the metadata and capabilities exposed by a solver adapter plugin.
bool SupportsCapability(SolverCapability capability)
Gets a value indicating whether this adapter supports the specified capability.
SolverKind
Identifies a supported mathematical optimization solver.
Definition SolverKind.cs:12
SolverCapability
Identifies an optional capability implemented by a solver adapter.
SolverAvailabilityStatus
Describes the availability state of a solver adapter on the current computer.