Skip to content

Commit d088fce

Browse files
committed
Add MergeEquivalentAnalyses
1 parent c304a75 commit d088fce

File tree

3 files changed

+77
-3
lines changed

3 files changed

+77
-3
lines changed

src/SIL.Machine.Morphology.HermitCrab/AnalysisStratumRule.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@ public IEnumerable<Word> Apply(Word input)
7272

7373
_prulesRule.Apply(input);
7474
input.Freeze();
75+
IDictionary<Shape, Word> shapeWord = null;
76+
// Don't merge if tracing because it messes up the tracing.
77+
bool mergeEquivalentAnalyses = _morpher.MergeEquivalentAnalyses && !_morpher.TraceManager.IsTracing;
78+
if (mergeEquivalentAnalyses)
79+
shapeWord = new Dictionary<Shape, Word>(FreezableEqualityComparer<Shape>.Default);
7580

7681
// AnalysisStratumRule.Apply should cover the inverse of SynthesisStratumRule.Apply.
7782
IEnumerable<Word> mruleOutWords = ApplyTemplates(input).Concat(ApplyMorphologicalRules(input));
@@ -82,6 +87,16 @@ public IEnumerable<Word> Apply(Word input)
8287
_morpher.TraceManager.EndUnapplyStratum(_stratum, input);
8388
foreach (Word mruleOutWord in mruleOutWords)
8489
{
90+
if (mergeEquivalentAnalyses)
91+
{
92+
Shape shape = mruleOutWord.Shape;
93+
if (shapeWord.ContainsKey(shape))
94+
{
95+
shapeWord[shape].Alternatives.Add(mruleOutWord);
96+
continue;
97+
}
98+
shapeWord[shape] = mruleOutWord;
99+
}
85100
output.Add(mruleOutWord);
86101
if (_morpher.TraceManager.IsTracing)
87102
_morpher.TraceManager.EndUnapplyStratum(_stratum, mruleOutWord);

src/SIL.Machine.Morphology.HermitCrab/Morpher.cs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ public Morpher(ITraceManager traceManager, Language lang)
5656
_synthesisRule = lang.CompileSynthesisRule(this);
5757
MaxStemCount = 2;
5858
MaxUnapplications = 0;
59+
MergeEquivalentAnalyses = true;
5960
LexEntrySelector = entry => true;
6061
RuleSelector = rule => true;
6162

@@ -78,6 +79,12 @@ public ITraceManager TraceManager
7879
/// </summary>
7980
public int MaxUnapplications { get; set; }
8081

82+
/// <summary>
83+
/// Merge analyses that have equivalent shapes.
84+
/// Merged analyses will be expanded if lexical lookup succeeds.
85+
/// </summary>
86+
public bool MergeEquivalentAnalyses { get; set; }
87+
8188
public Func<LexEntry, bool> LexEntrySelector { get; set; }
8289
public Func<IHCRule, bool> RuleSelector { get; set; }
8390

@@ -304,10 +311,13 @@ private IEnumerable<Word> Synthesize(string word, ConcurrentQueue<Word> analyses
304311
analyses.TryDequeue(out Word analysisWord);
305312
foreach (Word synthesisWord in LexicalLookup(analysisWord))
306313
{
307-
foreach (Word validWord in _synthesisRule.Apply(synthesisWord).Where(IsWordValid))
314+
foreach (Word alternativeSynthesis in synthesisWord.ExpandAlternatives())
308315
{
309-
if (IsMatch(word, validWord))
310-
matches.Add(validWord);
316+
foreach (Word validWord in _synthesisRule.Apply(alternativeSynthesis).Where(IsWordValid))
317+
{
318+
if (IsMatch(word, validWord))
319+
matches.Add(validWord);
320+
}
311321
}
312322
}
313323
}

src/SIL.Machine.Morphology.HermitCrab/Word.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ public class Word : Freezable<Word>, IAnnotatedData<ShapeNode>, ICloneable<Word>
3131
private bool _isPartial;
3232
private readonly Dictionary<string, HashSet<int>> _disjunctiveAllomorphIndices;
3333
private int _mruleAppCount = 0;
34+
private readonly Word _cloneOf = null;
35+
private readonly IList<Word> _alternatives = new List<Word>();
3436

3537
public Word(RootAllomorph rootAllomorph, FeatureStruct realizationalFS)
3638
{
@@ -92,6 +94,7 @@ protected Word(Word word)
9294
kvp => new HashSet<int>(kvp.Value)
9395
);
9496
_mruleAppCount = word._mruleAppCount;
97+
_cloneOf = word;
9598
}
9699

97100
public IEnumerable<Annotation<ShapeNode>> Morphs
@@ -396,6 +399,52 @@ internal void NonHeadUnapplied(Word nonHead)
396399
_nonHeadAppIndex++;
397400
}
398401

402+
internal Word CloneOf
403+
{
404+
get { return _cloneOf; }
405+
}
406+
407+
internal IList<Word> Alternatives
408+
{
409+
get { return _alternatives; }
410+
}
411+
412+
internal IList<Word> ExpandAlternatives()
413+
{
414+
IList<Word> alternatives = new List<Word>();
415+
IList<Word> originals = _cloneOf?.ExpandAlternatives();
416+
// Update the alternatives of _cloneOf with any changes made since the clone.
417+
if (originals == null || originals.Count < 2)
418+
{
419+
// Special case.
420+
alternatives.Add(this);
421+
}
422+
else
423+
{
424+
foreach (Word original in originals)
425+
{
426+
Word alternative = original.Clone();
427+
alternative._shape = this.Shape;
428+
// Add new rules to alternative.
429+
foreach (IMorphologicalRule rule in MorphologicalRules)
430+
{
431+
if (_cloneOf != null && _cloneOf.MorphologicalRules.Contains(rule))
432+
continue;
433+
alternative.MorphologicalRuleUnapplied(rule);
434+
}
435+
if (RootAllomorph != null)
436+
alternative.RootAllomorph = RootAllomorph;
437+
alternative.Freeze();
438+
alternatives.Add(alternative);
439+
}
440+
441+
}
442+
// Add local alternatives.
443+
foreach (Word alternative in _alternatives)
444+
alternatives.AddRange(alternative.ExpandAlternatives());
445+
return alternatives;
446+
}
447+
399448
public Allomorph GetAllomorph(Annotation<ShapeNode> morph)
400449
{
401450
var alloID = (string)morph.FeatureStruct.GetValue(HCFeatureSystem.Allomorph);

0 commit comments

Comments
 (0)