/** * /// Determines if the context pair needs an empty version. A context pair needs an empty version if the left * /// context has a max size of zero. * * /// @param cp the contex pair to check * /// @return <code>true</code> if the pair needs an empt version */ private Boolean NeedsEmptyVersion(ContextPair cp) { UnitContext left = cp.LeftContext; Unit[] units = left.Units; return(units.Length > 0 && (GetRightContextSize(units[0]) < GetRightContextSize())); }
/// <summary> /// Gets the context-free entry point to this state /// </summary> /// <returns>the entry point to the state</returns> /// TODO: ideally we'll look for entry points with no left // context, but those don't exist yet so we just take // the first entry point with an SILENCE left context // note that this assumes that the first node in a grammar has a // word and that word is a SIL. Not always a valid assumption. public SentenceHMMState GetEntryPoint() { ContextPair cp = ContextPair.Get(UnitContext.Silence, UnitContext.Silence); List <ISearchState> list = GetEntryPoints(cp); return(list == null || list.Count == 0 ? null : (SentenceHMMState)list[0]); }
/** * /// Gets the ContextPair for the given set of contexts. This is a factory method. If the ContextPair already exists, * /// return that one, otherwise, create it and store it so it can be reused. * * /// @param left the left context * /// @param right the right context * /// @return the unit context. */ public static ContextPair Get(UnitContext left, UnitContext right) { var newCp = new ContextPair(left, right); var cachedCp = ContextPairCache.cache(newCp); return(cachedCp ?? newCp); }
/** * /// Attaches the given unit to the given tail, expanding the unit if necessary. If an identical unit is already * /// attached, then this path is folded into the existing path. * * /// @param parent the parent state * /// @param tail the place to attach the unit to * /// @param units the set of units * /// @param which the index into the set of units * /// @param leftContext the left context for the unit * /// @param rightContext the right context for the unit * /// @return the tail of the added unit (or null if the path was folded onto an already expanded path. */ private SentenceHMMState AttachUnit(PronunciationState parent, SentenceHMMState tail, Unit[] units, int which, UnitContext leftContext, UnitContext rightContext) { Unit[] lc = GetLC(leftContext, units, which); Unit[] rc = GetRC(units, which, rightContext); UnitContext actualRightContext = UnitContext.Get(rc); LeftRightContext context = LeftRightContext.Get(lc, rc); Unit cdUnit = _parent.UnitManager.GetUnit(units[which].Name, units[which].IsFiller, context); UnitState unitState = new ExtendedUnitState(parent, which, cdUnit); float logInsertionProbability; if (unitState.Unit.IsSilence) { logInsertionProbability = _parent.LogSilenceInsertionProbability; } else if (unitState.Unit.IsFiller) { logInsertionProbability = _parent._logFillerInsertionProbability; } else if (unitState.GetWhich() == 0) { logInsertionProbability = _parent._logWordInsertionProbability; } else { logInsertionProbability = _parent._logUnitInsertionProbability; } // check to see if this state already exists, if so // branch to it and we are done, otherwise, branch to // the new state and expand it. SentenceHMMState existingState = GetExistingState(unitState); if (existingState != null) { AttachState(tail, existingState, LogOne, logInsertionProbability); // T(" Folding " + existingState); return(null); } else { AttachState(tail, unitState, LogOne, logInsertionProbability); AddStateToCache(unitState); // T(" Attaching " + unitState); tail = ExpandUnit(unitState); // if we are attaching the last state of a word, then // we add it to the exitPoints table. the exit points // table is indexed by a ContextPair, consisting of // the exiting left context and the right context. if (unitState.IsLast()) { UnitContext nextLeftContext = GenerateNextLeftContext(leftContext, units[which]); ContextPair cp = ContextPair.Get(nextLeftContext, actualRightContext); // T(" Adding to exitPoints " + cp); AddExitPoint(cp, tail); } return(tail); } }
public bool Equals(ContextPair o) { if (this == o) { return(true); } return(LeftContext.Equals(o.LeftContext) && RightContext.Equals(o.RightContext)); }
/// <summary> /// Expands each GState into the sentence HMM States /// </summary> public void Expand() { //this.LogDebug("Item Context: {0} : {1} : {2}",startingContexts.Count, rightContexts.Count, leftContexts.Count); // for each left context/starting context pair create a list // of starting states. foreach (UnitContext leftContext in _leftContexts) { foreach (UnitContext startingContext in GetStartingContexts()) { ContextPair contextPair = ContextPair.Get(leftContext, startingContext); if (!_entryPoints.ContainsKey(contextPair)) { _entryPoints.Add(contextPair, new List <ISearchState>()); } } } this.LogDebug("Item entryPoints Count: {0}", _entryPoints.Count); // if this is a final node don't expand it, just create a // state and add it to all entry points if (_node.IsFinalNode) { GrammarState gs = new GrammarState(_node); foreach (List <ISearchState> epList in _entryPoints.Values) { epList.Add(gs); } } else if (!_node.IsEmpty) { // its a full fledged node with a word // so expand it. Nodes without words don't need // to be expanded. foreach (UnitContext leftContext in _leftContexts) { ExpandWord(leftContext); } } else { //if the node is empty, populate the set of entry and exit //points with a branch state. The branch state // branches to the successor entry points for this // state // the exit point should consist of the set of // incoming left contexts and outgoing right contexts // the 'entryPoint' table already consists of such // pairs so we can use that foreach (var entry in _entryPoints) { ContextPair cp = entry.Key; List <ISearchState> epList = entry.Value; SentenceHMMState bs = new BranchState(cp.LeftContext.ToString(), cp.RightContext.ToString(), _node.ID); epList.Add(bs); AddExitPoint(cp, bs); } } AddEmptyEntryPoints(); }
/// <summary> /// Adds an exit point to this gstate /// </summary> /// <param name="cp">the context tag for the state</param> /// <param name="state">the state associated with the tag</param> private void AddExitPoint(ContextPair cp, SentenceHMMState state) { List <ISearchState> list = _exitPoints.Get(cp); if (list == null) { list = new List <ISearchState>(); _exitPoints.Put(cp, list); } list.Add(state); }
/** * /// Determines if the given object is equal to this UnitContext * * /// @param o the object to compare to * /// @return <code>true</code> if the objects are equal return; */ public override bool Equals(Object o) { if (this == o) { return(true); } else if (o is ContextPair) { ContextPair other = (ContextPair)o; return(LeftContext.Equals(other.LeftContext) && RightContext.Equals(other.RightContext)); } return(false); }
/** * /// Expand the pronunciation given the left context * * /// @param leftContext the left context * /// @param pronunciation the pronunciation to expand * /// @param which unique ID for this pronunciation */ // Each GState maintains a list of entry points. This list of // entry points is used when connecting up the end states of // one GState to the beginning states in another GState. The // entry points are tagged by a ContextPair which represents // the left context upon entering the state (the left context // of the initial units of the state), and the right context // of the previous states (corresponding to the starting // contexts for this state). // // When expanding a pronunciation, the following steps are // taken: // 1) Get the starting context for the pronunciation. // This is the set of units that correspond to the start // of the pronunciation. // // 2) Create a new PronunciationState for the // pronunciation. // // 3) Add the PronunciationState to the entry point table // (a hash table keyed by the ContextPair(LeftContext, // StartingContext). // // 4) Generate the set of context dependent units, using // the left and right context of the GState as necessary. // Note that there will be fan out at the end of the // pronunciation to allow for units with all of the // various right contexts. The point where the fan-out // occurs is the (length of the pronunciation - the max // right context size). // // 5) Attach each cd unit to the tree // // 6) Expand each cd unit into the set of HMM states // // 7) Attach the optional and looping back silence cd // unit // // 8) Collect the leaf states of the tree and add them to // the exitStates list. private void ExpandPronunciation(UnitContext leftContext, Pronunciation pronunciation, int which) { UnitContext startingContext = GetStartingContext(pronunciation); // Add the pronunciation state to the entry point list // (based upon its left and right context) string pname = "P(" + pronunciation.Word + '[' + leftContext + ',' + startingContext + "])-G" + GetNode().ID; PronunciationState ps = new PronunciationState(pname, pronunciation, which); _parent.T(" Expanding " + ps.Pronunciation + " for lc " + leftContext); ContextPair cp = ContextPair.Get(leftContext, startingContext); var epList = _entryPoints.Get(cp); if (epList == null) { throw new Error("No EP list for context pair " + cp); } else { epList.Add(ps); } Unit[] units = pronunciation.Units; int fanOutPoint = units.Length - GetRightContextSize(); if (fanOutPoint < 0) { fanOutPoint = 0; } SentenceHMMState tail = ps; for (int i = 0; tail != null && i < fanOutPoint; i++) { tail = AttachUnit(ps, tail, units, i, leftContext, UnitContext.Empty); } SentenceHMMState branchTail = tail; foreach (UnitContext finalRightContext in _rightContexts) { tail = branchTail; for (int i = fanOutPoint; tail != null && i < units.Length; i++) { tail = AttachUnit(ps, tail, units, i, leftContext, finalRightContext); } } }
/** * /// Adds the set of empty entry points. The list of entry points are tagged with a context pair. The context pair * /// represent the left context for the state and the starting context for the state, this allows states to be * /// hooked up properly. However, we may be transitioning from states that have no right hand context (CI units * /// such as SIL fall into this category). In this case we'd normally have no place to transition to since we add * /// entry points for each starting context. To make sure that there are entry points for empty contexts if * /// necessary, we go through the list of entry points and find all left contexts that have a right hand context * /// size of zero. These entry points will need an entry point with an empty starting context. These entries are * /// synthesized and added to the the list of entry points. */ private void AddEmptyEntryPoints() { var emptyEntryPoints = new HashMap <ContextPair, List <ISearchState> >(); foreach (var entry in _entryPoints) { ContextPair cp = entry.Key; if (NeedsEmptyVersion(cp)) { ContextPair emptyContextPair = ContextPair.Get(cp.LeftContext, UnitContext.Empty); List <ISearchState> epList = emptyEntryPoints.Get(emptyContextPair); if (epList == null) { epList = new List <ISearchState>(); emptyEntryPoints.Put(emptyContextPair, epList); } epList.AddRange(entry.Value); } } _entryPoints.PutAll(emptyEntryPoints); }
/// <summary> /// Returns the entry points for a given context pair /// </summary> /// <param name="contextPair"></param> /// <returns></returns> private List <ISearchState> GetEntryPoints(ContextPair contextPair) { return(_entryPoints.Get(contextPair)); }