Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/SIL.Machine.Morphology.HermitCrab/Morpher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ namespace SIL.Machine.Morphology.HermitCrab
{
public class Morpher : IMorphologicalAnalyzer, IMorphologicalGenerator
{
internal bool EdgePrefilterEnabled { get; set; } = true;

// Called from analysis threads, so a handler must be thread-safe.
internal Action EdgePrefilterRejected { get; set; }
Comment thread
claude[bot] marked this conversation as resolved.
Resolved

private readonly Language _lang;
private readonly IRule<Word, ShapeNode> _analysisRule;
private readonly IRule<Word, ShapeNode> _synthesisRule;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using SIL.Machine.Annotations;
using SIL.Machine.FeatureModel;
using SIL.Machine.Matching;
using SIL.Machine.Rules;

Expand All @@ -14,8 +15,13 @@ public AnalysisAffixProcessAllomorphRuleSpec(AffixProcessAllomorph allomorph)
_allomorph = allomorph;
Pattern.Acceptable = CopyAgreementCheck;
Pattern.Freeze();
LeftEdgeConstraint = (Pattern.Children.First as Constraint<Word, ShapeNode>)?.FeatureStruct;
Comment thread
claude[bot] marked this conversation as resolved.
Resolved
RightEdgeConstraint = (Pattern.Children.Last as Constraint<Word, ShapeNode>)?.FeatureStruct;
}

internal FeatureStruct LeftEdgeConstraint { get; }
internal FeatureStruct RightEdgeConstraint { get; }

public override Word ApplyRhs(PatternRule<Word, ShapeNode> rule, Match<Word, ShapeNode> match)
{
Word output = match.Input.Clone();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public class AnalysisAffixProcessRule : IRule<Word, ShapeNode>
private readonly Morpher _morpher;
private readonly AffixProcessRule _rule;
private readonly List<PatternRule<Word, ShapeNode>> _rules;
private readonly List<AnalysisAffixProcessAllomorphRuleSpec> _ruleSpecs;
private readonly FeatureStruct _outputFS;

public AnalysisAffixProcessRule(Morpher morpher, AffixProcessRule rule)
Expand All @@ -26,11 +27,14 @@ public AnalysisAffixProcessRule(Morpher morpher, AffixProcessRule rule)
_outputFS.Freeze();

_rules = new List<PatternRule<Word, ShapeNode>>();
_ruleSpecs = new List<AnalysisAffixProcessAllomorphRuleSpec>();
foreach (AffixProcessAllomorph allo in rule.Allomorphs)
{
var spec = new AnalysisAffixProcessAllomorphRuleSpec(allo) { PruningMorpher = morpher };
_ruleSpecs.Add(spec);
_rules.Add(
new MultiplePatternRule<Word, ShapeNode>(
new AnalysisAffixProcessAllomorphRuleSpec(allo) { PruningMorpher = morpher },
spec,
new MatcherSettings<ShapeNode>
{
Filter = ann => ann.Type() == HCFeatureSystem.Segment,
Expand All @@ -44,6 +48,22 @@ public AnalysisAffixProcessRule(Morpher morpher, AffixProcessRule rule)
}
}

private static ShapeNode FindEdge(Shape shape, bool first)
{
ShapeNode node = first ? shape.First : shape.Last;
ShapeNode end = first ? shape.End : shape.Begin;
while (node != null && node != end && node.Type() != HCFeatureSystem.Segment)
node = first ? node.Next : node.Prev;
return node == end ? null : node;
}

// The matcher can skip optional annotations, so only a mandatory edge can reject a match.
private static bool EdgePasses(FeatureStruct constraint, ShapeNode node) =>
constraint == null
|| node == null
|| node.Annotation.Optional
|| node.Annotation.FeatureStruct.IsUnifiable(constraint, false, null);

public IEnumerable<Word> Apply(Word input)
{
if (!_morpher.RuleSelector(_rule))
Expand All @@ -57,9 +77,24 @@ public IEnumerable<Word> Apply(Word input)
return Enumerable.Empty<Word>();
}

ShapeNode first = _morpher.EdgePrefilterEnabled ? FindEdge(input.Shape, true) : null;
ShapeNode last = _morpher.EdgePrefilterEnabled ? FindEdge(input.Shape, false) : null;
var output = new List<Word>();
for (int i = 0; i < _rules.Count; i++)
{
if (
Comment thread
claude[bot] marked this conversation as resolved.
Resolved
_morpher.EdgePrefilterEnabled
&& (
!EdgePasses(_ruleSpecs[i].LeftEdgeConstraint, first)
|| !EdgePasses(_ruleSpecs[i].RightEdgeConstraint, last)
)
)
{
_morpher.EdgePrefilterRejected?.Invoke();
if (_morpher.TraceManager.IsTracing)
_morpher.TraceManager.MorphologicalRuleNotUnapplied(_rule, i, input);
continue;
}
bool unapplied = false;
foreach (Word outWord in _rules[i].Apply(input).RemoveDuplicates())
{
Expand Down
Loading
Loading