static int
phone_loop_search_reinit(ps_search_t *search, dict_t *dict, dict2pid_t *d2p)
{
    phone_loop_search_t *pls = (phone_loop_search_t *)search;
    cmd_ln_t *config = ps_search_config(search);
    acmod_t *acmod = ps_search_acmod(search);
    int i;

    /* Free old dict2pid, dict, if necessary. */
    ps_search_base_reinit(search, dict, d2p);

    /* Initialize HMM context. */
    if (pls->hmmctx)
        hmm_context_free(pls->hmmctx);
    pls->hmmctx = hmm_context_init(bin_mdef_n_emit_state(acmod->mdef),
                                   acmod->tmat->tp, NULL, acmod->mdef->sseq);
    if (pls->hmmctx == NULL)
        return -1;

    /* Initialize penalty storage */
    pls->n_phones = bin_mdef_n_ciphone(acmod->mdef);
    pls->window = cmd_ln_int32_r(config, "-pl_window");
    if (pls->penalties)
        ckd_free(pls->penalties);
    pls->penalties = (int32 *)ckd_calloc(pls->n_phones, sizeof(*pls->penalties));
    if (pls->pen_buf)
        ckd_free_2d(pls->pen_buf);
    pls->pen_buf = (int32 **)ckd_calloc_2d(pls->window, pls->n_phones, sizeof(**pls->pen_buf));

    /* Initialize phone HMMs. */
    if (pls->hmms) {
        for (i = 0; i < pls->n_phones; ++i)
            hmm_deinit((hmm_t *)&pls->hmms[i]);
        ckd_free(pls->hmms);
    }
    pls->hmms = (hmm_t *)ckd_calloc(pls->n_phones, sizeof(*pls->hmms));
    for (i = 0; i < pls->n_phones; ++i) {
        hmm_init(pls->hmmctx, (hmm_t *)&pls->hmms[i],
                 FALSE,
                 bin_mdef_pid2ssid(acmod->mdef, i),
                 bin_mdef_pid2tmatid(acmod->mdef, i));
    }
    pls->penalty_weight = cmd_ln_float64_r(config, "-pl_weight");
    pls->beam = logmath_log(acmod->lmath, cmd_ln_float64_r(config, "-pl_beam")) >> SENSCR_SHIFT;
    pls->pbeam = logmath_log(acmod->lmath, cmd_ln_float64_r(config, "-pl_pbeam")) >> SENSCR_SHIFT;
    pls->pip = logmath_log(acmod->lmath, cmd_ln_float32_r(config, "-pl_pip")) >> SENSCR_SHIFT;
    E_INFO("State beam %d Phone exit beam %d Insertion penalty %d\n",
           pls->beam, pls->pbeam, pls->pip);

    return 0;
}
void
ngram_fwdflat_init(ngram_search_t *ngs)
{
    int n_words;

    n_words = ps_search_n_words(ngs);
    ngs->fwdflat_wordlist = ckd_calloc(n_words + 1, sizeof(*ngs->fwdflat_wordlist));
    ngs->expand_word_flag = bitvec_alloc(n_words);
    ngs->expand_word_list = ckd_calloc(n_words + 1, sizeof(*ngs->expand_word_list));
    ngs->frm_wordlist = ckd_calloc(ngs->n_frame_alloc, sizeof(*ngs->frm_wordlist));
    ngs->min_ef_width = cmd_ln_int32_r(ps_search_config(ngs), "-fwdflatefwid");
    ngs->max_sf_win = cmd_ln_int32_r(ps_search_config(ngs), "-fwdflatsfwin");
    E_INFO("fwdflat: min_ef_width = %d, max_sf_win = %d\n",
           ngs->min_ef_width, ngs->max_sf_win);

    /* No tree-search; pre-build the expansion list, including all LM words. */
    if (!ngs->fwdtree) {
        /* Build full expansion list from LM words. */
        ngram_fwdflat_expand_all(ngs);
        /* Allocate single phone words. */
        ngram_fwdflat_allocate_1ph(ngs);
    }
}
void
ngram_fwdflat_deinit(ngram_search_t *ngs)
{
    double n_speech = (double)ngs->n_tot_frame
            / cmd_ln_int32_r(ps_search_config(ngs), "-frate");

    E_INFO("TOTAL fwdflat %.2f CPU %.3f xRT\n",
           ngs->fwdflat_perf.t_tot_cpu,
           ngs->fwdflat_perf.t_tot_cpu / n_speech);
    E_INFO("TOTAL fwdflat %.2f wall %.3f xRT\n",
           ngs->fwdflat_perf.t_tot_elapsed,
           ngs->fwdflat_perf.t_tot_elapsed / n_speech);

    /* Free single-phone words if we allocated them. */
    if (!ngs->fwdtree) {
        ngram_fwdflat_free_1ph(ngs);
    }
    ckd_free(ngs->fwdflat_wordlist);
    bitvec_free(ngs->expand_word_flag);
    ckd_free(ngs->expand_word_list);
    ckd_free(ngs->frm_wordlist);
}
void
ngram_fwdflat_finish(ngram_search_t *ngs)
{
    int32 cf;

    destroy_fwdflat_chan(ngs);
    destroy_fwdflat_wordlist(ngs);
    bitvec_clear_all(ngs->word_active, ps_search_n_words(ngs));

    /* This is the number of frames processed. */
    cf = ps_search_acmod(ngs)->output_frame;
    /* Add a mark in the backpointer table for one past the final frame. */
    ngram_search_mark_bptable(ngs, cf);

    ptmr_stop(&ngs->fwdflat_perf);
    /* Print out some statistics. */
    if (cf > 0) {
        double n_speech = (double)(cf + 1)
            / cmd_ln_int32_r(ps_search_config(ngs), "-frate");
        E_INFO("%8d words recognized (%d/fr)\n",
               ngs->bpidx, (ngs->bpidx + (cf >> 1)) / (cf + 1));
        E_INFO("%8d senones evaluated (%d/fr)\n", ngs->st.n_senone_active_utt,
               (ngs->st.n_senone_active_utt + (cf >> 1)) / (cf + 1));
        E_INFO("%8d channels searched (%d/fr)\n",
               ngs->st.n_fwdflat_chan, ngs->st.n_fwdflat_chan / (cf + 1));
        E_INFO("%8d words searched (%d/fr)\n",
               ngs->st.n_fwdflat_words, ngs->st.n_fwdflat_words / (cf + 1));
        E_INFO("%8d word transitions (%d/fr)\n",
               ngs->st.n_fwdflat_word_transition,
               ngs->st.n_fwdflat_word_transition / (cf + 1));
        E_INFO("fwdflat %.2f CPU %.3f xRT\n",
               ngs->fwdflat_perf.t_cpu,
               ngs->fwdflat_perf.t_cpu / n_speech);
        E_INFO("fwdflat %.2f wall %.3f xRT\n",
               ngs->fwdflat_perf.t_elapsed,
               ngs->fwdflat_perf.t_elapsed / n_speech);
    }