/** Evaluate active PHMMs */
static int32
phmm_eval_all(allphone_search_t * allphs, const int16 * senscr)
{
    s3cipid_t ci;
    phmm_t *p;
    int32 best;
    bin_mdef_t *mdef;
    phmm_t **ci_phmm;

    mdef = ((ps_search_t *) allphs)->acmod->mdef;
    ci_phmm = allphs->ci_phmm;

    best = WORST_SCORE;

    hmm_context_set_senscore(allphs->hmmctx, senscr);
    for (ci = 0; ci < mdef->n_ciphone; ci++) {
        for (p = ci_phmm[(unsigned) ci]; p; p = p->next) {
            if (hmm_frame(&(p->hmm)) == allphs->frame) {
                int32 score;
                allphs->n_hmm_eval++;
                score = hmm_vit_eval((hmm_t *) p);
                if (score > best)
                    best = score;
            }
        }
    }

    return best;
}
static void
evaluate_hmms(phone_loop_search_t *pls, int16 const *senscr, int frame_idx)
{
    int32 bs = WORST_SCORE;
    int i;

    hmm_context_set_senscore(pls->hmmctx, senscr);

    for (i = 0; i < pls->n_phones; ++i) {
        hmm_t *hmm = (hmm_t *)&pls->hmms[i];
        int32 score;

        if (hmm_frame(hmm) < frame_idx)
            continue;
        score = hmm_vit_eval(hmm);
        if (score BETTER_THAN bs) {
            bs = score;
        }
    }
    pls->best_score = bs;
}
static int32
evaluate_hmms(state_align_search_t *sas, int16 const *senscr, int frame_idx)
{
    int32 bs = WORST_SCORE;
    int i;

    hmm_context_set_senscore(sas->hmmctx, senscr);

    for (i = 0; i < sas->n_phones; ++i) {
        hmm_t *hmm = sas->hmms + i;
        int32 score;

        if (hmm_frame(hmm) < frame_idx)
            continue;
        score = hmm_vit_eval(hmm);
        if (score BETTER_THAN bs) {
            bs = score;
        }
    }
    return bs;
}
int
ngram_fwdflat_search(ngram_search_t *ngs, int frame_idx)
{
    int16 const *senscr;
    int32 nf, i, j;
    int32 *nawl;

    /* Activate our HMMs for the current frame if need be. */
    if (!ps_search_acmod(ngs)->compallsen)
        compute_fwdflat_sen_active(ngs, frame_idx);

    /* Compute GMM scores for the current frame. */
    senscr = acmod_score(ps_search_acmod(ngs), &frame_idx);
    ngs->st.n_senone_active_utt += ps_search_acmod(ngs)->n_senone_active;

    /* Mark backpointer table for current frame. */
    ngram_search_mark_bptable(ngs, frame_idx);

    /* If the best score is equal to or worse than WORST_SCORE,
     * recognition has failed, don't bother to keep trying. */
    if (ngs->best_score == WORST_SCORE || ngs->best_score WORSE_THAN WORST_SCORE)
        return 0;
    /* Renormalize if necessary */
    if (ngs->best_score + (2 * ngs->beam) WORSE_THAN WORST_SCORE) {
        E_INFO("Renormalizing Scores at frame %d, best score %d\n",
               frame_idx, ngs->best_score);
        fwdflat_renormalize_scores(ngs, frame_idx, ngs->best_score);
    }

    ngs->best_score = WORST_SCORE;
    hmm_context_set_senscore(ngs->hmmctx, senscr);

    /* Evaluate HMMs */
    fwdflat_eval_chan(ngs, frame_idx);
    /* Prune HMMs and do phone transitions. */
    fwdflat_prune_chan(ngs, frame_idx);
    /* Do word transitions. */
    fwdflat_word_transition(ngs, frame_idx);

    /* Create next active word list */
    nf = frame_idx + 1;
    nawl = ngs->active_word_list[nf & 0x1];
    for (i = 0, j = 0; ngs->fwdflat_wordlist[i] >= 0; i++) {
        if (bitvec_is_set(ngs->word_active, ngs->fwdflat_wordlist[i])) {
            *(nawl++) = ngs->fwdflat_wordlist[i];
            j++;
        }
    }
    for (i = ps_search_start_wid(ngs); i < ps_search_n_words(ngs); i++) {
        if (bitvec_is_set(ngs->word_active, i)) {
            *(nawl++) = i;
            j++;
        }
    }
    if (!ngs->fwdtree)
        ++ngs->n_frame;
    ngs->n_active_word[nf & 0x1] = j;

    /* Return the number of frames processed. */
    return 1;
}