LotSizingDataModel.Instance 2.0.1
Lot-sizing instance representation, descriptors and problem characterization.
Loading...
Searching...
No Matches
MethodCompatibilityEvidence.cs
Go to the documentation of this file.
1using System;
2using System.Globalization;
3using System.Xml.Serialization;
4using LotSizingDataModel.Core.Common;
5
7
8/// <summary>
9/// Represents one piece of evidence used to evaluate the
10/// compatibility between a solution method and a lot-sizing
11/// problem instance.
12/// </summary>
13/// <remarks>
14/// Compatibility evidence may describe:
15/// <list type="bullet">
16/// <item>
17/// <description>
18/// a supported or unsupported problem family;
19/// </description>
20/// </item>
21/// <item>
22/// <description>
23/// a required problem feature;
24/// </description>
25/// </item>
26/// <item>
27/// <description>
28/// an excluded modeling characteristic;
29/// </description>
30/// </item>
31/// <item>
32/// <description>
33/// a method or implementation size limit;
34/// </description>
35/// </item>
36/// <item>
37/// <description>
38/// a favorable structural characteristic that can be
39/// exploited by the method.
40/// </description>
41/// </item>
42/// </list>
43///
44/// Evidence is deliberately independent from the mechanism
45/// used to evaluate the criterion. The expected and observed
46/// values are stored as text for traceability.
47/// </remarks>
48[Serializable]
49[XmlType(TypeName = "methodCompatibilityEvidence")]
50public sealed class MethodCompatibilityEvidence : ModelObject
51{
52 private string _criterionCode =
53 string.Empty;
54
55 private string _featureCode =
56 string.Empty;
57
58 private string _description =
59 string.Empty;
60
61 private string _expectedValue =
62 string.Empty;
63
64 private string _observedValue =
65 string.Empty;
66
67 private string _affectedEntityKey =
68 string.Empty;
69
70 private bool _isSatisfied;
71
72 private bool _isRequired =
73 true;
74
75 private bool _isBlocking;
76
77 private double _weight =
78 1.0;
79
80 private string _comment =
81 string.Empty;
82
83 /// <summary>
84 /// Initializes an empty compatibility-evidence record.
85 /// </summary>
86 /// <remarks>
87 /// This constructor is required for XML serialization.
88 /// </remarks>
90 {
91 }
92
93 /// <summary>
94 /// Initializes compatibility evidence for one evaluated
95 /// criterion.
96 /// </summary>
97 /// <param name="criterionCode">
98 /// Stable code identifying the evaluated criterion.
99 /// </param>
100 /// <param name="description">
101 /// Human-readable explanation of the criterion.
102 /// </param>
103 /// <param name="isSatisfied">
104 /// Value indicating whether the criterion is satisfied.
105 /// </param>
106 /// <param name="isRequired">
107 /// Value indicating whether the criterion represents a
108 /// required compatibility condition.
109 /// </param>
110 /// <param name="isBlocking">
111 /// Value indicating whether failure of the criterion makes
112 /// the method incompatible with the complete problem.
113 /// </param>
114 /// <param name="weight">
115 /// Non-negative importance assigned to the criterion.
116 /// </param>
117 /// <exception cref="ArgumentException">
118 /// Thrown when <paramref name="criterionCode"/> or
119 /// <paramref name="description"/> is empty.
120 /// </exception>
121 /// <exception cref="ArgumentOutOfRangeException">
122 /// Thrown when <paramref name="weight"/> is negative or
123 /// not finite.
124 /// </exception>
126 string criterionCode,
127 string description,
128 bool isSatisfied,
129 bool isRequired = true,
130 bool isBlocking = false,
131 double weight = 1.0)
132 {
133 if (string.IsNullOrWhiteSpace(criterionCode))
134 {
135 throw new ArgumentException(
136 "A compatibility criterion code is required.",
137 nameof(criterionCode));
138 }
139
140 if (string.IsNullOrWhiteSpace(description))
141 {
142 throw new ArgumentException(
143 "A compatibility criterion description is " +
144 "required.",
145 nameof(description));
146 }
147
149 criterionCode;
150
152 description;
153
155 isSatisfied;
156
157 IsRequired =
158 isRequired;
159
160 IsBlocking =
161 isBlocking;
162
163 Weight =
164 weight;
165 }
166
167 /// <summary>
168 /// Gets or sets the stable code identifying the evaluated
169 /// compatibility criterion.
170 /// </summary>
171 /// <remarks>
172 /// Examples include:
173 /// <list type="bullet">
174 /// <item>
175 /// <description><c>FAMILY.SUPPORTS_MLLP</c>;</description>
176 /// </item>
177 /// <item>
178 /// <description><c>FEATURE.NO_BACKLOGGING</c>;</description>
179 /// </item>
180 /// <item>
181 /// <description><c>LIMIT.MAX_ITEMS</c>;</description>
182 /// </item>
183 /// <item>
184 /// <description><c>STRUCTURE.SERIAL</c>.</description>
185 /// </item>
186 /// </list>
187 /// </remarks>
188 [XmlAttribute("criterionCode")]
189 public string CriterionCode
190 {
191 get => _criterionCode;
192 set
193 {
194 if (SetProperty(
195 ref _criterionCode,
196 value?.Trim() ?? string.Empty))
197 {
198 OnPropertyChanged(
199 nameof(HasCriterionCode));
200
201 OnPropertyChanged(
202 nameof(IsValidEvidence));
203 }
204 }
205 }
206
207 /// <summary>
208 /// Gets or sets the code of the problem feature evaluated
209 /// by this evidence.
210 /// </summary>
211 /// <remarks>
212 /// This property is optional because some criteria concern
213 /// a problem family, a method capability or a size limit
214 /// rather than one property of
215 /// <c>LotSizingProblemFeatures</c>.
216 /// </remarks>
217 [XmlAttribute("featureCode")]
218 public string FeatureCode
219 {
220 get => _featureCode;
221 set
222 {
223 if (SetProperty(
224 ref _featureCode,
225 value?.Trim() ?? string.Empty))
226 {
227 OnPropertyChanged(
228 nameof(HasFeatureCode));
229 }
230 }
231 }
232
233 /// <summary>
234 /// Gets or sets the human-readable explanation of the
235 /// compatibility criterion.
236 /// </summary>
237 /// <remarks>
238 /// The description should explain why the observed
239 /// characteristic supports or limits the applicability of
240 /// the method.
241 /// </remarks>
242 [XmlElement("description")]
243 public string Description
244 {
245 get => _description;
246 set
247 {
248 if (SetProperty(
249 ref _description,
250 value?.Trim() ?? string.Empty))
251 {
252 OnPropertyChanged(
253 nameof(HasDescription));
254
255 OnPropertyChanged(
256 nameof(IsValidEvidence));
257 }
258 }
259 }
260
261 /// <summary>
262 /// Gets or sets the value expected by the method or
263 /// compatibility criterion.
264 /// </summary>
265 /// <remarks>
266 /// Examples include <c>true</c>, <c>MLLP</c>,
267 /// <c>singleItem</c> and <c>&lt;= 100</c>.
268 /// </remarks>
269 [XmlAttribute("expectedValue")]
270 public string ExpectedValue
271 {
272 get => _expectedValue;
273 set
274 {
275 if (SetProperty(
276 ref _expectedValue,
277 value?.Trim() ?? string.Empty))
278 {
279 OnPropertyChanged(
280 nameof(HasExpectedValue));
281 }
282 }
283 }
284
285 /// <summary>
286 /// Gets or sets the value observed in the analyzed
287 /// instance.
288 /// </summary>
289 [XmlAttribute("observedValue")]
290 public string ObservedValue
291 {
292 get => _observedValue;
293 set
294 {
295 if (SetProperty(
296 ref _observedValue,
297 value?.Trim() ?? string.Empty))
298 {
299 OnPropertyChanged(
300 nameof(HasObservedValue));
301 }
302 }
303 }
304
305 /// <summary>
306 /// Gets or sets an optional key identifying the entity to
307 /// which the evidence applies.
308 /// </summary>
309 /// <remarks>
310 /// Examples include <c>item:12</c>,
311 /// <c>plant:3</c>, <c>workCenter:3/7</c> and
312 /// <c>transportResource:5</c>.
313 /// </remarks>
314 [XmlAttribute("affectedEntityKey")]
315 public string AffectedEntityKey
316 {
317 get => _affectedEntityKey;
318 set
319 {
320 if (SetProperty(
321 ref _affectedEntityKey,
322 value?.Trim() ?? string.Empty))
323 {
324 OnPropertyChanged(
325 nameof(HasAffectedEntityKey));
326 }
327 }
328 }
329
330 /// <summary>
331 /// Gets or sets a value indicating whether the
332 /// compatibility criterion is satisfied.
333 /// </summary>
334 [XmlAttribute("isSatisfied")]
335 public bool IsSatisfied
336 {
337 get => _isSatisfied;
338 set
339 {
340 if (SetProperty(
341 ref _isSatisfied,
342 value))
343 {
344 NotifyEvaluationProperties();
345 }
346 }
347 }
348
349 /// <summary>
350 /// Gets or sets a value indicating whether the criterion
351 /// represents a required condition.
352 /// </summary>
353 /// <remarks>
354 /// A required mismatch indicates that the method cannot
355 /// be applied directly under its standard assumptions.
356 ///
357 /// It does not necessarily make the method entirely
358 /// unusable when decomposition, relaxation or adaptation
359 /// is possible.
360 /// </remarks>
361 [XmlAttribute("isRequired")]
362 public bool IsRequired
363 {
364 get => _isRequired;
365 set
366 {
367 if (SetProperty(
368 ref _isRequired,
369 value))
370 {
371 NotifyEvaluationProperties();
372 }
373 }
374 }
375
376 /// <summary>
377 /// Gets or sets a value indicating whether failure of the
378 /// criterion makes the method incompatible with the
379 /// complete problem.
380 /// </summary>
381 /// <remarks>
382 /// Examples of blocking criteria include an unsupported
383 /// product structure, an excluded modeling feature or a
384 /// hard implementation limit.
385 /// </remarks>
386 [XmlAttribute("isBlocking")]
387 public bool IsBlocking
388 {
389 get => _isBlocking;
390 set
391 {
392 if (SetProperty(
393 ref _isBlocking,
394 value))
395 {
396 NotifyEvaluationProperties();
397 }
398 }
399 }
400
401 /// <summary>
402 /// Gets or sets the non-negative importance assigned to
403 /// the criterion.
404 /// </summary>
405 /// <remarks>
406 /// The advisor may use this weight when calculating an
407 /// overall compatibility score.
408 ///
409 /// Blocking mismatches remain blocking independently of
410 /// their numerical weight.
411 /// </remarks>
412 /// <exception cref="ArgumentOutOfRangeException">
413 /// Thrown when the supplied value is negative or not
414 /// finite.
415 /// </exception>
416 [XmlAttribute("weight")]
417 public double Weight
418 {
419 get => _weight;
420 set
421 {
422 if (!double.IsFinite(value) ||
423 value < 0.0)
424 {
425 throw new ArgumentOutOfRangeException(
426 nameof(value),
427 value,
428 "The compatibility-evidence weight must " +
429 "be finite and non-negative.");
430 }
431
432 if (SetProperty(
433 ref _weight,
434 value))
435 {
436 OnPropertyChanged(
437 nameof(ScoreContribution));
438
439 OnPropertyChanged(
440 nameof(IsValidEvidence));
441 }
442 }
443 }
444
445 /// <summary>
446 /// Gets or sets an optional explanatory comment.
447 /// </summary>
448 /// <remarks>
449 /// The comment may describe an adaptation, approximation
450 /// or implementation-specific limitation.
451 /// </remarks>
452 [XmlElement("comment")]
453 public string Comment
454 {
455 get => _comment;
456 set
457 {
458 if (SetProperty(
459 ref _comment,
460 value?.Trim() ?? string.Empty))
461 {
462 OnPropertyChanged(
463 nameof(HasComment));
464 }
465 }
466 }
467
468 /// <summary>
469 /// Gets a value indicating whether a criterion code has
470 /// been recorded.
471 /// </summary>
472 [XmlIgnore]
473 public bool HasCriterionCode =>
474 !string.IsNullOrWhiteSpace(
476
477 /// <summary>
478 /// Gets a value indicating whether a problem-feature code
479 /// has been recorded.
480 /// </summary>
481 [XmlIgnore]
482 public bool HasFeatureCode =>
483 !string.IsNullOrWhiteSpace(
485
486 /// <summary>
487 /// Gets a value indicating whether a human-readable
488 /// description has been recorded.
489 /// </summary>
490 [XmlIgnore]
491 public bool HasDescription =>
492 !string.IsNullOrWhiteSpace(
494
495 /// <summary>
496 /// Gets a value indicating whether an expected value has
497 /// been recorded.
498 /// </summary>
499 [XmlIgnore]
500 public bool HasExpectedValue =>
501 !string.IsNullOrWhiteSpace(
503
504 /// <summary>
505 /// Gets a value indicating whether an observed value has
506 /// been recorded.
507 /// </summary>
508 [XmlIgnore]
509 public bool HasObservedValue =>
510 !string.IsNullOrWhiteSpace(
512
513 /// <summary>
514 /// Gets a value indicating whether an affected entity key
515 /// has been recorded.
516 /// </summary>
517 [XmlIgnore]
518 public bool HasAffectedEntityKey =>
519 !string.IsNullOrWhiteSpace(
521
522 /// <summary>
523 /// Gets a value indicating whether an explanatory comment
524 /// has been recorded.
525 /// </summary>
526 [XmlIgnore]
527 public bool HasComment =>
528 !string.IsNullOrWhiteSpace(
529 Comment);
530
531 /// <summary>
532 /// Gets a value indicating whether this evidence supports
533 /// the compatibility of the method.
534 /// </summary>
535 [XmlIgnore]
538
539 /// <summary>
540 /// Gets a value indicating whether the evaluated
541 /// criterion is not satisfied.
542 /// </summary>
543 [XmlIgnore]
544 public bool IsMismatch =>
546
547 /// <summary>
548 /// Gets a value indicating whether the evidence represents
549 /// a blocking incompatibility.
550 /// </summary>
551 [XmlIgnore]
552 public bool IsBlockingMismatch =>
553 !IsSatisfied &&
555
556 /// <summary>
557 /// Gets a value indicating whether a required criterion
558 /// is not satisfied.
559 /// </summary>
560 [XmlIgnore]
561 public bool IsRequiredMismatch =>
562 !IsSatisfied &&
564
565 /// <summary>
566 /// Gets a value indicating whether a non-required and
567 /// non-blocking criterion is not satisfied.
568 /// </summary>
569 [XmlIgnore]
570 public bool IsOptionalMismatch =>
571 !IsSatisfied &&
572 !IsRequired &&
573 !IsBlocking;
574
575 /// <summary>
576 /// Gets the signed numerical contribution of this
577 /// evidence to a compatibility score.
578 /// </summary>
579 /// <remarks>
580 /// Satisfied evidence contributes a positive value and
581 /// unsatisfied evidence contributes a negative value.
582 ///
583 /// This value does not replace the explicit handling of
584 /// blocking criteria.
585 /// </remarks>
586 [XmlIgnore]
587 public double ScoreContribution =>
589 ? Weight
590 : -Weight;
591
592 /// <summary>
593 /// Gets a value indicating whether this evidence contains
594 /// the minimum information required for use by the method
595 /// advisor.
596 /// </summary>
597 [XmlIgnore]
598 public bool IsValidEvidence =>
601 double.IsFinite(Weight) &&
602 Weight >= 0.0;
603
604 /// <summary>
605 /// Sets the textual expected and observed values of the
606 /// evaluated criterion.
607 /// </summary>
608 /// <param name="expectedValue">
609 /// Value expected by the method.
610 /// </param>
611 /// <param name="observedValue">
612 /// Value observed in the problem instance.
613 /// </param>
614 public void SetComparedValues(
615 object? expectedValue,
616 object? observedValue)
617 {
619 ConvertToInvariantString(
620 expectedValue);
621
623 ConvertToInvariantString(
624 observedValue);
625 }
626
627 /// <summary>
628 /// Marks the criterion as satisfied.
629 /// </summary>
630 /// <param name="observedValue">
631 /// Optional observed value.
632 /// </param>
633 public void MarkAsSatisfied(
634 object? observedValue = null)
635 {
636 if (observedValue is not null)
637 {
639 ConvertToInvariantString(
640 observedValue);
641 }
642
644 true;
645 }
646
647 /// <summary>
648 /// Marks the criterion as unsatisfied.
649 /// </summary>
650 /// <param name="observedValue">
651 /// Optional observed value.
652 /// </param>
653 /// <param name="comment">
654 /// Optional explanation of the mismatch.
655 /// </param>
656 public void MarkAsUnsatisfied(
657 object? observedValue = null,
658 string comment = "")
659 {
660 if (observedValue is not null)
661 {
663 ConvertToInvariantString(
664 observedValue);
665 }
666
667 Comment =
668 comment;
669
671 false;
672 }
673
674 /// <inheritdoc/>
675 public override string ToString()
676 {
677 string state =
679 ? "satisfied"
680 : IsBlocking
681 ? "blocking mismatch"
682 : IsRequired
683 ? "required mismatch"
684 : "optional mismatch";
685
686 return
687 $"{CriterionCode}: {state}; " +
688 $"{Description}";
689 }
690
691 private static string ConvertToInvariantString(
692 object? value)
693 {
694 if (value is null)
695 {
696 return string.Empty;
697 }
698
699 if (value is bool booleanValue)
700 {
701 return booleanValue
702 ? "true"
703 : "false";
704 }
705
706 if (value is DateTime dateTimeValue)
707 {
708 return dateTimeValue.ToString(
709 "O",
710 CultureInfo.InvariantCulture);
711 }
712
713 if (value is DateTimeOffset dateTimeOffsetValue)
714 {
715 return dateTimeOffsetValue.ToString(
716 "O",
717 CultureInfo.InvariantCulture);
718 }
719
720 if (value is IFormattable formattableValue)
721 {
722 return formattableValue.ToString(
723 null,
724 CultureInfo.InvariantCulture) ??
725 string.Empty;
726 }
727
728 return value.ToString() ??
729 string.Empty;
730 }
731
732 private void NotifyEvaluationProperties()
733 {
734 OnPropertyChanged(
735 nameof(SupportsCompatibility));
736
737 OnPropertyChanged(
738 nameof(IsMismatch));
739
740 OnPropertyChanged(
741 nameof(IsBlockingMismatch));
742
743 OnPropertyChanged(
744 nameof(IsRequiredMismatch));
745
746 OnPropertyChanged(
747 nameof(IsOptionalMismatch));
748
749 OnPropertyChanged(
750 nameof(ScoreContribution));
751 }
752}
bool IsBlocking
Gets or sets a value indicating whether failure of the criterion makes the method incompatible with t...
string Description
Gets or sets the human-readable explanation of the compatibility criterion.
bool IsSatisfied
Gets or sets a value indicating whether the compatibility criterion is satisfied.
bool HasComment
Gets a value indicating whether an explanatory comment has been recorded.
double Weight
Gets or sets the non-negative importance assigned to the criterion.
bool HasDescription
Gets a value indicating whether a human-readable description has been recorded.
MethodCompatibilityEvidence(string criterionCode, string description, bool isSatisfied, bool isRequired=true, bool isBlocking=false, double weight=1.0)
Initializes compatibility evidence for one evaluated criterion.
string FeatureCode
Gets or sets the code of the problem feature evaluated by this evidence.
string ObservedValue
Gets or sets the value observed in the analyzed instance.
bool IsRequired
Gets or sets a value indicating whether the criterion represents a required condition.
void MarkAsUnsatisfied(object? observedValue=null, string comment="")
Marks the criterion as unsatisfied.
bool IsBlockingMismatch
Gets a value indicating whether the evidence represents a blocking incompatibility.
bool IsMismatch
Gets a value indicating whether the evaluated criterion is not satisfied.
string ExpectedValue
Gets or sets the value expected by the method or compatibility criterion.
bool HasExpectedValue
Gets a value indicating whether an expected value has been recorded.
bool HasFeatureCode
Gets a value indicating whether a problem-feature code has been recorded.
bool SupportsCompatibility
Gets a value indicating whether this evidence supports the compatibility of the method.
void MarkAsSatisfied(object? observedValue=null)
Marks the criterion as satisfied.
string AffectedEntityKey
Gets or sets an optional key identifying the entity to which the evidence applies.
bool IsValidEvidence
Gets a value indicating whether this evidence contains the minimum information required for use by th...
bool HasCriterionCode
Gets a value indicating whether a criterion code has been recorded.
bool HasObservedValue
Gets a value indicating whether an observed value has been recorded.
MethodCompatibilityEvidence()
Initializes an empty compatibility-evidence record.
double ScoreContribution
Gets the signed numerical contribution of this evidence to a compatibility score.
bool IsRequiredMismatch
Gets a value indicating whether a required criterion is not satisfied.
bool IsOptionalMismatch
Gets a value indicating whether a non-required and non-blocking criterion is not satisfied.
void SetComparedValues(object? expectedValue, object? observedValue)
Sets the textual expected and observed values of the evaluated criterion.
bool HasAffectedEntityKey
Gets a value indicating whether an affected entity key has been recorded.
string CriterionCode
Gets or sets the stable code identifying the evaluated compatibility criterion.