diff --git a/docs/review/hermitcrab.md b/docs/review/hermitcrab.md index 6bc033c7e..49ffb4bcf 100644 --- a/docs/review/hermitcrab.md +++ b/docs/review/hermitcrab.md @@ -11,7 +11,7 @@ Governs `src/SIL.Machine.Morphology.HermitCrab/**/*.cs`. whether equivalent analyses can be merged safely. The merge key (`AnalysisMergeKey`) compares exactly these fields: shape, stratum identity, syntactic feature structure, realizational feature structure, non-head count, per-rule - unapplication counts, and `FinalTemplateState`. Check a new field against that list. + unapplication counts, `FinalTemplateState`, and `NeedsPartial`. Check a new field against that list. - Inspect allocations and retained object lifetimes only in changed inner loops. If the change claims a performance improvement, require a reproducible benchmark or measured artifact in addition to semantic regression tests. diff --git a/src/SIL.Machine.Morphology.HermitCrab/AnalysisAffixTemplateRule.cs b/src/SIL.Machine.Morphology.HermitCrab/AnalysisAffixTemplateRule.cs index 407c7fdb1..27053349c 100644 --- a/src/SIL.Machine.Morphology.HermitCrab/AnalysisAffixTemplateRule.cs +++ b/src/SIL.Machine.Morphology.HermitCrab/AnalysisAffixTemplateRule.cs @@ -41,13 +41,12 @@ public IEnumerable Apply(Word input) if (_morpher.TraceManager.IsTracing) _morpher.TraceManager.BeginUnapplyTemplate(_template, input); - // Do not allow a final template to unapply if we don't need to worry about partial rules - // and a non-template was last unapplied. - if ( - (!_morpher.HasPartialRules || _morpher.AlwaysEnforceFinalTemplates) - && input.FinalTemplateState == FinalTemplateState.NonTemplate + // In synthesis a non-template rule follows a final template only if a partial rule applied earlier. + bool afterNonTemplate = + _morpher.TracksFinalTemplateState && _template.IsFinal - ) + && input.FinalTemplateState == FinalTemplateState.NonTemplate; + if (afterNonTemplate && _morpher.IsFinalTemplatePrunable(_template, input)) { if (_morpher.TraceManager.IsTracing) { @@ -55,13 +54,20 @@ public IEnumerable Apply(Word input) _template, input, false, - FailureReason.NonPartialRuleProhibitedAfterFinalTemplate + FailureReason.NonPartialRuleProhibitedAfterFinalTemplate, + null ); } return Enumerable.Empty(); } Word inWord = input.Clone(); + // The prune check above passed, so the word is partial at this template or the analysis fails. + if (afterNonTemplate) + { + inWord.NeedsPartial = true; + inWord.OwedPartialTemplate = _template; + } inWord.Freeze(); var output = new HashSet(FreezableEqualityComparer.Default); @@ -70,6 +76,14 @@ public IEnumerable Apply(Word input) else ParallelApplySlots(inWord, output); + // The output with every slot skipped did not unapply the template, so it owes nothing. + if (afterNonTemplate && output.Remove(inWord)) + { + Word unchanged = input.Clone(); + unchanged.Freeze(); + output.Add(unchanged); + } + return output; } @@ -83,13 +97,13 @@ private void ApplySlots(Word inWord, int index, HashSet output) if (!_template.Slots[i].Optional) { if (_morpher.TraceManager.IsTracing) - _morpher.TraceManager.EndUnapplyTemplate(_template, inWord, false, FailureReason.None); + _morpher.TraceManager.EndUnapplyTemplate(_template, inWord, false, FailureReason.None, null); return; } } if (_morpher.TraceManager.IsTracing) - _morpher.TraceManager.EndUnapplyTemplate(_template, inWord, true, FailureReason.None); + _morpher.TraceManager.EndUnapplyTemplate(_template, inWord, true, FailureReason.None, null); output.Add(inWord); } @@ -125,7 +139,8 @@ private void ParallelApplySlots(Word inWord, HashSet output) _template, work.Item1, false, - FailureReason.None + FailureReason.None, + null ); add = false; break; @@ -139,7 +154,8 @@ private void ParallelApplySlots(Word inWord, HashSet output) _template, work.Item1, true, - FailureReason.None + FailureReason.None, + null ); outStack.Push(work.Item1); } diff --git a/src/SIL.Machine.Morphology.HermitCrab/AnalysisStratumRule.cs b/src/SIL.Machine.Morphology.HermitCrab/AnalysisStratumRule.cs index ef48637ac..71a636c64 100644 --- a/src/SIL.Machine.Morphology.HermitCrab/AnalysisStratumRule.cs +++ b/src/SIL.Machine.Morphology.HermitCrab/AnalysisStratumRule.cs @@ -184,6 +184,11 @@ internal IEnumerable Apply(Word input, ref int alternativeCount) private IEnumerable ApplyMorphologicalRules(Word input) { + if (_morpher.OwesImpossiblePartial(input)) + { + _morpher.TraceOwedPartialDropped(input); + yield break; + } foreach (Word mruleOutWord in _mrulesRule.Apply(input).Distinct(FreezableEqualityComparer.Default)) { switch (_stratum.MorphologicalRuleOrder) @@ -203,6 +208,11 @@ private IEnumerable ApplyMorphologicalRules(Word input) private IEnumerable ApplyTemplates(Word input) { + if (_morpher.OwesImpossiblePartial(input)) + { + _morpher.TraceOwedPartialDropped(input); + yield break; + } foreach (Word tempOutWord in _templatesRule.Apply(input).Distinct(FreezableEqualityComparer.Default)) { switch (_stratum.MorphologicalRuleOrder) @@ -235,6 +245,7 @@ private IEnumerable ApplyTemplates(Word input) private readonly int _nonHeadCount; private readonly IReadOnlyDictionary _ruleCounts; private readonly FinalTemplateState _finalTemplateState; + private readonly bool _needsPartial; private readonly int _hashCode; // Freezes word.SyntacticFeatureStruct, which Word.Freeze leaves unfrozen. @@ -253,6 +264,7 @@ public AnalysisMergeKey(Word word) _nonHeadCount = word.NonHeadCount; _ruleCounts = word.UnappliedRuleCounts; _finalTemplateState = word.FinalTemplateState; + _needsPartial = word.NeedsPartial; _shape.Freeze(); _syntacticFS.Freeze(); @@ -265,6 +277,7 @@ public AnalysisMergeKey(Word word) hash = hash * 31 + _realizationalFS.GetFrozenHashCode(); hash = hash * 31 + _nonHeadCount; hash = hash * 31 + _finalTemplateState.GetHashCode(); + hash = hash * 31 + (_needsPartial ? 1 : 0); if (_ruleCounts != null) { int multisetHash = 0; @@ -292,7 +305,7 @@ public bool Equals(AnalysisMergeKey other) || !_realizationalFS.ValueEquals(other._realizationalFS) ) return false; - if (_finalTemplateState != other._finalTemplateState) + if (_finalTemplateState != other._finalTemplateState || _needsPartial != other._needsPartial) return false; return RuleCountsEqual(_ruleCounts, other._ruleCounts); } diff --git a/src/SIL.Machine.Morphology.HermitCrab/FinalTemplatePartialReachability.cs b/src/SIL.Machine.Morphology.HermitCrab/FinalTemplatePartialReachability.cs new file mode 100644 index 000000000..cb285b74c --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab/FinalTemplatePartialReachability.cs @@ -0,0 +1,142 @@ +using System.Collections.Generic; +using System.Linq; +using SIL.Machine.FeatureModel; +using SIL.Machine.Morphology.HermitCrab.MorphologicalRules; + +namespace SIL.Machine.Morphology.HermitCrab +{ + /// + /// Finds the affix templates that a partial word can reach in synthesis. A word is partial at a template only + /// if a partial affix-process rule that is neither a template-slot nor a clitic rule applied before it (a partial root takes no template), in the template's + /// stratum or an earlier one. Its part of speech is then whatever that rule leaves, changed by any rules + /// applied since. The search over-approximates: it tracks only the part-of-speech feature, treats an + /// unspecified or variable part of speech as every part of speech, ignores application counts, rule order, + /// template gating and every other feature, and lets every rule of a stratum apply any number of times. A + /// template it does not return can therefore never see a partial word. + /// + internal static class FinalTemplatePartialReachability + { + public static HashSet Compute(Language lang) + { + var result = new HashSet(); + SymbolicFeature posFeature = lang.SyntacticFeatureSystem.PartOfSpeechFeature; + HashSet all = + posFeature == null + ? new HashSet() + : new HashSet(posFeature.PossibleSymbols); + + // Part-of-speech values a partial word may carry on leaving the strata processed so far. + var reach = new HashSet(); + bool anyPartial = false; + foreach (Stratum stratum in lang.Strata) // synthesis order + { + List rules = stratum + .MorphologicalRules.Concat(stratum.AffixTemplates.SelectMany(t => t.Slots).SelectMany(s => s.Rules)) + .Distinct() + .ToList(); + + foreach (AffixProcessRule rule in rules.OfType().Where(IsSynthesisPartial)) + { + anyPartial = true; + reach.UnionWith( + Apply(all, all, rule.RequiredSyntacticFeatureStruct, rule.OutSyntacticFeatureStruct) + ); + } + if (!anyPartial) + continue; + if (all.Count == 0) + { + // No parts of speech to tell templates apart: every later template is reachable. + result.UnionWith(stratum.AffixTemplates); + continue; + } + + // Close the set under every rule of this stratum. + bool changed = true; + while (changed) + { + changed = false; + foreach (IMorphologicalRule rule in rules) + { + if (reach.Count == 0) + break; + IEnumerable next = ApplyRule(all, reach, rule); + foreach (FeatureSymbol symbol in next.ToList()) + changed |= reach.Add(symbol); + } + } + + foreach (AffixTemplate template in stratum.AffixTemplates) + { + if (reach.Count == 0) + continue; + HashSet required = Constraint(all, template.RequiredSyntacticFeatureStruct); + if (required == null || required.Overlaps(reach)) + result.Add(template); + } + } + return result; + } + + // Synthesis marks a word partial only for a non-template, non-clitic partial rule + // (SynthesisAffixProcessRule), and a slot or clitic rule is exempt from the final-template check. + internal static bool IsSynthesisPartial(AffixProcessRule rule) + { + return rule.IsPartial && !rule.IsTemplateRule && !rule.GetIsCliticRule(); + } + + private static IEnumerable ApplyRule( + HashSet all, + HashSet input, + IMorphologicalRule rule + ) + { + switch (rule) + { + case AffixProcessRule apr: + return Apply(all, input, apr.RequiredSyntacticFeatureStruct, apr.OutSyntacticFeatureStruct); + case CompoundingRule cr: + return Apply(all, input, cr.HeadRequiredSyntacticFeatureStruct, cr.OutSyntacticFeatureStruct); + case RealizationalAffixProcessRule rr: + return Apply(all, input, rr.RequiredSyntacticFeatureStruct, rr.RealizationalFeatureStruct); + default: + // Unknown rule kind: assume it can produce any part of speech. + return all; + } + } + + /// Unify with , then priority-union . + private static IEnumerable Apply( + HashSet all, + HashSet input, + FeatureStruct required, + FeatureStruct output + ) + { + HashSet req = Constraint(all, required); + bool applicable = req == null ? input.Count > 0 : req.Overlaps(input); + if (!applicable) + return Enumerable.Empty(); + HashSet outPos = Constraint(all, output); + if (outPos != null) + return outPos; + if (req == null) + return input; + return input.Where(req.Contains); + } + + /// The part-of-speech values a feature structure allows, or null if it leaves them open. + private static HashSet Constraint(HashSet all, FeatureStruct fs) + { + if (fs == null) + return null; + if (!fs.TryGetValue(SyntacticFeatureSystem.PartOfSpeechID, out SymbolicFeatureValue value)) + return null; + if (value.IsVariable) + return null; + var symbols = new HashSet(value.Values); + // A value that names no known symbol is treated as unconstrained, to stay conservative. + return symbols.Count == 0 ? null : symbols; + } + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab/ITraceManager.cs b/src/SIL.Machine.Morphology.HermitCrab/ITraceManager.cs index e004254de..7653e95b2 100644 --- a/src/SIL.Machine.Morphology.HermitCrab/ITraceManager.cs +++ b/src/SIL.Machine.Morphology.HermitCrab/ITraceManager.cs @@ -28,6 +28,7 @@ public enum FailureReason MaxApplicationCount, AllomorphNotApplicable, LexicalLookupFeatures, + OwedPartialCannotUnapply, } public interface ITraceManager @@ -45,7 +46,13 @@ public interface ITraceManager void PhonologicalRuleNotUnapplied(IPhonologicalRule rule, int subruleIndex, Word input); void BeginUnapplyTemplate(AffixTemplate template, Word input); - void EndUnapplyTemplate(AffixTemplate template, Word output, bool unapplied, FailureReason reason); + void EndUnapplyTemplate( + AffixTemplate template, + Word output, + bool unapplied, + FailureReason reason, + object failureObj + ); void MorphologicalRuleUnapplied(IMorphologicalRule rule, int subruleIndex, Word input, Word output); void MorphologicalRuleNotUnapplied(IMorphologicalRule rule, int subruleIndex, Word input); diff --git a/src/SIL.Machine.Morphology.HermitCrab/Morpher.cs b/src/SIL.Machine.Morphology.HermitCrab/Morpher.cs index 71fbb4fc4..48638713f 100644 --- a/src/SIL.Machine.Morphology.HermitCrab/Morpher.cs +++ b/src/SIL.Machine.Morphology.HermitCrab/Morpher.cs @@ -68,6 +68,82 @@ public Morpher(ITraceManager traceManager, Language lang, int maxDegreeOfParalle _morphemes = new ReadOnlyObservableCollection(morphemes); HasPartialRules = GetPartialMorphemes().Any(morpheme => !(morpheme is LexEntry)); + if (HasPartialRules) + { + _partialReachableTemplates = FinalTemplatePartialReachability.Compute(lang); + _partialLookAhead = new PartialRuleLookAhead(lang); + // Only a final template can arm the prune, so without one nothing is tracked. + _canPruneFinalTemplates = lang + .Strata.SelectMany(s => s.AffixTemplates) + .Any(t => t.IsFinal && (_partialLookAhead.IsActive || !_partialReachableTemplates.Contains(t))); + _partialRules = lang + .Strata.SelectMany(s => + s.MorphologicalRules.Concat( + s.AffixTemplates.SelectMany(t => t.Slots).SelectMany(sl => sl.Rules) + ) + ) + .OfType() + .Where(FinalTemplatePartialReachability.IsSynthesisPartial) + .Distinct() + .ToList(); + } + } + + private readonly HashSet _partialReachableTemplates; + private readonly PartialRuleLookAhead _partialLookAhead; + private readonly bool _canPruneFinalTemplates; + private readonly IReadOnlyList _partialRules; + + /// + /// Traces the drop of an analysis that still owes a partial rule as an unapplied + /// template, with the partial rules as the failure + /// object. + /// + internal void TraceOwedPartialDropped(Word input) + { + if (_traceManager.IsTracing && input.OwedPartialTemplate != null) + { + _traceManager.EndUnapplyTemplate( + input.OwedPartialTemplate, + input, + false, + FailureReason.OwedPartialCannotUnapply, + _partialRules + ); + } + } + + /// + /// Whether analysis records the template state: the prune is on, or some final template can be pruned in a + /// grammar with partial rules. Otherwise the state would only split equivalent analyses. + /// + internal bool TracksFinalTemplateState => + !HasPartialRules || AlwaysEnforceFinalTemplates || _canPruneFinalTemplates; + + /// + /// Whether analysis may refuse to unapply a final template that follows a non-template rule. The synthesis + /// derivation this refuses has a non-partial rule after the final template, which is allowed only when the + /// word is partial there: a partial rule applied before the template. A partial rule leaves the analysis + /// state at none, so it never arms this. Templates no partial word can reach are pruned outright, and + /// others when the shape shows that no partial rule can still be unapplied. In a grammar with both partial + /// rules and lexical families this can drop a duplicate analysis that master returns: a family member + /// that replaces the root is a fresh word that forgets the pending final template. Only a duplicate is + /// lost, never a distinct analysis. FieldWorks never writes a family. + /// + internal bool IsFinalTemplatePrunable(AffixTemplate template, Word input) + { + if (!HasPartialRules || AlwaysEnforceFinalTemplates) + return true; + return !_partialReachableTemplates.Contains(template) || !_partialLookAhead.PartialRuleMayUnapply(input); + } + + /// + /// Whether the analysis still owes a partial rule that its shape rules out for it and for anything derived + /// from it. + /// + internal bool OwesImpossiblePartial(Word input) + { + return input.NeedsPartial && !_partialLookAhead.PartialRuleMayUnapply(input); } public IEnumerable GetPartialMorphemes() @@ -103,8 +179,9 @@ public ITraceManager TraceManager public bool MergeEquivalentAnalyses { get; set; } /// - /// True if any morpheme other than a is partial. Analysis may prune a final - /// template that follows a non-template rule only when this is false or + /// True if any morpheme other than a is partial. Synthesis lets a non-template rule + /// follow a final template when the word or the rule is partial, so analysis prunes a final template that + /// follows a non-template rule only where no partial word can be involved, unless /// is set. /// public bool HasPartialRules { get; } @@ -202,7 +279,8 @@ public IEnumerable ParseWord(string word, out object trace, bool guessRoot { // Guess roots when there are no results. List matches = new List(); - foreach (Word analysisWord in origAnalyses) + // A partial root takes no template, so the slot rule a flagged analysis owes is never applied. + foreach (Word analysisWord in origAnalyses.Where(w => !w.NeedsPartial)) { var lexicalGuesses = LexicalGuess(analysisWord).Distinct(); foreach (Word synthesisWord in lexicalGuesses) @@ -355,6 +433,12 @@ private IEnumerable SynthesizeSequential(string word, IEnumerable an int alternativeCount = 0; foreach (Word analysisWord in analyses) { + // No partial rule was unapplied below the final template that followed a non-template rule. + if (analysisWord.NeedsPartial) + { + TraceOwedPartialDropped(analysisWord); + continue; + } foreach (Word synthesisWord in LexicalLookup(analysisWord)) { foreach (Word alternative in synthesisWord.ExpandAlternatives()) @@ -388,6 +472,11 @@ private IEnumerable SynthesizeParallel(string word, ConcurrentQueue for (int i = 0; i < range.Item2 - range.Item1; i++) { analyses.TryDequeue(out Word analysisWord); + if (analysisWord.NeedsPartial) + { + TraceOwedPartialDropped(analysisWord); + continue; + } foreach (Word synthesisWord in LexicalLookup(analysisWord)) { foreach (Word alternative in synthesisWord.ExpandAlternatives()) diff --git a/src/SIL.Machine.Morphology.HermitCrab/MorphologicalRules/AnalysisAffixProcessRule.cs b/src/SIL.Machine.Morphology.HermitCrab/MorphologicalRules/AnalysisAffixProcessRule.cs index cd036ee71..3c46a8784 100644 --- a/src/SIL.Machine.Morphology.HermitCrab/MorphologicalRules/AnalysisAffixProcessRule.cs +++ b/src/SIL.Machine.Morphology.HermitCrab/MorphologicalRules/AnalysisAffixProcessRule.cs @@ -115,14 +115,17 @@ out FeatureStruct syntacticFS outWord.SyntacticFeatureStruct = syntacticFS; } - if (!_morpher.HasPartialRules || _morpher.AlwaysEnforceFinalTemplates) + if (_morpher.TracksFinalTemplateState && !_rule.GetIsCliticRule()) { - if (!_rule.GetIsCliticRule()) - { - outWord.FinalTemplateState = !_rule.IsTemplateRule + // A partial rule may follow a final template in synthesis, so it never arms the prune. + // It also pays the debt of a final template unapplied after a non-template rule. + bool partialRule = !_rule.IsTemplateRule && _rule.IsPartial; + if (partialRule) + outWord.NeedsPartial = false; + outWord.FinalTemplateState = + !_rule.IsTemplateRule && (!partialRule || _morpher.AlwaysEnforceFinalTemplates) ? FinalTemplateState.NonTemplate : FinalTemplateState.None; - } } outWord.MorphologicalRuleUnapplied(_rule, _rule.Allomorphs[i]); outWord.Freeze(); diff --git a/src/SIL.Machine.Morphology.HermitCrab/PartialRuleLookAhead.cs b/src/SIL.Machine.Morphology.HermitCrab/PartialRuleLookAhead.cs new file mode 100644 index 000000000..ed2b95692 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab/PartialRuleLookAhead.cs @@ -0,0 +1,276 @@ +using System.Collections.Generic; +using System.Linq; +using SIL.Machine.Annotations; +using SIL.Machine.FeatureModel; +using SIL.Machine.Matching; +using SIL.Machine.Morphology.HermitCrab.MorphologicalRules; + +namespace SIL.Machine.Morphology.HermitCrab +{ + /// + /// Decides from a word's shape whether analysis can still unapply a partial rule below it. Within a stratum + /// analysis unapplies the phonological rules once, on entry, and afterwards only morphological rules. When every + /// morphological rule of the stratum uses only and , + /// each node of every later shape is a clone of a node of the current shape, or a node + /// AnalysisMorphologicalTransform rebuilds from the pattern of a part that was deleted or can be empty. + /// A partial rule unapplies only if each segment it inserts unifies with a node of the shape at that time. The + /// look-ahead is off for a stratum when a rule can edit copied nodes (, + /// , an unknown rule type), when a partial rule lives in a deeper stratum + /// whose phonological rules would change the shape, or when a partial rule inserts no segment. + /// + internal sealed class PartialRuleLookAhead + { + private sealed class StratumMaterial + { + // Every rule of the stratum leaves a contiguous run of its input and rebuilds no node that a partial + // rule's inserted segment unifies with, so the inserted segments must already stand side by side. + public bool Contiguous; + + // Per partial-rule allomorph, the runs of segments it inserts. + public FeatureStruct[][][] Runs; + + // Per segment of those runs, whether a rule of the stratum can rebuild a node that it unifies with. + public bool[][][] Rebuildable; + } + + private sealed class Transform + { + // The parts whose nodes make up the unapplied shape. + public IList> Parts; + public IList Rhs; + } + + private readonly Dictionary _material = new Dictionary(); + + public PartialRuleLookAhead(Language lang) + { + bool partialInDeeperStratum = false; + foreach (Stratum stratum in lang.Strata) + { + AffixProcessRule[] partial = stratum + .MorphologicalRules.OfType() + .Where(FinalTemplatePartialReachability.IsSynthesisPartial) + .ToArray(); + if (!partialInDeeperStratum && partial.Length > 0) + _material[stratum] = Inspect(stratum, partial); + partialInDeeperStratum |= partial.Length > 0; + } + } + + /// + /// False when no partial rule can be unapplied to this word or to anything analysis derives from it in + /// its stratum. + /// + public bool PartialRuleMayUnapply(Word input) + { + if (!_material.TryGetValue(input.Stratum, out StratumMaterial material) || material == null) + return true; + ShapeNode[] nodes = input.Shape.Where(n => n.Annotation.Type() == HCFeatureSystem.Segment).ToArray(); + if (nodes.Length != input.Shape.Count) + return true; + for (int a = 0; a < material.Runs.Length; a++) + { + bool possible = true; + for (int r = 0; possible && r < material.Runs[a].Length; r++) + { + FeatureStruct[] run = material.Runs[a][r]; + if (material.Contiguous) + { + possible = RunOccurs(nodes, run); + continue; + } + for (int i = 0; possible && i < run.Length; i++) + { + possible = + material.Rebuildable[a][r][i] + || nodes.Any(n => n.Annotation.FeatureStruct.IsUnifiable(run[i], false, null)); + } + } + if (possible) + return true; + } + return false; + } + + public bool IsActive => _material.Values.Any(m => m != null); + + private static StratumMaterial Inspect(Stratum stratum, AffixProcessRule[] partial) + { + IEnumerable rules = stratum + .MorphologicalRules.Concat(stratum.AffixTemplates.SelectMany(t => t.Slots).SelectMany(s => s.Rules)) + .Distinct(); + var rebuilt = new List(); + int notContiguous = 0; + foreach (IMorphologicalRule rule in rules) + { + IEnumerable transforms = Transforms(rule); + if (transforms == null) + return null; + foreach (Transform t in transforms) + { + if (!Inspect(t, rebuilt, out bool contiguous)) + return null; + if (!contiguous) + notContiguous++; + } + } + + FeatureStruct[][][] runs = partial + .SelectMany(r => r.Allomorphs) + .Select(a => + a.Rhs.OfType() + .Select(ins => + ins.Segments.Shape.Where(n => n.Annotation.Type() == HCFeatureSystem.Segment) + .Select(n => FrozenCopy(n.Annotation.FeatureStruct)) + .ToArray() + ) + .Where(run => run.Length > 0) + .ToArray() + ) + .ToArray(); + // An allomorph that inserts nothing can be unapplied to any shape. + if (runs.Any(allomorphRuns => allomorphRuns.Length == 0)) + return null; + + bool[][][] rebuildable = runs.Select(allomorphRuns => + allomorphRuns + .Select(run => + run.Select(fs => rebuilt.Any(c => c.HasVariables || c.IsUnifiable(fs, false, null))) + .ToArray() + ) + .ToArray() + ) + .ToArray(); + return new StratumMaterial + { + Runs = runs, + Rebuildable = rebuildable, + Contiguous = notContiguous == 0 && !rebuildable.Any(a => a.Any(r => r.Any(x => x))), + }; + } + + // Look-ahead runs on several threads, and unifying with an unfrozen structure is not thread-safe. + private static FeatureStruct FrozenCopy(FeatureStruct fs) + { + FeatureStruct copy = fs.Clone(); + copy.Freeze(); + return copy; + } + + private static IEnumerable Transforms(IMorphologicalRule rule) + { + switch (rule) + { + case AffixProcessRule ap: + return ap.Allomorphs.Select(a => new Transform { Parts = a.Lhs, Rhs = a.Rhs }); + case RealizationalAffixProcessRule rp: + return rp.Allomorphs.Select(a => new Transform { Parts = a.Lhs, Rhs = a.Rhs }); + case CompoundingRule cr: + return cr.Subrules.Select(sr => new Transform { Parts = sr.HeadLhs, Rhs = sr.Rhs }); + default: + return null; + } + } + + // Unapplying the transform keeps a contiguous run of the input's nodes, in order, and rebuilds only the + // nodes added to "rebuilt". Returns false if it can do anything else. + private static bool Inspect(Transform t, List rebuilt, out bool contiguous) + { + contiguous = false; + if (t.Rhs.Any(a => !(a is CopyFromInput) && !(a is InsertSegments))) + return false; + List names = t.Parts.Select(p => p.Name).ToList(); + var copies = new List(); + bool insertedAfterCopy = false; + bool insertedBetween = false; + foreach (MorphologicalOutputAction action in t.Rhs) + { + if (action is CopyFromInput) + { + int index = names.IndexOf(action.PartName); + if (index < 0) + { + // A non-head part leaves the head shape, so it separates head parts that follow it from + // those before it just as an inserted segment does. + if (copies.Count > 0) + insertedAfterCopy = true; + continue; + } + if (insertedAfterCopy) + insertedBetween = true; + copies.Add(index); + } + else if (copies.Count > 0) + { + insertedAfterCopy = true; + } + } + for (int i = 0; i < names.Count; i++) + { + if (!copies.Contains(i) || !NeverEmpty(t.Parts[i])) + CollectSegments(t.Parts[i], rebuilt); + } + bool increasing = true; + for (int i = 1; i < copies.Count; i++) + increasing &= copies[i] > copies[i - 1]; + contiguous = copies.Distinct().Count() <= 1 || (increasing && !insertedBetween); + return true; + } + + // A group over this part always captures at least one node. + private static bool NeverEmpty(PatternNode node) + { + foreach (PatternNode child in node.Children) + { + if (child is Constraint c && c.Type() == HCFeatureSystem.Segment) + return true; + if (child is Quantifier q) + { + if (q.MinOccur >= 1 && NeverEmpty(q)) + return true; + } + else if (child is Group g && NeverEmpty(g)) + { + return true; + } + } + return false; + } + + // Mirrors AnalysisMorphologicalTransform.Untruncate: an unbounded quantifier rebuilds nothing. + private static void CollectSegments(PatternNode node, List into) + { + if (node is Constraint c && c.Type() == HCFeatureSystem.Segment) + into.Add(c.FeatureStruct); + if (node is Quantifier q && q.MaxOccur <= 0) + return; + foreach (PatternNode child in node.Children) + CollectSegments(child, into); + } + + private static bool RunOccurs(ShapeNode[] nodes, FeatureStruct[] run) + { + for (int start = 0; start < nodes.Length; start++) + { + if (RunMatches(nodes, start, run, 0)) + return true; + } + return false; + } + + // Optional nodes may be passed over once the run has started. + private static bool RunMatches(ShapeNode[] nodes, int n, FeatureStruct[] run, int r) + { + if (r == run.Length) + return true; + if (n == nodes.Length) + return false; + if ( + nodes[n].Annotation.FeatureStruct.IsUnifiable(run[r], false, null) + && RunMatches(nodes, n + 1, run, r + 1) + ) + return true; + return r > 0 && nodes[n].Annotation.Optional && RunMatches(nodes, n + 1, run, r); + } + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab/Trace.cs b/src/SIL.Machine.Morphology.HermitCrab/Trace.cs index d9277a0b0..712266ea1 100644 --- a/src/SIL.Machine.Morphology.HermitCrab/Trace.cs +++ b/src/SIL.Machine.Morphology.HermitCrab/Trace.cs @@ -208,5 +208,12 @@ public IHCRule Source public string OutputText => _outputText ?? FormatText(Output); public FailureReason FailureReason { get; internal set; } + + /// + /// Gets what is about, when it has a subject: for + /// , the partial rules (a list of + /// ) that the analysis owes one of. Otherwise null. + /// + public object FailureObject { get; internal set; } } } diff --git a/src/SIL.Machine.Morphology.HermitCrab/TraceManager.cs b/src/SIL.Machine.Morphology.HermitCrab/TraceManager.cs index a890deb0b..a13ad9af2 100644 --- a/src/SIL.Machine.Morphology.HermitCrab/TraceManager.cs +++ b/src/SIL.Machine.Morphology.HermitCrab/TraceManager.cs @@ -90,11 +90,22 @@ public void BeginUnapplyTemplate(AffixTemplate template, Word input) ((Trace)input.CurrentTrace).Children.Add(Node(TraceType.TemplateAnalysisInput, template, input: input)); } - public void EndUnapplyTemplate(AffixTemplate template, Word output, bool unapplied, FailureReason reason) + public void EndUnapplyTemplate( + AffixTemplate template, + Word output, + bool unapplied, + FailureReason reason, + object failureObj + ) { - ((Trace)output.CurrentTrace).Children.Add( - Node(TraceType.TemplateAnalysisOutput, template, output: unapplied ? output : null, reason: reason) + Trace trace = Node( + TraceType.TemplateAnalysisOutput, + template, + output: unapplied ? output : null, + reason: reason ); + trace.FailureObject = failureObj; + ((Trace)output.CurrentTrace).Children.Add(trace); } public void MorphologicalRuleUnapplied(IMorphologicalRule rule, int subruleIndex, Word input, Word output) diff --git a/src/SIL.Machine.Morphology.HermitCrab/Word.cs b/src/SIL.Machine.Morphology.HermitCrab/Word.cs index 43b0e04c9..f874874dc 100644 --- a/src/SIL.Machine.Morphology.HermitCrab/Word.cs +++ b/src/SIL.Machine.Morphology.HermitCrab/Word.cs @@ -31,6 +31,8 @@ public class Word : Freezable, IAnnotatedData, ICloneable private bool? _isLastAppliedRuleFinal; private FinalTemplateState _finalTemplateState; private bool _isPartial; + private bool _needsPartial; + private AffixTemplate _owedPartialTemplate; private readonly Dictionary> _disjunctiveAllomorphIndices; private int _mruleAppCount = 0; private readonly IList _alternatives = new List(); @@ -97,6 +99,8 @@ protected Word(Word word) _isLastAppliedRuleFinal = word._isLastAppliedRuleFinal; _finalTemplateState = word._finalTemplateState; _isPartial = word._isPartial; + _needsPartial = word._needsPartial; + _owedPartialTemplate = word._owedPartialTemplate; CurrentTrace = word.CurrentTrace; _disjunctiveAllomorphIndices = word._disjunctiveAllomorphIndices.ToDictionary( kvp => kvp.Key, @@ -418,6 +422,31 @@ internal bool? IsLastAppliedRuleFinal } } + /// + /// Analysis unapplied a final template right after a non-template rule. Synthesis allows that only if a + /// partial rule applied before the template, so one must still be unapplied for the analysis to match. + /// + internal bool NeedsPartial + { + get { return _needsPartial; } + set + { + CheckFrozen(); + _needsPartial = value; + } + } + + /// The final template whose unapplication made this analysis owe a partial rule; for traces only. + internal AffixTemplate OwedPartialTemplate + { + get { return _owedPartialTemplate; } + set + { + CheckFrozen(); + _owedPartialTemplate = value; + } + } + internal FinalTemplateState FinalTemplateState { get { return _finalTemplateState; } @@ -588,6 +617,7 @@ protected override int FreezeImpl() code = code * 31 + _mruleAppIndex.GetHashCode(); code = code * 31 + _isLastAppliedRuleFinal.GetHashCode(); code = code * 31 + _finalTemplateState.GetHashCode(); + code = code * 31 + (_needsPartial ? 1 : 0); return code; } @@ -612,7 +642,8 @@ public override bool ValueEquals(Word other) && _mruleApps.SequenceEqual(other._mruleApps) && _mruleAppIndex == other._mruleAppIndex && _isLastAppliedRuleFinal == other._isLastAppliedRuleFinal - && _finalTemplateState == other._finalTemplateState; + && _finalTemplateState == other._finalTemplateState + && _needsPartial == other._needsPartial; } public Word Clone() diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/AffixTemplateTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/AffixTemplateTests.cs index 83498f566..fae09c598 100644 --- a/tests/SIL.Machine.Morphology.HermitCrab.Tests/AffixTemplateTests.cs +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/AffixTemplateTests.cs @@ -555,7 +555,7 @@ AffixProcessRule CreateSuffix(string name, string gloss, string suffix) AssertMorphsEqual(morpher.ParseWord("sabdv")); AssertMorphsEqual(morpher.ParseWord("sabv"), "partial_root NOM"); - // A partial rule still turns the prune off, and what it licenses after a final template survives. + // A partial rule leaves the state at none, so what it licenses after a final template survives. nominalizer.IsPartial = true; morpher = new Morpher(TraceManager, Language); Assert.That(morpher.HasPartialRules, Is.True); diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/PartialRulePruneTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/PartialRulePruneTests.cs new file mode 100644 index 000000000..91ad9261a --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/PartialRulePruneTests.cs @@ -0,0 +1,246 @@ +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.MorphologicalRules; + +namespace SIL.Machine.Morphology.HermitCrab; + +// Each grammar in TestData/PartialPrune puts partial material where a careless prune would miss it. The .expected +// files hold master's analyses, so a lost, extra or changed one fails. +public class PartialRulePruneTests +{ + private static readonly string[] Grammars = + [ + "g6", // partial rules with no category + "g6b", // partial rules in a deeper stratum than the template + "g7", // a slot rule shared by a final and a non-final template + "g8", // final templates a partial rule can reach and ones it cannot + "g10", // plain prefixes and suffixes around the partial material + "g11", // partial material wrapped by affixes and copied by reduplication + "g12", // an infix splits the partial material + "g13", // truncation replaces the partial rule's last segment + "g13b", // truncation of the partial prefix's first segment + "g13c", // truncation replaces the partial rule's last segment, minimal + "g14", // a copied part that can be empty + "g15", // two parts copied in swapped order move the material apart + "g16", // compounding outside the partial rule + "g17", // partial rules in a deeper stratum + "g18", // partial rules in both strata + "g19", // phonological deletion hides a partial segment + "g19c", // phonological deletion hides a partial segment, minimal + "g20", // three partial rules + "g21", // compounding and a partial rule the look-ahead cannot reason about + "cx1b", // a compound puts its non-head between two head parts, hiding the partial material + "cx2", // a flagged and an unflagged word differ only in NeedsPartial and must both survive + "cx3", // lexical family and a partial rule: master returns duplicates, see the pinning test below + "cx4", // ModifyFromInput changes the partial material + "cx10", // no final template, so no state is tracked + "cx11", // the only partial rule sits in a template slot + "cx12", // the only partial rule is a clitic rule + "cx9b", // ModifyFromInput on an unbounded part widens the node the partial rule needs + "cx5", // InsertSimpleContext splits the partial material + "cx6", // an infix and a copy of a part (reduplication) rearrange the partial material + "cx7", // a compound with the non-head before the head parts + "cx8", // a compound copies one head part twice around the non-head + ]; + + // Grammars whose words need the deletion rules to be reapplied. + private static readonly HashSet DeletionReapplied = ["g19", "g19c"]; + + private static string DataPath(string file) => + Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "TestData", "PartialPrune", file); + + private static IEnumerable Flatten(Trace trace) + { + yield return trace; + foreach (Trace child in trace.Children) + { + foreach (Trace descendant in Flatten(child)) + yield return descendant; + } + } + + private static IEnumerable GrammarCases() + { + foreach (string grammar in Grammars) + { + yield return new TestCaseData(grammar, 1).SetName($"{grammar}_Degree1"); + yield return new TestCaseData(grammar, 0).SetName($"{grammar}_DefaultDegree"); + } + } + + private static Morpher CreateMorpher( + string grammar, + int maxDegreeOfParallelism, + Func? selector = null, + bool tracing = false + ) + { + Language language = XmlLanguageLoader.Load(DataPath(grammar + ".xml")); + var morpher = new Morpher(new TraceManager { IsTracing = tracing }, language, maxDegreeOfParallelism); + if (DeletionReapplied.Contains(grammar)) + morpher.DeletionReapplications = 1; + if (selector != null) + morpher.RuleSelector = selector; + return morpher; + } + + // Allomorphs, not AllomorphsInMorphOrder: morph order comes from shape annotations, which a truncation can drop. + // Distinct: the number of identical analyses a parse returns varies between runs. + private static string Signature(Morpher morpher, string word) + { + try + { + List analyses = morpher + .ParseWord(word) + .Select(w => + string.Join( + "+", + w.Allomorphs.Select(a => $"{a.Morpheme.Id}.{a.Index}").OrderBy(n => n, StringComparer.Ordinal) + ) + + "|" + + w.Shape.ToRegexString(w.Stratum.CharacterDefinitionTable, true) + + "|" + + w.SyntacticFeatureStruct + ) + .Distinct() + .OrderBy(s => s, StringComparer.Ordinal) + .ToList(); + return analyses.Count == 0 ? "-" : string.Join(";", analyses); + } + catch (InvalidShapeException) + { + return "SKIPPED"; + } + } + + [TestCaseSource(nameof(GrammarCases))] + public void ParseWord_PartialRuleGrammar_KeepsEveryAnalysis(string grammar, int maxDegreeOfParallelism) + { + Morpher morpher = CreateMorpher(grammar, maxDegreeOfParallelism); + Assert.That(morpher.HasPartialRules, Is.True); + + var differences = new List(); + + foreach (string line in File.ReadAllLines(DataPath(grammar + ".expected"))) + { + string[] fields = line.Split('\t'); + string actual = Signature(morpher, fields[0]); + if (actual != fields[1]) + differences.Add($"{fields[0]}: expected {fields[1]} but was {actual}"); + } + Assert.That(differences, Is.Empty); + } + + // Master returns each word twice in a family grammar with partial rules; the prune drops only duplicates. + [TestCase("kamdtr")] + [TestCase("kamdtrt")] + public void ParseWord_FamilyAndPartialRuleGrammar_ReturnsEachAnalysisOnce(string word) + { + Morpher morpher = CreateMorpher("cx3", maxDegreeOfParallelism: 1); + Assert.That(morpher.ParseWord(word).Count(), Is.EqualTo(1)); + } + + // Rule-selector calls count work. At one thread the count is deterministic, so a bound tells a prune that + // fires from one that does not. + [TestCase("g8", "akamdt", 130, TestName = "TemplateNoPartialWordCanReach")] + [TestCase("g6", "loptr", 18, TestName = "ShapeHasNoRoomForPartialMaterialContiguous")] + [TestCase("g12", "loptr", 16, TestName = "ShapeHasNoRoomForPartialMaterialExistence")] + public void ParseWord_PartialRuleGrammar_PrunesWhatNoPartialWordCanUse(string grammar, string word, int maxCalls) + { + int calls = 0; + Morpher morpher = CreateMorpher( + grammar, + maxDegreeOfParallelism: 1, + selector: _ => + { + calls++; + return true; + } + ); + Signature(morpher, word); + Assert.That(calls, Is.LessThanOrEqualTo(maxCalls)); + } + + // The look-ahead assumes unapplying a rule copies input nodes and adds only inserted or rebuilt ones. Weigh a + // new output action type there before listing it here. + [Test] + public void MorphologicalOutputAction_Subtypes_AreTheOnesPartialRuleLookAheadKnows() + { + string[] subtypes = typeof(MorphologicalOutputAction) + .Assembly.GetTypes() + .Where(t => t.IsSubclassOf(typeof(MorphologicalOutputAction))) + .Select(t => t.Name) + .OrderBy(n => n, StringComparer.Ordinal) + .ToArray(); + Assert.That( + subtypes, + Is.EqualTo( + new[] + { + nameof(CopyFromInput), + nameof(InsertSegments), + nameof(InsertSimpleContext), + nameof(ModifyFromInput), + } + ) + ); + } + + // A pruned candidate must show in a trace, not vanish: the final template that owes a partial rule, with the + // partial rules as the failure object. + [TestCase("g6", "lopqtr")] + [TestCase("g6b", "loptr")] + [TestCase("cx1b", "lopkotr")] + public void ParseWord_OwedPartialDropped_IsTraced(string grammar, string word) + { + foreach (int degree in new[] { 1, 0 }) + { + Morpher morpher = CreateMorpher(grammar, degree, tracing: true); + morpher.ParseWord(word, out object root); + Trace[] dropped = Flatten((Trace)root) + .Where(t => t.FailureReason == FailureReason.OwedPartialCannotUnapply) + .ToArray(); + Assert.That(dropped, Is.Not.Empty); + foreach (Trace t in dropped) + { + Assert.That(t.Type, Is.EqualTo(TraceType.TemplateAnalysisOutput)); + Assert.That(t.Source, Is.InstanceOf().With.Property("IsFinal").True); + Assert.That(t.Output, Is.Null); + Assert.That(t.FailureObject, Is.InstanceOf>()); + Assert.That((IReadOnlyList)t.FailureObject, Is.Not.Empty); + } + } + } + + // Nothing arms the prune without a final template, so the analysis state must not be tracked. + [TestCase("cx10", false)] + [TestCase("cx1b", true)] + [TestCase("cx11", true)] + [TestCase("cx12", true)] + public void TracksFinalTemplateState_PartialRuleGrammar_OnlyWhenAFinalTemplateCanBePruned( + string grammar, + bool tracked + ) + { + Assert.That(CreateMorpher(grammar, 1).TracksFinalTemplateState, Is.EqualTo(tracked)); + } + + // Partial rules in a template slot or clitic rules never make a word partial in synthesis, so they do not + // keep the final-template prune off. + [TestCase("cx11", "lopkmootr", 15, TestName = "SlotPartialRuleDoesNotKeepPruneOff")] + [TestCase("cx12", "lopkotr", 13, TestName = "CliticPartialRuleDoesNotKeepPruneOff")] + public void ParseWord_OnlyNonPartialWordsReachTheTemplate_Prunes(string grammar, string word, int maxCalls) + { + int calls = 0; + Morpher morpher = CreateMorpher( + grammar, + maxDegreeOfParallelism: 1, + selector: _ => + { + calls++; + return true; + } + ); + Signature(morpher, word); + Assert.That(calls, Is.LessThanOrEqualTo(maxCalls)); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx10.expected b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx10.expected new file mode 100644 index 000000000..aef9673c9 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx10.expected @@ -0,0 +1,10 @@ +lopko LOP.0+PK.0|lopko|[POS:B] +lopkot LOP.0+PK.0+T.0|lopkot|[POS:B] +lopkotr LOP.0+PK.0+R.0+T.0|lopkotr|[POS:B] +lopt - +loptr - +lopkmoo LOP.0+MO.0+PK.0|lopkmoo|[POS:B] +lopkmoot LOP.0+MO.0+PK.0+T.0|lopkmoot|[POS:B] +lopkmootr LOP.0+MO.0+PK.0+R.0+T.0|lopkmootr|[POS:B] +lopkr - +lopkt - diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx10.words b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx10.words new file mode 100644 index 000000000..63bae33ad --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx10.words @@ -0,0 +1,10 @@ +lopko +lopkot +lopkotr +lopt +loptr +lopkmoo +lopkmoot +lopkmootr +lopkr +lopkt diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx10.xml b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx10.xml new file mode 100644 index 000000000..01d227b0d --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx10.xml @@ -0,0 +1,38 @@ + + + + LaComp + ABE + Main +abdegiklmnopqrstuwxyz + + AnyKO + +Main +pk + +ko +PKpk +t + +t +Tt +r + +r +Rr +cr + + + + +T1slotT1 + +lopLOPlop +kamKAMkam +moMOmo +koKOko + + + + diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx11.expected b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx11.expected new file mode 100644 index 000000000..2619725c9 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx11.expected @@ -0,0 +1,10 @@ +lopko - +lopkot - +lopkotr - +lopt LOP.0+T.0|lopt|[POS:B] +loptr - +lopkmoo - +lopkmoot LOP.0+MO.0+PK.0+T.0|lopkmoot|[POS:B] +lopkmootr - +lopkr - +lopkt - diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx11.words b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx11.words new file mode 100644 index 000000000..63bae33ad --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx11.words @@ -0,0 +1,10 @@ +lopko +lopkot +lopkotr +lopt +loptr +lopkmoo +lopkmoot +lopkmootr +lopkr +lopkt diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx11.xml b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx11.xml new file mode 100644 index 000000000..60097eaed --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx11.xml @@ -0,0 +1,39 @@ + + + + LaComp + ABE + Main +abdegiklmnopqrstuwxyz + + AnyKO + +Main +pk + +ko +PKpk +t + +t +Tt +r + +r +Rr +cr + + + + +T0slotPK +T1slotT1 + +lopLOPlop +kamKAMkam +moMOmo +koKOko + + + + diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx12.expected b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx12.expected new file mode 100644 index 000000000..e63762542 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx12.expected @@ -0,0 +1,10 @@ +lopko - +lopkot LOP.0+PK.0+T.0|lopkot|[POS:B] +lopkotr - +lopt LOP.0+T.0|lopt|[POS:B] +loptr - +lopkmoo - +lopkmoot LOP.0+MO.0+PK.0+T.0|lopkmoot|[POS:B] +lopkmootr - +lopkr - +lopkt - diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx12.words b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx12.words new file mode 100644 index 000000000..63bae33ad --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx12.words @@ -0,0 +1,10 @@ +lopko +lopkot +lopkotr +lopt +loptr +lopkmoo +lopkmoot +lopkmootr +lopkr +lopkt diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx12.xml b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx12.xml new file mode 100644 index 000000000..a67e3e31d --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx12.xml @@ -0,0 +1,38 @@ + + + + LaComp + ABE + Main +abdegiklmnopqrstuwxyz + + AnyKO + +Main +pk + +ko +PKpk +t + +t +Tt +r + +r +Rr +cr + + + + +T1slotT1 + +lopLOPlop +kamKAMkam +moMOmo +koKOko + + + + diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx1b.expected b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx1b.expected new file mode 100644 index 000000000..ba3061378 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx1b.expected @@ -0,0 +1,6 @@ +lopkmootr LOP.0+MO.0+PK.0+R.0+T.0|lopkmootr|[POS:B] +lopkmoot LOP.0+MO.0+PK.0+T.0|lopkmoot|[POS:B] +lopkootr - +lopkmoo LOP.0+MO.0+PK.0|lopkmoo|[POS:B] +lopkotr LOP.0+PK.0+R.0+T.0|lopkotr|[POS:B] +lopkmootrko - diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx1b.words b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx1b.words new file mode 100644 index 000000000..7e7021f3e --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx1b.words @@ -0,0 +1,6 @@ +lopkmootr +lopkmoot +lopkootr +lopkmoo +lopkotr +lopkmootrko diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx1b.xml b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx1b.xml new file mode 100644 index 000000000..f1b64b0ea --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx1b.xml @@ -0,0 +1,38 @@ + + + + LaComp + ABE + Main +abdegiklmnopqrstuwxyz + + AnyKO + +Main +pk + +ko +PKpk +t + +t +Tt +r + +r +Rr +cr + + + + +T1slotT1 + +lopLOPlop +kamKAMkam +moMOmo +koKOko + + + + diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx2.expected b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx2.expected new file mode 100644 index 000000000..fefc8c39a --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx2.expected @@ -0,0 +1,6 @@ +qoptr QOP.0+R.0+T.0|qoptr|[POS:B] +qopt QOP.0+T.0|qopt|[POS:B] +loptr LOP.0+R.0+T.0|loptr|[POS:B] +lopqtr LOP.0+Q.0+R.0+T.0|lopqtr|[POS:B] +qopqtr Q.0+QOP.0+R.0+T.0|qopqtr|[POS:B] +aqoptr P.0+QOP.0+R.0+T.0|aqoptr|[POS:B] diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx2.words b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx2.words new file mode 100644 index 000000000..23cdfd4aa --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx2.words @@ -0,0 +1,6 @@ +qoptr +qopt +loptr +lopqtr +qopqtr +aqoptr diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx2.xml b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx2.xml new file mode 100644 index 000000000..966fad77f --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx2.xml @@ -0,0 +1,39 @@ + + + + AdvShared + AB + Main +abdegiklmnopqrstuwxyz + + Any + +Main +q + +q +Qq +r + +r +Rr +t + +t +Tt +p + +a +Pp + +T1slotT1 +T2slotT2 +T3slotT3 + +qopQOPqop +kamKAMkam +lopLOPlop + + + + diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx3.expected b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx3.expected new file mode 100644 index 000000000..abbe3c63f --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx3.expected @@ -0,0 +1,7 @@ +kamdtr KAMDTR.0|kamdtr|[POS:A] +kamdt - +kamd - +kamtr - +kamdtrt KAMDTR.0+RR.0|kamdtrt|[Head:[hf:x], POS:A] +kamzdtr - +kamdtrz - diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx3.words b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx3.words new file mode 100644 index 000000000..20b67b8b1 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx3.words @@ -0,0 +1,7 @@ +kamdtr +kamdt +kamd +kamtr +kamdtrt +kamzdtr +kamdtrz diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx3.xml b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx3.xml new file mode 100644 index 000000000..07c92194d --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx3.xml @@ -0,0 +1,38 @@ + + + + AdvBlock + A + hfxy + Main +abdegiklmnopqrstuwxyz + + Any + fam1 + +Main +d1 + +d +D1d1 +r1 + +r +R1r1 +pz + +z +PZpz +rr + +t +RRrr + +T1slotT1 + +kamKAMkam +kamdtrKAMDTRkamdtr + + + + diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx4.expected b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx4.expected new file mode 100644 index 000000000..9466c760c --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx4.expected @@ -0,0 +1,7 @@ +lopko LOP.0+PK.0|lopko|[POS:B] +lopkot LOP.0+PK.0+T.0|lopkot|[POS:B] +lopku LOP.0+PK.0+X.0|lopku|[POS:B] +lopkut LOP.0+PK.0+T.0+X.0|lopkut|[POS:B] +lopkutr LOP.0+PK.0+R.0+T.0+X.0|lopkutr|[POS:B] +lopkotr LOP.0+PK.0+R.0+T.0|lopkotr|[POS:B] +lopkuot - diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx4.words b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx4.words new file mode 100644 index 000000000..11566ff5f --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx4.words @@ -0,0 +1,7 @@ +lopko +lopkot +lopku +lopkut +lopkutr +lopkotr +lopkuot diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx4.xml b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx4.xml new file mode 100644 index 000000000..edf22b171 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx4.xml @@ -0,0 +1,37 @@ + + + + LaComp + ABE + segabdegiklmnopqrstuwxyz + Main +abdegiklmnopqrstuwxyz + + AnyKUO + +Main +pk + +ko +PKpk +t + +t +Tt +r + +r +Rr +xXx + + +T1slotT1 + +lopLOPlop +kamKAMkam +moMOmo +koKOko + + + + diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx5.expected b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx5.expected new file mode 100644 index 000000000..114bbe686 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx5.expected @@ -0,0 +1,6 @@ +lopkot LOP.0+PK.0+T.0|lopkot|[POS:B] +lopkuo LOP.0+PK.0+X.0|lopkuo|[POS:B] +lopkuot LOP.0+PK.0+T.0+X.0|lopkuot|[POS:B] +lopkuotr LOP.0+PK.0+R.0+T.0+X.0|lopkuotr|[POS:B] +lopkuor LOP.0+PK.0+R.0+X.0|lopkuor|[POS:B] +lopkotr LOP.0+PK.0+R.0+T.0|lopkotr|[POS:B] diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx5.words b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx5.words new file mode 100644 index 000000000..51bfdc97a --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx5.words @@ -0,0 +1,6 @@ +lopkot +lopkuo +lopkuot +lopkuotr +lopkuor +lopkotr diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx5.xml b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx5.xml new file mode 100644 index 000000000..1d2c2c870 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx5.xml @@ -0,0 +1,36 @@ + + + + LaComp + ABE + Main +abdegiklmnopqrstuwxyz + + AnyKUO + +Main +pk + +ko +PKpk +t + +t +Tt +r + +r +Rr +xXx + + +T1slotT1 + +lopLOPlop +kamKAMkam +moMOmo +koKOko + + + + diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx6.expected b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx6.expected new file mode 100644 index 000000000..4cb2e05be --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx6.expected @@ -0,0 +1,6 @@ +lopkot LOP.0+PK.0+T.0|lopkot|[POS:B] +lopkmolopk LOP.0+PK.0+X.0|lopkmolopk|[POS:B] +lopkmolopkt LOP.0+PK.0+T.0+X.0|lopkmolopkt|[POS:B] +lopkmolopktr LOP.0+PK.0+R.0+T.0+X.0|lopkmolopktr|[POS:B] +lopkmolopr - +lopkotr LOP.0+PK.0+R.0+T.0|lopkotr|[POS:B] diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx6.words b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx6.words new file mode 100644 index 000000000..96e3e9360 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx6.words @@ -0,0 +1,6 @@ +lopkot +lopkmolopk +lopkmolopkt +lopkmolopktr +lopkmolopr +lopkotr diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx6.xml b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx6.xml new file mode 100644 index 000000000..9a802b20e --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx6.xml @@ -0,0 +1,36 @@ + + + + LaComp + ABE + Main +abdegiklmnopqrstuwxyz + + AnyKUO + +Main +pk + +ko +PKpk +t + +t +Tt +r + +r +Rr +xmXx + + +T1slotT1 + +lopLOPlop +kamKAMkam +moMOmo +koKOko + + + + diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx7.expected b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx7.expected new file mode 100644 index 000000000..937f46904 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx7.expected @@ -0,0 +1,6 @@ +lopkot LOP.0+PK.0+T.0|lopkot|[POS:B] +molopko LOP.0+MO.0+PK.0|molopko|[POS:B] +molopkot LOP.0+MO.0+PK.0+T.0|molopkot|[POS:B] +molopkotr LOP.0+MO.0+PK.0+R.0+T.0|molopkotr|[POS:B] +molopkt - +lopkotr LOP.0+PK.0+R.0+T.0|lopkotr|[POS:B] diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx7.words b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx7.words new file mode 100644 index 000000000..19951529c --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx7.words @@ -0,0 +1,6 @@ +lopkot +molopko +molopkot +molopkotr +molopkt +lopkotr diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx7.xml b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx7.xml new file mode 100644 index 000000000..4ec4d70b6 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx7.xml @@ -0,0 +1,36 @@ + + + + LaComp + ABE + Main +abdegiklmnopqrstuwxyz + + AnyKUO + +Main +pk + +ko +PKpk +t + +t +Tt +r + +r +Rr +cr + + +T1slotT1 + +lopLOPlop +kamKAMkam +moMOmo +koKOko + + + + diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx8.expected b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx8.expected new file mode 100644 index 000000000..95fb082d7 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx8.expected @@ -0,0 +1,6 @@ +lopkot LOP.0+PK.0+T.0|lopkot|[POS:B] +lopkmolopko LOP.0+MO.0+PK.0|lopkmolopko|[POS:B] +lopkmolopkot LOP.0+MO.0+PK.0+T.0|lopkmolopkot|[POS:B] +lopkmolopkotr LOP.0+MO.0+PK.0+R.0+T.0|lopkmolopkotr|[POS:B] +lopkmolopkt - +lopkotr LOP.0+PK.0+R.0+T.0|lopkotr|[POS:B] diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx8.words b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx8.words new file mode 100644 index 000000000..3e058dd1a --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx8.words @@ -0,0 +1,6 @@ +lopkot +lopkmolopko +lopkmolopkot +lopkmolopkotr +lopkmolopkt +lopkotr diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx8.xml b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx8.xml new file mode 100644 index 000000000..4f9f171ee --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx8.xml @@ -0,0 +1,36 @@ + + + + LaComp + ABE + Main +abdegiklmnopqrstuwxyz + + AnyKUO + +Main +pk + +ko +PKpk +t + +t +Tt +r + +r +Rr +cr + + +T1slotT1 + +lopLOPlop +kamKAMkam +moMOmo +koKOko + + + + diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx9b.expected b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx9b.expected new file mode 100644 index 000000000..45dbfdde5 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx9b.expected @@ -0,0 +1,9 @@ +lopko LOP.0+PK.0|lopko|[POS:B] +lopkot LOP.0+PK.0+T.0|lopkot|[POS:B] +lopku LOP.0+PK.0+X.0|lopku|[POS:B] +lopkut LOP.0+PK.0+T.0+X.0|lopkut|[POS:B] +lopkutr LOP.0+PK.0+R.0+T.0+X.0|lopkutr|[POS:B] +lopkotr LOP.0+PK.0+R.0+T.0|lopkotr|[POS:B] +lopkuot - +lopkutr LOP.0+PK.0+R.0+T.0+X.0|lopkutr|[POS:B] +lopkuutr - diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx9b.words b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx9b.words new file mode 100644 index 000000000..4256efb37 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx9b.words @@ -0,0 +1,9 @@ +lopko +lopkot +lopku +lopkut +lopkutr +lopkotr +lopkuot +lopkutr +lopkuutr diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx9b.xml b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx9b.xml new file mode 100644 index 000000000..3c8b3883a --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/cx9b.xml @@ -0,0 +1,37 @@ + + + + LaComp + ABE + segabdegiklmnopqrstuwxyz + Main +abdegiklmnopqrstuwxyz + + AnyKUO + +Main +pk + +ko +PKpk +t + +t +Tt +r + +r +Rr +xXx + + +T1slotT1 + +lopLOPlop +kamKAMkam +moMOmo +koKOko + + + + diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g10.expected b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g10.expected new file mode 100644 index 000000000..b583aa9ed --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g10.expected @@ -0,0 +1,13 @@ +lopkotr LOP.0+PK.0+R.0+T.0|lopkotr|[POS:B] +loptr - +lopkot LOP.0+PK.0+T.0|lopkot|[POS:B] +lopt LOP.0+T.0|lopt|[POS:B] +lopktr - +lopotr - +loptkor LOP.0+PK.0+R.0+T.0|loptkor|[POS:B] +lopkotkor - +kaloptr LOP.0+PC.0+R.0+T.0|kaloptr|[POS:B] +kalopkotr LOP.0+PC.0+PK.0+R.0+T.0|kalopkotr|[POS:B] +loptrko - +loptkr - +lopkor LOP.0+PK.0+R.0|lopkor|[POS:B] diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g10.words b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g10.words new file mode 100644 index 000000000..e7afb8792 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g10.words @@ -0,0 +1,13 @@ +lopkotr +loptr +lopkot +lopt +lopktr +lopotr +loptkor +lopkotkor +kaloptr +kalopkotr +loptrko +loptkr +lopkor diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g10.xml b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g10.xml new file mode 100644 index 000000000..ba73f655f --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g10.xml @@ -0,0 +1,37 @@ + + + + LaPlain + ABE + Main +abdegiklmnopqrstuwxyz + + Any + +Main +pk + +ko +PKpk +pc + +ka +PCpc +t + +t +Tt +r + +r +Rr + +T1slotT1 + +lopLOPlop +kamKAMkam +moMOmo + + + + diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g11.expected b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g11.expected new file mode 100644 index 000000000..cbfb7b00a --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g11.expected @@ -0,0 +1,21 @@ +lopkotr LOP.0+PK.0+R.0+T.0|lopkotr|[POS:B] +loptr - +lopkot LOP.0+PK.0+T.0|lopkot|[POS:B] +lopt LOP.0+T.0|lopt|[POS:B] +lopktr - +lopotr - +loptkor LOP.0+PK.0+R.0+T.0|loptkor|[POS:B] +lopkotkor - +kaloptr LOP.0+PC.0+R.0+T.0|kaloptr|[POS:B] +kalopkotr LOP.0+PC.0+PK.0+R.0+T.0|kalopkotr|[POS:B] +loptrko - +loptkr - +lopkor LOP.0+PK.0+R.0|lopkor|[POS:B] +lopkontr LOP.0+N.0+PK.0+R.0+T.0|lopkontr|[POS:B] +milopkotr LOP.0+M.0+PK.0+R.0+T.0|milopkotr|[POS:B] +mikaloptr LOP.0+M.0+PC.0+R.0+T.0|mikaloptr|[POS:B] +lopkolopkotr LOP.0+PK.0+R.0+RD.0+T.0|lopkolopkotr|[POS:B] +kalopkaloptr LOP.0+PC.0+R.0+RD.0+T.0|kalopkaloptr|[POS:B] +lopkonnt - +lopnkotr LOP.0+N.0+PK.0+R.0+T.0|lopnkotr|[POS:B] +lopkolopkontr LOP.0+N.0+PK.0+R.0+RD.0+T.0|lopkolopkontr|[POS:B] diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g11.words b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g11.words new file mode 100644 index 000000000..6fb91f13a --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g11.words @@ -0,0 +1,21 @@ +lopkotr +loptr +lopkot +lopt +lopktr +lopotr +loptkor +lopkotkor +kaloptr +kalopkotr +loptrko +loptkr +lopkor +lopkontr +milopkotr +mikaloptr +lopkolopkotr +kalopkaloptr +lopkonnt +lopnkotr +lopkolopkontr diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g11.xml b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g11.xml new file mode 100644 index 000000000..c031297f9 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g11.xml @@ -0,0 +1,48 @@ + + + + LaWrap + ABE + Main +abdegiklmnopqrstuwxyz + + Any + +Main +pk + +ko +PKpk +pc + +ka +PCpc +t + +t +Tt +r + +r +Rr +n + +n +Nn +m + +mi +Mm +rd + +RDrd + +T1slotT1 + +lopLOPlop +kamKAMkam +moMOmo + + + + diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g12.expected b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g12.expected new file mode 100644 index 000000000..26bef54a8 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g12.expected @@ -0,0 +1,19 @@ +lopkotr LOP.0+PK.0+R.0+T.0|lopkotr|[POS:B] +loptr - +lopkot LOP.0+PK.0+T.0|lopkot|[POS:B] +lopt LOP.0+T.0|lopt|[POS:B] +lopktr - +lopotr - +loptkor LOP.0+PK.0+R.0+T.0|loptkor|[POS:B] +lopkotkor - +kaloptr LOP.0+PC.0+R.0+T.0|kaloptr|[POS:B] +kalopkotr LOP.0+PC.0+PK.0+R.0+T.0|kalopkotr|[POS:B] +loptrko - +loptkr - +lopkor LOP.0+PK.0+R.0|lopkor|[POS:B] +lopkxotr IX.0+LOP.0+PK.0+R.0+T.0|lopkxotr|[POS:B] +lopkxot IX.0+LOP.0+PK.0+T.0|lopkxot|[POS:B] +loxptr - +lopxtr - +kalxoptr - +lopkxoxtr - diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g12.words b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g12.words new file mode 100644 index 000000000..b89db220d --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g12.words @@ -0,0 +1,19 @@ +lopkotr +loptr +lopkot +lopt +lopktr +lopotr +loptkor +lopkotkor +kaloptr +kalopkotr +loptrko +loptkr +lopkor +lopkxotr +lopkxot +loxptr +lopxtr +kalxoptr +lopkxoxtr diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g12.xml b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g12.xml new file mode 100644 index 000000000..75e6675ec --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g12.xml @@ -0,0 +1,40 @@ + + + + LaInfix + ABE + Main +abdegiklmnopqrstuwxyz + + Any + +Main +pk + +ko +PKpk +pc + +ka +PCpc +t + +t +Tt +r + +r +Rr +ix +x +IXix + +T1slotT1 + +lopLOPlop +kamKAMkam +moMOmo + + + + diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g13.expected b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g13.expected new file mode 100644 index 000000000..d90cbf496 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g13.expected @@ -0,0 +1,18 @@ +lopkotr LOP.0+PK.0+R.0+T.0|lopkotr|[POS:B] +loptr - +lopkot LOP.0+PK.0+T.0|lopkot|[POS:B] +lopt LOP.0+T.0|lopt|[POS:B] +lopktr - +lopotr - +loptkor LOP.0+PK.0+R.0+T.0|loptkor|[POS:B] +lopkotkor - +kaloptr LOP.0+PC.0+R.0+T.0|kaloptr|[POS:B] +kalopkotr LOP.0+PC.0+PK.0+R.0+T.0|kalopkotr|[POS:B] +loptrko - +loptkr - +lopkor LOP.0+PK.0+R.0|lopkor|[POS:B] +lopkatr LOP.0+PK.0+R.0+T.0+TR.0|lopkatr|[POS:B] +lopkat LOP.0+PK.0+T.0+TR.0|lopkat|[POS:B] +lopatr - +loptr - +lopkaktr - diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g13.words b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g13.words new file mode 100644 index 000000000..52b2a855f --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g13.words @@ -0,0 +1,18 @@ +lopkotr +loptr +lopkot +lopt +lopktr +lopotr +loptkor +lopkotkor +kaloptr +kalopkotr +loptrko +loptkr +lopkor +lopkatr +lopkat +lopatr +loptr +lopkaktr diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g13.xml b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g13.xml new file mode 100644 index 000000000..d4bff2e9f --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g13.xml @@ -0,0 +1,40 @@ + + + + LaTrunc + ABE + Main +abdegiklmnopqrstuwxyz + + Any + +Main +pk + +ko +PKpk +pc + +ka +PCpc +t + +t +Tt +r + +r +Rr +tr +a +TRtr + +T1slotT1 + +lopLOPlop +kamKAMkam +moMOmo + + + + diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g13b.expected b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g13b.expected new file mode 100644 index 000000000..fdd3e80fe --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g13b.expected @@ -0,0 +1,17 @@ +lopkotr LOP.0+PK.0+R.0+T.0|lopkotr|[POS:B] +loptr - +lopkot LOP.0+PK.0+T.0|lopkot|[POS:B] +lopt LOP.0+T.0|lopt|[POS:B] +lopktr - +lopotr - +loptkor LOP.0+PK.0+R.0+T.0|loptkor|[POS:B] +lopkotkor - +kaloptr LOP.0+PC.0+R.0+T.0|kaloptr|[POS:B] +kalopkotr LOP.0+PC.0+PK.0+R.0+T.0|kalopkotr|[POS:B] +loptrko - +loptkr - +lopkor LOP.0+PK.0+R.0|lopkor|[POS:B] +aloptr LOP.0+PC.0+R.0+T.0+TR.0|aloptr|[POS:B] +alopt LOP.0+PC.0+T.0+TR.0|alopt|[POS:B] +oloptr - +lopkotr LOP.0+PK.0+R.0+T.0|lopkotr|[POS:B] diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g13b.words b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g13b.words new file mode 100644 index 000000000..5a2fc13d4 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g13b.words @@ -0,0 +1,17 @@ +lopkotr +loptr +lopkot +lopt +lopktr +lopotr +loptkor +lopkotkor +kaloptr +kalopkotr +loptrko +loptkr +lopkor +aloptr +alopt +oloptr +lopkotr diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g13b.xml b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g13b.xml new file mode 100644 index 000000000..7fc17c873 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g13b.xml @@ -0,0 +1,40 @@ + + + + LaTruncPre + ABE + Main +abdegiklmnopqrstuwxyz + + Any + +Main +pk + +ko +PKpk +pc + +ka +PCpc +t + +t +Tt +r + +r +Rr +tr + +TRtr + +T1slotT1 + +lopLOPlop +kamKAMkam +moMOmo + + + + diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g13c.expected b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g13c.expected new file mode 100644 index 000000000..4276161cc --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g13c.expected @@ -0,0 +1,7 @@ +lipkatr LIP.0+PK.0+R.0+T.0+TR.0|lipkatr|[POS:B] +lipkat LIP.0+PK.0+T.0+TR.0|lipkat|[POS:B] +lipatr - +liptr - +lipkotr LIP.0+PK.0+R.0+T.0|lipkotr|[POS:B] +lipkaktr - +kalipatr - diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g13c.words b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g13c.words new file mode 100644 index 000000000..dcb87d2e4 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g13c.words @@ -0,0 +1,7 @@ +lipkatr +lipkat +lipatr +liptr +lipkotr +lipkaktr +kalipatr diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g13c.xml b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g13c.xml new file mode 100644 index 000000000..9e0d36045 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g13c.xml @@ -0,0 +1,35 @@ + + + + LaTrunc2 + ABE + Main +abdegiklmnopqrstuwxyz + + Any + +Main +pk + +ko +PKpk +t + +t +Tt +r + +r +Rr +tr +a +TRtr + +T1slotT1 + +lipLIPlip +moMOmo + + + + diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g14.expected b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g14.expected new file mode 100644 index 000000000..651f53a1a --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g14.expected @@ -0,0 +1,17 @@ +lopkotr LOP.0+PK.0+R.0+T.0|lopkotr|[POS:B] +loptr - +lopkot LOP.0+PK.0+T.0|lopkot|[POS:B] +lopt LOP.0+T.0|lopt|[POS:B] +lopktr - +lopotr - +loptkor LOP.0+PK.0+R.0+T.0|loptkor|[POS:B] +lopkotkor - +kaloptr LOP.0+PC.0+R.0+T.0|kaloptr|[POS:B] +kalopkotr LOP.0+PC.0+PK.0+R.0+T.0|kalopkotr|[POS:B] +loptrko - +loptkr - +lopkor LOP.0+PK.0+R.0|lopkor|[POS:B] +lopkontr LOP.0+OQ.0+PK.0+R.0+T.0|lopkontr|[POS:B] +lopkntr - +lopntr - +lopknotr - diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g14.words b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g14.words new file mode 100644 index 000000000..39a6b9882 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g14.words @@ -0,0 +1,17 @@ +lopkotr +loptr +lopkot +lopt +lopktr +lopotr +loptkor +lopkotkor +kaloptr +kalopkotr +loptrko +loptkr +lopkor +lopkontr +lopkntr +lopntr +lopknotr diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g14.xml b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g14.xml new file mode 100644 index 000000000..0d8133c2e --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g14.xml @@ -0,0 +1,40 @@ + + + + LaOptPart + ABE + Main +abdegiklmnopqrstuwxyz + + Any + +Main +pk + +ko +PKpk +pc + +ka +PCpc +t + +t +Tt +r + +r +Rr +oq +n +OQoq + +T1slotT1 + +lopLOPlop +kamKAMkam +moMOmo + + + + diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g15.expected b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g15.expected new file mode 100644 index 000000000..0bc1ed36c --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g15.expected @@ -0,0 +1,18 @@ +lopkotr LOP.0+PK.0+R.0+T.0|lopkotr|[POS:B] +loptr - +lopkot LOP.0+PK.0+T.0|lopkot|[POS:B] +lopt LOP.0+T.0|lopt|[POS:B] +lopktr - +lopotr - +loptkor LOP.0+PK.0+R.0+T.0|loptkor|[POS:B] +lopkotkor - +kaloptr LOP.0+PC.0+R.0+T.0|kaloptr|[POS:B] +kalopkotr LOP.0+PC.0+PK.0+R.0+T.0|kalopkotr|[POS:B] +loptrko - +loptkr - +lopkor LOP.0+PK.0+R.0|lopkor|[POS:B] +olopktr LOP.0+PK.0+R.0+SW.0+T.0|olopktr|[POS:B] +olopkt LOP.0+PK.0+SW.0+T.0|olopkt|[POS:B] +klopotr - +aklopt - +akloptr - diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g15.words b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g15.words new file mode 100644 index 000000000..d8e0ba5c5 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g15.words @@ -0,0 +1,18 @@ +lopkotr +loptr +lopkot +lopt +lopktr +lopotr +loptkor +lopkotkor +kaloptr +kalopkotr +loptrko +loptkr +lopkor +olopktr +olopkt +klopotr +aklopt +akloptr diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g15.xml b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g15.xml new file mode 100644 index 000000000..5a2d82fb5 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g15.xml @@ -0,0 +1,40 @@ + + + + LaSwap + ABE + Main +abdegiklmnopqrstuwxyz + + Any + +Main +pk + +ko +PKpk +pc + +ka +PCpc +t + +t +Tt +r + +r +Rr +sw + +SWsw + +T1slotT1 + +lopLOPlop +kamKAMkam +moMOmo + + + + diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g16.expected b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g16.expected new file mode 100644 index 000000000..d097ca0ab --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g16.expected @@ -0,0 +1,18 @@ +lopkotr LOP.0+PK.0+R.0+T.0|lopkotr|[POS:B] +loptr - +lopkot KO.0+LOP.0+T.0|lopkot|[POS:B];LOP.0+PK.0+T.0|lopkot|[POS:B] +lopt LOP.0+T.0|lopt|[POS:B] +lopktr - +lopotr - +loptkor LOP.0+PK.0+R.0+T.0|loptkor|[POS:B] +lopkotkor KO.0+LOP.0+PK.0+R.0+T.0|lopkotkor|[POS:B] +kaloptr LOP.0+PC.0+R.0+T.0|kaloptr|[POS:B] +kalopkotr KO.0+LOP.0+PC.0+R.0+T.0|kalopkotr|[POS:B];LOP.0+PC.0+PK.0+R.0+T.0|kalopkotr|[POS:B] +loptrko - +loptkr - +lopkor LOP.0+PK.0+R.0|lopkor|[POS:B] +lopkomotr LOP.0+MO.0+PK.0+R.0+T.0|lopkomotr|[POS:B] +lopmotr - +lopkotr LOP.0+PK.0+R.0+T.0|lopkotr|[POS:B] +lopkokotr KO.0+LOP.0+PK.0+R.0+T.0|lopkokotr|[POS:B] +lopkomot LOP.0+MO.0+PK.0+T.0|lopkomot|[POS:B] diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g16.words b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g16.words new file mode 100644 index 000000000..2e1af36f0 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g16.words @@ -0,0 +1,18 @@ +lopkotr +loptr +lopkot +lopt +lopktr +lopotr +loptkor +lopkotkor +kaloptr +kalopkotr +loptrko +loptkr +lopkor +lopkomotr +lopmotr +lopkotr +lopkokotr +lopkomot diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g16.xml b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g16.xml new file mode 100644 index 000000000..401853d39 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g16.xml @@ -0,0 +1,42 @@ + + + + LaComp + ABE + Main +abdegiklmnopqrstuwxyz + + Any + +Main +pk + +ko +PKpk +pc + +ka +PCpc +t + +t +Tt +r + +r +Rr +cr + + + + +T1slotT1 + +lopLOPlop +kamKAMkam +moMOmo +koKOko + + + + diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g17.expected b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g17.expected new file mode 100644 index 000000000..28af542b1 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g17.expected @@ -0,0 +1,13 @@ +lopkotr LOP.0+PK.0+R.0+T.0|lopkotr|[POS:B] +loptr - +lopkot LOP.0+PK.0+T.0|lopkot|[POS:B] +lopt LOP.0+T.0|lopt|[POS:B] +lopktr - +lopotr - +loptkor - +lopkotkor - +kaloptr LOP.0+PC.0+R.0+T.0|kaloptr|[POS:B] +kalopkotr LOP.0+PC.0+PK.0+R.0+T.0|kalopkotr|[POS:B] +loptrko - +loptkr - +lopkor LOP.0+PK.0+R.0|lopkor|[POS:B] diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g17.words b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g17.words new file mode 100644 index 000000000..e7afb8792 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g17.words @@ -0,0 +1,13 @@ +lopkotr +loptr +lopkot +lopt +lopktr +lopotr +loptkor +lopkotkor +kaloptr +kalopkotr +loptrko +loptkr +lopkor diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g17.xml b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g17.xml new file mode 100644 index 000000000..e86b46225 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g17.xml @@ -0,0 +1,41 @@ + + + + LaDeep + ABE + Main +abdegiklmnopqrstuwxyz + + Any + +Deep +pk + +ko +PKpk +pc + +ka +PCpc + + +lopLOPlop +kamKAMkam +moMOmo + +Shallow +t + +t +Tt +r + +r +Rr + +T1slotT1 + + + + + diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g18.expected b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g18.expected new file mode 100644 index 000000000..28af542b1 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g18.expected @@ -0,0 +1,13 @@ +lopkotr LOP.0+PK.0+R.0+T.0|lopkotr|[POS:B] +loptr - +lopkot LOP.0+PK.0+T.0|lopkot|[POS:B] +lopt LOP.0+T.0|lopt|[POS:B] +lopktr - +lopotr - +loptkor - +lopkotkor - +kaloptr LOP.0+PC.0+R.0+T.0|kaloptr|[POS:B] +kalopkotr LOP.0+PC.0+PK.0+R.0+T.0|kalopkotr|[POS:B] +loptrko - +loptkr - +lopkor LOP.0+PK.0+R.0|lopkor|[POS:B] diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g18.words b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g18.words new file mode 100644 index 000000000..e7afb8792 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g18.words @@ -0,0 +1,13 @@ +lopkotr +loptr +lopkot +lopt +lopktr +lopotr +loptkor +lopkotkor +kaloptr +kalopkotr +loptrko +loptkr +lopkor diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g18.xml b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g18.xml new file mode 100644 index 000000000..378c1fc5f --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g18.xml @@ -0,0 +1,41 @@ + + + + LaBoth + ABE + Main +abdegiklmnopqrstuwxyz + + Any + +Deep +pk + +ko +PKpk + + +lopLOPlop +kamKAMkam +moMOmo + +Shallow +pc + +ka +PCpc +t + +t +Tt +r + +r +Rr + +T1slotT1 + + + + + diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g19.expected b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g19.expected new file mode 100644 index 000000000..2466498b4 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g19.expected @@ -0,0 +1,16 @@ +lopkotr - +loptr - +lopkot - +lopt LOP.0+T.0|lopt|[POS:B] +lopktr LOP.0+PK.0+R.0+T.0|lopktr|[POS:B] +lopotr - +loptkor LOP.0+PK.0+R.0+T.0|loptkor|[POS:B] +lopkotkor - +kaloptr LOP.0+PC.0+R.0+T.0|kaloptr|[POS:B] +kalopkotr - +loptrko - +loptkr - +lopkor LOP.0+PK.0+R.0|lopkor|[POS:B] +lopktr LOP.0+PK.0+R.0+T.0|lopktr|[POS:B] +lopkt LOP.0+PK.0+T.0|lopkt|[POS:B] +loptr - diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g19.words b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g19.words new file mode 100644 index 000000000..29c6fb45a --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g19.words @@ -0,0 +1,16 @@ +lopkotr +loptr +lopkot +lopt +lopktr +lopotr +loptkor +lopkotkor +kaloptr +kalopkotr +loptrko +loptkr +lopkor +lopktr +lopkt +loptr diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g19.xml b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g19.xml new file mode 100644 index 000000000..3e2d44261 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g19.xml @@ -0,0 +1,42 @@ + + + + LaPrule + ABE + Main +abdegiklmnopqrstuwxyz + + Any +del + + + + + +Main +pk + +ko +PKpk +pc + +ka +PCpc +t + +t +Tt +r + +r +Rr + +T1slotT1 + +lopLOPlop +kamKAMkam +moMOmo + + + + diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g19c.expected b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g19c.expected new file mode 100644 index 000000000..b7ca0a5c0 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g19c.expected @@ -0,0 +1,6 @@ +lipktr LIP.0+PK.0+R.0+T.0|lipktr|[POS:B] +lipkt LIP.0+PK.0+T.0|lipkt|[POS:B] +liptr - +lipkotr - +kaliptr LIP.0+PC.0+R.0+T.0|kaliptr|[POS:B] +liptkor LIP.0+PK.0+R.0+T.0|liptkor|[POS:B] diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g19c.words b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g19c.words new file mode 100644 index 000000000..941e4ef02 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g19c.words @@ -0,0 +1,6 @@ +lipktr +lipkt +liptr +lipkotr +kaliptr +liptkor diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g19c.xml b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g19c.xml new file mode 100644 index 000000000..36efd0195 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g19c.xml @@ -0,0 +1,42 @@ + + + + LaPrule + ABE + Main +abdegiklmnopqrstuwxyz + + Any +del + + + + + +Main +pk + +ko +PKpk +pc + +ka +PCpc +t + +t +Tt +r + +r +Rr + +T1slotT1 + +lipLIPlip +kamKAMkam +moMOmo + + + + diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g20.expected b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g20.expected new file mode 100644 index 000000000..892ff3434 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g20.expected @@ -0,0 +1,17 @@ +lopkotr LOP.0+PK.0+R.0+T.0|lopkotr|[POS:B] +loptr - +lopkot LOP.0+PK.0+T.0|lopkot|[POS:B] +lopt LOP.0+T.0|lopt|[POS:B] +lopktr - +lopotr - +loptkor LOP.0+PK.0+R.0+T.0|loptkor|[POS:B] +lopkotkor - +kaloptr LOP.0+PC.0+R.0+T.0|kaloptr|[POS:B] +kalopkotr LOP.0+PC.0+PK.0+R.0+T.0|kalopkotr|[POS:B] +loptrko - +loptkr - +lopkor LOP.0+PK.0+R.0|lopkor|[POS:B] +lopztr LOP.0+PZ.0+R.0+T.0|lopztr|[POS:B] +lopzt LOP.0+PZ.0+T.0|lopzt|[POS:B] +loptzr LOP.0+PZ.0+R.0+T.0|loptzr|[POS:B] +lopzkotr LOP.0+PK.0+PZ.0+R.0+T.0|lopzkotr|[POS:B] diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g20.words b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g20.words new file mode 100644 index 000000000..149a9c42d --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g20.words @@ -0,0 +1,17 @@ +lopkotr +loptr +lopkot +lopt +lopktr +lopotr +loptkor +lopkotkor +kaloptr +kalopkotr +loptrko +loptkr +lopkor +lopztr +lopzt +loptzr +lopzkotr diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g20.xml b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g20.xml new file mode 100644 index 000000000..b0998562d --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g20.xml @@ -0,0 +1,41 @@ + + + + LaTwo + ABE + Main +abdegiklmnopqrstuwxyz + + Any + +Main +pk + +ko +PKpk +pc + +ka +PCpc +pz + +z +PZpz +t + +t +Tt +r + +r +Rr + +T1slotT1 + +lopLOPlop +kamKAMkam +moMOmo + + + + diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g21.expected b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g21.expected new file mode 100644 index 000000000..b05ec684a --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g21.expected @@ -0,0 +1,18 @@ +lopqtr LOP.0+Q.0+R.0+T.0+Z.0|lopqtr|[POS:B];LOP.0+Q.0+R.0+T.0|lopqtr|[POS:B] +loptr LOP.0+R.0+T.0+Z.0|loptr|[POS:B] +loptqr LOP.0+Q.0+R.0+T.0+Z.0|loptqr|[POS:B];LOP.0+Q.0+R.0+T.0|loptqr|[POS:B] +loptrq LOP.0+Q.0+R.0+T.0+Z.0|loptrq|[POS:B] +lopqtmo LOP.0+MO.0+Q.0+T.0+Z.0|lopqtmo|[POS:B];LOP.0+MO.0+Q.0+T.0|lopqtmo|[POS:B] +loptmo LOP.0+MO.0+T.0+Z.0|loptmo|[POS:B] +lopqtrq - +lopwtrq LOP.0+Q.0+R.0+T.0+W.0+Z.0|lopwtrq|[POS:B];LOP.0+Q.0+R.0+T.0+W.0|lopwtrq|[POS:B] +lopwtrw - +kamdqtr D.0+KAM.0+Q.0+R.0+T.0+Z.0|kamdqtr|[POS:B];D.0+KAM.0+Q.0+R.0+T.0|kamdqtr|[POS:B] +kamqdtr D.0+KAM.0+Q.0+R.0+T.0+Z.0|kamqdtr|[POS:B];D.0+KAM.0+Q.0+R.0+T.0|kamqdtr|[POS:B] +kamdtr D.0+KAM.0+R.0+T.0+Z.0|kamdtr|[POS:B] +kamdtqr D.0+KAM.0+Q.0+R.0+T.0+Z.0|kamdtqr|[POS:B];D.0+KAM.0+Q.0+R.0+T.0|kamdtqr|[POS:B] +lopt LOP.0+T.0+Z.0|lopt|[POS:B];LOP.0+T.0|lopt|[POS:B] +lopqt LOP.0+Q.0+T.0+Z.0|lopqt|[POS:B];LOP.0+Q.0+T.0|lopqt|[POS:B] +loptq LOP.0+Q.0+T.0+Z.0|loptq|[POS:B];LOP.0+Q.0+T.0|loptq|[POS:B] +lopqtrmo LOP.0+MO.0+Q.0+R.0+T.0+Z.0|lopqtrmo|[POS:B];LOP.0+MO.0+Q.0+R.0+T.0|lopqtrmo|[POS:B] +lopzqtmo - diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g21.words b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g21.words new file mode 100644 index 000000000..54e4ea2d5 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g21.words @@ -0,0 +1,18 @@ +lopqtr +loptr +loptqr +loptrq +lopqtmo +loptmo +lopqtrq +lopwtrq +lopwtrw +kamdqtr +kamqdtr +kamdtr +kamdtqr +lopt +lopqt +loptq +lopqtrmo +lopzqtmo diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g21.xml b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g21.xml new file mode 100644 index 000000000..66247204d --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g21.xml @@ -0,0 +1,49 @@ + + + + AdvOblig + ABE + Main +abdegiklmnopqrstuwxyz + + Any + +Main +z + + +Zz +q + +q +Qq +w + +w +Ww +d + +d +Dd +r + +r +Rr +t + +t +Tt +cr + + + + +T1slotT1 + +kamKAMkam +lopLOPlop +moMOmo + + + + diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g6.expected b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g6.expected new file mode 100644 index 000000000..04c4b743b --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g6.expected @@ -0,0 +1,17 @@ +lopqtr LOP.0+Q.0+R.0+T.0|lopqtr|[POS:B] +loptr - +loptqr LOP.0+Q.0+R.0+T.0|loptqr|[POS:B] +loptrq - +lopqtmo LOP.0+MO.0+Q.0+T.0|lopqtmo|[POS:B] +loptmo - +lopqtrq - +lopwtrq LOP.0+Q.0+R.0+T.0+W.0|lopwtrq|[POS:B] +lopwtrw - +kamdqtr D.0+KAM.0+Q.0+R.0+T.0|kamdqtr|[POS:B] +kamqdtr D.0+KAM.0+Q.0+R.0+T.0|kamqdtr|[POS:B] +kamdtr - +kamdtqr D.0+KAM.0+Q.0+R.0+T.0|kamdtqr|[POS:B] +lopt LOP.0+T.0|lopt|[POS:B] +lopqt LOP.0+Q.0+T.0|lopqt|[POS:B] +loptq LOP.0+Q.0+T.0|loptq|[POS:B] +lopqtrmo LOP.0+MO.0+Q.0+R.0+T.0|lopqtrmo|[POS:B] diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g6.words b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g6.words new file mode 100644 index 000000000..e6f62e331 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g6.words @@ -0,0 +1,17 @@ +lopqtr +loptr +loptqr +loptrq +lopqtmo +loptmo +lopqtrq +lopwtrq +lopwtrw +kamdqtr +kamqdtr +kamdtr +kamdtqr +lopt +lopqt +loptq +lopqtrmo diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g6.xml b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g6.xml new file mode 100644 index 000000000..6b6dff2dc --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g6.xml @@ -0,0 +1,45 @@ + + + + AdvOblig + ABE + Main +abdegiklmnopqrstuwxyz + + Any + +Main +q + +q +Qq +w + +w +Ww +d + +d +Dd +r + +r +Rr +t + +t +Tt +cr + + + + +T1slotT1 + +kamKAMkam +lopLOPlop +moMOmo + + + + diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g6b.expected b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g6b.expected new file mode 100644 index 000000000..20a6ff4f0 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g6b.expected @@ -0,0 +1,10 @@ +lopqtr LOP.0+Q.0+R.0+T.0|lopqtr|[POS:B] +loptr - +lopwtr LOP.0+R.0+T.0+W.0|lopwtr|[POS:B] +kamdqtr D.0+KAM.0+Q.0+R.0+T.0|kamdqtr|[POS:B] +kamqdtr D.0+KAM.0+Q.0+R.0+T.0|kamqdtr|[POS:B] +kamdtr - +lopt LOP.0+T.0|lopt|[POS:B] +lopqt LOP.0+Q.0+T.0|lopqt|[POS:B] +lopqtmo - +loptmo - diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g6b.words b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g6b.words new file mode 100644 index 000000000..ffd82196f --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g6b.words @@ -0,0 +1,10 @@ +lopqtr +loptr +lopwtr +kamdqtr +kamqdtr +kamdtr +lopt +lopqt +lopqtmo +loptmo diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g6b.xml b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g6b.xml new file mode 100644 index 000000000..8449259ce --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g6b.xml @@ -0,0 +1,49 @@ + + + + AdvOblig2 + ABE + Main +abdegiklmnopqrstuwxyz + + Any + +Deep +q + +q +Qq +w + +w +Ww +d + +d +Dd + + +kamKAMkam +lopLOPlop +moMOmo + +Shallow +r + +r +Rr +t + +t +Tt +cr + + + + +T1slotT1 + + + + + diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g7.expected b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g7.expected new file mode 100644 index 000000000..206a9b192 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g7.expected @@ -0,0 +1,8 @@ +loptr LOP.0+R.0+T.0|loptr|[POS:B] +lopt LOP.0+T.0|lopt|[POS:B] +lopqtr LOP.0+Q.0+R.0+T.0|lopqtr|[POS:B] +loptqr LOP.0+Q.0+R.0+T.0|loptqr|[POS:B] +aloptr LOP.0+P.0+R.0+T.0|aloptr|[POS:B] +alopt LOP.0+P.0+T.0|alopt|[POS:B] +lopr LOP.0+R.0|lopr|[POS:B] +alopqtr LOP.0+P.0+Q.0+R.0+T.0|alopqtr|[POS:B] diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g7.words b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g7.words new file mode 100644 index 000000000..b7dfd3466 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g7.words @@ -0,0 +1,8 @@ +loptr +lopt +lopqtr +loptqr +aloptr +alopt +lopr +alopqtr diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g7.xml b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g7.xml new file mode 100644 index 000000000..63ab4ab1c --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g7.xml @@ -0,0 +1,38 @@ + + + + AdvShared + AB + Main +abdegiklmnopqrstuwxyz + + Any + +Main +q + +q +Qq +r + +r +Rr +t + +t +Tt +p + +a +Pp + +T1slotT1 +T2slotT2 +T3slotT3 + +kamKAMkam +lopLOPlop + + + + diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g8.expected b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g8.expected new file mode 100644 index 000000000..5db241d06 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g8.expected @@ -0,0 +1,24 @@ +kamd - +kamt KAMB.0+T.0|kamt|[POS:B] +kamdt D.0+KAM.0+T.0|kamdt|[POS:B] +kamet E.0+KAM.0+T.0|kamet|[POS:B];E.0+KAMB.0+T.0|kamet|[POS:B] +kamu KAMB.0+U.0|kamu|[POS:B] +kamut KAMB.0+T.0+U.0|kamut|[POS:B] +lopt LOP.0+T.0|lopt|[POS:B] +lopu LOP.0+U.0|lopu|[POS:B] +nukx NUK.0+X.0|nukx|[POS:C] +kamx KAM.0+X.0|kamx|[POS:A] +lopx - +akamt KAMB.0+P.0+T.0|akamt|[POS:B] +akamdt D.0+KAM.0+P.0+T.0|akamdt|[POS:B] +alopt LOP.0+P.0+T.0|alopt|[POS:B] +kammo - +lopmo - +kamdmo - +pat - +pau PA.0+U.0|pau|ANY +pad D.0+PA.0|pad|[POS:B] +nukqx NUK.0+Q.0+X.0|nukqx|[POS:C] +nukxq NUK.0+Q.0+X.0|nukxq|[POS:C] +kamtd - +nuket E.0+NUK.0+T.0|nuket|[POS:B] diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g8.words b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g8.words new file mode 100644 index 000000000..c1c4dd165 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g8.words @@ -0,0 +1,24 @@ +kamd +kamt +kamdt +kamet +kamu +kamut +lopt +lopu +nukx +kamx +lopx +akamt +akamdt +alopt +kammo +lopmo +kamdmo +pat +pau +pad +nukqx +nukxq +kamtd +nuket diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g8.xml b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g8.xml new file mode 100644 index 000000000..ff3b32366 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/TestData/PartialPrune/g8.xml @@ -0,0 +1,59 @@ + + + + AdvGate + ABCE + Main +abdegiklmnopqrstuwxyz + + Any + +Main +d + +d +Dd +e + +e +Ee +t + +t +Tt +u + +u +Uu +x + +x +Xx +p + +a +Pp +cr + + + +q + +q +Qq + +T1slotT1 +T2slotT2 +T3slotT3 +T4slotT4 + +kamKAMkam +kamKAMBkamb +lopLOPlop +nukNUKnuk +moMOmo +paPApa + + + +