public void Add(PhoneticShapeNode node, T value, Direction dir) { switch (node.Type) { case PhoneticShapeNode.NodeType.MARGIN: if (node == node.Owner.GetLast(dir)) { // we are at the end of the phonetic shape, so add the lexical // entry to this node m_values.Add(value); return; } else { // skip first margin Add(node.GetNext(dir), value, dir); } break; case PhoneticShapeNode.NodeType.BOUNDARY: // skip boundaries Add(node.GetNext(dir), value, dir); break; case PhoneticShapeNode.NodeType.SEGMENT: Segment seg = (Segment)node; TrieNode tnode = null; foreach (TrieNode child in m_children) { if (seg.FeatureValues.FeatureSystem.HasFeatures) { // we check for exact matches of feature sets when adding if (child.m_segDef.SynthFeatures.Equals(seg.FeatureValues)) { tnode = child; break; } } else if (child.m_segDef == seg.SegmentDefinition) { tnode = child; break; } } if (tnode == null) { // new node needs to be added tnode = new TrieNode(seg.SegmentDefinition); m_children.Add(tnode); } // recursive call matching child node tnode.Add(node.GetNext(dir), value, dir); break; } }
protected IList <Match> MatchNext(PhoneticShapeNode node, Direction dir, ModeType mode, VariableValues instantiatedVars) { PhoneticPatternNode n = GetNext(dir); // skip boundaries in analysis mode if (mode == ModeType.ANALYSIS) { while (n != null && n.Type == NodeType.BDRY_CTXT) { n = n.GetNext(dir); } } List <Match> matches = new List <Match>(); if (n == null) { // we are at the end of the pattern, so we have a match matches.Add(new Match(instantiatedVars)); } else { // try skipping over optional shape nodes do { // try the next node in the pattern node = node.GetNext(dir); matches.AddRange(n.Match(node, dir, mode, instantiatedVars)); }while (node != null && node.IsOptional); } return(matches); }
bool FindNextMatchLHS(PhoneticShapeNode node, Direction dir, out Match match) { for (; node != node.Owner.GetLast(dir); node = node.GetNext(dir)) { VariableValues instantiatedVars = new VariableValues(m_alphaVars); if (m_lhs.Count == 0) { // epenthesis rules always match the LHS match = new Match(instantiatedVars); match.Add(node); return(true); } else { IList <Match> matches; if (m_lhs.IsMatch(node, dir, ModeType.SYNTHESIS, instantiatedVars, out matches)) { match = matches[0]; return(true); } } } match = null; return(false); }
bool FindNextMatchRHS(PhoneticShapeNode node, Direction dir, out Match match) { for (; node != node.Owner.GetLast(dir); node = node.GetNext(dir)) { if (node.Type == PhoneticShapeNode.NodeType.BOUNDARY) { continue; } if (m_analysisTarget.Count == 0) { // if the analysis target is empty (deletion rule), // just check environment VariableValues instantiatedVars = new VariableValues(m_rule.m_alphaVars); if (MatchEnvEmpty(node, dir, ModeType.ANALYSIS, instantiatedVars)) { match = new Match(instantiatedVars); match.Add(node); return(true); } } else { // analysis target is non-empty, check everything if (MatchAnalysisTarget(node, dir, out match)) { return(true); } } } match = null; return(false); }
public bool MatchEnvEmpty(PhoneticShapeNode node, Direction dir, ModeType mode, VariableValues instantiatedVars) { PhoneticShapeNode leftNode = null; PhoneticShapeNode rightNode = null; switch (dir) { case Direction.LEFT: rightNode = node; leftNode = node.GetNext(Direction.LEFT); break; case Direction.RIGHT: rightNode = node.GetNext(Direction.RIGHT); leftNode = node; break; } // in case this is an epenthesis rule, we want to ensure that the segment to the right // of where we're going to do the epenthesis is not a boundary marker, unless the // environment calls for one. if (mode == ModeType.SYNTHESIS && m_env.RightEnvironment != null && m_env.RightEnvironment.Count > 0) { if (rightNode.Type == PhoneticShapeNode.NodeType.BOUNDARY && m_env.RightEnvironment.First.Type != PhoneticPatternNode.NodeType.BDRY_CTXT) { return(false); } } // there is a small difference between legacy HC and HC.NET in matching environments when the // analysis target is empty and one of the environments is empty. In this case, legacy HC does // not try to skip the initial optional segments when matching the right environment. I think // this will cause HC.NET to overproduce a little more during analysis, which isn't that big of a // deal if (!m_env.IsMatch(leftNode, rightNode, mode, instantiatedVars)) { return(false); } // remove ambiguous variables instantiatedVars.RemoveAmbiguousVariables(); return(true); }
/// <summary> /// Checks if the specified phonetic shape node matches this boundary context. /// </summary> /// <param name="node">The phonetic shape node.</param> /// <param name="dir">The direction.</param> /// <param name="mode">The mode.</param> /// <param name="instantiatedVars">The instantiated variables.</param> /// <returns>All matches.</returns> internal override IList <Match> Match(PhoneticShapeNode node, Direction dir, ModeType mode, VariableValues instantiatedVars) { // only match boundaries in synthesis mode if (mode == ModeType.SYNTHESIS) { switch (node.Type) { case PhoneticShapeNode.NodeType.BOUNDARY: Boundary bdry = node as Boundary; // check if string representations match if (m_bdryDef.StrRep != bdry.BoundaryDefinition.StrRep) { return(new List <Match>()); } // move to next node IList <Match> matches = MatchNext(node, dir, mode, instantiatedVars); foreach (Match match in matches) { match.Add(node, m_partition); } return(matches); case PhoneticShapeNode.NodeType.MARGIN: Margin margin = node as Margin; if (dir == margin.MarginType) { // we are at the end of the phonetic shape, so it does not match return(new List <Match>()); } else { return(Match(node.GetNext(dir), dir, mode, instantiatedVars)); } } return(new List <Match>()); } else { PhoneticPatternNode n = GetNext(dir); if (n == null) { // this was the last node in the pattern, so we have a match List <Match> matches = new List <Match>(); matches.Add(new Match(instantiatedVars)); return(matches); } else { return(n.Match(node, dir, mode, instantiatedVars)); } } }
/// <summary> /// Checks if a phonetic shape matches this pattern starting at the specified node. /// </summary> /// <param name="node">The phonetic shape node.</param> /// <param name="dir">The direction.</param> /// <param name="mode">The mode.</param> /// <param name="instantiatedVars">The instantiated variables.</param> /// <param name="matches">The matches.</param> /// <returns><c>true</c> if the shape successfully matched this pattern, otherwise <c>false</c></returns> public bool IsMatch(PhoneticShapeNode node, Direction dir, ModeType mode, VariableValues instantiatedVars, out IList <Match> matches) { List <Match> matchesList = new List <Match>(); matches = matchesList; PhoneticPatternNode n = GetFirst(dir); // skip boundaries during analysis if (mode == ModeType.ANALYSIS) { while (n != null && n.Type == PhoneticPatternNode.NodeType.BDRY_CTXT) { n = n.GetNext(dir); } } if (n == null) { // we are at the end of the pattern, so it is a match matchesList.Add(new Match(instantiatedVars)); } else { PhoneticShapeNode cur = node; PhoneticShapeNode prev = null; do { matchesList.AddRange(n.Match(cur, dir, mode, instantiatedVars)); prev = cur; if (cur != null) { cur = cur.GetNext(dir); } }while (cur != null && prev.IsOptional); } //matchesList.Sort(); return(matchesList.Count > 0); }
/// <summary> /// Checks if the specified phonetic shape node matches this margin context. /// </summary> /// <param name="node">The phonetic shape node.</param> /// <param name="dir">The direction.</param> /// <param name="mode">The mode.</param> /// <param name="instantiatedVars">The instantiated variables.</param> /// <returns>All matches.</returns> internal override IList <Match> Match(PhoneticShapeNode node, Direction dir, ModeType mode, VariableValues instantiatedVars) { switch (node.Type) { case PhoneticShapeNode.NodeType.MARGIN: Margin margin = node as Margin; if (m_marginType != margin.MarginType) { return(new List <Match>()); } // move to next node return(MatchNext(node, dir, mode, instantiatedVars)); case PhoneticShapeNode.NodeType.BOUNDARY: return(Match(node.GetNext(dir), dir, mode, instantiatedVars)); } return(new List <Match>()); }
bool FindNextMatch(PhoneticShapeNode node, Direction dir, PhoneticPattern ptemp, ModeType mode, out Match match) { for (; node != node.Owner.GetLast(dir); node = node.GetNext(dir)) { if (mode == ModeType.ANALYSIS && node.Type == PhoneticShapeNode.NodeType.BOUNDARY) { continue; } IList <Match> matches; if (ptemp.IsMatch(node, dir, mode, out matches)) { match = matches[0]; return(true); } } match = null; return(false); }
public IList <Match> Search(PhoneticShapeNode node, Direction dir, bool partialMatch) { IList <Match> matches = null; switch (node.Type) { case PhoneticShapeNode.NodeType.MARGIN: if (node == node.Owner.GetLast(dir)) { matches = new List <Match>(); if (!partialMatch) { // we are at the end of the phonetic shape, so return // all values in this node foreach (T value in m_values) { matches.Add(new Match(value)); } } } else { // skip the first margin matches = Search(node.GetNext(dir), dir, partialMatch); } break; case PhoneticShapeNode.NodeType.BOUNDARY: // skip boundaries matches = Search(node.GetNext(dir), dir, partialMatch); foreach (Match match in matches) { match.AddNode(node); } break; case PhoneticShapeNode.NodeType.SEGMENT: Segment seg = (Segment)node; PhoneticShapeNode nextNode = node.GetNext(dir); List <Match> segMatches = new List <Match>(); foreach (TrieNode child in m_children) { // check for unifiability when searching if (seg.FeatureValues.FeatureSystem.HasFeatures) { if (seg.FeatureValues.IsUnifiable(child.m_segDef.SynthFeatures)) { segMatches.AddRange(child.Search(nextNode, dir, partialMatch)); } } else if (seg.IsSegmentInstantiated(child.m_segDef)) { segMatches.AddRange(child.Search(nextNode, dir, partialMatch)); } } // if this is an optional node, we can try skipping it if (node.IsOptional) { segMatches.AddRange(Search(nextNode, dir, partialMatch)); } matches = segMatches; foreach (Match match in matches) { match.AddNode(node); } break; } if (partialMatch) { foreach (T value in m_values) { matches.Add(new Match(value)); } } return(matches); }
/// <summary> /// Checks if the specified phonetic shape node matches this simple context. /// </summary> /// <param name="node">The phonetic shape node.</param> /// <param name="dir">The direction.</param> /// <param name="mode">The mode.</param> /// <param name="instantiatedVars">The instantiated variables.</param> /// <returns>All matches.</returns> internal override IList <Match> Match(PhoneticShapeNode node, Direction dir, ModeType mode, VariableValues instantiatedVars) { switch (node.Type) { case PhoneticShapeNode.NodeType.BOUNDARY: // only check boundaries in synthesis mode when the pattern is a target, // otherwise skip if (mode == ModeType.SYNTHESIS) { if (Owner.IsTarget) { return(new List <Match>()); } else { IList <Match> bdryMatches = Match(node.GetNext(dir), dir, mode, instantiatedVars); foreach (Match match in bdryMatches) { match.Add(node, m_partition); } return(bdryMatches); } } else { return(Match(node.GetNext(dir), dir, mode, instantiatedVars)); } case PhoneticShapeNode.NodeType.MARGIN: Margin margin = node as Margin; if (dir == margin.MarginType) { // we are at the end of the shape, so no match return(new List <Match>()); } else { return(Match(node.GetNext(dir), dir, mode, instantiatedVars)); } case PhoneticShapeNode.NodeType.SEGMENT: Segment seg = node as Segment; if (mode == ModeType.SYNTHESIS && Owner.IsTarget) { // check segment to see if it has already been altered by another // subrule, only matters for simultaneously applying rules if (!seg.IsClean) { return(new List <Match>()); } } VariableValues tempVars = instantiatedVars.Clone(); if (m_featSys.HasFeatures) { if (!IsFeatureMatch(seg, tempVars, mode)) { return(new List <Match>()); } } else { if (!IsSegmentMatch(seg)) { return(new List <Match>()); } } // move to the next node IList <Match> segMatches = MatchNext(node, dir, mode, tempVars); foreach (Match match in segMatches) { match.Add(node, m_partition); } return(segMatches); } return(new List <Match>()); }