LotSizingDataModel.Solution 2.0.1
Solution objects for production, setup, inventory and related decisions.
Loading...
Searching...
No Matches
SolutionEvaluation.cs
Go to the documentation of this file.
1using System;
2using System.Xml.Serialization;
3using LotSizingDataModel.Core.Common;
5
7
8/// <summary>
9/// Describes the independent evaluation of a
10/// lot-sizing solution candidate.
11/// </summary>
12/// <remarks>
13/// A solution may be generated by one method and evaluated
14/// by another component. For example, a heuristic solution
15/// may be checked by an independent feasibility validator
16/// and evaluated by a cost calculator.
17/// </remarks>
18[Serializable]
19[XmlType(TypeName = "solutionEvaluation")]
20public sealed class SolutionEvaluation : ModelObject
21{
22 private FeasibilityStatus _feasibilityStatus =
23 FeasibilityStatus.NotEvaluated;
24
25 private OptimalityStatus _optimalityStatus =
26 OptimalityStatus.NotEvaluated;
27
28 private DateTime _evaluatedAtUtc =
29 DateTime.UtcNow;
30
31 private string _evaluatorName =
32 string.Empty;
33
34 private string _evaluatorVersion =
35 string.Empty;
36
37 private string _objectiveValueSource =
38 string.Empty;
39
40 private string _comment =
41 string.Empty;
42
43 private double? _objectiveValue;
44 private double? _bestBound;
45 private double? _absoluteGap;
46 private double? _relativeGap;
47
48 private double? _maximumConstraintViolation;
49 private double? _totalConstraintViolation;
50
51 private int? _violatedConstraintCount;
52
53 /// <summary>
54 /// Initializes an empty solution evaluation.
55 /// </summary>
56 /// <remarks>
57 /// The evaluation date is initialized with the current
58 /// Coordinated Universal Time.
59 /// </remarks>
61 {
62 }
63
64 /// <summary>
65 /// Initializes a solution evaluation with feasibility
66 /// and optimality information.
67 /// </summary>
68 /// <param name="feasibilityStatus">
69 /// Evaluated feasibility status of the solution.
70 /// </param>
71 /// <param name="optimalityStatus">
72 /// Available information about solution optimality.
73 /// </param>
75 FeasibilityStatus feasibilityStatus,
76 OptimalityStatus optimalityStatus)
77 : this()
78 {
79 FeasibilityStatus = feasibilityStatus;
80 OptimalityStatus = optimalityStatus;
81 }
82
83 /// <summary>
84 /// Gets or sets the evaluated feasibility status
85 /// of the solution.
86 /// </summary>
87 [XmlAttribute("feasibilityStatus")]
89 {
90 get => _feasibilityStatus;
91 set => SetProperty(
92 ref _feasibilityStatus,
93 value);
94 }
95
96 /// <summary>
97 /// Gets or sets the available information about
98 /// the optimality of the solution.
99 /// </summary>
100 [XmlAttribute("optimalityStatus")]
102 {
103 get => _optimalityStatus;
104 set => SetProperty(
105 ref _optimalityStatus,
106 value);
107 }
108
109 /// <summary>
110 /// Gets or sets the UTC date and time at which
111 /// the evaluation was performed.
112 /// </summary>
113 [XmlElement("evaluatedAtUtc")]
114 public DateTime EvaluatedAtUtc
115 {
116 get => _evaluatedAtUtc;
117 set
118 {
119 DateTime utcValue =
120 value.Kind switch
121 {
122 DateTimeKind.Utc =>
123 value,
124
125 DateTimeKind.Local =>
126 value.ToUniversalTime(),
127
128 _ =>
129 DateTime.SpecifyKind(
130 value,
131 DateTimeKind.Utc)
132 };
133
134 SetProperty(
135 ref _evaluatedAtUtc,
136 utcValue);
137 }
138 }
139
140 /// <summary>
141 /// Gets or sets the name of the component
142 /// that evaluated the solution.
143 /// </summary>
144 /// <example>
145 /// LotSizingSolutionEvaluator, IBM ILOG CPLEX
146 /// or Independent feasibility checker.
147 /// </example>
148 [XmlAttribute("evaluatorName")]
149 public string EvaluatorName
150 {
151 get => _evaluatorName;
152 set => SetProperty(
153 ref _evaluatorName,
154 value?.Trim() ?? string.Empty);
155 }
156
157 /// <summary>
158 /// Gets or sets the version of the component
159 /// that evaluated the solution.
160 /// </summary>
161 [XmlAttribute("evaluatorVersion")]
162 public string EvaluatorVersion
163 {
164 get => _evaluatorVersion;
165 set => SetProperty(
166 ref _evaluatorVersion,
167 value?.Trim() ?? string.Empty);
168 }
169
170 /// <summary>
171 /// Gets or sets a description of the source
172 /// of the recorded objective value.
173 /// </summary>
174 /// <example>
175 /// CostAnalyzer, CPLEX incumbent value
176 /// or imported benchmark value.
177 /// </example>
178 [XmlAttribute("objectiveValueSource")]
180 {
181 get => _objectiveValueSource;
182 set => SetProperty(
183 ref _objectiveValueSource,
184 value?.Trim() ?? string.Empty);
185 }
186
187 /// <summary>
188 /// Gets or sets the evaluated objective value.
189 /// </summary>
190 /// <remarks>
191 /// A null value means that no objective value
192 /// has been calculated or recorded.
193 /// </remarks>
194 [XmlElement("objectiveValue", IsNullable = true)]
195 public double? ObjectiveValue
196 {
197 get => _objectiveValue;
198 set
199 {
200 ValidateNullableFiniteValue(
201 value,
202 nameof(value));
203
204 if (SetProperty(
205 ref _objectiveValue,
206 value))
207 {
208 OnPropertyChanged(
209 nameof(HasObjectiveValue));
210 }
211 }
212 }
213
214 /// <summary>
215 /// Gets or sets a valid bound on the optimal
216 /// objective value.
217 /// </summary>
218 /// <remarks>
219 /// For a minimization problem, this is normally a lower
220 /// bound. For a maximization problem, it is normally
221 /// an upper bound. A null value means that no bound
222 /// is available.
223 /// </remarks>
224 [XmlElement("bestBound", IsNullable = true)]
225 public double? BestBound
226 {
227 get => _bestBound;
228 set
229 {
230 ValidateNullableFiniteValue(
231 value,
232 nameof(value));
233
234 if (SetProperty(
235 ref _bestBound,
236 value))
237 {
238 OnPropertyChanged(
239 nameof(HasBestBound));
240 }
241 }
242 }
243
244 /// <summary>
245 /// Gets or sets the absolute optimality gap.
246 /// </summary>
247 /// <remarks>
248 /// A null value means that no absolute gap
249 /// has been calculated.
250 /// </remarks>
251 [XmlElement("absoluteGap", IsNullable = true)]
252 public double? AbsoluteGap
253 {
254 get => _absoluteGap;
255 set
256 {
257 ValidateNullableNonNegativeFiniteValue(
258 value,
259 nameof(value));
260
261 SetProperty(
262 ref _absoluteGap,
263 value);
264 }
265 }
266
267 /// <summary>
268 /// Gets or sets the relative optimality gap.
269 /// </summary>
270 /// <remarks>
271 /// The value is stored as a ratio. For example,
272 /// 0.01 represents a relative gap of one percent.
273 /// A null value means that no relative gap
274 /// has been calculated.
275 /// </remarks>
276 [XmlElement("relativeGap", IsNullable = true)]
277 public double? RelativeGap
278 {
279 get => _relativeGap;
280 set
281 {
282 ValidateNullableNonNegativeFiniteValue(
283 value,
284 nameof(value));
285
286 SetProperty(
287 ref _relativeGap,
288 value);
289 }
290 }
291
292 /// <summary>
293 /// Gets or sets the largest absolute constraint
294 /// violation detected in the solution.
295 /// </summary>
296 /// <remarks>
297 /// A null value means that this measure
298 /// has not been calculated.
299 /// </remarks>
300 [XmlElement(
301 "maximumConstraintViolation",
302 IsNullable = true)]
304 {
305 get => _maximumConstraintViolation;
306 set
307 {
308 ValidateNullableNonNegativeFiniteValue(
309 value,
310 nameof(value));
311
312 if (SetProperty(
313 ref _maximumConstraintViolation,
314 value))
315 {
316 OnPropertyChanged(
318 }
319 }
320 }
321
322 /// <summary>
323 /// Gets or sets the sum of the absolute
324 /// constraint violations detected in the solution.
325 /// </summary>
326 /// <remarks>
327 /// A null value means that this measure
328 /// has not been calculated.
329 /// </remarks>
330 [XmlElement(
331 "totalConstraintViolation",
332 IsNullable = true)]
334 {
335 get => _totalConstraintViolation;
336 set
337 {
338 ValidateNullableNonNegativeFiniteValue(
339 value,
340 nameof(value));
341
342 if (SetProperty(
343 ref _totalConstraintViolation,
344 value))
345 {
346 OnPropertyChanged(
348 }
349 }
350 }
351
352 /// <summary>
353 /// Gets or sets the number of violated constraints.
354 /// </summary>
355 /// <remarks>
356 /// A null value means that the number of violations
357 /// has not been calculated.
358 /// </remarks>
359 [XmlElement(
360 "violatedConstraintCount",
361 IsNullable = true)]
363 {
364 get => _violatedConstraintCount;
365 set
366 {
367 if (value.HasValue &&
368 value.Value < 0)
369 {
370 throw new ArgumentOutOfRangeException(
371 nameof(value),
372 value,
373 "The violated-constraint count " +
374 "cannot be negative.");
375 }
376
377 if (SetProperty(
378 ref _violatedConstraintCount,
379 value))
380 {
381 OnPropertyChanged(
383 }
384 }
385 }
386
387 /// <summary>
388 /// Gets or sets an optional human-readable comment
389 /// about the evaluation.
390 /// </summary>
391 [XmlElement("comment")]
392 public string Comment
393 {
394 get => _comment;
395 set => SetProperty(
396 ref _comment,
397 value ?? string.Empty);
398 }
399
400 /// <summary>
401 /// Gets a value indicating whether an objective
402 /// value has been recorded.
403 /// </summary>
404 [XmlIgnore]
405 public bool HasObjectiveValue =>
406 ObjectiveValue.HasValue;
407
408 /// <summary>
409 /// Gets a value indicating whether a valid
410 /// objective bound has been recorded.
411 /// </summary>
412 [XmlIgnore]
413 public bool HasBestBound =>
414 BestBound.HasValue;
415
416 /// <summary>
417 /// Gets a value indicating whether at least one
418 /// constraint-violation metric has been recorded.
419 /// </summary>
420 [XmlIgnore]
422 MaximumConstraintViolation.HasValue ||
423 TotalConstraintViolation.HasValue ||
425
426 /// <summary>
427 /// Records the objective value and its source.
428 /// </summary>
429 /// <param name="objectiveValue">
430 /// Finite objective value.
431 /// </param>
432 /// <param name="source">
433 /// Optional description of the objective-value source.
434 /// </param>
435 public void SetObjectiveValue(
436 double objectiveValue,
437 string source = "")
438 {
439 ObjectiveValue = objectiveValue;
440 ObjectiveValueSource = source;
441 }
442
443 /// <summary>
444 /// Records bound and optimality-gap information.
445 /// </summary>
446 /// <param name="bestBound">
447 /// Finite bound on the optimal objective value.
448 /// </param>
449 /// <param name="absoluteGap">
450 /// Non-negative absolute optimality gap.
451 /// </param>
452 /// <param name="relativeGap">
453 /// Non-negative relative optimality gap expressed
454 /// as a ratio.
455 /// </param>
457 double bestBound,
458 double absoluteGap,
459 double relativeGap)
460 {
461 BestBound = bestBound;
462 AbsoluteGap = absoluteGap;
463 RelativeGap = relativeGap;
464 }
465
466 /// <summary>
467 /// Records constraint-violation metrics.
468 /// </summary>
469 /// <param name="maximumViolation">
470 /// Largest non-negative absolute constraint violation.
471 /// </param>
472 /// <param name="totalViolation">
473 /// Sum of non-negative absolute constraint violations.
474 /// </param>
475 /// <param name="violatedConstraintCount">
476 /// Number of violated constraints.
477 /// </param>
479 double maximumViolation,
480 double totalViolation,
481 int violatedConstraintCount)
482 {
483 if (maximumViolation > totalViolation)
484 {
485 throw new ArgumentException(
486 "The maximum constraint violation cannot " +
487 "exceed the total constraint violation.",
488 nameof(maximumViolation));
489 }
490
492 maximumViolation;
493
495 totalViolation;
496
498 violatedConstraintCount;
499 }
500
501 /// <summary>
502 /// Removes all recorded quantitative
503 /// optimality information.
504 /// </summary>
506 {
507 BestBound = null;
508 AbsoluteGap = null;
509 RelativeGap = null;
510 }
511
512 /// <summary>
513 /// Removes all recorded constraint-violation metrics.
514 /// </summary>
521
522 /// <inheritdoc/>
523 public override string ToString()
524 {
525 string objectiveDescription =
526 ObjectiveValue.HasValue
527 ? ObjectiveValue.Value.ToString(
528 System.Globalization.CultureInfo
529 .InvariantCulture)
530 : "not evaluated";
531
532 return
533 $"Feasibility: {FeasibilityStatus}; " +
534 $"optimality: {OptimalityStatus}; " +
535 $"objective: {objectiveDescription}";
536 }
537
538 private static void ValidateNullableFiniteValue(
539 double? value,
540 string parameterName)
541 {
542 if (value.HasValue &&
543 !double.IsFinite(value.Value))
544 {
545 throw new ArgumentOutOfRangeException(
546 parameterName,
547 value,
548 "The value must be finite.");
549 }
550 }
551
552 private static void
553 ValidateNullableNonNegativeFiniteValue(
554 double? value,
555 string parameterName)
556 {
557 if (value.HasValue &&
558 (!double.IsFinite(value.Value) ||
559 value.Value < 0.0))
560 {
561 throw new ArgumentOutOfRangeException(
562 parameterName,
563 value,
564 "The value must be finite and non-negative.");
565 }
566 }
567}
void SetConstraintViolationMetrics(double maximumViolation, double totalViolation, int violatedConstraintCount)
Records constraint-violation metrics.
double? AbsoluteGap
Gets or sets the absolute optimality gap.
string ObjectiveValueSource
Gets or sets a description of the source of the recorded objective value.
SolutionEvaluation(FeasibilityStatus feasibilityStatus, OptimalityStatus optimalityStatus)
Initializes a solution evaluation with feasibility and optimality information.
int? ViolatedConstraintCount
Gets or sets the number of violated constraints.
void ClearOptimalityInformation()
Removes all recorded quantitative optimality information.
double? BestBound
Gets or sets a valid bound on the optimal objective value.
double? MaximumConstraintViolation
Gets or sets the largest absolute constraint violation detected in the solution.
double? RelativeGap
Gets or sets the relative optimality gap.
string EvaluatorName
Gets or sets the name of the component that evaluated the solution.
OptimalityStatus OptimalityStatus
Gets or sets the available information about the optimality of the solution.
SolutionEvaluation()
Initializes an empty solution evaluation.
bool HasBestBound
Gets a value indicating whether a valid objective bound has been recorded.
DateTime EvaluatedAtUtc
Gets or sets the UTC date and time at which the evaluation was performed.
string Comment
Gets or sets an optional human-readable comment about the evaluation.
FeasibilityStatus FeasibilityStatus
Gets or sets the evaluated feasibility status of the solution.
double? TotalConstraintViolation
Gets or sets the sum of the absolute constraint violations detected in the solution.
void ClearConstraintViolationMetrics()
Removes all recorded constraint-violation metrics.
bool HasConstraintViolationMetrics
Gets a value indicating whether at least one constraint-violation metric has been recorded.
void SetObjectiveValue(double objectiveValue, string source="")
Records the objective value and its source.
double? ObjectiveValue
Gets or sets the evaluated objective value.
bool HasObjectiveValue
Gets a value indicating whether an objective value has been recorded.
string EvaluatorVersion
Gets or sets the version of the component that evaluated the solution.
void SetOptimalityInformation(double bestBound, double absoluteGap, double relativeGap)
Records bound and optimality-gap information.