LotSizingDataModel.Instance 2.0.1
Lot-sizing instance representation, descriptors and problem characterization.
Loading...
Searching...
No Matches
UniversalNotationMatcher.cs
Go to the documentation of this file.
4
6
7/// <summary>
8/// Matches a typed lot-sizing descriptor against a universal-notation
9/// problem specification.
10/// </summary>
11/// <remarks>
12/// Explicit specification tokens are requirements. Omitted beta tokens and
13/// omitted optional network modifiers are unconstrained, not false.
14///
15/// Precedence is:
16/// Contradiction > Incomplete > Exact > Compatible.
17/// Exact is established by equality with the descriptor's generated canonical
18/// notation after all explicit requirements have been satisfied.
19/// </remarks>
20public sealed class UniversalNotationMatcher
21{
22 private readonly UniversalNotationGenerator _generator;
23
25 : this(new UniversalNotationGenerator())
26 {
27 }
28
31 {
32 _generator =
33 generator ??
34 throw new ArgumentNullException(nameof(generator));
35 }
36
39 string specificationText,
40 string? schemeVersion = null)
41 {
42 return Match(
43 descriptor,
44 specificationText,
46 schemeVersion);
47 }
48
51 string specificationText,
52 IEnumerable<UniversalTemporalQualifier>
53 actualTemporalQualifiers,
54 string? schemeVersion = null)
55 {
56 ArgumentNullException.ThrowIfNull(actualTemporalQualifiers);
57
58 return Match(
59 descriptor,
60 specificationText,
62 temporalQualifiers:
63 actualTemporalQualifiers),
64 schemeVersion);
65 }
66
69 string specificationText,
70 UniversalDerivedSemantics actualDerivedSemantics,
71 string? schemeVersion = null)
72 {
73 ArgumentNullException.ThrowIfNull(descriptor);
74 ArgumentNullException.ThrowIfNull(actualDerivedSemantics);
75
76 UniversalProblemSpecification specification =
78 specificationText,
79 schemeVersion);
80
81 return Match(
82 descriptor,
83 specification,
84 actualDerivedSemantics);
85 }
86
90 {
91 return Match(
92 descriptor,
93 specification,
95 }
96
100 IEnumerable<UniversalTemporalQualifier>
101 actualTemporalQualifiers)
102 {
103 ArgumentNullException.ThrowIfNull(actualTemporalQualifiers);
104
105 return Match(
106 descriptor,
107 specification,
109 temporalQualifiers:
110 actualTemporalQualifiers));
111 }
112
115 UniversalProblemSpecification specification,
116 UniversalDerivedSemantics actualDerivedSemantics)
117 {
118 ArgumentNullException.ThrowIfNull(descriptor);
119 ArgumentNullException.ThrowIfNull(specification);
120 ArgumentNullException.ThrowIfNull(actualDerivedSemantics);
121
123 _generator.Generate(
124 descriptor,
125 actualDerivedSemantics);
126
127 string generatedText =
128 generated.Render();
129
130 var issues =
131 new List<UniversalNotationMatchIssue>();
132
133 MatchAlpha(
134 generated.Alpha,
135 specification.Notation.Alpha,
136 issues);
137
138 MatchBeta(
139 generated.Beta,
140 specification.Notation.Beta,
141 actualDerivedSemantics,
142 issues);
143
144 MatchGamma(
145 generated.Gamma,
146 specification.Notation.Gamma,
147 issues);
148
150
151 if (issues.Any(issue => issue.IsContradiction))
152 {
153 kind =
154 UniversalNotationMatchKind.Contradiction;
155 }
156 else if (issues.Count > 0)
157 {
158 kind =
160 }
161 else if (
162 string.Equals(
163 generatedText,
164 specification.CanonicalText,
165 StringComparison.Ordinal))
166 {
167 kind =
169 }
170 else
171 {
172 kind =
174 }
175
177 kind,
178 specification,
179 generatedText,
180 issues);
181 }
182
183 private static void MatchAlpha(
185 UniversalNotationAlpha expected,
186 ICollection<UniversalNotationMatchIssue> issues)
187 {
188 MatchEnumRequirement(
189 actual.ItemCardinality,
190 expected.ItemCardinality,
192 "LSDM-MATCH-001",
193 "LSDM-MATCH-002",
194 "alpha.itemCardinality",
195 issues);
196
197 MatchEnumRequirement(
198 actual.ProblemLevel,
199 expected.ProblemLevel,
200 UniversalProblemLevel.Unknown,
201 "LSDM-MATCH-010",
202 "LSDM-MATCH-011",
203 "alpha.problemLevel",
204 issues);
205
206 if (
207 expected.ProblemLevel ==
208 UniversalProblemLevel.MultiLevel &&
209 expected.ProductStructureType !=
210 ProductStructureType.Unknown)
211 {
212 if (
213 actual.ProductStructureType ==
214 ProductStructureType.Unknown)
215 {
216 AddIncomplete(
217 issues,
218 "LSDM-MATCH-013",
219 "alpha.productStructure",
220 expected.ProductStructureType.ToString(),
221 "Unknown",
222 "The descriptor does not determine the BOM topology.");
223 }
224 else if (
225 actual.ProductStructureType !=
226 expected.ProductStructureType)
227 {
228 AddContradiction(
229 issues,
230 "LSDM-MATCH-012",
231 "alpha.productStructure",
232 expected.ProductStructureType.ToString(),
233 actual.ProductStructureType.ToString(),
234 "The known BOM topology contradicts the specification.");
235 }
236 }
237
238 MatchNetwork(
239 actual.Network,
240 expected.Network,
241 issues);
242 }
243
244 private static void MatchNetwork(
245 UniversalNetworkNotation actual,
246 UniversalNetworkNotation expected,
247 ICollection<UniversalNotationMatchIssue> issues)
248 {
249 if (actual.Coupling != expected.Coupling)
250 {
251 AddContradiction(
252 issues,
253 "LSDM-MATCH-020",
254 "alpha.network.coupling",
255 expected.Coupling.ToString(),
256 actual.Coupling.ToString(),
257 "The physical-network coupling contradicts the specification.");
258
259 return;
260 }
261
262 if (
263 expected.ForwardTopology !=
265 {
266 if (
267 actual.ForwardTopology ==
269 {
270 AddIncomplete(
271 issues,
272 "LSDM-MATCH-022",
273 "alpha.network.forwardTopology",
274 expected.ForwardTopology.ToString(),
275 "Unknown",
276 "The forward topology cannot currently be determined.");
277 }
278 else if (
279 actual.ForwardTopology !=
280 expected.ForwardTopology)
281 {
282 AddContradiction(
283 issues,
284 "LSDM-MATCH-021",
285 "alpha.network.forwardTopology",
286 expected.ForwardTopology.ToString(),
287 actual.ForwardTopology.ToString(),
288 "The known forward topology contradicts the specification.");
289 }
290 }
291
292 if (
293 expected.Coupling is
294 NetworkCouplingType.ReverseOnly or
295 NetworkCouplingType.ClosedLoop &&
296 expected.ReverseTopology.HasValue &&
297 expected.ReverseTopology.Value !=
299 {
300 if (
301 !actual.ReverseTopology.HasValue ||
302 actual.ReverseTopology.Value ==
304 {
305 AddIncomplete(
306 issues,
307 "LSDM-MATCH-028",
308 "alpha.network.reverseTopology",
309 expected.ReverseTopology.Value.ToString(),
310 "Unknown",
311 "The reverse topology cannot currently be determined.");
312 }
313 else if (
314 actual.ReverseTopology.Value !=
315 expected.ReverseTopology.Value)
316 {
317 AddContradiction(
318 issues,
319 "LSDM-MATCH-029",
320 "alpha.network.reverseTopology",
321 expected.ReverseTopology.Value.ToString(),
322 actual.ReverseTopology.Value.ToString(),
323 "The known reverse topology contradicts the specification.");
324 }
325 }
326
327 if (expected.EchelonCount.HasValue)
328 {
329 if (!actual.EchelonCount.HasValue)
330 {
331 if (actual.HasCycles)
332 {
333 AddContradiction(
334 issues,
335 "LSDM-MATCH-023",
336 "alpha.network.echelonCount",
337 expected.EchelonCount.Value.ToString(),
338 "undefined(cyclic)",
339 "A cyclic physical network cannot satisfy the requested acyclic echelon count.");
340 }
341 else
342 {
343 AddIncomplete(
344 issues,
345 "LSDM-MATCH-024",
346 "alpha.network.echelonCount",
347 expected.EchelonCount.Value.ToString(),
348 "Unknown",
349 "The descriptor does not determine an echelon count.");
350 }
351 }
352 else if (
353 actual.EchelonCount.Value !=
354 expected.EchelonCount.Value)
355 {
356 AddContradiction(
357 issues,
358 "LSDM-MATCH-023",
359 "alpha.network.echelonCount",
360 expected.EchelonCount.Value.ToString(),
361 actual.EchelonCount.Value.ToString(),
362 "The known echelon count contradicts the specification.");
363 }
364 }
365
366 RequirePositiveFlag(
367 expected.HasCycles,
368 actual.HasCycles,
369 "LSDM-MATCH-025",
370 "alpha.network.cycles",
371 "CY",
372 issues);
373
374 RequirePositiveFlag(
375 expected.HasMultiSourcing,
376 actual.HasMultiSourcing,
377 "LSDM-MATCH-026",
378 "alpha.network.multiSourcing",
379 "MS",
380 issues);
381
382 RequirePositiveFlag(
383 expected.HasTransshipment,
384 actual.HasTransshipment,
385 "LSDM-MATCH-027",
386 "alpha.network.transshipment",
387 "TS",
388 issues);
389 }
390
391 private static void MatchBeta(
392 UniversalNotationBeta actual,
393 UniversalNotationBeta expected,
394 UniversalDerivedSemantics actualDerivedSemantics,
395 ICollection<UniversalNotationMatchIssue> issues)
396 {
397 foreach (
398 UniversalNotationFeature requiredFeature
399 in expected.Features)
400 {
401 if (!actual.Contains(requiredFeature))
402 {
403 AddContradiction(
404 issues,
405 "LSDM-MATCH-030",
406 "beta.features",
407 requiredFeature.ToString(),
408 "Absent",
409 "A required beta feature is not present in the descriptor.");
410 }
411 }
412
413 foreach (
414 UniversalTemporalQualifier requiredQualifier
415 in expected.TemporalQualifiers)
416 {
417 if (!actual.TryGetTemporalQualifier(
418 requiredQualifier.Parameter,
419 out UniversalTemporalQualifier? actualQualifier))
420 {
421 AddIncomplete(
422 issues,
423 "LSDM-MATCH-031",
424 "beta.temporalPatterns." +
425 requiredQualifier.Parameter,
426 requiredQualifier.Pattern.ToString(),
427 "Unknown",
428 "The requested temporal pattern has not been supplied " +
429 "by the descriptor/projection analysis.");
430
431 continue;
432 }
433
434 if (
435 actualQualifier!.Pattern !=
436 requiredQualifier.Pattern)
437 {
438 AddContradiction(
439 issues,
440 "LSDM-MATCH-032",
441 "beta.temporalPatterns." +
442 requiredQualifier.Parameter,
443 requiredQualifier.Pattern.ToString(),
444 actualQualifier.Pattern.ToString(),
445 "The known temporal pattern contradicts the specification.");
446 }
447 }
448
449 foreach (
450 UniversalSemanticCondition requiredCondition
451 in expected.SemanticConditions)
452 {
453 actualDerivedSemantics.TryGetConditionState(
454 requiredCondition,
455 out UniversalConditionState state);
456
457 if (state == UniversalConditionState.Unknown)
458 {
459 AddIncomplete(
460 issues,
461 "LSDM-MATCH-033",
462 "beta.semanticConditions." +
463 requiredCondition,
464 "Satisfied",
465 "Unknown",
466 "The requested derived semantic condition has not been " +
467 "analyzed for this instance/projection.");
468
469 continue;
470 }
471
472 if (state == UniversalConditionState.NotSatisfied)
473 {
474 AddContradiction(
475 issues,
476 "LSDM-MATCH-034",
477 "beta.semanticConditions." +
478 requiredCondition,
479 "Satisfied",
480 "NotSatisfied",
481 "The analyzed semantic condition contradicts the " +
482 "specification.");
483 }
484 }
485 }
486
487 private static void MatchGamma(
488 UniversalNotationGamma actual,
489 UniversalNotationGamma expected,
490 ICollection<UniversalNotationMatchIssue> issues)
491 {
492 if (
493 expected.Objective ==
495 {
496 return;
497 }
498
499 if (
500 actual.Objective ==
502 {
503 AddIncomplete(
504 issues,
505 "LSDM-MATCH-041",
506 "gamma.objective",
507 expected.Objective.ToString(),
508 "Unknown",
509 "The descriptor does not determine the requested objective family.");
510
511 return;
512 }
513
514 if (
515 actual.Objective !=
516 expected.Objective)
517 {
518 AddContradiction(
519 issues,
520 "LSDM-MATCH-040",
521 "gamma.objective",
522 expected.Objective.ToString(),
523 actual.Objective.ToString(),
524 "The known objective family contradicts the specification.");
525 }
526 }
527
528 private static void MatchEnumRequirement<T>(
529 T actual,
530 T expected,
531 T unknown,
532 string contradictionCode,
533 string incompleteCode,
534 string path,
535 ICollection<UniversalNotationMatchIssue> issues)
536 where T : struct, Enum
537 {
538 if (EqualityComparer<T>.Default.Equals(expected, unknown))
539 {
540 return;
541 }
542
543 if (EqualityComparer<T>.Default.Equals(actual, unknown))
544 {
545 AddIncomplete(
546 issues,
547 incompleteCode,
548 path,
549 expected.ToString(),
550 unknown.ToString(),
551 "The descriptor does not determine this requested characteristic.");
552
553 return;
554 }
555
556 if (!EqualityComparer<T>.Default.Equals(actual, expected))
557 {
558 AddContradiction(
559 issues,
560 contradictionCode,
561 path,
562 expected.ToString(),
563 actual.ToString(),
564 "The known descriptor characteristic contradicts the specification.");
565 }
566 }
567
568 private static void RequirePositiveFlag(
569 bool expected,
570 bool actual,
571 string code,
572 string path,
573 string token,
574 ICollection<UniversalNotationMatchIssue> issues)
575 {
576 if (expected && !actual)
577 {
578 AddContradiction(
579 issues,
580 code,
581 path,
582 token,
583 "Absent",
584 $"The specification explicitly requires network modifier {token}.");
585 }
586 }
587
588 private static void AddContradiction(
589 ICollection<UniversalNotationMatchIssue> issues,
590 string code,
591 string path,
592 string expected,
593 string actual,
594 string message)
595 {
596 issues.Add(
597 new UniversalNotationMatchIssue(
598 code,
599 path,
600 expected,
601 actual,
602 message,
603 isContradiction: true));
604 }
605
606 private static void AddIncomplete(
607 ICollection<UniversalNotationMatchIssue> issues,
608 string code,
609 string path,
610 string expected,
611 string actual,
612 string message)
613 {
614 issues.Add(
615 new UniversalNotationMatchIssue(
616 code,
617 path,
618 expected,
619 actual,
620 message,
621 isContradiction: false));
622 }
623}
Typed structured description of the factual lot-sizing problem characteristics currently represented ...
Represents the complete result of matching a typed descriptor against a universal problem specificati...
UniversalNotationMatchResult Match(LotSizingProblemDescriptor descriptor, string specificationText, UniversalDerivedSemantics actualDerivedSemantics, string? schemeVersion=null)
UniversalNotationMatchResult Match(LotSizingProblemDescriptor descriptor, UniversalProblemSpecification specification, UniversalDerivedSemantics actualDerivedSemantics)
UniversalNotationMatchResult Match(LotSizingProblemDescriptor descriptor, string specificationText, IEnumerable< UniversalTemporalQualifier > actualTemporalQualifiers, string? schemeVersion=null)
UniversalNotationMatchResult Match(LotSizingProblemDescriptor descriptor, UniversalProblemSpecification specification, IEnumerable< UniversalTemporalQualifier > actualTemporalQualifiers)
UniversalNotationMatchResult Match(LotSizingProblemDescriptor descriptor, UniversalProblemSpecification specification)
UniversalNotationMatchResult Match(LotSizingProblemDescriptor descriptor, string specificationText, string? schemeVersion=null)
Represents a universal notation interpreted as a problem specification.
static UniversalProblemSpecification Parse(string text, string? schemeVersion=null)
Carries explicit derived analyses that cannot be inferred from the coarse typed descriptor alone.
Typed abstract syntax tree for the versioned alpha | beta | gamma scheme.
Alpha field: structural/environment characteristics.
Generates notation scheme version 1 from typed problem descriptors.
ProductStructureType
Identifies the structural category of a product bill-of-materials graph.
NetworkCouplingType
Describes coupling between forward and reverse physical networks.
SupplyNetworkTopologyType
Classifies the directed physical topology of a supply-flow network.
UniversalNotationMatchKind
Describes the semantic relationship between an instance descriptor and a universal-notation problem s...
UniversalSemanticCondition
Generic derived semantic conditions that may be required by a universal problem specification.
UniversalObjectiveKind
Objective family represented in the gamma field of notation v1.
UniversalNotationFeature
Feature vocabulary represented in the beta field of notation v1. Enum order is the canonical renderin...
UniversalConditionState
Three-valued state of a derived semantic condition.
UniversalProblemLevel
Canonical BOM-level token.
record UniversalTemporalQualifier
Qualifies one universal model-parameter family with a generic temporal pattern.
UniversalItemCardinality
Canonical item-cardinality token.