Skip to content
Merged
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
246 changes: 123 additions & 123 deletions Machine.sln

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd
Original file line number Diff line number Diff line change
Expand Up @@ -371,8 +371,11 @@
nonheadPartsOfSpeech refers to one or more PartOfSpeech IDs
headSubcategorizedRules refers to one or more SyntacticRule IDs
nonheadSubcategorizedRules refers to one or more SyntacticRule IDs
headProdRestrictionsMprFeatures refers to zero or more exception "features" IDs
nonHeadProdRestrictionsMprFeatures refers to zero or more exception "features" IDs
outputPartOfSpeech refers to a PartOfSpeech ID
outputSubcategorization refers to one or more SyntacticRule IDs
outputProdRestrictionsMprFeatures refers to zero or more exception "features" IDs
outputObligatoryFeatures refers to one or more (HeadFeature) FeatureDefinition IDs
(Note: what was Output Subcategorization (sub) in the text form of Hermit Crab has been split into
the outputSubcategorization attribute plus the OutputSubcategorizationOverrides element (and its content).)
Expand All @@ -388,8 +391,11 @@
nonHeadPartsOfSpeech IDREFS #IMPLIED
headSubcategorizedRules IDREFS #IMPLIED
nonHeadSubcategorizedRules IDREFS #IMPLIED
headProdRestrictionsMprFeatures IDREFS #IMPLIED
nonHeadProdRestrictionsMprFeatures IDREFS #IMPLIED
outputPartOfSpeech IDREF #IMPLIED
outputSubcategorization IDREFS #IMPLIED
outputProdRestrictionsMprFeatures IDREFS #IMPLIED
outputObligatoryFeatures IDREFS #IMPLIED
>

Expand Down
18 changes: 18 additions & 0 deletions src/SIL.Machine.Morphology.HermitCrab/ITraceManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ public enum FailureReason
RequiredSyntacticFeatureStruct,
HeadRequiredSyntacticFeatureStruct,
NonHeadRequiredSyntacticFeatureStruct,
HeadProdRestrictMprFeatures,
NonHeadProdRestrictMprFeatures,
RequiredMprFeatures,
ExcludedMprFeatures,
RequiredStemName,
Expand Down Expand Up @@ -46,6 +48,22 @@ public interface ITraceManager
void MorphologicalRuleUnapplied(IMorphologicalRule rule, int subruleIndex, Word input, Word output);
void MorphologicalRuleNotUnapplied(IMorphologicalRule rule, int subruleIndex, Word input);

void CompoundingRuleNotUnapplied(
IMorphologicalRule rule,
int subruleIndex,
Word input,
FailureReason reason,
object failureObj
);

void CompoundingRuleNotApplied(
IMorphologicalRule rule,
int subruleIndex,
Word input,
FailureReason reason,
object failureObj
);

void LexicalLookup(Stratum stratum, Word input);

void SynthesizeWord(Language lang, Word input);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,28 @@ RootAllomorph allo in _morpher.SearchRootAllomorphs(_rule.Stratum, outWord.Curre
{
continue;
}
// make sure any productivity restrictions on the stem are in the set the member has
if (
!_rule.NonHeadProdRestrictionsMprFeatures.CompoundMprFeaturesMatch(
((LexEntry)allo.Morpheme).MprFeatures
)
)
{
if (_morpher.TraceManager.IsTracing)
{
Word tempInput = outWord.Clone();
tempInput.CurrentNonHead.RootAllomorph = allo;
tempInput.CurrentTrace = input.CurrentTrace;
_morpher.TraceManager.CompoundingRuleNotUnapplied(
_rule,
-1,
tempInput,
FailureReason.NonHeadProdRestrictMprFeatures,
((LexEntry)allo.Morpheme).MprFeatures
);
}
continue;
}

// check to see if this is a duplicate of another output analysis, this is not strictly necessary, but
// it helps to reduce the search space
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ public CompoundingRule()
Blockable = true;
HeadRequiredSyntacticFeatureStruct = FeatureStruct.New().Value;
NonHeadRequiredSyntacticFeatureStruct = FeatureStruct.New().Value;
HeadProdRestrictionsMprFeatures = new MprFeatureSet();
NonHeadProdRestrictionsMprFeatures = new MprFeatureSet();
OutputProdRestrictionsMprFeatures = new MprFeatureSet();
OutSyntacticFeatureStruct = FeatureStruct.New().Value;

_subrules = new List<CompoundingSubrule>();
Expand All @@ -40,6 +43,12 @@ public IList<CompoundingSubrule> Subrules

public FeatureStruct NonHeadRequiredSyntacticFeatureStruct { get; set; }

public MprFeatureSet HeadProdRestrictionsMprFeatures { get; set; }

public MprFeatureSet NonHeadProdRestrictionsMprFeatures { get; set; }

public MprFeatureSet OutputProdRestrictionsMprFeatures { get; set; }

public FeatureStruct OutSyntacticFeatureStruct { get; set; }

public ICollection<Feature> ObligatorySyntacticFeatures
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,21 @@ public IEnumerable<Word> Apply(Word input)
return Enumerable.Empty<Word>();
}

if (!_rule.HeadProdRestrictionsMprFeatures.CompoundMprFeaturesMatch(input.MprFeatures))
{
if (_morpher.TraceManager.IsTracing)
{
_morpher.TraceManager.CompoundingRuleNotApplied(
_rule,
-1,
input,
FailureReason.HeadProdRestrictMprFeatures,
_rule.HeadProdRestrictionsMprFeatures
);
}
return Enumerable.Empty<Word>();
}

var output = new List<Word>();
for (int i = 0; i < _rule.Subrules.Count; i++)
{
Expand Down Expand Up @@ -161,6 +176,7 @@ public IEnumerable<Word> Apply(Word input)
Word outWord = ApplySubrule(_rule.Subrules[i], headMatch, nonHeadMatch);

outWord.MprFeatures.AddOutput(_rule.Subrules[i].OutMprFeatures);
outWord.MprFeatures.AddOutput(_rule.OutputProdRestrictionsMprFeatures);

outWord.SyntacticFeatureStruct = syntacticFS;
outWord.SyntacticFeatureStruct.PriorityUnion(_rule.OutSyntacticFeatureStruct);
Expand Down
5 changes: 5 additions & 0 deletions src/SIL.Machine.Morphology.HermitCrab/MprFeatureSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ public bool IsMatchExcluded(MprFeatureSet mprFeats, out MprFeatureGroup mismatch
return true;
}

public bool CompoundMprFeaturesMatch(MprFeatureSet stemMprFeatures)
{
return Count == 0 || this.Intersect(stemMprFeatures).Any();
}

public MprFeatureSet Clone()
{
return new MprFeatureSet(this);
Expand Down
10 changes: 10 additions & 0 deletions src/SIL.Machine.Morphology.HermitCrab/Trace.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,16 @@ public enum TraceType
/// </summary>
MorphologicalRuleSynthesis,

/// <summary>
/// Compounding rule analysis trace
/// </summary>
CompoundingRuleAnalysis,

/// <summary>
/// Compounding rule synthesis trace
/// </summary>
CompoundingRuleSynthesis,

/// <summary>
/// Parse successful trace
/// </summary>
Expand Down
36 changes: 36 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,42 @@ public void MorphologicalRuleNotUnapplied(IMorphologicalRule rule, int subruleIn
);
}

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

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

public void LexicalLookup(Stratum stratum, Word input)
{
((Trace)input.CurrentTrace).Children.Add(
Expand Down
10 changes: 10 additions & 0 deletions src/SIL.Machine.Morphology.HermitCrab/XmlLanguageLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1214,6 +1214,16 @@ out IMorphologicalRule mrule
fs.Freeze();
compRule.OutSyntacticFeatureStruct = fs;

compRule.HeadProdRestrictionsMprFeatures.UnionWith(
LoadMprFeatures((string)compRuleElem.Attribute("headProdRestrictionsMprFeatures"))
);
compRule.NonHeadProdRestrictionsMprFeatures.UnionWith(
LoadMprFeatures((string)compRuleElem.Attribute("nonHeadProdRestrictionsMprFeatures"))
);
compRule.OutputProdRestrictionsMprFeatures.UnionWith(
LoadMprFeatures((string)compRuleElem.Attribute("outputProdRestrictionsMprFeatures"))
);

var obligHeadIDsStr = (string)compRuleElem.Attribute("outputObligatoryFeatures");
if (!string.IsNullOrEmpty(obligHeadIDsStr))
{
Expand Down
20 changes: 20 additions & 0 deletions src/SIL.Machine.Morphology.HermitCrab/XmlLanguageWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,26 @@ private XElement WriteCompoundingRule(CompoundingRule crule, Dictionary<IMorphol
if (nonHeadRequiredFootFS != null)
ruleElem.Add(new XElement("NonHeadRequiredFootFeatures", WriteFeatureStruct(nonHeadRequiredFootFS)));

MprFeatureSet headProdRestrictionsMprFeatures = crule.HeadProdRestrictionsMprFeatures;
if (headProdRestrictionsMprFeatures.Count > 0)
ruleElem.Add(
WriteIDs("headProdRestrictionsMprFeatures", crule.HeadProdRestrictionsMprFeatures, _mprFeatures)
);
MprFeatureSet nonHeadProdRestrictionsMprFeatures = crule.NonHeadProdRestrictionsMprFeatures;
if (nonHeadProdRestrictionsMprFeatures.Count > 0)
ruleElem.Add(
WriteIDs(
"nonHeadProdRestrictionsMprFeatures",
crule.NonHeadProdRestrictionsMprFeatures,
_mprFeatures
)
);
MprFeatureSet outputProdRestrictionsMprFeatures = crule.OutputProdRestrictionsMprFeatures;
if (outputProdRestrictionsMprFeatures.Count > 0)
ruleElem.Add(
WriteIDs("outputProdRestrictionsMprFeatures", crule.OutputProdRestrictionsMprFeatures, _mprFeatures)
);

return ruleElem;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,72 @@ public void MorphosyntacticRules()
AssertRootAllomorphsEquals(output, "Perc0", "Perc3");
}

[Test]
public void ProdRestrictRule()
{
var any = FeatureStruct.New().Symbol(HCFeatureSystem.Segment).Value;
var rule1 = new CompoundingRule { Name = "rule1" };
Allophonic.MorphologicalRules.Add(rule1);
rule1.Subrules.Add(
new CompoundingSubrule
{
HeadLhs = { Pattern<Word, ShapeNode>.New("head").Annotation(any).OneOrMore.Value },
NonHeadLhs = { Pattern<Word, ShapeNode>.New("nonHead").Annotation(any).OneOrMore.Value },
Rhs = { new CopyFromInput("head"), new InsertSegments(Table3, "+"), new CopyFromInput("nonHead") }
}
);

var morpher = new Morpher(TraceManager, Language);
List<Word> output = morpher.ParseWord("pʰutdat").ToList();
AssertMorphsEqual(output, "5 8", "5 9");
AssertRootAllomorphsEquals(output, "5");

// Create an exception "feature"
var excFeat = new MprFeature();
excFeat.Name = "Allows compounding";
Language.MprFeatures.Add(excFeat);
// Add the exception "feature" to the head of the rule
rule1.HeadProdRestrictionsMprFeatures.Add(excFeat);
// The word should no longer parse
Assert.That(morpher.ParseWord("pʰutdat"), Is.Empty);

// Add the exception "feature" to the head root
var head = Allophonic.Entries.ElementAt(2);
head.MprFeatures.Add(excFeat);
// It should now parse
output = morpher.ParseWord("pʰutdat").ToList();
AssertMorphsEqual(output, "5 8", "5 9");
AssertRootAllomorphsEquals(output, "5");

// Remove the exception "feature" from the head of the rule
// and add it to the nonhead
rule1.HeadProdRestrictionsMprFeatures.Remove(excFeat);
rule1.NonHeadProdRestrictionsMprFeatures.Add(excFeat);
// The word should no longer parse
Assert.That(morpher.ParseWord("pʰutdat"), Is.Empty);

// Remove the exception "feature" from the head root
head.MprFeatures.Remove(excFeat);
// Add the exception "feature" to the nonhead root
var nonhead = Allophonic.Entries.ElementAt(5);
nonhead.MprFeatures.Add(excFeat);
// It should now parse
output = morpher.ParseWord("pʰutdat").ToList();
AssertMorphsEqual(output, "5 8");
AssertRootAllomorphsEquals(output, "5");

// Test output exception "feature"
// The output should not have it yet
Assert.That(rule1.OutputProdRestrictionsMprFeatures.Count == 0);
// Add the exception "feature" to the output set
rule1.OutputProdRestrictionsMprFeatures.Add(excFeat);
// It should still parse and the output MprFeatures should have the exception "feature"
output = morpher.ParseWord("pʰutdat").ToList();
AssertMorphsEqual(output, "5 8");
AssertRootAllomorphsEquals(output, "5");
Assert.That(rule1.OutputProdRestrictionsMprFeatures.Contains(excFeat));
}

private static void AssertRootAllomorphsEquals(IEnumerable<Word> words, params string[] expected)
{
Assert.That(words.Select(w => w.RootAllomorph.Morpheme.Gloss).Distinct(), Is.EquivalentTo(expected));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@
<Stratum characterDefinitionTable="table1" morphologicalRuleOrder="unordered" phonologicalRules="prule1 prule2" morphologicalRules="mrule1">
<Name>stratum 1</Name>
<MorphologicalRuleDefinitions>
<CompoundingRule id="mrule1" blockable="false" multipleApplication="3" headPartsOfSpeech="pos1" nonHeadPartsOfSpeech="pos2" outputPartOfSpeech="pos2" outputObligatoryFeatures="hfeat2">
<CompoundingRule id="mrule1" blockable="false" multipleApplication="3" headPartsOfSpeech="pos1" nonHeadPartsOfSpeech="pos2" outputPartOfSpeech="pos2" outputObligatoryFeatures="hfeat2" headProdRestrictionsMprFeatures="mpr1" nonHeadProdRestrictionsMprFeatures="mpr2" outputProdRestrictionsMprFeatures="mpr3">
<Name>compounding rule 1</Name>
<CompoundingSubrules>
<CompoundingSubrule>
Expand Down
Loading