LotSizingDataModel.Solver 2.0.1
Solver-independent modeling, execution, monitoring and adapter infrastructure.
Loading...
Searching...
No Matches
SolverDiscoveryCandidateCollector.cs
Go to the documentation of this file.
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Linq;
6
8
9/// <summary>
10/// Collects candidate native solver locations from explicit
11/// paths, environment variables, the operating-system PATH,
12/// and conventional installation directories.
13/// </summary>
15{
16 /// <summary>
17 /// Initializes a new discovery-candidate collector.
18 /// </summary>
22
23 /// <summary>
24 /// Collects native solver location candidates.
25 /// </summary>
26 /// <param name="options">
27 /// Solver-discovery options.
28 /// </param>
29 /// <returns>
30 /// Distinct candidates ordered by priority and path.
31 /// </returns>
32 /// <exception cref="ArgumentNullException">
33 /// Thrown when <paramref name="options"/> is
34 /// <see langword="null"/>.
35 /// </exception>
36 public IReadOnlyList<SolverDiscoveryCandidate> Collect(
38 {
39 ArgumentNullException.ThrowIfNull(
40 options);
41
42 options.EnsureValid();
43
44 var candidates =
45 new List<SolverDiscoveryCandidate>();
46
47 AddExplicitDirectories(
48 candidates,
49 options);
50
52 {
53 AddEnvironmentVariableCandidates(
54 candidates);
55 }
56
57 if (options.SearchSystemPath)
58 {
59 AddSystemPathCandidates(
60 candidates);
61 }
62
64 {
65 AddCommonInstallationCandidates(
66 candidates);
67 }
68
69 return candidates
70 .GroupBy(
71 candidate =>
72 BuildCandidateKey(
73 candidate),
74 StringComparer.OrdinalIgnoreCase)
75 .Select(
76 group =>
77 group
78 .OrderBy(
79 candidate =>
80 candidate.Priority)
81 .First())
82 .OrderBy(
83 candidate =>
84 candidate.Priority)
85 .ThenBy(
86 candidate =>
87 candidate.SolverKind)
88 .ThenBy(
89 candidate =>
90 candidate.Path,
91 StringComparer.OrdinalIgnoreCase)
92 .ToArray();
93 }
94
95 private static void AddExplicitDirectories(
96 ICollection<SolverDiscoveryCandidate> candidates,
98 {
99 foreach (
100 string configuredDirectory
101 in options.SolverSearchDirectories)
102 {
103 string expandedPath =
104 ExpandPath(
105 configuredDirectory);
106
107 foreach (
108 SolverKind solverKind
109 in GetConcreteSolverKinds())
110 {
111 candidates.Add(
112 CreateCandidate(
113 solverKind,
116 expandedPath,
117 "Explicitly configured solver search " +
118 "directory.",
119 priority:
120 10));
121 }
122 }
123 }
124
125 private static void AddEnvironmentVariableCandidates(
126 ICollection<SolverDiscoveryCandidate> candidates)
127 {
128 foreach (
129 SolverEnvironmentVariableDefinition definition
130 in SolverEnvironmentVariableCatalog.All)
131 {
132 if (definition.IsLicenseVariable)
133 {
134 continue;
135 }
136
137 string? value =
138 Environment.GetEnvironmentVariable(
139 definition.VariableName);
140
141 if (string.IsNullOrWhiteSpace(
142 value))
143 {
144 continue;
145 }
146
147 candidates.Add(
148 CreateCandidate(
149 definition.SolverKind,
151 .EnvironmentVariable,
152 ExpandPath(
153 value),
154 $"Environment variable " +
155 $"{definition.VariableName}.",
156 priority:
157 20 +
158 definition.Priority));
159 }
160 }
161
162 private static void AddSystemPathCandidates(
163 ICollection<SolverDiscoveryCandidate> candidates)
164 {
165 string? pathValue =
166 Environment.GetEnvironmentVariable(
167 "PATH");
168
169 if (string.IsNullOrWhiteSpace(
170 pathValue))
171 {
172 return;
173 }
174
175 string[] directories =
176 pathValue.Split(
177 Path.PathSeparator,
178 StringSplitOptions.RemoveEmptyEntries |
179 StringSplitOptions.TrimEntries);
180
181 foreach (
182 string directory
183 in directories)
184 {
185 string expandedDirectory =
186 ExpandPath(
187 directory);
188
189 foreach (
190 SolverKind solverKind
191 in GetConcreteSolverKinds())
192 {
193 if (!ContainsSolverExecutable(
194 expandedDirectory,
195 solverKind))
196 {
197 continue;
198 }
199
200 candidates.Add(
201 CreateCandidate(
202 solverKind,
203 SolverDiscoverySource.SystemPath,
204 expandedDirectory,
205 "Solver executable found through the " +
206 "operating-system PATH.",
207 priority:
208 200));
209 }
210 }
211 }
212
213 private static void AddCommonInstallationCandidates(
214 ICollection<SolverDiscoveryCandidate> candidates)
215 {
216 foreach (
217 SolverInstallationPathDefinition definition
218 in SolverInstallationPathCatalog.All)
219 {
220 string expandedPath =
221 ExpandPath(
222 definition.PathPattern);
223
224 candidates.Add(
225 CreateCandidate(
226 definition.SolverKind,
228 .CommonInstallationDirectory,
229 expandedPath,
230 definition.Description,
231 priority:
232 300 +
233 definition.Priority));
234 }
235 }
236
237 private static SolverDiscoveryCandidate CreateCandidate(
238 SolverKind solverKind,
240 string path,
241 string description,
242 int priority)
243 {
244 return new SolverDiscoveryCandidate
245 {
246 SolverKind =
247 solverKind,
248
249 Source =
250 source,
251
252 Path =
253 path,
254
255 Description =
256 description,
257
258 Priority =
259 priority,
260
261 Exists =
262 Directory.Exists(
263 path) ||
264 File.Exists(
265 path)
266 };
267 }
268
269 private static bool ContainsSolverExecutable(
270 string directory,
271 SolverKind solverKind)
272 {
273 if (!Directory.Exists(
274 directory))
275 {
276 return false;
277 }
278
279 foreach (
280 string executableName
281 in GetExecutableNames(
282 solverKind))
283 {
284 if (File.Exists(
285 Path.Combine(
286 directory,
287 executableName)))
288 {
289 return true;
290 }
291 }
292
293 return false;
294 }
295
296 private static IReadOnlyList<string> GetExecutableNames(
297 SolverKind solverKind)
298 {
299 bool isWindows =
300 OperatingSystem.IsWindows();
301
302 return solverKind switch
303 {
304 SolverKind.Cplex =>
305 isWindows
306 ? new[]
307 {
308 "cplex.exe"
309 }
310 : new[]
311 {
312 "cplex"
313 },
314
315 SolverKind.Gurobi =>
316 isWindows
317 ? new[]
318 {
319 "gurobi_cl.exe"
320 }
321 : new[]
322 {
323 "gurobi_cl"
324 },
325
326 SolverKind.Xpress =>
327 isWindows
328 ? new[]
329 {
330 "optimizer.exe",
331 "xprs.exe"
332 }
333 : new[]
334 {
335 "optimizer",
336 "xprs"
337 },
338
339 SolverKind.CoinOrCbc =>
340 isWindows
341 ? new[]
342 {
343 "cbc.exe"
344 }
345 : new[]
346 {
347 "cbc"
348 },
349
350 _ =>
351 Array.Empty<string>()
352 };
353 }
354
355 private static IReadOnlyList<SolverKind>
356 GetConcreteSolverKinds()
357 {
358 return new[]
359 {
360 SolverKind.Cplex,
361 SolverKind.Gurobi,
362 SolverKind.Xpress,
363 SolverKind.CoinOrCbc
364 };
365 }
366
367 private static string ExpandPath(
368 string path)
369 {
370 string expanded =
371 Environment.ExpandEnvironmentVariables(
372 path.Trim());
373
374 return Path.GetFullPath(
375 expanded);
376 }
377
378 private static string BuildCandidateKey(
379 SolverDiscoveryCandidate candidate)
380 {
381 return
382 $"{candidate.SolverKind}|" +
383 $"{Path.GetFullPath(candidate.Path)}";
384 }
385}
IReadOnlyList< SolverDiscoveryCandidate > Collect(SolverDiscoveryOptions options)
Collects native solver location candidates.
Configures how solver adapter plugins and native solver installations are discovered on the current c...
List< string > SolverSearchDirectories
Gets additional directories searched for native solver installations, libraries, and executables.
bool SearchEnvironmentVariables
Gets or sets whether known solver environment variables are inspected.
bool SearchCommonInstallationDirectories
Gets or sets whether common installation directories are inspected.
bool SearchSystemPath
Gets or sets whether directories listed in the operating system PATH are inspected.
void EnsureValid()
Validates the solver-discovery options.
SolverKind
Identifies a supported mathematical optimization solver.
Definition SolverKind.cs:12
SolverDiscoverySource
Identifies how a solver installation or adapter location was discovered.
@ ExplicitConfiguration
The location was supplied explicitly by the user or by application configuration.