/* * Copyright 1999-2003 Carnegie Mellon University. * Portions Copyright 2003 Sun Microsystems, Inc. * Portions Copyright 2003 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.linguist.util; import edu.cmu.sphinx.linguist.*; import edu.cmu.sphinx.util.Cache; import edu.cmu.sphinx.util.props.*; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.PrintStream; import java.util.*; /** * A linguist processor that dumps out the search space in a simple format. This processor is designed so that it can be * easily extended by replacing the dumpNode and the dumpEdge methods. */ public class LinguistDumper extends LinguistProcessor { /** The property for the destination of the LinguistDumper */ @S4String(defaultValue = "linguistDump.txt") public final static String PROP_FILENAME = "filename"; // ------------------------------ // Configuration data // ------------------------------- private boolean depthFirst = true; private String filename; public LinguistDumper( String filename, Linguist linguist ) { super( linguist ); this.filename = filename; } public LinguistDumper() { } /* * (non-Javadoc) * * @see edu.cmu.sphinx.util.props.Configurable#newProperties(edu.cmu.sphinx.util.props.PropertySheet) */ @Override public void newProperties(PropertySheet ps) throws PropertyException { super.newProperties(ps); filename = ps.getString(PROP_FILENAME); } /** Dumps the search space hmm in GDL format */ @Override public void run() { try { FileOutputStream fos = new FileOutputStream(filename); PrintStream out = new PrintStream(fos); SearchState firstState = getLinguist().getSearchGraph().getInitialState(); dumpSearchGraph(out, firstState); out.close(); } catch (FileNotFoundException fnfe) { System.out.println("Can't dump to file " + filename + ' ' + fnfe); } } /** * Sets whether the traversal is depth first or breadth first * * @param depthFirst if true traversal is depth first, otherwise the traversal is breadth first */ protected void setDepthFirst(boolean depthFirst) { this.depthFirst = depthFirst; } /** * Called at the start of the dump * * @param out the output stream. */ protected void startDump(PrintStream out) { } /** * Called at the end of the dump * * @param out the output stream. */ protected void endDump(PrintStream out) { } /** * Called to dump out a node in the search space * * @param out the output stream. * @param state the state to dump * @param level the level of the state */ protected void startDumpNode(PrintStream out, SearchState state, int level) { } /** * Called to dump out a node in the search space * * @param out the output stream. * @param state the state to dump * @param level the level of the state */ protected void endDumpNode(PrintStream out, SearchState state, int level) { } /** * Dumps an arc * * @param out the output stream. * @param from arc leaves this state * @param arc the arc to dump * @param level the level of the state */ protected void dumpArc(PrintStream out, SearchState from, SearchStateArc arc, int level) { } /** * Dumps the search graph * * @param out place to dump the output * @param startingState the initial state of the search space */ private void dumpSearchGraph(PrintStream out, SearchState startingState) { List<StateLevel> queue = new LinkedList<StateLevel>(); Set<String> visitedStates = new HashSet<String>(); startDump(out); queue.add(new StateLevel(startingState, 0)); while (!queue.isEmpty()) { StateLevel stateLevel = queue.remove(0); int level = stateLevel.getLevel(); SearchState state = stateLevel.getState(); // equalCheck(state); if (!visitedStates.contains(state.getSignature())) { visitedStates.add(state.getSignature()); startDumpNode(out, state, level); SearchStateArc[] arcs = state.getSuccessors(); for (int i = arcs.length - 1; i >= 0; i--) { SearchState nextState = arcs[i].getState(); dumpArc(out, state, arcs[i], level); if (depthFirst) { // if depth first, its a stack queue.add(0, new StateLevel(nextState, level + 1)); } else { queue.add(new StateLevel(nextState, level + 1)); } } endDumpNode(out, state, level); } } endDump(out); } final Cache<SearchState> eqStates = new Cache<SearchState>(); final Map<String, SearchState> eqSigs = new HashMap<String, SearchState>(); /** * This is a bit of test/debugging code that ensures that the states that have equal signatures are also considered * to be object.equals and vice versa.. This method will dump out any states where this contract is not true * * @param state the state to check */ @SuppressWarnings("unused") private void equalCheck(SearchState state) { SearchState eqState = eqStates.cache(state); SearchState eqSig = eqSigs.get(state.getSignature()); if (eqState == null ^ eqSig == null) { System.out.println("Missing one: "); System.out.println(" state val: " + state); System.out.println(" state sig: " + state.getSignature()); System.out.println(" eqState val: " + eqState); System.out.println(" eqSig val: " + eqSig); if (eqState != null) { System.out.println(" eqState sig: " + eqState.getSignature()); } if (eqSig != null) { System.out.println(" eqSig sig: " + eqSig.getSignature()); } } if (eqState == null) { eqState = state; } if (eqSig == null) { eqSigs.put(state.getSignature(), state); eqSig = state; } if (!eqState.getSignature().equals(state.getSignature())) { System.out.println("Sigs mismatch for: "); System.out.println(" state sig: " + state.getSignature()); System.out.println(" eqSig sig: " + eqSig.getSignature()); System.out.println(" state val: " + state); System.out.println(" eqSig val: " + eqSig); } if (!eqState.equals(state)) { System.out.println("obj mismatch for: "); System.out.println(" state sig: " + state.getSignature()); System.out.println(" eqSig sig: " + eqSig.getSignature()); System.out.println(" state val: " + state); System.out.println(" eqSig val: " + eqSig); } } } /** A class for bundling together a SearchState and its level. */ class StateLevel { private final int level; private final SearchState state; /** * Constructs a StateLevel from its primitive components. * * @param state the state to be bundled in the StateLevel * @param level the level of the state */ StateLevel(SearchState state, int level) { this.state = state; this.level = level; } /** * Returns the state * * @return the state */ SearchState getState() { return state; } /** * Returns the level * * @return the level. */ int getLevel() { return level; } /** * Returns a string representation of the object * * @return a string representation */ @Override public String toString() { return String.valueOf(level) + ' ' + state.getSignature() + " 1 " + getTypeLabel(state); } /** * Retrieves a type label for a state * * @param state the state of interest * @return a label for the type of state (one of Unit, Word, HMM or other */ public String getTypeLabel(SearchState state) { if (state instanceof UnitSearchState) { return "Unit"; } if (state instanceof WordSearchState) { return "Word"; } if (state instanceof HMMSearchState) { return "HMM"; } return "other"; } }