LotSizingDataModel.Solver 2.0.1
Solver-independent modeling, execution, monitoring and adapter infrastructure.
Loading...
Searching...
No Matches
SolverAdapterRegistry.cs
Go to the documentation of this file.
1using System;
2using System.Collections.Generic;
3using System.Linq;
6
8
9/// <summary>
10/// Stores solver adapters that were loaded successfully and
11/// provides lookup services by adapter identifier or solver
12/// kind.
13/// </summary>
14public sealed class SolverAdapterRegistry
15{
16 private readonly Dictionary<string, ISolverAdapter>
17 _adaptersById =
18 new(
19 StringComparer.OrdinalIgnoreCase);
20
21 private readonly Dictionary<SolverKind, List<ISolverAdapter>>
22 _adaptersBySolverKind =
23 new();
24
25 /// <summary>
26 /// Initializes an empty solver-adapter registry.
27 /// </summary>
29 {
30 }
31
32 /// <summary>
33 /// Gets all registered solver adapters.
34 /// </summary>
35 public IReadOnlyCollection<ISolverAdapter> Adapters =>
36 _adaptersById.Values.ToArray();
37
38 /// <summary>
39 /// Gets the number of registered adapters.
40 /// </summary>
41 public int Count =>
42 _adaptersById.Count;
43
44 /// <summary>
45 /// Registers a solver adapter.
46 /// </summary>
47 /// <param name="adapter">
48 /// Adapter to register.
49 /// </param>
50 /// <exception cref="ArgumentNullException">
51 /// Thrown when <paramref name="adapter"/> is
52 /// <see langword="null"/>.
53 /// </exception>
54 /// <exception cref="InvalidOperationException">
55 /// Thrown when the adapter identifier is empty, the solver
56 /// kind is not concrete, or another adapter already uses the
57 /// same identifier.
58 /// </exception>
59 public void Register(
60 ISolverAdapter adapter)
61 {
62 ArgumentNullException.ThrowIfNull(
63 adapter);
64
65 if (string.IsNullOrWhiteSpace(
66 adapter.AdapterId))
67 {
68 throw new InvalidOperationException(
69 "A solver adapter identifier is required.");
70 }
71
72 if (adapter.SolverKind is
73 SolverKind.Unknown or
74 SolverKind.Automatic)
75 {
76 throw new InvalidOperationException(
77 "A solver adapter must target a concrete " +
78 "solver kind.");
79 }
80
81 string adapterId =
82 adapter.AdapterId.Trim();
83
84 if (_adaptersById.ContainsKey(
85 adapterId))
86 {
87 throw new InvalidOperationException(
88 $"A solver adapter with identifier " +
89 $"'{adapterId}' is already registered.");
90 }
91
92 _adaptersById.Add(
93 adapterId,
94 adapter);
95
96 if (!_adaptersBySolverKind.TryGetValue(
97 adapter.SolverKind,
98 out List<ISolverAdapter>? solverAdapters))
99 {
100 solverAdapters =
101 new List<ISolverAdapter>();
102
103 _adaptersBySolverKind.Add(
104 adapter.SolverKind,
105 solverAdapters);
106 }
107
108 solverAdapters.Add(
109 adapter);
110 }
111
112 /// <summary>
113 /// Registers an adapter from a successful load result.
114 /// </summary>
115 /// <param name="loadResult">
116 /// Adapter-loading result.
117 /// </param>
118 /// <returns>
119 /// <see langword="true"/> when the adapter was registered;
120 /// otherwise, <see langword="false"/>.
121 /// </returns>
122 /// <exception cref="ArgumentNullException">
123 /// Thrown when <paramref name="loadResult"/> is
124 /// <see langword="null"/>.
125 /// </exception>
126 public bool TryRegister(
127 SolverAdapterLoadResult loadResult)
128 {
129 ArgumentNullException.ThrowIfNull(
130 loadResult);
131
132 if (!loadResult.IsLoaded ||
133 loadResult.Adapter is null)
134 {
135 return false;
136 }
137
138 if (_adaptersById.ContainsKey(
139 loadResult.Adapter.AdapterId))
140 {
141 return false;
142 }
143
144 Register(
145 loadResult.Adapter);
146
147 return true;
148 }
149
150 /// <summary>
151 /// Finds a registered adapter by identifier.
152 /// </summary>
153 /// <param name="adapterId">
154 /// Adapter identifier.
155 /// </param>
156 /// <returns>
157 /// Matching adapter, or <see langword="null"/> when no
158 /// adapter is registered with that identifier.
159 /// </returns>
160 /// <exception cref="ArgumentException">
161 /// Thrown when <paramref name="adapterId"/> is empty.
162 /// </exception>
164 string adapterId)
165 {
166 if (string.IsNullOrWhiteSpace(
167 adapterId))
168 {
169 throw new ArgumentException(
170 "A solver adapter identifier is required.",
171 nameof(adapterId));
172 }
173
174 _adaptersById.TryGetValue(
175 adapterId.Trim(),
176 out ISolverAdapter? adapter);
177
178 return adapter;
179 }
180
181 /// <summary>
182 /// Gets all registered adapters targeting a solver kind.
183 /// </summary>
184 /// <param name="solverKind">
185 /// Concrete solver kind.
186 /// </param>
187 /// <returns>
188 /// Registered adapters for the selected solver.
189 /// </returns>
190 public IReadOnlyList<ISolverAdapter> FindBySolverKind(
191 SolverKind solverKind)
192 {
193 if (!_adaptersBySolverKind.TryGetValue(
194 solverKind,
195 out List<ISolverAdapter>? adapters))
196 {
197 return Array.Empty<ISolverAdapter>();
198 }
199
200 return adapters.ToArray();
201 }
202
203 /// <summary>
204 /// Gets the first registered adapter targeting a solver
205 /// kind.
206 /// </summary>
207 /// <param name="solverKind">
208 /// Concrete solver kind.
209 /// </param>
210 /// <returns>
211 /// First matching adapter, or <see langword="null"/> when
212 /// none is registered.
213 /// </returns>
215 SolverKind solverKind)
216 {
217 if (!_adaptersBySolverKind.TryGetValue(
218 solverKind,
219 out List<ISolverAdapter>? adapters) ||
220 adapters.Count == 0)
221 {
222 return null;
223 }
224
225 return adapters[0];
226 }
227
228 /// <summary>
229 /// Removes a registered adapter.
230 /// </summary>
231 /// <param name="adapterId">
232 /// Adapter identifier.
233 /// </param>
234 /// <returns>
235 /// <see langword="true"/> when an adapter was removed;
236 /// otherwise, <see langword="false"/>.
237 /// </returns>
238 public bool Remove(
239 string adapterId)
240 {
241 ISolverAdapter? adapter =
242 FindById(
243 adapterId);
244
245 if (adapter is null)
246 {
247 return false;
248 }
249
250 _adaptersById.Remove(
251 adapterId.Trim());
252
253 if (_adaptersBySolverKind.TryGetValue(
254 adapter.SolverKind,
255 out List<ISolverAdapter>? solverAdapters))
256 {
257 solverAdapters.Remove(
258 adapter);
259
260 if (solverAdapters.Count == 0)
261 {
262 _adaptersBySolverKind.Remove(
263 adapter.SolverKind);
264 }
265 }
266
267 return true;
268 }
269
270 /// <summary>
271 /// Removes all registered adapters.
272 /// </summary>
273 public void Clear()
274 {
275 _adaptersById.Clear();
276 _adaptersBySolverKind.Clear();
277 }
278}
Represents the result of attempting to load a solver adapter plugin.
ISolverAdapter? Adapter
Gets or sets the loaded adapter instance.
bool IsLoaded
Gets a value indicating whether the adapter was loaded successfully.
ISolverAdapter? FindById(string adapterId)
Finds a registered adapter by identifier.
SolverAdapterRegistry()
Initializes an empty solver-adapter registry.
bool Remove(string adapterId)
Removes a registered adapter.
bool TryRegister(SolverAdapterLoadResult loadResult)
Registers an adapter from a successful load result.
IReadOnlyCollection< ISolverAdapter > Adapters
Gets all registered solver adapters.
ISolverAdapter? FindFirstBySolverKind(SolverKind solverKind)
Gets the first registered adapter targeting a solver kind.
IReadOnlyList< ISolverAdapter > FindBySolverKind(SolverKind solverKind)
Gets all registered adapters targeting a solver kind.
void Register(ISolverAdapter adapter)
Registers a solver adapter.
SolverKind SolverKind
Gets the solver kind implemented by this adapter.
Defines the metadata and capabilities exposed by a solver adapter plugin.
string AdapterId
Gets the unique adapter identifier.
SolverKind
Identifies a supported mathematical optimization solver.
Definition SolverKind.cs:12