public void SimpleRuleNotUnapplied()
        {
            var any = FeatureStruct.New().Symbol(HCFeatureSystem.Segment).Value;

            var prule = new MetathesisRule
            {
                Name    = "rule1",
                Pattern = Pattern <Word, ShapeNode> .New()
                          .Group("1", group => group.Annotation(Char(Table3, "i")))
                          .Group("2", group => group.Annotation(Char(Table3, "u"))).Value,
                LeftSwitchName  = "2",
                RightSwitchName = "1"
            };

            Morphophonemic.PhonologicalRules.Add(prule);

            var iSuffix = new AffixProcessRule
            {
                Name  = "i_suffix",
                Gloss = "3SG"
            };

            Morphophonemic.MorphologicalRules.Add(iSuffix);
            iSuffix.Allomorphs.Add(
                new AffixProcessAllomorph
            {
                Lhs = { Pattern <Word, ShapeNode> .New("1").Annotation(any).OneOrMore.Value },
                Rhs = { new CopyFromInput("1"), new InsertSegments(Table3, "i") }
            });

            var morpher = new Morpher(TraceManager, Language);

            AssertMorphsEqual(morpher.ParseWord("pui"), "52 3SG");
        }
Esempio n. 2
0
        public void AnalyzeWord_CanAnalyze_ReturnsCorrectAnalysis()
        {
            var any = FeatureStruct.New().Symbol(HCFeatureSystem.Segment).Value;

            var edSuffix = new AffixProcessRule
            {
                Id    = "PAST",
                Name  = "ed_suffix",
                Gloss = "PAST",
                RequiredSyntacticFeatureStruct = FeatureStruct.New(Language.SyntacticFeatureSystem).Symbol("V").Value
            };

            edSuffix.Allomorphs.Add(new AffixProcessAllomorph
            {
                Lhs = { Pattern <Word, ShapeNode> .New("1").Annotation(any).OneOrMore.Value },
                Rhs = { new CopyFromInput("1"), new InsertSegments(Table3, "+d") }
            });
            Morphophonemic.MorphologicalRules.Add(edSuffix);

            var morpher = new Morpher(TraceManager, Language);

            Assert.That(morpher.AnalyzeWord("sagd"), Is.EquivalentTo(new[]
            {
                new WordAnalysis(new IMorpheme[] { Entries["32"], edSuffix }, 0, "V")
            }));
        }
Esempio n. 3
0
        public void DisjunctiveAllomorphs()
        {
            var any = FeatureStruct.New().Symbol(HCFeatureSystem.Segment).Value;

            var edSuffix = new AffixProcessRule
            {
                Name  = "ed_suffix",
                Gloss = "PAST",
                RequiredSyntacticFeatureStruct = FeatureStruct.New(Language.SyntacticFeatureSystem).Symbol("V").Value
            };

            edSuffix.Allomorphs.Add(new AffixProcessAllomorph
            {
                Lhs = { Pattern <Word, ShapeNode> .New("1").Annotation(any).OneOrMore.Value },
                Rhs = { new CopyFromInput("1"), new InsertSegments(Table3, "+ɯd") }
            });
            Morphophonemic.MorphologicalRules.Add(edSuffix);

            var morpher = new Morpher(TraceManager, Language);

            AssertMorphsEqual(morpher.ParseWord("bazɯd"), "disj PAST");
            Assert.That(morpher.ParseWord("batɯd"), Is.Empty);
            Assert.That(morpher.ParseWord("badɯd"), Is.Empty);
            Assert.That(morpher.ParseWord("basɯd"), Is.Empty);
            AssertMorphsEqual(morpher.ParseWord("bas"), "disj");
        }
Esempio n. 4
0
        public void ComplexRule()
        {
            var any = FeatureStruct.New().Symbol(HCFeatureSystem.Segment).Value;

            var rule1 = new MetathesisRule
            {
                Name    = "rule1",
                Pattern = Pattern <Word, ShapeNode> .New()
                          .Group("1", group => group.Annotation(Char(Table3, "i")))
                          .Group("middle", group => group.Annotation(Char(Table3, "+")))
                          .Group("2", group => group.Annotation(Char(Table3, "u")))
                          .Group("rightEnv", group => group.Annotation(HCFeatureSystem.RightSideAnchor)).Value,
                LeftSwitchName  = "2",
                RightSwitchName = "1"
            };

            Morphophonemic.PhonologicalRules.Add(rule1);

            var uSuffix = new AffixProcessRule
            {
                Name  = "u_suffix",
                Gloss = "3SG"
            };

            Morphophonemic.MorphologicalRules.Add(uSuffix);
            uSuffix.Allomorphs.Add(new AffixProcessAllomorph
            {
                Lhs = { Pattern <Word, ShapeNode> .New("1").Annotation(any).OneOrMore.Value },
                Rhs = { new CopyFromInput("1"), new InsertSegments(Table3, "+u") }
            });

            var morpher = new Morpher(SpanFactory, TraceManager, Language);

            AssertMorphsEqual(morpher.ParseWord("mui"), "53 3SG");
        }
Esempio n. 5
0
        public void SameRuleUsedInMultipleTemplates()
        {
            var any = FeatureStruct.New().Symbol(HCFeatureSystem.Segment).Value;

            var edSuffix = new AffixProcessRule
            {
                Name  = "ed_suffix",
                Gloss = "PAST",
                RequiredSyntacticFeatureStruct = FeatureStruct.New(Language.SyntacticFeatureSystem)
                                                 .Symbol("V", "IV", "TV").Value,
            };

            edSuffix.Allomorphs.Add(new AffixProcessAllomorph
            {
                Lhs = { Pattern <Word, ShapeNode> .New("1").Annotation(any).OneOrMore.Value },
                Rhs = { new CopyFromInput("1"), new InsertSegments(Table3, "d") }
            });

            var transitiveVerbTemplate = new AffixTemplate
            {
                Name = "Transitive Verb",
                RequiredSyntacticFeatureStruct = FeatureStruct.New(Language.SyntacticFeatureSystem).Symbol("TV").Value
            };

            transitiveVerbTemplate.Slots.Add(new AffixTemplateSlot(edSuffix));
            Morphophonemic.AffixTemplates.Add(transitiveVerbTemplate);

            var intransitiveVerbTemplate = new AffixTemplate
            {
                Name = "Intransitive Verb",
                RequiredSyntacticFeatureStruct = FeatureStruct.New(Language.SyntacticFeatureSystem).Symbol("IV").Value
            };

            intransitiveVerbTemplate.Slots.Add(new AffixTemplateSlot(edSuffix));
            Morphophonemic.AffixTemplates.Add(intransitiveVerbTemplate);

            var nominalizer = new AffixProcessRule
            {
                Name  = "intransitive verbalizer",
                Gloss = "IVERB",
                RequiredSyntacticFeatureStruct = FeatureStruct.New(Language.SyntacticFeatureSystem).Symbol("N").Value,
                OutSyntacticFeatureStruct      = FeatureStruct.New(Language.SyntacticFeatureSystem).Symbol("IV").Value
            };

            nominalizer.Allomorphs.Add(new AffixProcessAllomorph
            {
                Lhs = { Pattern <Word, ShapeNode> .New("1").Annotation(any).OneOrMore.Value },
                Rhs = { new CopyFromInput("1"), new InsertSegments(Table3, "v") }
            });
            Morphophonemic.MorphologicalRules.Add(nominalizer);

            var morpher = new Morpher(TraceManager, Language);

            AssertMorphsEqual(morpher.ParseWord("mivd"), "53 IVERB PAST");
        }
Esempio n. 6
0
        public void PartialEntry()
        {
            var any         = FeatureStruct.New().Symbol(HCFeatureSystem.Segment).Value;
            var nominalizer = new AffixProcessRule
            {
                Name  = "nominalizer",
                Gloss = "NOM",
                RequiredSyntacticFeatureStruct = FeatureStruct.New(Language.SyntacticFeatureSystem).Symbol("V").Value,
                OutSyntacticFeatureStruct      = FeatureStruct.New(Language.SyntacticFeatureSystem).Symbol("N").Value
            };

            nominalizer.Allomorphs.Add(new AffixProcessAllomorph
            {
                Lhs = { Pattern <Word, ShapeNode> .New("1").Annotation(any).OneOrMore.Value },
                Rhs = { new CopyFromInput("1"), new InsertSegments(Table3, "v") }
            });
            Morphophonemic.MorphologicalRules.Add(nominalizer);

            var morpher = new Morpher(TraceManager, Language);

            AssertMorphsEqual(morpher.ParseWord("pi"), "54");
            AssertMorphsEqual(morpher.ParseWord("piv"), "54 NOM");

            Morphophonemic.MorphologicalRules.Clear();

            var sSuffix = new AffixProcessRule
            {
                Name  = "s_suffix",
                Gloss = "PAST",
                RequiredSyntacticFeatureStruct = FeatureStruct.New(Language.SyntacticFeatureSystem).Symbol("V").Value,
            };

            sSuffix.Allomorphs.Add(new AffixProcessAllomorph
            {
                Lhs = { Pattern <Word, ShapeNode> .New("1").Annotation(any).OneOrMore.Value },
                Rhs = { new CopyFromInput("1"), new InsertSegments(Table3, "s") }
            });

            var verbTemplate = new AffixTemplate
            {
                Name = "verb",
                RequiredSyntacticFeatureStruct = FeatureStruct.New(Language.SyntacticFeatureSystem).Symbol("V").Value
            };

            verbTemplate.Slots.Add(new AffixTemplateSlot(sSuffix)
            {
                Optional = true
            });
            Morphophonemic.AffixTemplates.Add(verbTemplate);

            morpher = new Morpher(TraceManager, Language);
            AssertMorphsEqual(morpher.ParseWord("pi"), "54");
            AssertMorphsEqual(morpher.ParseWord("pis"));
        }
Esempio n. 7
0
        public void AffixTemplateAppliedAfterMorphologicalRule()
        {
            var any         = FeatureStruct.New().Symbol(HCFeatureSystem.Segment).Value;
            var nominalizer = new AffixProcessRule
            {
                Name  = "nominalizer",
                Gloss = "NOM",
                RequiredSyntacticFeatureStruct = FeatureStruct.New(Language.SyntacticFeatureSystem).Symbol("V").Value,
                OutSyntacticFeatureStruct      = FeatureStruct.New(Language.SyntacticFeatureSystem).Symbol("N").Value
            };

            nominalizer.Allomorphs.Add(new AffixProcessAllomorph
            {
                Lhs = { Pattern <Word, ShapeNode> .New("1").Annotation(any).OneOrMore.Value },
                Rhs = { new CopyFromInput("1"), new InsertSegments(Table3, "v") }
            });
            Morphophonemic.MorphologicalRules.Add(nominalizer);

            var sSuffix = new AffixProcessRule
            {
                Name  = "s_suffix",
                Gloss = "PL",
                RequiredSyntacticFeatureStruct = FeatureStruct.New(Language.SyntacticFeatureSystem).Symbol("N").Value,
            };

            sSuffix.Allomorphs.Add(new AffixProcessAllomorph
            {
                Lhs = { Pattern <Word, ShapeNode> .New("1").Annotation(any).OneOrMore.Value },
                Rhs = { new CopyFromInput("1"), new InsertSegments(Table3, "s") }
            });

            var nounTemplate = new AffixTemplate {
                Name = "noun", RequiredSyntacticFeatureStruct = FeatureStruct.New(Language.SyntacticFeatureSystem).Symbol("N").Value
            };

            nounTemplate.Slots.Add(new AffixTemplateSlot(sSuffix)
            {
                Optional = true
            });
            Morphophonemic.AffixTemplates.Add(nounTemplate);

            var morpher = new Morpher(SpanFactory, TraceManager, Language);

            AssertMorphsEqual(morpher.ParseWord("sagv"), "32 NOM");
            AssertMorphsEqual(morpher.ParseWord("sagvs"), "32 NOM PL");
        }
Esempio n. 8
0
        public void GenerateWords_CanGenerate_ReturnsCorrectWord()
        {
            var any = FeatureStruct.New().Symbol(HCFeatureSystem.Segment).Value;

            var siPrefix = new AffixProcessRule
            {
                Id    = "3SG",
                Name  = "si_prefix",
                Gloss = "3SG",
                RequiredSyntacticFeatureStruct = FeatureStruct.New(Language.SyntacticFeatureSystem).Symbol("V").Value
            };

            siPrefix.Allomorphs.Add(new AffixProcessAllomorph
            {
                Lhs = { Pattern <Word, ShapeNode> .New("1").Annotation(any).OneOrMore.Value },
                Rhs = { new InsertSegments(Table3, "si+"), new CopyFromInput("1") }
            });
            Morphophonemic.MorphologicalRules.Add(siPrefix);

            var edSuffix = new AffixProcessRule
            {
                Id    = "PAST",
                Name  = "ed_suffix",
                Gloss = "PAST",
                RequiredSyntacticFeatureStruct = FeatureStruct.New(Language.SyntacticFeatureSystem).Symbol("V").Value
            };

            edSuffix.Allomorphs.Add(new AffixProcessAllomorph
            {
                Lhs = { Pattern <Word, ShapeNode> .New("1").Annotation(any).OneOrMore.Value },
                Rhs = { new CopyFromInput("1"), new InsertSegments(Table3, "+ɯd") }
            });
            Morphophonemic.MorphologicalRules.Add(edSuffix);

            var morpher = new Morpher(TraceManager, Language);

            var analysis = new WordAnalysis(new IMorpheme[] { siPrefix, Entries["33"], edSuffix }, 1, "V");

            string[] words = morpher.GenerateWords(analysis).ToArray();
            Assert.That(words, Is.EquivalentTo(new[] { "sisasɯd" }));
        }
Esempio n. 9
0
        public void FreeFluctuation()
        {
            var any = FeatureStruct.New().Symbol(HCFeatureSystem.Segment).Value;
            var d   = FeatureStruct.New(Language.PhonologicalFeatureSystem)
                      .Symbol(HCFeatureSystem.Segment)
                      .Symbol("cons+")
                      .Symbol("strident-")
                      .Symbol("del_rel-")
                      .Symbol("alveolar")
                      .Symbol("nasal-")
                      .Symbol("vd+").Value;

            var edSuffix = new AffixProcessRule
            {
                Name  = "ed_suffix",
                Gloss = "PAST",
                RequiredSyntacticFeatureStruct = FeatureStruct.New(Language.SyntacticFeatureSystem).Symbol("V").Value
            };

            edSuffix.Allomorphs.Add(new AffixProcessAllomorph
            {
                Lhs = { Pattern <Word, ShapeNode> .New("1").Annotation(any).OneOrMore.Value },
                Rhs = { new CopyFromInput("1"), new InsertSegments(Table3, "+t") }
            });
            edSuffix.Allomorphs.Add(new AffixProcessAllomorph
            {
                Lhs = { Pattern <Word, ShapeNode> .New("1").Annotation(any).OneOrMore.Value },
                Rhs = { new CopyFromInput("1"), new InsertSegments(Table3, "+"), new InsertSimpleContext(d) }
            });
            Morphophonemic.MorphologicalRules.Add(edSuffix);

            var morpher = new Morpher(TraceManager, Language);

            AssertMorphsEqual(morpher.ParseWord("tazd"), "free PAST");
            AssertMorphsEqual(morpher.ParseWord("tast"), "free PAST");
            AssertMorphsEqual(morpher.ParseWord("tazt"), "free PAST");
            AssertMorphsEqual(morpher.ParseWord("tasd"), "free PAST");
        }
Esempio n. 10
0
        public void SimpleRules()
        {
            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(SpanFactory, TraceManager, Language);
            List <Word> output  = morpher.ParseWord("pʰutdat").ToList();

            AssertMorphsEqual(output, "5 8", "5 9");
            AssertRootAllomorphsEquals(output, "5");
            Assert.That(morpher.ParseWord("pʰutdas"), Is.Empty);
            Assert.That(morpher.ParseWord("pʰusdat"), Is.Empty);

            rule1.Subrules.Clear();
            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("nonHead"), new InsertSegments(Table3, "+"), new CopyFromInput("head") }
            });

            morpher = new Morpher(SpanFactory, TraceManager, Language);
            output  = morpher.ParseWord("pʰutdat").ToList();
            AssertMorphsEqual(output, "5 8", "5 9");
            AssertRootAllomorphsEquals(output, "8", "9");
            Assert.That(morpher.ParseWord("pʰutdas"), Is.Empty);
            Assert.That(morpher.ParseWord("pʰusdat"), Is.Empty);

            var prefix = new AffixProcessRule
            {
                Name  = "prefix",
                Gloss = "PAST",
                RequiredSyntacticFeatureStruct = FeatureStruct.New(Language.SyntacticFeatureSystem).Symbol("V").Value,
                OutSyntacticFeatureStruct      = FeatureStruct.New(Language.SyntacticFeatureSystem)
                                                 .Feature(Head).EqualTo(head => head
                                                                        .Feature("tense").EqualTo("past")).Value
            };

            Allophonic.MorphologicalRules.Insert(0, prefix);
            prefix.Allomorphs.Add(new AffixProcessAllomorph
            {
                Lhs = { Pattern <Word, ShapeNode> .New("1").Annotation(any).OneOrMore.Value },
                Rhs = { new InsertSegments(Table3, "di+"), new CopyFromInput("1") }
            });

            morpher = new Morpher(SpanFactory, TraceManager, Language);
            output  = morpher.ParseWord("pʰutdidat").ToList();
            AssertMorphsEqual(output, "5 PAST 9");
            AssertRootAllomorphsEquals(output, "9");

            Allophonic.MorphologicalRules.RemoveAt(0);

            rule1.MaxApplicationCount = 2;
            rule1.Subrules.Clear();
            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") }
            });

            morpher = new Morpher(SpanFactory, TraceManager, Language)
            {
                MaxStemCount = 3
            };
            output = morpher.ParseWord("pʰutdatpip").ToList();
            AssertMorphsEqual(output, "5 8 41", "5 9 41");
            AssertRootAllomorphsEquals(output, "5");

            rule1.MaxApplicationCount = 1;

            var rule2 = new CompoundingRule {
                Name = "rule2"
            };

            Allophonic.MorphologicalRules.Add(rule2);
            rule2.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("nonHead"), new InsertSegments(Table3, "+"), new CopyFromInput("head") }
            });

            morpher = new Morpher(SpanFactory, TraceManager, Language)
            {
                MaxStemCount = 3
            };
            output = morpher.ParseWord("pʰutdatpip").ToList();
            AssertMorphsEqual(output, "5 8 41", "5 9 41");
            AssertRootAllomorphsEquals(output, "8", "9");
        }
Esempio n. 11
0
        public void StemNames()
        {
            var any = FeatureStruct.New().Symbol(HCFeatureSystem.Segment).Value;

            var edSuffix = new AffixProcessRule
            {
                Name  = "ed_suffix",
                Gloss = "1",
                RequiredSyntacticFeatureStruct = FeatureStruct.New(Language.SyntacticFeatureSystem).Symbol("V").Value,
                OutSyntacticFeatureStruct      = FeatureStruct.New(Language.SyntacticFeatureSystem)
                                                 .Feature(Head).EqualTo(head => head
                                                                        .Feature("pers").EqualTo("1")).Value
            };

            edSuffix.Allomorphs.Add(new AffixProcessAllomorph
            {
                Lhs = { Pattern <Word, ShapeNode> .New("1").Annotation(any).OneOrMore.Value },
                Rhs = { new CopyFromInput("1"), new InsertSegments(Table3, "+ɯd") }
            });
            Morphophonemic.MorphologicalRules.Add(edSuffix);

            var tSuffix = new AffixProcessRule
            {
                Name  = "t_suffix",
                Gloss = "2",
                RequiredSyntacticFeatureStruct = FeatureStruct.New(Language.SyntacticFeatureSystem).Symbol("V").Value,
                OutSyntacticFeatureStruct      = FeatureStruct.New(Language.SyntacticFeatureSystem)
                                                 .Feature(Head).EqualTo(head => head
                                                                        .Feature("pers").EqualTo("2")).Value
            };

            tSuffix.Allomorphs.Add(new AffixProcessAllomorph
            {
                Lhs = { Pattern <Word, ShapeNode> .New("1").Annotation(any).OneOrMore.Value },
                Rhs = { new CopyFromInput("1"), new InsertSegments(Table3, "+t") }
            });
            Morphophonemic.MorphologicalRules.Add(tSuffix);

            var sSuffix = new AffixProcessRule
            {
                Name  = "s_suffix",
                Gloss = "3",
                RequiredSyntacticFeatureStruct = FeatureStruct.New(Language.SyntacticFeatureSystem).Symbol("V").Value,
                OutSyntacticFeatureStruct      = FeatureStruct.New(Language.SyntacticFeatureSystem)
                                                 .Feature(Head).EqualTo(head => head
                                                                        .Feature("pers").EqualTo("3")).Value
            };

            sSuffix.Allomorphs.Add(new AffixProcessAllomorph
            {
                Lhs = { Pattern <Word, ShapeNode> .New("1").Annotation(any).OneOrMore.Value },
                Rhs = { new CopyFromInput("1"), new InsertSegments(Table3, "+s") }
            });
            Morphophonemic.MorphologicalRules.Add(sSuffix);

            var morpher = new Morpher(TraceManager, Language);

            AssertMorphsEqual(morpher.ParseWord("sanɯd"));
            AssertMorphsEqual(morpher.ParseWord("sant"));
            AssertMorphsEqual(morpher.ParseWord("sans"));
            AssertMorphsEqual(morpher.ParseWord("san"), "stemname");

            AssertMorphsEqual(morpher.ParseWord("sadɯd"), "stemname 1");
            AssertMorphsEqual(morpher.ParseWord("sadt"), "stemname 2");
            AssertMorphsEqual(morpher.ParseWord("sads"));
            AssertMorphsEqual(morpher.ParseWord("sad"));

            AssertMorphsEqual(morpher.ParseWord("sapɯd"), "stemname 1");
            AssertMorphsEqual(morpher.ParseWord("sapt"));
            AssertMorphsEqual(morpher.ParseWord("saps"), "stemname 3");
            AssertMorphsEqual(morpher.ParseWord("sap"));
        }
Esempio n. 12
0
        public void NonFinalTemplate()
        {
            var any     = FeatureStruct.New().Symbol(HCFeatureSystem.Segment).Value;
            var alvStop = FeatureStruct.New(Language.PhonologicalFeatureSystem)
                          .Symbol(HCFeatureSystem.Segment)
                          .Symbol("cons+")
                          .Symbol("strident-")
                          .Symbol("del_rel-")
                          .Symbol("alveolar").Value;
            var voicelessCons = FeatureStruct.New(Language.PhonologicalFeatureSystem)
                                .Symbol(HCFeatureSystem.Segment)
                                .Symbol("cons+")
                                .Symbol("vd-").Value;

            var edSuffix = new AffixProcessRule
            {
                Name  = "ed_suffix",
                Gloss = "PAST",
            };

            edSuffix.Allomorphs.Add(new AffixProcessAllomorph
            {
                Lhs =
                {
                    Pattern <Word, ShapeNode> .New("1").Annotation(any).OneOrMore.Value,
                    Pattern <Word, ShapeNode> .New("2").Annotation(alvStop).Value
                },
                Rhs = { new CopyFromInput("1"), new CopyFromInput("2"), new InsertSegments(Table3, "ɯd") }
            });
            edSuffix.Allomorphs.Add(new AffixProcessAllomorph
            {
                Lhs = { Pattern <Word, ShapeNode> .New("1").Annotation(any).OneOrMore.Annotation(voicelessCons).Value },
                Rhs = { new CopyFromInput("1"), new InsertSegments(Table3, "t") }
            });
            edSuffix.Allomorphs.Add(new AffixProcessAllomorph
            {
                Lhs = { Pattern <Word, ShapeNode> .New("1").Annotation(any).OneOrMore.Value },
                Rhs = { new CopyFromInput("1"), new InsertSegments(Table3, "d") }
            });

            var verbTemplate = new AffixTemplate
            {
                Name = "verb",
                RequiredSyntacticFeatureStruct = FeatureStruct.New(Language.SyntacticFeatureSystem).Symbol("V").Value
            };

            verbTemplate.Slots.Add(new AffixTemplateSlot(edSuffix));
            Morphophonemic.AffixTemplates.Add(verbTemplate);

            var nominalizer = new AffixProcessRule
            {
                Name  = "nominalizer",
                Gloss = "NOM",
                RequiredSyntacticFeatureStruct = FeatureStruct.New(Language.SyntacticFeatureSystem).Symbol("V").Value,
                OutSyntacticFeatureStruct      = FeatureStruct.New(Language.SyntacticFeatureSystem).Symbol("N").Value
            };

            nominalizer.Allomorphs.Add(new AffixProcessAllomorph
            {
                Lhs = { Pattern <Word, ShapeNode> .New("1").Annotation(any).OneOrMore.Value },
                Rhs = { new CopyFromInput("1"), new InsertSegments(Table3, "v") }
            });
            Morphophonemic.MorphologicalRules.Add(nominalizer);

            var crule = new CompoundingRule
            {
                Name = "rule1",
                HeadRequiredSyntacticFeatureStruct = FeatureStruct.New(Language.SyntacticFeatureSystem)
                                                     .Symbol("V").Value,
                NonHeadRequiredSyntacticFeatureStruct = FeatureStruct.New(Language.SyntacticFeatureSystem)
                                                        .Symbol("N").Value,
                OutSyntacticFeatureStruct = FeatureStruct.New(Language.SyntacticFeatureSystem).Symbol("N").Value
            };

            crule.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") }
            });
            Morphophonemic.MorphologicalRules.Add(crule);

            var sSuffix = new AffixProcessRule
            {
                Name  = "s_suffix",
                Gloss = "PL",
                RequiredSyntacticFeatureStruct = FeatureStruct.New(Language.SyntacticFeatureSystem).Symbol("N").Value,
            };

            sSuffix.Allomorphs.Add(new AffixProcessAllomorph
            {
                Lhs = { Pattern <Word, ShapeNode> .New("1").Annotation(any).OneOrMore.Value },
                Rhs = { new CopyFromInput("1"), new InsertSegments(Table3, "s") }
            });

            var nounTemplate = new AffixTemplate
            {
                Name = "noun",
                RequiredSyntacticFeatureStruct = FeatureStruct.New(Language.SyntacticFeatureSystem).Symbol("N").Value
            };

            nounTemplate.Slots.Add(new AffixTemplateSlot(sSuffix)
            {
                Optional = true
            });
            Morphophonemic.AffixTemplates.Add(nounTemplate);

            var morpher = new Morpher(TraceManager, Language);

            AssertMorphsEqual(morpher.ParseWord("sagd"), "32 PAST");
            AssertMorphsEqual(morpher.ParseWord("sagdv"));
            AssertMorphsEqual(morpher.ParseWord("sagdvs"));
            AssertMorphsEqual(morpher.ParseWord("sagdmi"));
            AssertMorphsEqual(morpher.ParseWord("sagdmis"));

            verbTemplate.IsFinal = false;
            morpher = new Morpher(TraceManager, Language);
            AssertMorphsEqual(morpher.ParseWord("sagd"));
            AssertMorphsEqual(morpher.ParseWord("sagdv"), "32 PAST NOM");
            AssertMorphsEqual(morpher.ParseWord("sagdvs"), "32 PAST NOM PL");
            AssertMorphsEqual(morpher.ParseWord("sagdmi"), "32 PAST 53");
            AssertMorphsEqual(morpher.ParseWord("sagdmis"), "32 PAST 53 PL");
        }