void ApplyMorphologicalRules(WordSynthesis input, int rIndex, Set <WordSynthesis> output) { // iterate thru all rules starting from the specified rule in synthesis order for (int i = rIndex; i < m_mrules.Count; i++) { if (m_mrules[i].IsApplicable(input)) { ICollection <WordSynthesis> syntheses; if (m_mrules[i].Apply(input, out syntheses)) { foreach (WordSynthesis ws in syntheses) { // recursive call so that we can cover every permutation of rule application switch (m_mruleOrder) { case MRuleOrder.LINEAR: ApplyMorphologicalRules(ws, i, output); break; case MRuleOrder.UNORDERED: ApplyMorphologicalRules(ws, 0, output); break; } } } } } ApplyTemplates(input, output); }
void ApplyPhonologicalRules(WordSynthesis input) { for (int i = 0; i < m_prules.Count; i++) { m_prules[i].Apply(input); } }
/// <summary> /// If the list of Realizational Features is non-empty, choose from either the input stem or its relatives /// of this stratum that stem which incorporates the most realizational features (without being incompatible /// with any realizational feature or with the head and foot features of the input stem). /// </summary> /// <param name="ws">The input word synthesis.</param> /// <returns>The resulting word synthesis.</returns> WordSynthesis ChooseInflStem(WordSynthesis ws) { if (ws.RealizationalFeatures.NumFeatures == 0 || ws.Root.Family == null) { return(ws); } WordSynthesis best = ws; // iterate thru all relatives foreach (LexEntry relative in ws.Root.Family.Entries) { if (relative != ws.Root && relative.Stratum == ws.Stratum && ws.RealizationalFeatures.IsCompatible(relative.HeadFeatures) && ws.POS == relative.POS && relative.FootFeatures.Equals(ws.FootFeatures)) { FeatureValues remainder; if (best.HeadFeatures.GetSupersetRemainder(relative.HeadFeatures, out remainder) && remainder.NumFeatures > 0 && ws.RealizationalFeatures.IsCompatible(remainder)) { if (Morpher.TraceBlocking) { // create blocking trace record, should this become the current trace? ws.CurrentTrace.AddChild(new BlockingTrace(BlockingTrace.BlockType.TEMPLATE, relative)); } best = new WordSynthesis(relative.PrimaryAllomorph, ws.RealizationalFeatures, ws.CurrentTrace); } } } return(best); }
/// <summary> /// Applies the simple context to the input partition and copies it over to the output /// phonetic shape. /// </summary> /// <param name="match">The match.</param> /// <param name="input">The input word synthesis.</param> /// <param name="output">The output word synthesis.</param> /// <param name="morpheme">The morpheme info.</param> public override void Apply(Match match, WordSynthesis input, WordSynthesis output, Allomorph allomorph) { IList <PhoneticShapeNode> nodes = match.GetPartition(m_partition); if (nodes != null && nodes.Count > 0) { Morph morph = null; if (allomorph != null) { morph = new Morph(allomorph); output.Morphs.Add(morph); } for (PhoneticShapeNode node = nodes[0]; node != nodes[nodes.Count - 1].Next; node = node.Next) { PhoneticShapeNode newNode = node.Clone(); if (node.Type == PhoneticShapeNode.NodeType.SEGMENT) { Segment seg = newNode as Segment; // sets the context's features on the segment m_ctxt.Apply(seg, match.VariableValues); seg.IsClean = false; seg.Partition = morph == null ? -1 : morph.Partition; } if (morph != null) { morph.Shape.Add(newNode.Clone()); } output.Shape.Add(newNode); } } }
protected WordSynthesis CheckBlocking(WordSynthesis ws) { if (!m_isBlockable || ws.Root.Family == null) { return(ws); } // check all relatives foreach (LexEntry entry in ws.Root.Family.Entries) { // a relative will block if the part of speech, stratum, head features, and foot features match if (entry != ws.Root && ws.POS == entry.POS && entry.Stratum == ws.Stratum && entry.HeadFeatures.Equals(ws.HeadFeatures) && entry.FootFeatures.Equals(ws.FootFeatures)) { if (Morpher.TraceBlocking) { // create a blocking trace record, should this become the current trace? ws.CurrentTrace.AddChild(new BlockingTrace(BlockingTrace.BlockType.RULE, entry)); } return(new WordSynthesis(entry.PrimaryAllomorph, ws.RealizationalFeatures, ws.CurrentTrace)); } } return(ws); }
/// <summary> /// Determines whether this subrule is applicable to the specified word analysis. /// </summary> /// <param name="input">The word analysis.</param> /// <returns> /// <c>true</c> if this subrule is applicable, otherwise <c>false</c>. /// </returns> public bool IsApplicable(WordSynthesis input) { // check part of speech and MPR features return((m_requiredPOSs == null || m_requiredPOSs.Count == 0 || m_requiredPOSs.Contains(input.POS)) && (m_requiredMPRFeatures == null || m_requiredMPRFeatures.Count == 0 || m_requiredMPRFeatures.IsMatch(input.MPRFeatures)) && (m_excludedMPRFeatures == null || m_excludedMPRFeatures.Count == 0 || !m_excludedMPRFeatures.IsMatch(input.MPRFeatures))); }
/// <summary> /// Applies this subrule to the specified word synthesis. /// </summary> /// <param name="input">The input word synthesis.</param> /// <param name="output">The output word synthesis.</param> /// <returns><c>true</c> if the subrule was successfully applied, otherwise <c>false</c></returns> public bool Apply(WordSynthesis input, out WordSynthesis output) { output = null; // check MPR features if ((m_requiredMPRFeatures != null && m_requiredMPRFeatures.Count > 0 && !m_requiredMPRFeatures.IsMatch(input.MPRFeatures)) || (m_excludedMPRFeatures != null && m_excludedMPRFeatures.Count > 0 && m_excludedMPRFeatures.IsMatch(input.MPRFeatures))) { return(false); } VariableValues instantiatedVars = new VariableValues(m_alphaVars); IList <Match> headMatches, nonHeadMatches; if (m_headLhsTemp.IsMatch(input.Shape.First, Direction.RIGHT, ModeType.SYNTHESIS, instantiatedVars, out headMatches) && m_nonHeadLhsTemp.IsMatch(input.NonHead.Shape.First, Direction.RIGHT, ModeType.SYNTHESIS, instantiatedVars, out nonHeadMatches)) { output = input.Clone(); ApplyRHS(headMatches[0], nonHeadMatches[0], input, output); if (m_outputMPRFeatures != null) { output.MPRFeatures.AddOutput(m_outputMPRFeatures); } return(true); } return(false); }
/// <summary> /// Determines if the allomorphs in the two syntheses are not disjunctive. /// </summary> /// <param name="synthesis1">The first synthesis.</param> /// <param name="synthesis2">The second synthesis.</param> /// <returns></returns> private bool AreAllomorphsNondisjunctive(WordSynthesis synthesis1, WordSynthesis synthesis2) { if (synthesis1.Morphs.Count != synthesis2.Morphs.Count) { return(true); } IEnumerator <Morph> enum1 = synthesis1.Morphs.GetEnumerator(); IEnumerator <Morph> enum2 = synthesis2.Morphs.GetEnumerator(); while (enum1.MoveNext() && enum2.MoveNext()) { // if they have different morphemes then these allomorphs are not disjunctive if (enum1.Current.Allomorph.Morpheme != enum2.Current.Allomorph.Morpheme) { return(true); } // morphemes are the same, so check if they have the same constraints, // if they do then these allomorphs are not disjunctive if (enum1.Current.Allomorph.ConstraintsEqual(enum2.Current.Allomorph)) { return(true); } } return(false); }
bool ApplyTemplates(WordSynthesis input, Set <WordSynthesis> output) { // if this word synthesis is not compatible with the realizational features, // then skip it if (!input.RealizationalFeatures.IsCompatible(input.HeadFeatures)) { return(false); } WordSynthesis ws = ChooseInflStem(input); bool applicableTemplate = false; foreach (AffixTemplate template in m_templates) { // HC.NET does not treat templates as applying disjunctively, as opposed to legacy HC, // which does if (template.IsApplicable(ws)) { applicableTemplate = true; IEnumerable <WordSynthesis> tempOutput; if (template.Apply(ws, out tempOutput)) { output.AddMany(tempOutput); } } } if (!applicableTemplate) { output.Add(ws); } return(applicableTemplate); }
/// <summary> /// Determines whether this subrule is applicable to the specified word analysis. /// </summary> /// <param name="input">The word analysis.</param> /// <param name="trace"> </param> /// <returns> /// <c>true</c> if this subrule is applicable, otherwise <c>false</c>. /// </returns> public bool IsApplicable(WordSynthesis input, Trace trace) { // check part of speech and MPR features bool fRequiredPOSMet = m_requiredPOSs == null || m_requiredPOSs.Count == 0 || m_requiredPOSs.Contains(input.POS); bool fRequiredMPRFeaturesMet = m_requiredMPRFeatures == null || m_requiredMPRFeatures.Count == 0 || m_requiredMPRFeatures.IsMatch(input.MPRFeatures); bool fExcludedMPRFeaturesMet = m_excludedMPRFeatures == null || m_excludedMPRFeatures.Count == 0 || !m_excludedMPRFeatures.IsMatch(input.MPRFeatures); if (trace != null) { if (!fRequiredPOSMet) { var badPosTrace = new PhonologicalRuleSynthesisRequiredPOSTrace(input.POS, m_requiredPOSs); trace.AddChild(badPosTrace); } if (!fRequiredMPRFeaturesMet) { var badRequiredMPRFeaturesTrace = new PhonologicalRuleSynthesisMPRFeaturesTrace( PhonologicalRuleSynthesisMPRFeaturesTrace.PhonologicalRuleSynthesisMPRFeaturesTraceType.REQUIRED, input.MPRFeatures, m_requiredMPRFeatures); trace.AddChild(badRequiredMPRFeaturesTrace); } if (!fExcludedMPRFeaturesMet) { var badExcludedMPRFeaturesTrace = new PhonologicalRuleSynthesisMPRFeaturesTrace( PhonologicalRuleSynthesisMPRFeaturesTrace.PhonologicalRuleSynthesisMPRFeaturesTraceType.EXCLUDED, input.MPRFeatures, m_excludedMPRFeatures); trace.AddChild(badExcludedMPRFeaturesTrace); } } return(fRequiredPOSMet && fRequiredMPRFeaturesMet && fExcludedMPRFeaturesMet); }
/// <summary> /// Determines whether this rule is applicable to the specified word synthesis. /// </summary> /// <param name="input">The input word synthesis.</param> /// <returns> /// <c>true</c> if the rule is applicable, otherwise <c>false</c>. /// </returns> public override bool IsApplicable(WordSynthesis input) { // TODO: check subcats. // check required parts of speech return(input.NextRule == this && input.GetNumAppliesForMorphologicalRule(this) < m_maxNumApps && (m_requiredPOSs == null || m_requiredPOSs.Count == 0 || m_requiredPOSs.Contains(input.POS))); }
/// <summary> /// Applies the rule to the specified word synthesis. /// </summary> /// <param name="input">The word synthesis.</param> public override void Apply(WordSynthesis input) { PhonologicalRuleSynthesisTrace trace = null; if (TraceSynthesis) { // create phonological rule synthesis trace record trace = new PhonologicalRuleSynthesisTrace(this, input.Clone()); input.CurrentTrace.AddChild(trace); } // only try to apply applicable subrules List <Subrule> subrules = new List <Subrule>(); foreach (Subrule sr in m_subrules) { if (sr.IsApplicable(input)) { subrules.Add(sr); } } if (subrules.Count > 0) { // set all segments to clean PhoneticShape pshape = input.Shape; foreach (PhoneticShapeNode node in pshape) { if (node.Type == PhoneticShapeNode.NodeType.SEGMENT) { (node as Segment).IsClean = true; } } switch (m_multApplication) { case MultAppOrder.SIMULTANEOUS: ApplySimultaneous(input.Shape, subrules); break; case MultAppOrder.LR_ITERATIVE: ApplyIterative(input.Shape, Direction.RIGHT, subrules); break; case MultAppOrder.RL_ITERATIVE: ApplyIterative(input.Shape, Direction.LEFT, subrules); break; } } // add output to phonological rule trace record if (trace != null) { trace.Output = input.Clone(); } }
public override bool ApplySlotAffix(WordSynthesis input, FeatureValues origHeadFeatures, out ICollection <WordSynthesis> output) { output = null; if (IsBlockedSlotAffix(origHeadFeatures)) { return(false); } return(base.ApplySlotAffix(input, origHeadFeatures, out output)); }
void ApplyRHS(Match match, WordSynthesis input, WordSynthesis output) { output.Shape.Clear(); output.Morphs.Clear(); output.Shape.Add(new Margin(Direction.LEFT)); foreach (MorphologicalOutput outputMember in m_transform.RHS) { outputMember.Apply(match, input, output, this); } output.Shape.Add(new Margin(Direction.RIGHT)); }
void PrettyPrintWordSynthesis(WordSynthesis ws) { StringBuilder sb = new StringBuilder(); sb.Append("ID: "); sb.AppendLine(ws.Root.ID); sb.Append("POS: "); sb.AppendLine(ws.POS.Description); sb.Append("Morphs: "); bool firstItem = true; foreach (Morph morph in ws.Morphs) { string gl = morph.Allomorph.Morpheme.Gloss == null ? "?" : morph.Allomorph.Morpheme.Gloss.Description; string shapeStr = ws.Stratum.CharacterDefinitionTable.ToString(morph.Shape, ModeType.SYNTHESIS, false); int len = Math.Max(shapeStr.Length, gl.Length); if (len > 0) { if (!firstItem) { sb.Append(' '); } sb.Append(shapeStr.PadRight(len)); firstItem = false; } } sb.AppendLine(); sb.Append("Gloss: "); firstItem = true; foreach (Morph morph in ws.Morphs) { string gl = morph.Allomorph.Morpheme.Gloss == null ? "?" : morph.Allomorph.Morpheme.Gloss.Description; string shapeStr = ws.Stratum.CharacterDefinitionTable.ToString(morph.Shape, ModeType.SYNTHESIS, false); int len = Math.Max(shapeStr.Length, gl.Length); if (len > 0) { if (!firstItem) { sb.Append(' '); } sb.Append(gl.PadRight(len)); firstItem = false; } } sb.AppendLine(); sb.Append("MPR Features: "); sb.AppendLine(ws.MPRFeatures.ToString()); sb.Append("Head Features: "); sb.AppendLine(ws.HeadFeatures.ToString()); sb.Append("Foot Features: "); sb.Append(ws.FootFeatures.ToString()); m_out.WriteLine(sb.ToString()); }
public virtual void Write(WordSynthesis ws, bool prettyPrint) { if (prettyPrint) { PrettyPrintWordSynthesis(ws); } else { m_out.WriteLine(ws.ToString()); } m_out.WriteLine(); }
/// <summary> /// Inserts a segment based on a simple context to the output. /// </summary> /// <param name="match">The match.</param> /// <param name="input">The input word synthesis.</param> /// <param name="output">The output word synthesis.</param> /// <param name="morpheme">The morpheme info.</param> public override void Apply(Match match, WordSynthesis input, WordSynthesis output, Allomorph allomorph) { Segment newSeg = m_ctxt.ApplyInsertion(match.VariableValues); if (allomorph != null) { Morph morph = new Morph(allomorph); output.Morphs.Add(morph); morph.Shape.Add(newSeg.Clone()); newSeg.Partition = morph.Partition; } output.Shape.Add(newSeg); }
public virtual void Write(WordSynthesis ws, bool prettyPrint) { m_xmlWriter.WriteStartElement("Result"); Write("Root", ws.Root); m_xmlWriter.WriteElementString("POS", ws.POS.Description); m_xmlWriter.WriteStartElement("Morphs"); foreach (Morph morph in ws.Morphs) { Write("Allomorph", morph.Allomorph); } m_xmlWriter.WriteEndElement(); m_xmlWriter.WriteElementString("MPRFeatures", ws.MPRFeatures.ToString()); m_xmlWriter.WriteElementString("HeadFeatures", ws.HeadFeatures.ToString()); m_xmlWriter.WriteElementString("FootFeatures", ws.FootFeatures.ToString()); m_xmlWriter.WriteEndElement(); }
/// <summary> /// Copies a partition from the input phonetic shape to the output phonetic shape. /// </summary> /// <param name="match">The match.</param> /// <param name="input">The input word synthesis.</param> /// <param name="output">The output word synthesis.</param> /// <param name="morpheme">The morpheme info.</param> public override void Apply(Match match, WordSynthesis input, WordSynthesis output, Allomorph allomorph) { IList <PhoneticShapeNode> nodes = match.GetPartition(m_partition); if (nodes != null && nodes.Count > 0) { Morph morph = null; for (PhoneticShapeNode node = nodes[0]; node != nodes[nodes.Count - 1].Next; node = node.Next) { PhoneticShapeNode newNode = node.Clone(); // mark the reduplicated segments with the gloss partition if (m_redup) { if (allomorph != null) { if (morph == null) { morph = new Morph(allomorph); output.Morphs.Add(morph); } newNode.Partition = morph.Partition; morph.Shape.Add(node.Clone()); } else { newNode.Partition = -1; } } else if (node.Partition != -1) { if (morph == null || morph.Partition != node.Partition) { morph = input.Morphs[node.Partition].Clone(); morph.Shape.Clear(); output.Morphs.Add(morph); } newNode.Partition = morph.Partition; morph.Shape.Add(node.Clone()); } output.Shape.Add(newNode); } } }
/// <summary> /// Applies the rule to the specified word synthesis. /// </summary> /// <param name="input">The word synthesis.</param> public override void Apply(WordSynthesis input) { // I don't think there is any difference between iterative and // simultaneous application Direction dir = Direction.RIGHT; switch (m_multApplication) { case MultAppOrder.LR_ITERATIVE: case MultAppOrder.SIMULTANEOUS: dir = Direction.RIGHT; break; case MultAppOrder.RL_ITERATIVE: dir = Direction.LEFT; break; } ProcessIterative(input.Shape, dir, m_lhsTemp, ModeType.SYNTHESIS); }
void ApplyRHS(Match headMatch, Match nonHeadMatch, WordSynthesis input, WordSynthesis output) { output.Shape.Clear(); output.Morphs.Clear(); output.Shape.Add(new Margin(Direction.LEFT)); foreach (MorphologicalOutput outputMember in m_transform.RHS) { Match curMatch; WordSynthesis curInput; if (outputMember.Partition < m_firstNonHeadPartition) { curMatch = headMatch; curInput = input; } else { curMatch = nonHeadMatch; curInput = input.NonHead; } outputMember.Apply(curMatch, curInput, output, m_morpheme.Gloss != null ? this : null); } output.Shape.Add(new Margin(Direction.RIGHT)); }
void ApplySlots(WordSynthesis input, int sIndex, FeatureValues origHeadFeatures, Set <WordSynthesis> output) { for (int i = sIndex; i < m_slots.Count; i++) { foreach (MorphologicalRule rule in m_slots[i].MorphologicalRules) { if (rule.IsApplicable(input)) { // this is the slot affix that realizes the features ICollection <WordSynthesis> syntheses; if (rule.ApplySlotAffix(input, origHeadFeatures, out syntheses)) { foreach (WordSynthesis ws in syntheses) { ApplySlots(ws, i + 1, origHeadFeatures, output); } } } } if (!m_slots[i].IsOptional) { if (Morpher.TraceTemplatesSynthesis) { input.CurrentTrace.AddChild(new TemplateSynthesisTrace(this, false, null)); } return; } } if (Morpher.TraceTemplatesSynthesis) { input.CurrentTrace.AddChild(new TemplateSynthesisTrace(this, false, input.Clone())); } output.Add(input); }
/// <summary> /// Inserts the segments and boundaries in to the output phonetic shape. /// </summary> /// <param name="match">The match.</param> /// <param name="input">The input word synthesis.</param> /// <param name="output">The output word synthesis.</param> /// <param name="morpheme">The morpheme info.</param> public override void Apply(Match match, WordSynthesis input, WordSynthesis output, Allomorph allomorph) { Morph morph = null; if (allomorph != null) { morph = new Morph(allomorph); output.Morphs.Add(morph); } for (PhoneticShapeNode node = m_pshape.Begin; node != m_pshape.Last; node = node.Next) { PhoneticShapeNode newNode = node.Clone(); if (morph != null) { newNode.Partition = morph.Partition; morph.Shape.Add(node.Clone()); } else { newNode.Partition = -1; } output.Shape.Add(newNode); } }
/// <summary> /// Applies this affix template to the specified input word synthesis. /// </summary> /// <param name="input">The input word synthesis.</param> /// <param name="output">The output word synthesis.</param> /// <returns><c>true</c> if the affix template applied, otherwise <c>false</c>.</returns> public bool Apply(WordSynthesis input, out IEnumerable <WordSynthesis> output) { FeatureValues headFeatures = input.HeadFeatures.Clone(); Set <WordSynthesis> results = new Set <WordSynthesis>(); if (Morpher.TraceTemplatesSynthesis) { // create the template synthesis input trace record TemplateSynthesisTrace tempTrace = new TemplateSynthesisTrace(this, true, input.Clone()); input.CurrentTrace.AddChild(tempTrace); } ApplySlots(input.Clone(), 0, headFeatures, results); if (results.Count > 0) { output = results; return(true); } else { output = null; return(false); } }
/// <summary> /// Applies all of the rules to the specified word synthesis. /// </summary> /// <param name="input">The input word synthesis.</param> /// <returns>All word synthesis records that result from the application of rules.</returns> public IEnumerable <WordSynthesis> Apply(WordSynthesis input) { if (m_isCyclic) { throw new NotImplementedException(HCStrings.kstidCyclicStratumNotSupported); } if (m_pruleOrder == PRuleOrder.SIMULTANEOUS) { throw new NotImplementedException(HCStrings.kstidSimultOrderNotSupported); } // TODO: handle cyclicity Set <WordSynthesis> output = new Set <WordSynthesis>(); ApplyMorphologicalRules(input.Clone(), 0, output); foreach (WordSynthesis cur in output) { ApplyPhonologicalRules(cur); } return(output); }
public override bool IsApplicable(WordSynthesis input) { return(RealizationalFeatures.IsMatch(input.RealizationalFeatures)); }
/// <summary> /// Does the real work of morphing the specified word. /// </summary> /// <param name="word">The word.</param> /// <param name="prev">The previous word.</param> /// <param name="next">The next word.</param> /// <param name="trace">The trace.</param> /// <returns>All valid word synthesis records.</returns> ICollection <WordSynthesis> MorphAndLookupToken(string word, string prev, string next, out WordAnalysisTrace trace, string[] selectTraceMorphs) { // convert the word to its phonetic shape PhoneticShape input = SurfaceStratum.CharacterDefinitionTable.ToPhoneticShape(word, ModeType.ANALYSIS); // if word contains invalid segments, the char def table will return null if (input == null) { MorphException me = new MorphException(MorphException.MorphErrorType.INVALID_SHAPE, this, string.Format(HCStrings.kstidInvalidWord, word, SurfaceStratum.CharacterDefinitionTable.ID)); me.Data["shape"] = word; me.Data["charDefTable"] = SurfaceStratum.CharacterDefinitionTable.ID; throw me; } // create the root of the trace tree trace = new WordAnalysisTrace(word, input.Clone()); Set <WordSynthesis> candidates = new Set <WordSynthesis>(); Set <WordAnalysis> inAnalysis = new Set <WordAnalysis>(); Set <WordAnalysis> outAnalysis = new Set <WordAnalysis>(); inAnalysis.Add(new WordAnalysis(input, SurfaceStratum, trace)); // Unapply rules for (int i = m_strata.Count - 1; i >= 0; i--) { outAnalysis.Clear(); foreach (WordAnalysis wa in inAnalysis) { if (m_traceStrataAnalysis) { // create the stratum analysis input trace record StratumAnalysisTrace stratumTrace = new StratumAnalysisTrace(m_strata[i], true, wa.Clone()); wa.CurrentTrace.AddChild(stratumTrace); } foreach (WordAnalysis outWa in m_strata[i].Unapply(wa, candidates, selectTraceMorphs)) { // promote each analysis to the next stratum if (i != 0) { outWa.Stratum = m_strata[i - 1]; } if (m_traceStrataAnalysis) { // create the stratum analysis output trace record for the output word synthesis outWa.CurrentTrace.AddChild(new StratumAnalysisTrace(m_strata[i], false, outWa.Clone())); } outAnalysis.Add(outWa); } } inAnalysis.Clear(); inAnalysis.AddMany(outAnalysis); } Set <WordSynthesis> allValidSyntheses = new Set <WordSynthesis>(); // Apply rules for each candidate entry foreach (WordSynthesis candidate in candidates) { Set <WordSynthesis> inSynthesis = new Set <WordSynthesis>(); Set <WordSynthesis> outSynthesis = new Set <WordSynthesis>(); for (int i = 0; i < m_strata.Count; i++) { // start applying at the stratum that this lex entry belongs to if (m_strata[i] == candidate.Root.Stratum) { inSynthesis.Add(candidate); } outSynthesis.Clear(); foreach (WordSynthesis cur in inSynthesis) { if (m_traceStrataSynthesis) { // create the stratum synthesis input trace record StratumSynthesisTrace stratumTrace = new StratumSynthesisTrace(m_strata[i], true, cur.Clone()); cur.CurrentTrace.AddChild(stratumTrace); } foreach (WordSynthesis outWs in m_strata[i].Apply(cur)) { // promote the word synthesis to the next stratum if (i != m_strata.Count - 1) { outWs.Stratum = m_strata[i + 1]; } if (m_traceStrataSynthesis) { // create the stratum synthesis output trace record for the output analysis outWs.CurrentTrace.AddChild(new StratumSynthesisTrace(m_strata[i], false, outWs.Clone())); } outSynthesis.Add(outWs); } } inSynthesis.Clear(); inSynthesis.AddMany(outSynthesis); } foreach (WordSynthesis ws in outSynthesis) { if (ws.IsValid) { allValidSyntheses.Add(ws); } } } Set <WordSynthesis> results = new Set <WordSynthesis>(); // sort the resulting syntheses according to the order of precedence of each allomorph in // their respective morphemes List <WordSynthesis> sortedSyntheses = new List <WordSynthesis>(allValidSyntheses); sortedSyntheses.Sort(); WordSynthesis prevValidSynthesis = null; foreach (WordSynthesis cur in sortedSyntheses) { // enforce the disjunctive property of allomorphs by ensuring that this word synthesis // has the highest order of precedence for its allomorphs while also allowing for free // fluctuation, also check that the phonetic shape matches the original input word if ((prevValidSynthesis == null || AreAllomorphsNondisjunctive(cur, prevValidSynthesis)) && SurfaceStratum.CharacterDefinitionTable.IsMatch(word, cur.Shape)) { if (m_traceSuccess) { // create the report a success output trace record for the output analysis cur.CurrentTrace.AddChild(new ReportSuccessTrace(cur)); } // do not add to the result if it has the same root, shape, and morphemes as another result bool duplicate = false; foreach (WordSynthesis ws in results) { if (cur.Duplicates(ws)) { duplicate = true; break; } } if (!duplicate) { results.Add(cur); } } prevValidSynthesis = cur; } return(results); }
/// <summary> /// Initializes a new instance of the <see cref="TemplateSynthesisTrace"/> class. /// </summary> /// <param name="template">The template.</param> /// <param name="input">if <c>true</c> this is an input record, if <c>false</c> this is an output record.</param> /// <param name="synthesis">The input or output word synthesis.</param> internal TemplateSynthesisTrace(AffixTemplate template, bool input, WordSynthesis synthesis) : base(template, input) { m_synthesis = synthesis; }
/// <summary> /// Initializes a new instance of the <see cref="PhonologicalRuleSynthesisTrace"/> class. /// </summary> /// <param name="rule">The rule.</param> /// <param name="input">The input.</param> internal PhonologicalRuleSynthesisTrace(PhonologicalRule rule, WordSynthesis input) : base(rule) { m_input = input; }
/// <summary> /// Initializes a new instance of the <see cref="StratumSynthesisTrace"/> class. /// </summary> /// <param name="stratum">The stratum.</param> /// <param name="input">if <c>true</c> this is an input record, if <c>false</c> this is an output record.</param> /// <param name="synthesis">The input or output word synthesis.</param> internal StratumSynthesisTrace(Stratum stratum, bool input, WordSynthesis synthesis) : base(stratum, input) { m_synthesis = synthesis; }