Viterbi(String[] emissions) {
            mEmissions = emissions;
            HiddenMarkovModel hmm = mHmm;
            int numStates = hmm.stateSymbolTable().numSymbols();
            int numEmits = emissions.length;
            double[][] lattice = new double[numEmits][numStates];
            mLattice = lattice;
            int[][] backPts = new int[numEmits][numStates];
            mBackPts = backPts;
            if (emissions.length == 0) {
                return;
            }
            double[] emitLog2Probs = emitLog2Probs(emissions[0]);
            
            for (int stateId = 0; stateId < numStates; ++stateId) {
                lattice[0][stateId] 
                    = emitLog2Probs[stateId]
                    + hmm.startLog2Prob(stateId);
            }
        
            int[] unprunedSources = new int[numStates+1];
            for (int i = 1; i < numEmits; ++i) {
                double[] lastSlice = lattice[i-1];
                unprunedSources(lastSlice,unprunedSources,mLog2Beam);
                double[] emitLog2Probs2 = emitLog2Probs(emissions[i]);
                for (int targetId = 0; targetId < numStates; ++targetId) {
                    if (Double.NEGATIVE_INFINITY != emitLog2Probs2[targetId]) {
                        double best = Double.NEGATIVE_INFINITY;
                        int bk = 0; // default tag
                        for (int next = 0; unprunedSources[next] != -1; ++next) {
                            int sourceId = unprunedSources[next];
                            double est = lastSlice[sourceId]
                                + hmm.transitLog2Prob(sourceId,targetId);
                            if (est > best) {
                                best = est;
                                bk = sourceId;
                            }
                        }
                        lattice[i][targetId] 
                            = best + emitLog2Probs2[targetId];
                        backPts[i][targetId] = bk;
                    } else {
                        lattice[i][targetId] = Double.NEGATIVE_INFINITY;
                        backPts[i][targetId] = 0; // default tag
                    }
                }
            }
            // handles finals even if only one emission
            double[] lastColumn = lattice[numEmits-1];
            for (int i = 0; i < numStates; ++i)
                lastColumn[i] += hmm.endLog2Prob(i);
        }