ULSAlgorithms 1.1.0-g3e5595996d
High-performance exact and heuristic algorithms for uncapacitated lot sizing
Loading...
Searching...
No Matches
CoinOrCbcSolverAdapter.cs
Go to the documentation of this file.
1using System.Text.RegularExpressions;
3
5
6/// <summary>
7/// Detects and validates the stand-alone COIN-OR CBC executable.
8/// </summary>
9public sealed partial class CoinOrCbcSolverAdapter :
11{
12 private readonly ExternalSolverProcessProbe _probe =
13 new();
14
15 /// <summary>Initializes the CBC adapter.</summary>
26
27 /// <inheritdoc />
28 public override string AdapterId =>
29 "ULSAlgorithms.Solver.CoinOrCbc";
30
31 /// <inheritdoc />
32 public override string AdapterName =>
33 "ULSAlgorithms COIN-OR CBC Adapter";
34
35 /// <inheritdoc />
36 public override SolverKind SolverKind =>
37 SolverKind.CoinOrCbc;
38
39 /// <inheritdoc />
40 public override async ValueTask<SolverAvailabilityInfo>
42 CancellationToken cancellationToken = default)
43 {
44 cancellationToken.ThrowIfCancellationRequested();
45
46 string executablePath =
47 ResolveExecutablePath();
48
49 if (string.IsNullOrWhiteSpace(executablePath))
50 {
51 return new SolverAvailabilityInfo(
52 SolverKind.CoinOrCbc,
53 SolverAvailabilityStatus.NotInstalled,
54 solverName: "COIN-OR CBC",
55 diagnostics:
56 [
57 "cbc executable was not found. Put it on PATH, define " +
58 "CBC_HOME/COINOR_HOME, or set " +
59 "ULSALGORITHMS_CBC_EXECUTABLE."
60 ]);
61 }
62
63 try
64 {
66 await _probe.RunAsync(
67 executablePath,
68 ["-quit"],
69 cancellationToken);
70
71 string output =
72 processResult.CombinedOutput;
73
74 if (processResult.ExitCode != 0)
75 {
76 return Failure(
77 executablePath,
78 FirstMeaningfulLine(output) ??
79 $"cbc exited with code {processResult.ExitCode}.");
80 }
81
82 return new SolverAvailabilityInfo(
83 SolverKind.CoinOrCbc,
85 solverName: "COIN-OR CBC",
86 solverVersion:
87 ParseVersion(output),
88 installationPath:
89 Path.GetDirectoryName(executablePath) ??
90 string.Empty,
91 nativeLibraryPath:
92 executablePath,
93 licenseInformation:
94 "Open-source solver; no runtime license required.",
95 diagnostics:
96 [
97 $"CBC executable detected at '{executablePath}'.",
98 FirstMeaningfulLine(output) ??
99 "CBC process probe completed successfully."
100 ]);
101 }
102 catch (OperationCanceledException)
103 {
104 throw;
105 }
106 catch (Exception exception)
107 {
108 return Failure(
109 executablePath,
110 exception.Message);
111 }
112 }
113
114 private static SolverAvailabilityInfo Failure(
115 string executablePath,
116 string diagnostic)
117 {
118 return new SolverAvailabilityInfo(
119 SolverKind.CoinOrCbc,
120 SolverAvailabilityStatus.LoadFailure,
121 solverName: "COIN-OR CBC",
122 installationPath:
123 Path.GetDirectoryName(executablePath) ??
124 string.Empty,
125 nativeLibraryPath:
126 executablePath,
127 diagnostics: [diagnostic]);
128 }
129
130 private static string ResolveExecutablePath()
131 {
133 [
134 "ULSALGORITHMS_CBC_EXECUTABLE",
135 "LOTSIZING_CBC_EXECUTABLE"
136 ],
137 [
138 "CBC_HOME",
139 "COINOR_HOME"
140 ],
141 [
142 Path.Combine("bin", "cbc.exe"),
143 Path.Combine("bin", "cbc"),
144 "cbc.exe",
145 "cbc"
146 ],
147 ["cbc.exe", "cbc"],
148 EnumerateLocalCandidates());
149 }
150
151 private static IEnumerable<string>
152 EnumerateLocalCandidates()
153 {
154 string[] roots =
155 [
156 AppContext.BaseDirectory,
157 Environment.CurrentDirectory
158 ];
159
160 foreach (string root in roots)
161 {
162 yield return
163 Path.Combine(root, "cbc.exe");
164
165 yield return
166 Path.Combine(root, "cbc");
167
168 yield return
169 Path.Combine(
170 root,
171 "cbc",
172 "bin",
173 "cbc.exe");
174
175 yield return
176 Path.Combine(
177 root,
178 "tools",
179 "cbc",
180 "bin",
181 "cbc.exe");
182
183 yield return
184 Path.Combine(
185 root,
186 "solver",
187 "cbc",
188 "bin",
189 "cbc.exe");
190 }
191 }
192
193 private static string ParseVersion(
194 string text)
195 {
196 Match match =
197 VersionRegex().Match(text ?? string.Empty);
198
199 return match.Success
200 ? match.Groups[1].Value
201 : string.Empty;
202 }
203
204 private static string? FirstMeaningfulLine(
205 string text)
206 {
207 return text
208 .Split(
209 ['\r', '\n'],
210 StringSplitOptions.RemoveEmptyEntries |
211 StringSplitOptions.TrimEntries)
212 .FirstOrDefault();
213 }
214
215 [GeneratedRegex(
216 @"Version:\s*([0-9]+(?:\.[0-9]+){1,3})",
217 RegexOptions.IgnoreCase |
218 RegexOptions.CultureInvariant)]
219 private static partial Regex VersionRegex();
220}
override SolverKind SolverKind
Gets the concrete solver targeted by this adapter.
override string AdapterId
Gets the stable adapter identifier.
override async ValueTask< SolverAvailabilityInfo > CheckAvailabilityAsync(CancellationToken cancellationToken=default)
Performs the adapter-specific machine discovery / load / license check.
OptimizationSolverAdapterBase(params SolverCapability[] capabilities)
Initializes an adapter with its supported capabilities.
Locates optional native-solver command-line executables without requiring their SDKs at compile time.
static string Resolve(IEnumerable< string > explicitExecutableEnvironmentVariables, IEnumerable< string > homeEnvironmentVariables, IEnumerable< string > relativeExecutablePaths, IEnumerable< string > pathExecutableNames, IEnumerable< string >? directCandidates=null)
Resolves an executable from explicit environment variables, installation-home hints,...
Executes short solver command-line probes and captures their output.
Describes solver availability and the installation selected by an adapter.
SolverAvailabilityStatus
Describes whether a solver can currently be used on the current computer.
SolverCapability
Identifies an optional capability exposed by an optimization-solver adapter.
@ LinearProgramming
Continuous linear programming.
@ OptimalityGapReporting
Best-bound and optimality-gap reporting.
@ MixedIntegerLinearProgramming
Mixed-integer linear programming.
@ SearchStatistics
Search-node and iteration statistics.
SolverKind
Identifies a mathematical optimization solver that can be used by solver-backed ULS algorithms.
Definition SolverKind.cs:15