/// <summary> /// Gets the unit context for the given units. There is a single unit context for each unit combination. /// </summary> /// <param name="units">the units of interest</param> /// <returns>the unit context.</returns> public static UnitContext Get(Unit[] units) { var newUc = new UnitContext(units); var cachedUc = UnitContextCache.cache(newUc); return(cachedUc ?? newUc); }
/// <summary> /// Retrieves the set of starting contexts for this node. The starting contexts are the set of Unit[] with a size /// equal to the maximum right context size. /// </summary> /// <returns>the set of starting contexts across nodes.</returns> private HashSet <UnitContext> GetStartingContexts() { if (_startingContexts == null) { _startingContexts = new HashSet <UnitContext>(); // if this is an empty node, the starting context is the set of starting contexts for all successor // nodes, otherwise, it is built up from each pronunciation of this word if (_node.IsEmpty) { GrammarArc[] arcs = GetSuccessors(); foreach (GrammarArc arc in arcs) { GState gstate = _parent.GetGState(arc.GrammarNode); _startingContexts.AddAll(gstate.GetStartingContexts()); } } else { // int maxSize = getRightContextSize(); Word word = _node.GetWord(); Pronunciation[] prons = word.GetPronunciations(null); foreach (Pronunciation pron in prons) { UnitContext startingContext = GetStartingContext(pron); _startingContexts.Add(startingContext); } } } return(_startingContexts); }
/** * /// 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())); }
/** * /// 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); } }
/** * /// Retrieves the starting UnitContext for the given pronunciation * * /// @param pronunciation the pronunciation * /// @return a UnitContext representing the starting context of the pronunciation */ private UnitContext GetStartingContext(Pronunciation pronunciation) { int maxSize = GetRightContextSize(); Unit[] units = pronunciation.Units; Unit[] context = units.Length > maxSize?Arrays.copyOf(units, maxSize) : units; return(UnitContext.Get(context)); }
/** * /// Expand the the word given the left context * * /// @param leftContext the left context */ private void ExpandWord(UnitContext leftContext) { Word word = _node.GetWord(); _parent.T("Expanding word " + word + " for lc " + leftContext); Pronunciation[] pronunciations = word.GetPronunciations(null); this.LogDebug("Item Pronounciation Count: {0}", pronunciations.Length); for (int i = 0; i < pronunciations.Length; i++) { ExpandPronunciation(leftContext, pronunciations[i], i); } }
/// <summary> /// Generates the next left context based upon a previous context and a unit /// </summary> /// <param name="prevLeftContext">the previous left context</param> /// <param name="unit">the current unit</param> /// <returns></returns> UnitContext GenerateNextLeftContext(UnitContext prevLeftContext, Unit unit) { Unit[] prevUnits = prevLeftContext.Units; int actSize = Math.Min(prevUnits.Length, GetLeftContextSize()); if (actSize == 0) { return(UnitContext.Empty); } Unit[] leftUnits = Arrays.copyOfRange(prevUnits, 1, actSize + 1); leftUnits[actSize - 1] = unit; return(UnitContext.Get(leftUnits)); }
/** * /// 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); } } }
/// <summary> /// Retrieves the set of trailing contexts for this node. the trailing contexts are the set of Unit[] with a size /// equal to the maximum left context size that align with the end of the node /// </summary> /// <returns></returns> List <UnitContext> GetEndingContexts() { List <UnitContext> endingContexts = new List <UnitContext>(); if (!_node.IsEmpty) { int maxSize = GetLeftContextSize(); Word word = _node.GetWord(); Pronunciation[] prons = word.GetPronunciations(null); foreach (Pronunciation pron in prons) { Unit[] units = pron.Units; int size = units.Length; Unit[] context = size > maxSize?Arrays.copyOfRange(units, size - maxSize, size) : units; endingContexts.Add(UnitContext.Get(context)); } } return(endingContexts); }
/** * /// Get the right context for a unit based upon the right context size, the exit right context and the current * /// unit. * * /// @param units the set of units * /// @param index the index of the current unit * /// @param right the exiting right context * */ private Unit[] GetRC(Unit[] units, int index, UnitContext right) { Unit[] rightUnits = right.Units; int leftIndex = index + 1; int curSize = units.Length - leftIndex + rightUnits.Length; int actSize = Math.Min(curSize, GetRightContextSize(units[index])); Unit[] rc = new Unit[actSize]; for (int i = 0; i < rc.Length; i++) { int rcIndex = leftIndex + i; if (rcIndex < units.Length) { rc[i] = units[rcIndex]; } else { rc[i] = rightUnits[rcIndex - units.Length]; } } return(rc); }
/** * /// Get the left context for a unit based upon the left context size, the entry left context and the current * /// unit. * * /// @param left the entry left context * /// @param units the set of units * /// @param index the index of the current unit * */ private Unit[] GetLC(UnitContext left, Unit[] units, int index) { Unit[] leftUnits = left.Units; int curSize = leftUnits.Length + index; int actSize = Math.Min(curSize, GetLeftContextSize(units[index])); int leftIndex = index - actSize; Unit[] lc = new Unit[actSize]; for (int i = 0; i < lc.Length; i++) { int lcIndex = leftIndex + i; if (lcIndex < 0) { lc[i] = leftUnits[leftUnits.Length + lcIndex]; } else { lc[i] = units[lcIndex]; } } return(lc); }
/// <summary> /// Determines if the given object is equal to this UnitContext /// </summary> /// <param name="o">the object to compare to</param> /// <returns><code>true</code> if the objects are equal</returns> public override bool Equals(Object o) { if (this == o) { return(true); } if (o is UnitContext) { UnitContext other = (UnitContext)o; if (Units.Length != other.Units.Length) { return(false); } for (int i = 0; i < Units.Length; i++) { if (Units[i] != other.Units[i]) { return(false); } } return(true); } return(false); }
/** * /// Adds the given context to the set of left contexts for this state * * /// @param context the context to add */ public void AddLeftContext(UnitContext context) { _leftContexts.Add(context); }
/** * /// Creates a UnitContext for the given context. This constructor is not directly accessible, use the factory method * /// instead. * * /// @param left the left context * /// @param right the right context */ private ContextPair(UnitContext left, UnitContext right) { LeftContext = left; RightContext = right; _hashCode = 99 + left.GetHashCode() * 113 + right.GetHashCode(); }