Skip to content
Draft
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
20 changes: 19 additions & 1 deletion src/SIL.Machine.Morphology.HermitCrab/AffixTemplate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public class AffixTemplate : HCRuleBase
private Stratum _stratum;
private readonly ObservableCollection<AffixTemplateSlot> _slots;

private bool _isFinal;

/// <summary>
/// Initializes a new instance of the <see cref="AffixTemplate"/> class.
/// </summary>
Expand All @@ -37,6 +39,7 @@ private void SlotsChanged(object sender, NotifyCollectionChangedEventArgs e)
{
rule.Stratum = null;
rule.IsTemplateRule = false;
rule.IsFinalTemplateRule = false;
}
}
}
Expand All @@ -48,14 +51,29 @@ private void SlotsChanged(object sender, NotifyCollectionChangedEventArgs e)
{
rule.Stratum = Stratum;
rule.IsTemplateRule = true;
rule.IsFinalTemplateRule = IsFinal;
}
}
}
}

public FeatureStruct RequiredSyntacticFeatureStruct { get; set; }

public bool IsFinal { get; set; }
public bool IsFinal
{
get { return _isFinal; }
set
{
_isFinal = value;
foreach (AffixTemplateSlot slot in Slots)
{
foreach (MorphemicMorphologicalRule rule in slot.Rules)
{
rule.IsFinalTemplateRule = value;
}
}
}
}

public IList<AffixTemplateSlot> Slots
{
Expand Down
5 changes: 5 additions & 0 deletions src/SIL.Machine.Morphology.HermitCrab/AnalysisStateKey.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ namespace SIL.Machine.Morphology.HermitCrab
private readonly FeatureStruct _realizationalFS;
private readonly int _nonHeadCount;
private readonly IReadOnlyDictionary<IMorphologicalRule, int> _ruleCounts;
private readonly bool? _isLastUnappliedRuleNonTemplate;
private readonly int _hashCode;

/// <summary>
Expand Down Expand Up @@ -62,6 +63,7 @@ private AnalysisStateKey(Word word)
_realizationalFS = word.RealizationalFeatureStruct;
_nonHeadCount = word.NonHeadCount;
_ruleCounts = word.UnappliedRuleCounts;
_isLastUnappliedRuleNonTemplate = word.IsLastUnappliedRuleNonTemplate;

// See PinAndKey for why the key pins these rather than just reading them.
_shape.Freeze();
Expand All @@ -74,6 +76,7 @@ private AnalysisStateKey(Word word)
hash = hash * 31 + _syntacticFS.GetFrozenHashCode();
hash = hash * 31 + _realizationalFS.GetFrozenHashCode();
hash = hash * 31 + _nonHeadCount;
hash = hash * 31 + _isLastUnappliedRuleNonTemplate.GetHashCode();
if (_ruleCounts != null)
{
// XOR rather than the usual *31 rolling combine: the multiset is unordered, so entries
Expand All @@ -100,6 +103,8 @@ public bool Equals(AnalysisStateKey other)
return false;
if (!_syntacticFS.ValueEquals(other._syntacticFS) || !_realizationalFS.ValueEquals(other._realizationalFS))
return false;
if (_isLastUnappliedRuleNonTemplate != other._isLastUnappliedRuleNonTemplate)
return false;
return RuleCountsEqual(_ruleCounts, other._ruleCounts);
}

Expand Down
7 changes: 7 additions & 0 deletions src/SIL.Machine.Morphology.HermitCrab/ITraceManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ public interface ITraceManager

void MorphologicalRuleUnapplied(IMorphologicalRule rule, int subruleIndex, Word input, Word output);
void MorphologicalRuleNotUnapplied(IMorphologicalRule rule, int subruleIndex, Word input);
void MorphologicalRuleNotUnapplied(
IMorphologicalRule rule,
int subruleIndex,
Word input,
FailureReason reason,
object failureObj
);

void CompoundingRuleNotUnapplied(
IMorphologicalRule rule,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ public abstract class MorphemicMorphologicalRule : Morpheme, IMorphologicalRule
{
public string Name { get; set; }
public bool IsTemplateRule { get; set; }
public bool IsFinalTemplateRule { get; set; }

public override MorphemeType MorphemeType
{
Expand Down
17 changes: 17 additions & 0 deletions src/SIL.Machine.Morphology.HermitCrab/Morpher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,18 @@ public Morpher(ITraceManager traceManager, Language lang, int maxDegreeOfParalle
RuleSelector = rule => true;

_morphemes = new ReadOnlyObservableCollection<Morpheme>(morphemes);
IsPartial = GetPartialMorphemes().Count() > 0;
}

public IEnumerable<Morpheme> GetPartialMorphemes()
{
var morphemes = new HashSet<Morpheme>();
foreach (Morpheme morpheme in _morphemes)
{
if (morpheme.IsPartial)
morphemes.Add(morpheme);
}
return morphemes;
}

public ITraceManager TraceManager
Expand All @@ -88,6 +100,11 @@ public ITraceManager TraceManager
/// </summary>
public bool MergeEquivalentAnalyses { get; set; }

/// <summary>
/// A Morpher is partial if any of the elements are partial.
/// </summary>
public bool IsPartial { get; set; }

/// <summary>
/// Caps the concurrency used within a single parse or generation -- analysis cascade,
/// affix-template unapplication and synthesis alike. A value of 1 runs the work fully
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,23 @@ public IEnumerable<Word> Apply(Word input)
return Enumerable.Empty<Word>();
}

// Do not allow a final template to unapply if the grammar is not partial
// and a non-template was last unapplied.
if (!_morpher.IsPartial && _rule.IsFinalTemplateRule && input.IsLastUnappliedRuleNonTemplate == true)
{
if (_morpher.TraceManager.IsTracing)
{
_morpher.TraceManager.MorphologicalRuleNotUnapplied(
_rule,
-1,
input,
FailureReason.NonPartialRuleProhibitedAfterFinalTemplate,
null
);
}
return Enumerable.Empty<Word>();
}

var output = new List<Word>();
for (int i = 0; i < _rules.Count; i++)
{
Expand Down
18 changes: 18 additions & 0 deletions src/SIL.Machine.Morphology.HermitCrab/TraceManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,24 @@ public void MorphologicalRuleNotUnapplied(IMorphologicalRule rule, int subruleIn
);
}

public void MorphologicalRuleNotUnapplied(
IMorphologicalRule rule,
int subruleIndex,
Word input,
FailureReason reason,
object failureObj
)
{
((Trace)input.CurrentTrace).Children.Add(
new Trace(TraceType.MorphologicalRuleAnalysis, rule)
{
SubruleIndex = subruleIndex,
Input = input,
FailureReason = reason,
}
);
}

public void CompoundingRuleNotUnapplied(
IMorphologicalRule rule,
int subruleIndex,
Expand Down
20 changes: 19 additions & 1 deletion src/SIL.Machine.Morphology.HermitCrab/Word.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public class Word : Freezable<Word>, IAnnotatedData<ShapeNode>, ICloneable<Word>
private FeatureStruct _realizationalFS;
private Stratum _stratum;
private bool? _isLastAppliedRuleFinal;
private bool? _isLastUnappliedRuleNonTemplate;
private bool _isPartial;
private readonly Dictionary<string, HashSet<int>> _disjunctiveAllomorphIndices;
private int _mruleAppCount = 0;
Expand All @@ -47,6 +48,7 @@ public Word(RootAllomorph rootAllomorph, FeatureStruct realizationalFS)
_nonHeadApps = new List<Word>();
_obligatorySyntacticFeatures = new IDBearerSet<Feature>();
_isLastAppliedRuleFinal = null;
_isLastUnappliedRuleNonTemplate = null;
_disjunctiveAllomorphIndices = new Dictionary<string, HashSet<int>>();
}

Expand All @@ -65,6 +67,7 @@ public Word(Stratum stratum, Shape shape)
_nonHeadApps = new List<Word>();
_obligatorySyntacticFeatures = new IDBearerSet<Feature>();
_isLastAppliedRuleFinal = null;
_isLastUnappliedRuleNonTemplate = null;
_isPartial = false;
_disjunctiveAllomorphIndices = new Dictionary<string, HashSet<int>>();
}
Expand Down Expand Up @@ -93,6 +96,7 @@ private Word(Word word, bool cloneNonHeadApps)
_nonHeadAppIndex = word._nonHeadAppIndex;
_obligatorySyntacticFeatures = new IDBearerSet<Feature>(word._obligatorySyntacticFeatures);
_isLastAppliedRuleFinal = word._isLastAppliedRuleFinal;
_isLastUnappliedRuleNonTemplate = word._isLastUnappliedRuleNonTemplate;
_isPartial = word._isPartial;
CurrentTrace = word.CurrentTrace;
AnalysisScope = word.AnalysisScope;
Expand Down Expand Up @@ -346,6 +350,8 @@ internal void MorphologicalRuleUnapplied(IMorphologicalRule mrule)
_mruleApps.Add(mrule);
_mruleAppIndex++;
}
_isLastUnappliedRuleNonTemplate =
(mrule is MorphemicMorphologicalRule morphRule) && !morphRule.IsTemplateRule;
}

/// <summary>
Expand Down Expand Up @@ -392,6 +398,16 @@ internal bool? IsLastAppliedRuleFinal
}
}

internal bool? IsLastUnappliedRuleNonTemplate
{
get { return _isLastUnappliedRuleNonTemplate; }
set
{
CheckFrozen();
_isLastUnappliedRuleNonTemplate = value;
}
}

/// <summary>
/// Gets the number of times the specified morphological rule has been applied.
/// </summary>
Expand Down Expand Up @@ -621,6 +637,7 @@ protected override int FreezeImpl()
code = code * 31 + _mruleApps.GetSequenceHashCode();
code = code * 31 + _mruleAppIndex.GetHashCode();
code = code * 31 + _isLastAppliedRuleFinal.GetHashCode();
code = code * 31 + _isLastUnappliedRuleNonTemplate.GetHashCode();
return code;
}

Expand All @@ -640,7 +657,8 @@ public override bool ValueEquals(Word other)
&& _rootAllomorph == other._rootAllomorph
&& _mruleApps.SequenceEqual(other._mruleApps)
&& _mruleAppIndex == other._mruleAppIndex
&& _isLastAppliedRuleFinal == other._isLastAppliedRuleFinal;
&& _isLastAppliedRuleFinal == other._isLastAppliedRuleFinal
&& _isLastUnappliedRuleNonTemplate == other._isLastUnappliedRuleNonTemplate;
}

public Word Clone()
Expand Down
Loading
Loading