/* * Copyright 1999-2002 Carnegie Mellon University. * Portions Copyright 2002 Sun Microsystems, Inc. * Portions Copyright 2002 Mitsubishi Electric Research Laboratories. * All Rights Reserved. Use is subject to license terms. * * See the file "license.terms" for information on usage and * redistribution of this file, and for a DISCLAIMER OF ALL * WARRANTIES. * */ package edu.cmu.sphinx.decoder.search; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import edu.cmu.sphinx.decoder.scorer.Scoreable; import edu.cmu.sphinx.linguist.SearchState; /** * The token heap search manager that maintains the heap of best tokens for each * search state instead of single one best token * */ public class TokenHeapSearchManager extends WordPruningBreadthFirstSearchManager { protected final int maxTokenHeapSize = 3; Map<Object, TokenHeap> bestTokenMap; @Override protected void createBestTokenMap() { int mapSize = activeList.size() << 2; if (mapSize == 0) { mapSize = 1; } bestTokenMap = new HashMap<Object, TokenHeap>(mapSize, 0.3F); } @Override protected void setBestToken(Token token, SearchState state) { TokenHeap th = bestTokenMap.get(state); if (th == null) { th = new TokenHeap(maxTokenHeapSize); bestTokenMap.put(state, th); } th.add(token); } @Override protected Token getBestToken(SearchState state) { // new way... if the heap for this state isn't full return // null, otherwise return the worst scoring token TokenHeap th = bestTokenMap.get(state); Token t; if (th == null) { return null; } else if ((t = th.get(state)) != null) { return t; } else if (!th.isFull()) { return null; } else { return th.getSmallest(); } } /** * A quick and dirty token heap that allows us to perform token stack * experiments. It is not very efficient. We will likely replace this with * something better once we figure out how we want to prune things. */ class TokenHeap { final Token[] tokens; int curSize; /** * Creates a token heap with the maximum size * * @param maxSize * the maximum size of the heap */ TokenHeap(int maxSize) { tokens = new Token[maxSize]; } /** * Adds a token to the heap * * @param token * the token to add */ void add(Token token) { // first, if an identical state exists, replace // it. if (!tryReplace(token)) { if (curSize < tokens.length) { tokens[curSize++] = token; } else if (token.getScore() > tokens[curSize - 1].getScore()) { tokens[curSize - 1] = token; } } fixupInsert(); } /** * Returns the smallest scoring token on the heap * * @return the smallest scoring token */ Token getSmallest() { if (curSize == 0) { return null; } else { return tokens[curSize - 1]; } } /** * Determines if the heap is full * * @return <code>true</code> if the heap is full */ boolean isFull() { return curSize == tokens.length; } /** * Checks to see if there is already a token t on the heap that has the * same search state. If so, this token replaces that one * * @param t * the token to try to add to the heap * @return <code>true</code> if the token was added */ private boolean tryReplace(Token t) { for (int i = 0; i < curSize; i++) { if (t.getSearchState().equals(tokens[i].getSearchState())) { assert t.getScore() > tokens[i].getScore(); tokens[i] = t; return true; } } return false; } /** Orders the heap after an insert */ private void fixupInsert() { Arrays.sort(tokens, 0, curSize - 1, Scoreable.COMPARATOR); } /** * returns a token on the heap that matches the given search state * * @param s * the search state * @return the token that matches, or null */ Token get(SearchState s) { for (int i = 0; i < curSize; i++) { if (tokens[i].getSearchState().equals(s)) { return tokens[i]; } } return null; } } }