public override bool ApplySlotAffix(WordSynthesis input, FeatureValues origHeadFeatures, TraceManager trace, out ICollection<WordSynthesis> output) { output = null; if (IsBlockedSlotAffix(origHeadFeatures)) return false; return base.ApplySlotAffix(input, origHeadFeatures, trace, out output); }
public override bool Unapply(WordAnalysis input, int srIndex, TraceManager trace, string[] selectTraceMorphs, out ICollection<WordAnalysis> output) { output = null; FeatureValues rzFeats; if (!RealizationalFeatures.Unify(input.RealizationalFeatures, out rzFeats)) return false; if (base.Unapply(input, srIndex, trace, selectTraceMorphs, out output)) { foreach (WordAnalysis wa in output) wa.RealizationalFeatures = rzFeats; return true; } return false; }
/// <summary> /// Applies the rule to the specified word synthesis. /// </summary> /// <param name="input">The word synthesis.</param> /// <param name="trace"></param> public override void Apply(WordSynthesis input, TraceManager trace) { if (trace != null) trace.BeginApplyPhonologicalRule(this, input); // only try to apply applicable subrules var subrules = new List<Subrule>(); foreach (Subrule sr in m_subrules) { if (sr.IsApplicable(input, trace)) 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) ((Segment) node).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.EndApplyPhonologicalRule(this, input); }
/// <summary> /// Applies the rule to the specified word synthesis. /// </summary> /// <param name="input">The input word synthesis.</param> /// <param name="output">The output word syntheses.</param> /// <returns> /// <c>true</c> if the rule was successfully applied, otherwise <c>false</c> /// </returns> public override bool Apply(WordSynthesis input, TraceManager trace, out ICollection<WordSynthesis> output) { output = null; // these should probably be moved to IsApplicable, but we will leave it here for // now so we don't have to call it again to set the features for the output word // synthesis record // check head features FeatureValues headFeatures; if (!m_requiredHeadFeatures.UnifyDefaults(input.HeadFeatures, out headFeatures)) return false; // check foot features FeatureValues footFeatures; if (!m_requiredFootFeatures.UnifyDefaults(input.FootFeatures, out footFeatures)) return false; output = new List<WordSynthesis>(); for (int i = 0; i < m_subrules.Count; i++) { WordSynthesis ws; if (m_subrules[i].Apply(input, out ws)) { if (m_outPOS != null) ws.POS = m_outPOS; if (m_outHeadFeatures != null) ws.HeadFeatures = m_outHeadFeatures.Clone(); ws.HeadFeatures.Add(headFeatures); if (m_outFootFeatures != null) ws.FootFeatures = m_outFootFeatures.Clone(); ws.FootFeatures.Add(footFeatures); if (m_obligHeadFeatures != null) { foreach (Feature feature in m_obligHeadFeatures) ws.AddObligatoryHeadFeature(feature); } ws.MorphologicalRuleApplied(this); ws = CheckBlocking(ws, trace); if (trace != null) trace.MorphologicalRuleApplied(this, input, ws, m_subrules[i]); output.Add(ws); // return all word syntheses that match subrules that are constrained by environments, // HC violates the disjunctive property of allomorphs here because it cannot check the // environmental constraints until it has a surface form, we will enforce the disjunctive // property of allomorphs at that time // HC also checks for free fluctuation, if the next subrule has the same constraints, we // do not treat them as disjunctive if ((i != m_subrules.Count - 1 && !m_subrules[i].ConstraintsEqual(m_subrules[i + 1])) && m_subrules[i].RequiredEnvironments == null && m_subrules[i].ExcludedEnvironments == null) { break; } } } if (trace != null && output.Count == 0) trace.MorphologicalRuleNotApplied(this, input); return output.Count > 0; }
/// <summary> /// Unapplies the specified subrule to the specified word analysis. /// </summary> /// <param name="input">The input word analysis.</param> /// <param name="srIndex">Index of the subrule.</param> /// <param name="output">All resulting word analyses.</param> /// <param name="selectTraceMorphs">list of ids to be used in a selective trace</param> /// <returns> /// <c>true</c> if the subrule was successfully unapplied, otherwise <c>false</c> /// </returns> public override bool Unapply(WordAnalysis input, int srIndex, TraceManager trace, string[] selectTraceMorphs, out ICollection<WordAnalysis> output) { if (UseThisRule(selectTraceMorphs) && m_subrules[srIndex].Unapply(input, out output)) { foreach (WordAnalysis wa in output) { if (m_requiredPOSs != null && m_requiredPOSs.Count > 0) { foreach (PartOfSpeech pos in m_requiredPOSs) wa.AddPOS(pos); } else if (m_outPOS == null) { wa.UninstantiatePOS(); } wa.MorphologicalRuleUnapplied(this); if (trace != null) trace.MorphologicalRuleUnapplied(this, input, wa, m_subrules[srIndex]); } return true; } output = null; return false; }
/// <summary> /// Applies the rule to the specified word synthesis. /// </summary> /// <param name="input">The input word synthesis.</param> /// <param name="trace"></param> public abstract void Apply(WordSynthesis input, TraceManager trace);
} // end MorphAndLookupToken private void AddResult(string word, Set<WordSynthesis> results, WordSynthesis cur, TraceManager trace) { if (SurfaceStratum.CharacterDefinitionTable.IsMatch(word, cur.Shape)) { if (trace != null) trace.ReportSuccess(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); } } }
ICollection<WordSynthesis> MorphAndLookupToken(string word, string prev, string next, TraceManager trace) { return MorphAndLookupToken(word, prev, next, trace, null); }
/// <summary> /// Applies the rule to the specified word synthesis. This method is used by affix templates. /// </summary> /// <param name="input">The input word synthesis.</param> /// <param name="origHeadFeatures">The original head features before template application.</param> /// <param name="trace"></param> /// <param name="output">The output word syntheses.</param> /// <returns> /// <c>true</c> if the rule was successfully applied, otherwise <c>false</c> /// </returns> public abstract bool ApplySlotAffix(WordSynthesis input, FeatureValues origHeadFeatures, TraceManager trace, out ICollection<WordSynthesis> output);
void ApplySlots(WordSynthesis input, int sIndex, FeatureValues origHeadFeatures, TraceManager trace, 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, trace, out syntheses)) { foreach (WordSynthesis ws in syntheses) ApplySlots(ws, i + 1, origHeadFeatures, trace, output); } } } if (!m_slots[i].IsOptional) { if (trace != null) trace.EndApplyTemplate(this, input, false); return; } } if (trace != null) trace.EndApplyTemplate(this, input, true); output.Add(input); }
/// <summary> /// Applies this affix template to the specified input word synthesis. /// </summary> /// <param name="input">The input word synthesis.</param> /// <param name="trace"></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, TraceManager trace, out IEnumerable<WordSynthesis> output) { FeatureValues headFeatures = input.HeadFeatures.Clone(); var results = new Set<WordSynthesis>(); if (trace != null) trace.BeginApplyTemplate(this, input); ApplySlots(input.Clone(), 0, headFeatures, trace, results); if (results.Count > 0) { output = results; return true; } output = null; return false; }
void UnapplySlots(WordAnalysis input, int sIndex, TraceManager trace, string[] selectTraceMorphs, Set<WordAnalysis> output) { for (int i = sIndex; i >= 0; i--) { foreach (MorphologicalRule rule in m_slots[i].MorphologicalRules) { if (rule.BeginUnapplication(input)) { bool ruleUnapplied = false; for (int j = 0; j < rule.SubruleCount; j++) { ICollection<WordAnalysis> analyses; if (rule.Unapply(input, j, trace, selectTraceMorphs, out analyses)) { ruleUnapplied = true; foreach (WordAnalysis wa in analyses) { if (wa.Shape.Count > 2) UnapplySlots(wa, i - 1, trace, selectTraceMorphs, output); } } } rule.EndUnapplication(input, trace, ruleUnapplied); } } // we can skip this slot if it is optional if (!m_slots[i].IsOptional) { if (trace != null) trace.EndUnapplyTemplate(this, input, false); return; } } if (trace != null) trace.EndUnapplyTemplate(this, input, true); output.Add(input); }
/// <summary> /// Unapplies this affix template to specified input word analysis. /// </summary> /// <param name="input">The input word analysis.</param> /// <param name="selectTraceMorphs"></param> /// <param name="output">The output word analyses.</param> /// <param name="trace"></param> /// <returns>The resulting word analyses.</returns> public bool Unapply(WordAnalysis input, TraceManager trace, string[] selectTraceMorphs, out IEnumerable<WordAnalysis> output) { var results = new Set<WordAnalysis>(); if (trace != null) trace.BeginUnapplyTemplate(this, input); UnapplySlots(input.Clone(), m_slots.Count - 1, trace, selectTraceMorphs, results); foreach (WordAnalysis wa in results) { foreach (PartOfSpeech pos in m_requiredPOSs) wa.AddPOS(pos); } if (results.Count > 0) { output = results; return true; } output = null; return false; }
/// <summary> /// Applies the rule to the specified word analysis. /// </summary> /// <param name="input">The input word synthesis.</param> /// <param name="output">The output word syntheses.</param> /// <returns> /// <c>true</c> if the rule was successfully applied, otherwise <c>false</c> /// </returns> public override bool Apply(WordSynthesis input, TraceManager trace, out ICollection<WordSynthesis> output) { output = null; // these should probably be moved to IsApplicable, but we will leave it here for // now so we don't have to call it again to set the features for the output word // synthesis record // check head features FeatureValues headHeadFeatures; if (!m_headRequiredHeadFeatures.UnifyDefaults(input.HeadFeatures, out headHeadFeatures)) return false; FeatureValues nonHeadHeadFeatures; if (!m_nonHeadRequiredHeadFeatures.UnifyDefaults(input.NonHead.HeadFeatures, out nonHeadHeadFeatures)) return false; // check foot features FeatureValues headFootFeatures; if (!m_headRequiredFootFeatures.UnifyDefaults(input.FootFeatures, out headFootFeatures)) return false; FeatureValues nonHeadFootFeatures; if (!m_nonHeadRequiredFootFeatures.UnifyDefaults(input.NonHead.FootFeatures, out nonHeadFootFeatures)) return false; output = new List<WordSynthesis>(); foreach (Subrule sr in m_subrules) { WordSynthesis ws; if (sr.Apply(input, out ws)) { if (m_outPOS != null) ws.POS = m_outPOS; if (m_outHeadFeatures != null) ws.HeadFeatures = m_outHeadFeatures.Clone(); ws.HeadFeatures.Add(headHeadFeatures); if (m_outFootFeatures != null) ws.FootFeatures = m_outFootFeatures.Clone(); ws.FootFeatures.Add(headFootFeatures); if (m_obligHeadFeatures != null) { foreach (Feature feature in m_obligHeadFeatures) ws.AddObligatoryHeadFeature(feature); } ws.MorphologicalRuleApplied(this); ws = CheckBlocking(ws, trace); if (trace != null) trace.MorphologicalRuleApplied(this, input, ws, sr); output.Add(ws); // return all word syntheses that match subrules that are constrained by environments, // HC violates the disjunctive property of allomorphs here because it cannot check the // environmental constraints until it has a surface form, we will enforce the disjunctive // property of allomorphs at that time if (sr.RequiredEnvironments == null && sr.ExcludedEnvironments == null) { break; } } } return output.Count > 0; }
public ICollection<WordSynthesis> MorphAndLookupWord(string word, TraceManager trace, string[] selectTraceMorphs) { return MorphAndLookupToken(word, null, null, trace, selectTraceMorphs); }
public IList<ICollection<WordSynthesis>> MorphAndLookupWordList(IList<string> wordList, TraceManager trace) { var results = new List<ICollection<WordSynthesis>>(); string prev = null; string word = wordList[0]; for (int i = 0; i < wordList.Count; i++) { string next = null; if (i + 1 < wordList.Count) next = wordList[i + 1]; results.Add(MorphAndLookupToken(word, prev, next, trace)); prev = word; word = next; } return results; }
protected WordSynthesis CheckBlocking(WordSynthesis ws, TraceManager trace) { 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 (trace != null) trace.Blocking(BlockType.RULE, ws, entry); return new WordSynthesis(entry.PrimaryAllomorph, ws.RealizationalFeatures, ws.CurrentTraceObject); } } return ws; }
/// <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> /// <param name="selectTraceMorphs"></param> /// <returns>All valid word synthesis records.</returns> ICollection<WordSynthesis> MorphAndLookupToken(string word, string prev, string next, TraceManager trace, string[] selectTraceMorphs) { PhoneticShape input; try { // convert the word to its phonetic shape; it could throw a missing phonetic shape exception input = SurfaceStratum.CharacterDefinitionTable.ToPhoneticShape(word, ModeType.ANALYSIS); } catch (MissingPhoneticShapeException mpse) { var me = new MorphException(MorphException.MorphErrorType.INVALID_SHAPE, this, string.Format(HCStrings.kstidInvalidWord, word, SurfaceStratum.CharacterDefinitionTable.ID, mpse.Position+1, word.Substring(mpse.Position), mpse.PhonemesFoundSoFar)); me.Data["shape"] = word; me.Data["charDefTable"] = SurfaceStratum.CharacterDefinitionTable.ID; me.Data["position"] = mpse.Position; me.Data["phonemesFoundSoFar"] = mpse.PhonemesFoundSoFar; throw me; } var inputAnalysis = new WordAnalysis(input, SurfaceStratum); if (trace != null) trace.BeginAnalyzeWord(word, inputAnalysis); var candidates = new Set<WordSynthesis>(); var inAnalysis = new Set<WordAnalysis>(); var outAnalysis = new Set<WordAnalysis>(); inAnalysis.Add(inputAnalysis); // Unapply rules for (int i = m_strata.Count - 1; i >= 0; i--) { outAnalysis.Clear(); foreach (WordAnalysis wa in inAnalysis) { if (trace != null) trace.BeginUnapplyStratum(m_strata[i], wa); foreach (WordAnalysis outWa in m_strata[i].Unapply(wa, trace, selectTraceMorphs, candidates)) { // promote each analysis to the next stratum if (i != 0) outWa.Stratum = m_strata[i - 1]; if (trace != null) trace.EndUnapplyStratum(m_strata[i], outWa); outAnalysis.Add(outWa); } } inAnalysis.Clear(); inAnalysis.AddMany(outAnalysis); } var allValidSyntheses = new Set<WordSynthesis>(); // Apply rules for each candidate entry foreach (WordSynthesis candidate in candidates) { var inSynthesis = new Set<WordSynthesis>(); var 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 (trace != null) trace.BeginApplyStratum(m_strata[i], cur); foreach (WordSynthesis outWs in m_strata[i].Apply(cur, trace)) { // promote the word synthesis to the next stratum if (i != m_strata.Count - 1) outWs.Stratum = m_strata[i + 1]; if (trace != null) trace.EndApplyStratum(m_strata[i], outWs); outSynthesis.Add(outWs); } } inSynthesis.Clear(); inSynthesis.AddMany(outSynthesis); } foreach (WordSynthesis ws in outSynthesis) { if (ws.IsValid(trace)) allValidSyntheses.Add(ws); } } var results = new Set<WordSynthesis>(); // sort the resulting syntheses according to the order of precedence of each allomorph in // their respective morphemes var sortedSyntheses = new List<WordSynthesis>(allValidSyntheses); sortedSyntheses.Sort(); WordSynthesis prevValidSynthesis = null; bool allFreeFluctuation = true; 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 if (prevValidSynthesis == null || AreAllomorphsNondisjunctive(cur, prevValidSynthesis)) { AddResult(word, results, cur, trace); allFreeFluctuation = true; } else if (allFreeFluctuation && CheckFreeFluctuation(cur, prevValidSynthesis)) { AddResult(word, results, cur, trace); } else { allFreeFluctuation = false; } prevValidSynthesis = cur; } return results; } // end MorphAndLookupToken
/// <summary> /// Unapplies the specified subrule to the specified word analysis. /// </summary> /// <param name="input">The input word analysis.</param> /// <param name="srIndex">Index of the subrule.</param> /// <param name="output">All resulting word analyses.</param> /// <param name="trace"></param> /// <param name="selectTraceMorphs">list of ids to be used in a selective trace</param> /// <returns><c>true</c> if the subrule was successfully unapplied, otherwise <c>false</c></returns> public abstract bool Unapply(WordAnalysis input, int srIndex, TraceManager trace, string[] selectTraceMorphs, out ICollection<WordAnalysis> output);
/// <summary> /// Unapplies the rule to the specified word analysis. /// </summary> /// <param name="input">The input word analysis.</param> /// <param name="trace"></param> public abstract void Unapply(WordAnalysis input, TraceManager trace);
/// <summary> /// Performs any post-processing required after the unapplication of a word analysis. This must /// be called after a successful <c>BeginUnapplication</c> call and any <c>Unapply</c> calls. /// </summary> /// <param name="input">The input word analysis.</param> /// <param name="trace"></param> /// <param name="unapplied">if set to <c>true</c> if the input word analysis was successfully unapplied.</param> public abstract void EndUnapplication(WordAnalysis input, TraceManager trace, bool unapplied);
/// <summary> /// Applies the rule to the specified word synthesis. /// </summary> /// <param name="input">The word synthesis.</param> /// <param name="trace"></param> public override void Apply(WordSynthesis input, TraceManager trace) { // I don't think there is any difference between iterative and // simultaneous application var 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); }
/// <summary> /// Applies the rule to the specified word synthesis. /// </summary> /// <param name="input">The input word synthesis.</param> /// <param name="trace"></param> /// <param name="output">The output word syntheses.</param> /// <returns><c>true</c> if the rule was successfully applied, otherwise <c>false</c></returns> public abstract bool Apply(WordSynthesis input, TraceManager trace, out ICollection<WordSynthesis> output);
/// <summary> /// Performs any post-processing required after the unapplication of a word analysis. This must /// be called after a successful <c>BeginUnapplication</c> call and any <c>Unapply</c> calls. /// </summary> /// <param name="input">The input word analysis.</param> /// <param name="trace"></param> /// <param name="unapplied">if set to <c>true</c> if the input word analysis was successfully unapplied.</param> public override void EndUnapplication(WordAnalysis input, TraceManager trace, bool unapplied) { if (trace != null && !unapplied) trace.MorphologicalRuleNotUnapplied(this, input); }
/// <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, TraceManager 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) trace.PhonologicalRuleNotApplicablePOS(input, m_requiredPOSs); if (!fRequiredMPRFeaturesMet) trace.PhonologicalRuleNotApplicableMPRFeatures(MPRFeaturesType.REQUIRED, input, m_requiredMPRFeatures); if (!fExcludedMPRFeaturesMet) trace.PhonologicalRuleNotApplicableMPRFeatures(MPRFeaturesType.EXCLUDED, input, m_excludedMPRFeatures); } return (fRequiredPOSMet && fRequiredMPRFeaturesMet && fExcludedMPRFeaturesMet); }
/// <summary> /// Applies the rule to the specified word synthesis. This method is used by affix templates. /// </summary> /// <param name="input">The input word synthesis.</param> /// <param name="origHeadFeatures">The original head features before template application.</param> /// <param name="output">The output word syntheses.</param> /// <returns> /// <c>true</c> if the rule was successfully applied, otherwise <c>false</c> /// </returns> public override bool ApplySlotAffix(WordSynthesis input, FeatureValues origHeadFeatures, TraceManager trace, out ICollection<WordSynthesis> output) { return Apply(input, trace, out output); }
/// <summary> /// Unapplies the rule to the specified word analysis. /// </summary> /// <param name="input">The input word analysis.</param> /// <param name="trace"></param> public override void Unapply(WordAnalysis input, TraceManager trace) { if (trace != null) trace.BeginUnapplyPhonologicalRule(this, input); foreach (Subrule sr in m_subrules) sr.Unapply(input.Shape); if (trace != null) trace.EndUnapplyPhonologicalRule(this, input); }