LotSizingDataModel.Solution 2.0.1
Solution objects for production, setup, inventory and related decisions.
Loading...
Searching...
No Matches
SolutionGenerationMetadata.cs
Go to the documentation of this file.
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Xml.Serialization;
5using LotSizingDataModel.Core.Common;
7
9
10/// <summary>
11/// Describes how a lot-sizing solution was generated.
12/// </summary>
13/// <remarks>
14/// This class is independent of any particular solver,
15/// heuristic, metaheuristic or software implementation.
16/// </remarks>
17[Serializable]
18[XmlType(TypeName = "solutionGenerationMetadata")]
19public sealed class SolutionGenerationMetadata : ModelObject
20{
21 private SolutionMethodKind _methodKind =
22 SolutionMethodKind.Unknown;
23
24 private TerminationReason _terminationReason =
25 TerminationReason.Unknown;
26
27 private string _methodName = string.Empty;
28 private string _methodVersion = string.Empty;
29 private string _implementationName = string.Empty;
30 private string _implementationVersion = string.Empty;
31 private string _comment = string.Empty;
32
33 private DateTime _createdAtUtc =
34 DateTime.UtcNow;
35
36 private double? _durationSeconds;
37 private int? _randomSeed;
38 private long? _iterationCount;
39 private long? _evaluationCount;
40 private bool? _isDeterministic;
41
42 /// <summary>
43 /// Initializes empty solution-generation metadata.
44 /// </summary>
45 /// <remarks>
46 /// The creation date is initialized with the current
47 /// Coordinated Universal Time.
48 /// </remarks>
50 {
51 }
52
53 /// <summary>
54 /// Initializes solution-generation metadata for a method.
55 /// </summary>
56 /// <param name="methodKind">
57 /// General category of the solution-generation method.
58 /// </param>
59 /// <param name="methodName">
60 /// Human-readable name of the method.
61 /// </param>
63 SolutionMethodKind methodKind,
64 string methodName)
65 : this()
66 {
67 MethodKind = methodKind;
68 MethodName = methodName;
69 }
70
71 /// <summary>
72 /// Gets or sets the general category of the method
73 /// used to generate the solution.
74 /// </summary>
75 [XmlAttribute("methodKind")]
77 {
78 get => _methodKind;
79 set => SetProperty(
80 ref _methodKind,
81 value);
82 }
83
84 /// <summary>
85 /// Gets or sets the reason why the execution stopped.
86 /// </summary>
87 [XmlAttribute("terminationReason")]
89 {
90 get => _terminationReason;
91 set => SetProperty(
92 ref _terminationReason,
93 value);
94 }
95
96 /// <summary>
97 /// Gets or sets the human-readable name of the algorithm
98 /// or solution-generation method.
99 /// </summary>
100 /// <example>
101 /// Genetic algorithm, branch-and-cut, Silver-Meal heuristic
102 /// or manual construction.
103 /// </example>
104 [XmlAttribute("methodName")]
105 public string MethodName
106 {
107 get => _methodName;
108 set => SetProperty(
109 ref _methodName,
110 value?.Trim() ?? string.Empty);
111 }
112
113 /// <summary>
114 /// Gets or sets the version of the algorithm
115 /// or solution-generation method.
116 /// </summary>
117 [XmlAttribute("methodVersion")]
118 public string MethodVersion
119 {
120 get => _methodVersion;
121 set => SetProperty(
122 ref _methodVersion,
123 value?.Trim() ?? string.Empty);
124 }
125
126 /// <summary>
127 /// Gets or sets the name of the software implementation
128 /// used to execute the method.
129 /// </summary>
130 /// <example>
131 /// IBM ILOG CPLEX, Custom genetic algorithm
132 /// or LotSizingDataModel.Heuristics.
133 /// </example>
134 [XmlAttribute("implementationName")]
135 public string ImplementationName
136 {
137 get => _implementationName;
138 set => SetProperty(
139 ref _implementationName,
140 value?.Trim() ?? string.Empty);
141 }
142
143 /// <summary>
144 /// Gets or sets the version of the software implementation.
145 /// </summary>
146 [XmlAttribute("implementationVersion")]
148 {
149 get => _implementationVersion;
150 set => SetProperty(
151 ref _implementationVersion,
152 value?.Trim() ?? string.Empty);
153 }
154
155 /// <summary>
156 /// Gets or sets the UTC date and time at which
157 /// the solution was generated.
158 /// </summary>
159 [XmlElement("createdAtUtc")]
160 public DateTime CreatedAtUtc
161 {
162 get => _createdAtUtc;
163 set
164 {
165 DateTime utcValue =
166 value.Kind switch
167 {
168 DateTimeKind.Utc => value,
169
170 DateTimeKind.Local =>
171 value.ToUniversalTime(),
172
173 _ => DateTime.SpecifyKind(
174 value,
175 DateTimeKind.Utc)
176 };
177
178 SetProperty(
179 ref _createdAtUtc,
180 utcValue);
181 }
182 }
183
184 /// <summary>
185 /// Gets or sets the execution duration in seconds.
186 /// </summary>
187 /// <remarks>
188 /// A null value means that the duration was not recorded.
189 /// </remarks>
190 [XmlElement("durationSeconds", IsNullable = true)]
191 public double? DurationSeconds
192 {
193 get => _durationSeconds;
194 set
195 {
196 if (value.HasValue &&
197 (!double.IsFinite(value.Value) ||
198 value.Value < 0.0))
199 {
200 throw new ArgumentOutOfRangeException(
201 nameof(value),
202 value,
203 "The execution duration must be finite " +
204 "and non-negative.");
205 }
206
207 SetProperty(
208 ref _durationSeconds,
209 value);
210 }
211 }
212
213 /// <summary>
214 /// Gets or sets the random seed used by the method.
215 /// </summary>
216 /// <remarks>
217 /// A null value means that no seed was used
218 /// or that it was not recorded.
219 /// </remarks>
220 [XmlElement("randomSeed", IsNullable = true)]
221 public int? RandomSeed
222 {
223 get => _randomSeed;
224 set => SetProperty(
225 ref _randomSeed,
226 value);
227 }
228
229 /// <summary>
230 /// Gets or sets the number of algorithm iterations
231 /// performed before termination.
232 /// </summary>
233 /// <remarks>
234 /// A null value means that the iteration count
235 /// is not applicable or was not recorded.
236 /// </remarks>
237 [XmlElement("iterationCount", IsNullable = true)]
238 public long? IterationCount
239 {
240 get => _iterationCount;
241 set
242 {
243 if (value < 0)
244 {
245 throw new ArgumentOutOfRangeException(
246 nameof(value),
247 value,
248 "The iteration count cannot be negative.");
249 }
250
251 SetProperty(
252 ref _iterationCount,
253 value);
254 }
255 }
256
257 /// <summary>
258 /// Gets or sets the number of candidate-solution
259 /// or objective evaluations performed.
260 /// </summary>
261 /// <remarks>
262 /// A null value means that the evaluation count
263 /// is not applicable or was not recorded.
264 /// </remarks>
265 [XmlElement("evaluationCount", IsNullable = true)]
266 public long? EvaluationCount
267 {
268 get => _evaluationCount;
269 set
270 {
271 if (value < 0)
272 {
273 throw new ArgumentOutOfRangeException(
274 nameof(value),
275 value,
276 "The evaluation count cannot be negative.");
277 }
278
279 SetProperty(
280 ref _evaluationCount,
281 value);
282 }
283 }
284
285 /// <summary>
286 /// Gets or sets whether the method is deterministic
287 /// under the recorded configuration.
288 /// </summary>
289 /// <remarks>
290 /// A null value means that determinism is unknown
291 /// or has not been specified.
292 /// </remarks>
293 [XmlElement("isDeterministic", IsNullable = true)]
294 public bool? IsDeterministic
295 {
296 get => _isDeterministic;
297 set => SetProperty(
298 ref _isDeterministic,
299 value);
300 }
301
302 /// <summary>
303 /// Gets or sets an optional human-readable comment
304 /// about the solution-generation execution.
305 /// </summary>
306 [XmlElement("comment")]
307 public string Comment
308 {
309 get => _comment;
310 set => SetProperty(
311 ref _comment,
312 value ?? string.Empty);
313 }
314
315 /// <summary>
316 /// Gets the parameters used by the algorithm,
317 /// solver or solution-generation method.
318 /// </summary>
319 [XmlArray("parameters")]
320 [XmlArrayItem("parameter")]
321 public List<AlgorithmParameter> Parameters { get; } =
322 new();
323
324 /// <summary>
325 /// Gets a value indicating whether at least one
326 /// algorithm parameter is recorded.
327 /// </summary>
328 [XmlIgnore]
329 public bool HasParameters =>
330 Parameters.Count > 0;
331
332 /// <summary>
333 /// Adds an algorithm parameter.
334 /// </summary>
335 /// <param name="parameter">
336 /// Parameter to add.
337 /// </param>
338 /// <exception cref="ArgumentNullException">
339 /// Thrown when the parameter is null.
340 /// </exception>
341 /// <exception cref="InvalidOperationException">
342 /// Thrown when another parameter has the same name.
343 /// </exception>
344 public void AddParameter(
345 AlgorithmParameter parameter)
346 {
347 ArgumentNullException.ThrowIfNull(parameter);
348
349 if (Parameters.Any(
350 existing =>
351 string.Equals(
352 existing.Name,
353 parameter.Name,
354 StringComparison.OrdinalIgnoreCase)))
355 {
356 throw new InvalidOperationException(
357 $"An algorithm parameter named " +
358 $"'{parameter.Name}' already exists.");
359 }
360
361 Parameters.Add(parameter);
362
363 OnPropertyChanged(
364 nameof(Parameters));
365
366 OnPropertyChanged(
367 nameof(HasParameters));
368 }
369
370 /// <summary>
371 /// Adds or replaces an algorithm parameter.
372 /// </summary>
373 /// <param name="parameter">
374 /// Parameter to add or use as a replacement.
375 /// </param>
376 public void SetParameter(
377 AlgorithmParameter parameter)
378 {
379 ArgumentNullException.ThrowIfNull(parameter);
380
381 int index =
382 Parameters.FindIndex(
383 existing =>
384 string.Equals(
385 existing.Name,
386 parameter.Name,
387 StringComparison.OrdinalIgnoreCase));
388
389 if (index >= 0)
390 {
391 Parameters[index] = parameter;
392 }
393 else
394 {
395 Parameters.Add(parameter);
396 }
397
398 OnPropertyChanged(
399 nameof(Parameters));
400
401 OnPropertyChanged(
402 nameof(HasParameters));
403 }
404
405 /// <summary>
406 /// Finds an algorithm parameter by name.
407 /// </summary>
408 /// <param name="name">
409 /// Name of the parameter to find.
410 /// </param>
411 /// <returns>
412 /// The matching parameter, or null when it does not exist.
413 /// </returns>
415 string name)
416 {
417 ArgumentException.ThrowIfNullOrWhiteSpace(name);
418
419 return Parameters.FirstOrDefault(
420 parameter =>
421 string.Equals(
422 parameter.Name,
423 name,
424 StringComparison.OrdinalIgnoreCase));
425 }
426
427 /// <summary>
428 /// Removes an algorithm parameter by name.
429 /// </summary>
430 /// <param name="name">
431 /// Name of the parameter to remove.
432 /// </param>
433 /// <returns>
434 /// True when a parameter was removed; otherwise, false.
435 /// </returns>
436 public bool RemoveParameter(
437 string name)
438 {
439 ArgumentException.ThrowIfNullOrWhiteSpace(name);
440
441 AlgorithmParameter? parameter =
442 FindParameter(name);
443
444 if (parameter is null)
445 {
446 return false;
447 }
448
449 bool removed =
450 Parameters.Remove(parameter);
451
452 if (removed)
453 {
454 OnPropertyChanged(
455 nameof(Parameters));
456
457 OnPropertyChanged(
458 nameof(HasParameters));
459 }
460
461 return removed;
462 }
463
464 /// <summary>
465 /// Removes every recorded algorithm parameter.
466 /// </summary>
467 public void ClearParameters()
468 {
469 if (Parameters.Count == 0)
470 {
471 return;
472 }
473
474 Parameters.Clear();
475
476 OnPropertyChanged(
477 nameof(Parameters));
478
479 OnPropertyChanged(
480 nameof(HasParameters));
481 }
482
483 /// <inheritdoc/>
484 public override string ToString()
485 {
486 string name =
487 string.IsNullOrWhiteSpace(MethodName)
488 ? MethodKind.ToString()
489 : MethodName;
490
491 return
492 $"{name} — {TerminationReason}";
493 }
494}
Represents one named parameter used by a solution-generation method.
string ImplementationVersion
Gets or sets the version of the software implementation.
string ImplementationName
Gets or sets the name of the software implementation used to execute the method.
bool HasParameters
Gets a value indicating whether at least one algorithm parameter is recorded.
int? RandomSeed
Gets or sets the random seed used by the method.
AlgorithmParameter? FindParameter(string name)
Finds an algorithm parameter by name.
void ClearParameters()
Removes every recorded algorithm parameter.
string MethodName
Gets or sets the human-readable name of the algorithm or solution-generation method.
long? IterationCount
Gets or sets the number of algorithm iterations performed before termination.
string MethodVersion
Gets or sets the version of the algorithm or solution-generation method.
bool RemoveParameter(string name)
Removes an algorithm parameter by name.
SolutionGenerationMetadata(SolutionMethodKind methodKind, string methodName)
Initializes solution-generation metadata for a method.
void SetParameter(AlgorithmParameter parameter)
Adds or replaces an algorithm parameter.
double? DurationSeconds
Gets or sets the execution duration in seconds.
List< AlgorithmParameter > Parameters
Gets the parameters used by the algorithm, solver or solution-generation method.
SolutionMethodKind MethodKind
Gets or sets the general category of the method used to generate the solution.
bool? IsDeterministic
Gets or sets whether the method is deterministic under the recorded configuration.
DateTime CreatedAtUtc
Gets or sets the UTC date and time at which the solution was generated.
SolutionGenerationMetadata()
Initializes empty solution-generation metadata.
TerminationReason TerminationReason
Gets or sets the reason why the execution stopped.
string Comment
Gets or sets an optional human-readable comment about the solution-generation execution.
long? EvaluationCount
Gets or sets the number of candidate-solution or objective evaluations performed.
void AddParameter(AlgorithmParameter parameter)
Adds an algorithm parameter.
SolutionMethodKind
Identifies the general type of method used to generate a lot-sizing solution.