2using System.Collections.Generic;
4using System.Reflection;
5using System.Xml.Serialization;
6using LotSizingDataModel.Core.Common;
25[XmlRoot(
"solutionMethodCatalog")]
26[XmlType(TypeName =
"solutionMethodCatalog")]
29 private string _catalogName =
32 private string _catalogVersion =
35 private string _description =
38 private bool _allowUnknownFeatureCodes;
65 string catalogVersion)
67 if (
string.IsNullOrWhiteSpace(catalogName))
69 throw new ArgumentException(
70 "A solution-method catalog name is required.",
74 if (
string.IsNullOrWhiteSpace(catalogVersion))
76 throw new ArgumentException(
77 "A solution-method catalog version is required.",
78 nameof(catalogVersion));
91 [XmlAttribute(
"catalogName")]
99 value?.Trim() ??
string.Empty))
104 NotifyCatalogValidityProperties();
113 [XmlAttribute(
"catalogVersion")]
116 get => _catalogVersion;
121 value?.Trim() ??
string.Empty))
126 NotifyCatalogValidityProperties();
135 [XmlElement(
"description")]
143 value?.Trim() ??
string.Empty))
164 [XmlAttribute(
"allowUnknownFeatureCodes")]
167 get => _allowUnknownFeatureCodes;
171 ref _allowUnknownFeatureCodes,
174 NotifyCatalogValidityProperties();
183 [XmlArray(
"methods")]
184 [XmlArrayItem(
"method")]
185 public List<SolutionMethodDefinition>
Methods {
get; } =
194 !
string.IsNullOrWhiteSpace(
203 !
string.IsNullOrWhiteSpace(
212 !
string.IsNullOrWhiteSpace(
238 method is not
null &&
249 method is not
null &&
250 method.IsValidDefinition);
260 method is not
null &&
261 method.CanBeEvaluated);
297 ArgumentNullException.ThrowIfNull(
302 throw new ArgumentException(
303 "The solution method must have a stable code.",
310 throw new ArgumentException(
311 $
"Solution-method code " +
312 $
"'{method.MethodCode}' is already used.",
319 NotifyMethodCollectionProperties();
339 IEnumerable<SolutionMethodDefinition> methods)
341 ArgumentNullException.ThrowIfNull(
347 if (normalizedMethods.Any(
351 throw new ArgumentException(
352 "The method collection cannot contain a null " +
357 if (normalizedMethods.Any(
359 !method.HasMethodCode))
361 throw new ArgumentException(
362 "Every solution method must have a stable " +
367 string[] duplicateCodes =
372 StringComparer.OrdinalIgnoreCase)
382 StringComparer.OrdinalIgnoreCase)
385 if (duplicateCodes.Length > 0)
387 throw new ArgumentException(
388 "Duplicate solution-method codes: " +
401 NotifyMethodCollectionProperties();
421 if (
string.IsNullOrWhiteSpace(methodCode))
426 string normalizedCode =
433 method is not
null &&
437 StringComparison.OrdinalIgnoreCase))
441 return matches.Length
switch
450 throw new InvalidOperationException(
451 $
"Solution-method code '{methodCode}' is " +
452 "ambiguous in the current catalog.")
471 methodCode) is not
null;
502 NotifyMethodCollectionProperties();
520 NotifyMethodCollectionProperties();
537 public IReadOnlyList<SolutionMethodDefinition>
543 method is not
null &&
551 StringComparer.OrdinalIgnoreCase)
555 StringComparer.OrdinalIgnoreCase)
567 public IReadOnlyList<SolutionMethodDefinition>
573 method is not
null &&
574 method.CanBeEvaluated)
581 StringComparer.OrdinalIgnoreCase)
585 StringComparer.OrdinalIgnoreCase)
597 public static IReadOnlyList<string>
602 BindingFlags.Instance |
607 property.GetIndexParameters().Length == 0 &&
608 property.PropertyType ==
616 StringComparer.OrdinalIgnoreCase)
636 "The solution-method catalog name is missing.");
642 "The solution-method catalog version is " +
649 "The solution-method catalog does not contain " +
650 "any method definition.");
653 ValidateMethodDefinitions(
656 ValidateMethodCodeUniqueness(
661 ValidateReferencedFeatureCodes(
668 !
string.IsNullOrWhiteSpace(error))
673 StringComparer.Ordinal)
677 StringComparer.Ordinal)
690 IReadOnlyList<string> errors =
693 if (errors.Count == 0)
698 throw new InvalidOperationException(
699 "The solution-method catalog is invalid:" +
700 Environment.NewLine +
712 $
"{CatalogName}; version {CatalogVersion}; " +
713 $
"{MethodCount} method(s); " +
714 $
"{EvaluableMethodCount} evaluable";
717 private void ValidateMethodDefinitions(
718 ICollection<string> errors)
730 $
"Solution-method definition at index " +
731 $
"{index} is null.");
736 IReadOnlyList<string> methodErrors =
739 foreach (
string methodError
in methodErrors)
742 $
"Method '{DisplayMethodCode(method)}': " +
748 private void ValidateMethodCodeUniqueness(
749 ICollection<string> errors)
751 string[] missingCodeIndexes =
765 entry.Method is not
null &&
766 !entry.Method.HasMethodCode)
769 entry.Index.ToString(
771 .CultureInfo.InvariantCulture))
774 if (missingCodeIndexes.Length > 0)
777 "Method definitions without a stable code " +
778 "exist at indexes: " +
781 missingCodeIndexes) +
785 string[] duplicateMethodCodes =
789 method is not
null &&
794 StringComparer.OrdinalIgnoreCase)
804 StringComparer.OrdinalIgnoreCase)
807 if (duplicateMethodCodes.Length > 0)
810 "Duplicate solution-method codes: " +
813 duplicateMethodCodes) +
818 private void ValidateReferencedFeatureCodes(
819 ICollection<string> errors)
821 HashSet<string> knownBooleanFeatureCodes =
824 StringComparer.OrdinalIgnoreCase);
826 foreach (SolutionMethodDefinition method
831 string[] unknownFeatureCodes =
833 .GetAllFeatureCodes()
836 !knownBooleanFeatureCodes.Contains(
841 StringComparer.OrdinalIgnoreCase)
844 if (unknownFeatureCodes.Length == 0)
850 $
"Method '{DisplayMethodCode(method)}' " +
851 "references feature codes that are not " +
852 "public Boolean properties of " +
853 $
"{nameof(LotSizingProblemFeatures)}: " +
856 unknownFeatureCodes) +
861 private static string DisplayMethodCode(
862 SolutionMethodDefinition method)
864 return method.HasMethodCode
869 private void NotifyMethodCollectionProperties()
889 NotifyCatalogValidityProperties();
892 private void NotifyCatalogValidityProperties()
Describes the factual structural and modeling features detected in a lot-sizing supply-chain instance...
int EnabledMethodCount
Gets the number of enabled method definitions.
static IReadOnlyList< string > GetKnownBooleanFeatureCodes()
Gets all standard Boolean feature codes that may be referenced by a solution-method definition.
IReadOnlyList< SolutionMethodDefinition > GetEnabledMethods()
Gets the enabled method definitions in deterministic priority order.
string Description
Gets or sets a human-readable description of the catalog.
List< SolutionMethodDefinition > Methods
Gets the solution-method definitions contained in the catalog.
bool CanRecommend
Gets a value indicating whether the catalog can be used by the solution-method advisor.
bool ContainsMethodCode(string methodCode)
Determines whether the catalog contains a method with the supplied code.
bool HasCatalogName
Gets a value indicating whether the catalog has a human-readable name.
void ReplaceMethods(IEnumerable< SolutionMethodDefinition > methods)
Replaces all solution-method definitions in the catalog.
bool IsValidCatalog
Gets a value indicating whether the catalog is structurally valid.
IReadOnlyList< SolutionMethodDefinition > GetMethodsForEvaluation()
Gets the method definitions that can be evaluated by the solution-method advisor.
void AddMethod(SolutionMethodDefinition method)
Adds a solution-method definition to the catalog.
void EnsureValid()
Validates the catalog and throws an exception when at least one error is found.
int ValidMethodCount
Gets the number of structurally valid method definitions.
int MethodCount
Gets the number of method definitions contained in the catalog.
string CatalogVersion
Gets or sets the version of the catalog contents and compatibility semantics.
SolutionMethodCatalog()
Initializes an empty solution-method catalog.
string CatalogName
Gets or sets the human-readable name of the catalog.
IReadOnlyList< string > Validate()
Validates the structural consistency of the catalog and its method definitions.
override string ToString()
bool AllowUnknownFeatureCodes
Gets or sets a value indicating whether method definitions may reference feature codes that are not s...
bool HasCatalogVersion
Gets a value indicating whether the catalog has a version.
bool HasMethods
Gets a value indicating whether the catalog contains at least one method definition.
SolutionMethodDefinition? FindMethod(string methodCode)
Finds a solution method from its stable code.
SolutionMethodCatalog(string catalogName, string catalogVersion)
Initializes a solution-method catalog.
int EvaluableMethodCount
Gets the number of methods that may currently be evaluated by the method advisor.
void ClearMethods()
Removes all method definitions from the catalog.
bool RemoveMethod(string methodCode)
Removes a solution method from the catalog.
bool HasDescription
Gets a value indicating whether the catalog has a description.
Describes the applicability, capabilities and limitations of a solution method for lot-sizing problem...
bool HasMethodCode
Gets a value indicating whether a stable method code has been recorded.
string MethodCode
Gets or sets the stable code identifying the solution method.
IReadOnlyList< string > Validate()
Validates the structural consistency of this method definition.