Repository navigation
Trace HermitCrab failure reasons and template slot outcomes #534
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| namespace SIL.Machine.Morphology.HermitCrab | ||
| { | ||
| public enum TemplateSlotOutcome | ||
| { | ||
| RuleApplied, | ||
| OptionalSkipped, | ||
| RequiredUnfilled, | ||
| } | ||
|
|
||
| public enum PartialParseCause | ||
| { | ||
| RealizationalFeatureMismatch, | ||
| UnappliedMorphologicalRules, | ||
| NonFinalTemplateAppliedLast, | ||
| ApplicableTemplatesNotApplied, | ||
| } | ||
|
|
||
| public class PartialParseFailure | ||
| { | ||
| public PartialParseFailure(PartialParseCause cause, IMorphologicalRule rule = null) | ||
| { | ||
| Cause = cause; | ||
| Rule = rule; | ||
| } | ||
|
|
||
| public PartialParseCause Cause { get; } | ||
|
|
||
| public IMorphologicalRule Rule { get; } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Optional tracing capability. ITraceManager implementations receive the existing callbacks without opting in. | ||
| /// </summary> | ||
| public interface IDetailedTraceManager : ITraceManager | ||
| { | ||
| void MorphologicalRuleNotUnapplied( | ||
| IMorphologicalRule rule, | ||
| int subruleIndex, | ||
| Word input, | ||
| FailureReason reason, | ||
| object failureObj | ||
| ); | ||
|
|
||
| /// <summary> | ||
| /// Reports fully enumerated lookup results as yielded Word candidates, before surface validation. | ||
| /// Interrupted lookups do not receive this callback. Each input has at most one active lookup. | ||
| /// </summary> | ||
| void LexicalLookupCompleted(Stratum stratum, Word input, int candidateCount, bool guessed); | ||
|
|
||
| /// <summary> | ||
| /// Reports a slot branch. OptionalSkipped can accompany RuleApplied for the same input. | ||
| /// RequiredUnfilled means the slot produced no output; no linguistic cause is implied. | ||
| /// </summary> | ||
| void TemplateSlotProcessed( | ||
| AffixTemplate template, | ||
| int slotIndex, | ||
| Word input, | ||
| Word output, | ||
| bool analysis, | ||
| TemplateSlotOutcome outcome | ||
| ); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -444,6 +444,7 @@ internal IEnumerable<RootAllomorph> SearchRootAllomorphs(Stratum stratum, Shape | |
|
|
||
| private IEnumerable<Word> LexicalLookup(Word input) | ||
| { | ||
| int candidateCount = 0; | ||
| if (_traceManager.IsTracing) | ||
| _traceManager.LexicalLookup(input.Stratum, input); | ||
| foreach ( | ||
|
|
@@ -464,16 +465,20 @@ LexEntry entry in SearchRootAllomorphs(input.Stratum, input.Shape) | |
| if (_traceManager.IsTracing) | ||
| _traceManager.SynthesizeWord(_lang, newWord); | ||
| newWord.Freeze(); | ||
| candidateCount++; | ||
| yield return newWord; | ||
| } | ||
| } | ||
| if (_traceManager.IsTracing) | ||
| _traceManager.LexicalLookupCompleted(input.Stratum, input, candidateCount, false); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Match the input against lexical patterns and return matches. | ||
| /// </summary> | ||
| private IEnumerable<Word> LexicalGuess(Word input) | ||
| { | ||
| int candidateCount = 0; | ||
| if (_traceManager.IsTracing) | ||
| _traceManager.LexicalLookup(input.Stratum, input); | ||
| CharacterDefinitionTable table = input.Stratum.CharacterDefinitionTable; | ||
|
|
@@ -540,10 +545,13 @@ private IEnumerable<Word> LexicalGuess(Word input) | |
| if (_traceManager.IsTracing) | ||
| _traceManager.SynthesizeWord(_lang, newWord); | ||
| newWord.Freeze(); | ||
| candidateCount++; | ||
| yield return newWord; | ||
| } | ||
| } | ||
| } | ||
| if (_traceManager.IsTracing) | ||
| _traceManager.LexicalLookupCompleted(input.Stratum, input, candidateCount, true); | ||
| } | ||
|
|
||
| /// <summary> | ||
|
|
@@ -657,13 +665,31 @@ private IEnumerable<string> GetShapeStrings(IList<ShapeNode> nodes, CharacterDef | |
|
|
||
| private bool IsWordValid(Word word) | ||
| { | ||
| if ( | ||
| !word.RealizationalFeatureStruct.IsUnifiable(word.SyntacticFeatureStruct) | ||
| || !word.IsAllMorphologicalRulesApplied | ||
| ) | ||
| if (!word.RealizationalFeatureStruct.IsUnifiable(word.SyntacticFeatureStruct)) | ||
| { | ||
| if (_traceManager.IsTracing) | ||
| _traceManager.Failed( | ||
| _lang, | ||
| word, | ||
| FailureReason.PartialParse, | ||
| null, | ||
| new PartialParseFailure(PartialParseCause.RealizationalFeatureMismatch) | ||
| ); | ||
| return false; | ||
| } | ||
| if (!word.IsAllMorphologicalRulesApplied) | ||
| { | ||
| if (_traceManager.IsTracing) | ||
| _traceManager.Failed(_lang, word, FailureReason.PartialParse, null, null); | ||
| _traceManager.Failed( | ||
| _lang, | ||
| word, | ||
| FailureReason.PartialParse, | ||
| null, | ||
| new PartialParseFailure( | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FYI: F4. |
||
| PartialParseCause.UnappliedMorphologicalRules, | ||
| word.NextMorphologicalRule | ||
| ) | ||
| ); | ||
| return false; | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -49,20 +49,38 @@ public IEnumerable<Word> Apply(Word input) | |
| if (!_morpher.RuleSelector(_rule)) | ||
| return Enumerable.Empty<Word>(); | ||
|
|
||
| if ( | ||
| input.GetUnapplicationCount(_rule) >= _rule.MaxApplicationCount | ||
| || !_outputFS.IsUnifiable(input.SyntacticFeatureStruct) | ||
| ) | ||
| if (input.GetUnapplicationCount(_rule) >= _rule.MaxApplicationCount) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor: F2. Plain managers now get calls they never got before: |
||
| { | ||
| if (_morpher.TraceManager.IsTracing) | ||
| _morpher.TraceManager.MorphologicalRuleNotUnapplied( | ||
| _rule, | ||
| -1, | ||
| input, | ||
| FailureReason.MaxApplicationCount, | ||
| _rule.MaxApplicationCount | ||
| ); | ||
| return Enumerable.Empty<Word>(); | ||
| } | ||
| if (!_outputFS.IsUnifiable(input.SyntacticFeatureStruct)) | ||
| { | ||
| if (_morpher.TraceManager.IsTracing) | ||
| _morpher.TraceManager.MorphologicalRuleNotUnapplied( | ||
| _rule, | ||
| -1, | ||
| input, | ||
| FailureReason.OutputSyntacticFeatureStruct, | ||
| _outputFS | ||
| ); | ||
| return Enumerable.Empty<Word>(); | ||
| } | ||
|
|
||
| var output = new List<Word>(); | ||
| for (int i = 0; i < _rules.Count; i++) | ||
| { | ||
| bool unapplied = false; | ||
| bool matched = false; | ||
| foreach (Word outWord in _rules[i].Apply(input).RemoveDuplicates()) | ||
| { | ||
| matched = true; | ||
| // the paths Out writes describe this rule's output, not the stem it applied to, so they are | ||
| // stripped rather than carried backwards; what is left must unify with Required | ||
| outWord.SyntacticFeatureStruct.Restrict(_rule.OutSyntacticFeatureStruct); | ||
|
|
@@ -75,6 +93,14 @@ out FeatureStruct syntacticFS | |
| ) | ||
| ) | ||
| { | ||
| if (_morpher.TraceManager.IsTracing) | ||
| _morpher.TraceManager.MorphologicalRuleNotUnapplied( | ||
| _rule, | ||
| i, | ||
| outWord, | ||
| FailureReason.RequiredSyntacticFeatureStruct, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FYI: F3. The legacy callback changes shape here. When every match fails Required, base made one call with |
||
| _rule.RequiredSyntacticFeatureStruct | ||
| ); | ||
| continue; | ||
| } | ||
|
|
||
|
|
@@ -91,11 +117,10 @@ out FeatureStruct syntacticFS | |
| if (_morpher.TraceManager.IsTracing) | ||
| _morpher.TraceManager.MorphologicalRuleUnapplied(_rule, i, input, outWord); | ||
| output.Add(outWord); | ||
| unapplied = true; | ||
| } | ||
|
|
||
| if (_morpher.TraceManager.IsTracing && !unapplied) | ||
| _morpher.TraceManager.MorphologicalRuleNotUnapplied(_rule, i, input); | ||
| if (_morpher.TraceManager.IsTracing && !matched) | ||
| _morpher.TraceManager.MorphologicalRuleNotUnapplied(_rule, i, input, FailureReason.Pattern, null); | ||
| } | ||
| return output; | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI: F6. The HC tool now prints slot traces without
SlotIndexorSlotOutcome:PrintTracewrites only source, input, output, and reason. Applied, skipped, and unfilled lines for the same template look alike, so the tool trace gets longer without telling the reader more.