src/libpocketsphinx/tst_search.c

Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */
00002 /* ====================================================================
00003  * Copyright (c) 2009 Carnegie Mellon University.  All rights
00004  * reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  *
00010  * 1. Redistributions of source code must retain the above copyright
00011  *    notice, this list of conditions and the following disclaimer. 
00012  *
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in
00015  *    the documentation and/or other materials provided with the
00016  *    distribution.
00017  *
00018  * This work was supported in part by funding from the Defense Advanced 
00019  * Research Projects Agency and the National Science Foundation of the 
00020  * United States of America, and the CMU Sphinx Speech Consortium.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND 
00023  * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
00024  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00025  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY
00026  * NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00027  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
00028  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
00029  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
00030  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
00031  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
00032  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00033  *
00034  * ====================================================================
00035  *
00036  */
00037 
00043 /* System headers. */
00044 #include <string.h>
00045 #include <assert.h>
00046 
00047 /* SphinxBase headers. */
00048 #include <ckd_alloc.h>
00049 #include <listelem_alloc.h>
00050 #include <profile.h>
00051 #include <err.h>
00052 
00053 /* Local headers. */
00054 #include "pocketsphinx_internal.h"
00055 #include "ps_lattice_internal.h"
00056 #include "tst_search.h"
00057 
00058 static int tst_search_start(ps_search_t *search);
00059 static int tst_search_step(ps_search_t *search, int frame_idx);
00060 static int tst_search_finish(ps_search_t *search);
00061 static int tst_search_reinit(ps_search_t *search);
00062 static ps_lattice_t *tst_search_lattice(ps_search_t *search);
00063 static char const *tst_search_hyp(ps_search_t *search, int32 *out_score);
00064 static int32 tst_search_prob(ps_search_t *search);
00065 static ps_seg_t *tst_search_seg_iter(ps_search_t *search, int32 *out_score);
00066 
00067 static ps_searchfuncs_t tst_funcs = {
00068     /* name: */   "tst",
00069     /* start: */  tst_search_start,
00070     /* step: */   tst_search_step,
00071     /* finish: */ tst_search_finish,
00072     /* reinit: */ tst_search_reinit,
00073     /* free: */   tst_search_free,
00074     /* lattice: */  tst_search_lattice,
00075     /* hyp: */      tst_search_hyp,
00076     /* prob: */     tst_search_prob,
00077     /* seg_iter: */ tst_search_seg_iter,
00078 };
00079 
00080 static histprune_t *
00081 histprune_init(int32 maxhmm, int32 maxhist, int32 maxword,
00082                int32 hmmhistbinsize, int32 numNodes)
00083 {
00084     histprune_t *h;
00085     int32 n;
00086 
00087     h = (histprune_t *) ckd_calloc(1, sizeof(histprune_t));
00088     h->maxwpf = maxword;
00089     h->maxhmmpf = maxhmm;
00090     h->maxhistpf = maxhist;
00091     h->hmm_hist_binsize = hmmhistbinsize;
00092 
00093     n = numNodes;
00094     n /= h->hmm_hist_binsize;
00095 
00096     h->hmm_hist_bins = n + 1;
00097 
00098     h->hmm_hist = (int32 *) ckd_calloc(h->hmm_hist_bins, sizeof(int32));
00099 
00100 
00101     return h;
00102 }
00103 
00104 static void
00105 histprune_zero_histbin(histprune_t * h)
00106 {
00107     int32 *hmm_hist;
00108     int32 numhistbins;          /* Local version of number of histogram bins, don't expect it to change */
00109     int32 i;
00110 
00111     hmm_hist = h->hmm_hist;
00112     numhistbins = h->hmm_hist_bins;
00113 
00114     for (i = 0; i < numhistbins; i++)
00115         hmm_hist[i] = 0;
00116 
00117 }
00118 
00119 static void
00120 histprune_free(histprune_t * h)
00121 {
00122     if (h != NULL) {
00123         if (h->hmm_hist != NULL) {
00124             ckd_free(h->hmm_hist);
00125         }
00126         free(h);
00127     }
00128 }
00129 
00130 static void
00131 histprune_showhistbin(histprune_t * hp, int32 nfr, char *uttid)
00132 {
00133     int32 i, j, k;
00134 
00135     if (nfr == 0) {
00136         nfr = 1;
00137         E_WARN("Set number of frame to 1\n");
00138     }
00139 
00140     for (j = hp->hmm_hist_bins - 1; (j >= 0) && (hp->hmm_hist[j] == 0);
00141          --j);
00142     E_INFO("HMMHist[0..%d](%s):", j, uttid);
00143     for (i = 0, k = 0; i <= j; i++) {
00144         k += hp->hmm_hist[i];
00145         E_INFOCONT(" %d(%d)", hp->hmm_hist[i], (k * 100) / nfr);
00146     }
00147     E_INFOCONT("\n");
00148 }
00149 
00150 
00151 static void
00152 histprune_report(histprune_t * h)
00153 {
00154     E_INFO_NOFN("Initialization of histprune_t, report:\n");
00155     E_INFO_NOFN("Parameters used in histogram pruning:\n");
00156     E_INFO_NOFN("Max.     HMM per frame=%d\n", h->maxhmmpf);
00157     E_INFO_NOFN("Max. history per frame=%d\n", h->maxhistpf);
00158     E_INFO_NOFN("Max.    word per frame=%d\n", h->maxwpf);
00159     E_INFO_NOFN("Size of histogram  bin=%d\n", h->hmm_hist_binsize);
00160     E_INFO_NOFN("No.  of histogram  bin=%d\n", h->hmm_hist_bins);
00161     E_INFO_NOFN("\n");
00162 }
00163 
00164 static beam_t *
00165 beam_init(float64 hmm, float64 ptr, float64 wd, float64 wdend,
00166           int32 ptranskip, int32 n_ciphone, logmath_t *logmath)
00167 {
00168     beam_t *beam;
00169 
00170     beam = (beam_t *) ckd_calloc(1, sizeof(beam_t));
00171 
00172     beam->hmm = logmath_log(logmath, hmm);
00173     beam->ptrans = logmath_log(logmath, ptr);
00174     beam->word = logmath_log(logmath, wd);
00175     beam->wordend = logmath_log(logmath, wdend);
00176     beam->ptranskip = ptranskip;
00177     beam->bestscore = MAX_NEG_INT32;
00178     beam->bestwordscore = MAX_NEG_INT32;
00179     beam->n_ciphone = n_ciphone;
00180 
00181     beam->wordbestscores = (int32 *) ckd_calloc(n_ciphone, sizeof(int32));
00182     beam->wordbestexits = (int32 *) ckd_calloc(n_ciphone, sizeof(int32));
00183 
00184     return beam;
00185 }
00186 
00187 static void
00188 beam_report(beam_t * b)
00189 {
00190     E_INFO_NOFN("Initialization of beam_t, report:\n");
00191     E_INFO_NOFN("Parameters used in Beam Pruning of Viterbi Search:\n");
00192     E_INFO_NOFN("Beam=%d\n", b->hmm);
00193     E_INFO_NOFN("PBeam=%d\n", b->ptrans);
00194     E_INFO_NOFN("WBeam=%d (Skip=%d)\n", b->word, b->ptranskip);
00195     E_INFO_NOFN("WEndBeam=%d \n", b->wordend);
00196     E_INFO_NOFN("No of CI Phone assumed=%d \n", b->n_ciphone);
00197     E_INFO_NOFN("\n");
00198 }
00199 
00200 static void
00201 beam_free(beam_t * b)
00202 {
00203     if (b) {
00204         if (b->wordbestscores) {
00205             free(b->wordbestscores);
00206         }
00207         if (b->wordbestexits) {
00208             free(b->wordbestexits);
00209         }
00210         free(b);
00211     }
00212 }
00213 
00214 
00215 static lextree_t **
00216 create_lextree(tst_search_t *tstg, const char *lmname, ptmr_t *tm_build)
00217 {
00218     int j;
00219     lextree_t **lextree;
00220 
00221     lextree = (lextree_t **)ckd_calloc(tstg->n_lextree, sizeof(lextree_t *));
00222     hash_table_enter(tstg->ugtree, lmname, lextree);
00223     for (j = 0; j < tstg->n_lextree; ++j) {
00224         if (tm_build)
00225             ptmr_start(tm_build);
00226 
00227         lextree[j] = lextree_init(ps_search_acmod(tstg)->mdef,
00228                                   ps_search_acmod(tstg)->tmat,
00229                                   ps_search_dict(tstg),
00230                                   ps_search_dict2pid(tstg),
00231                                   tstg->fillpen,
00232                                   tstg->lmset,
00233                                   lmname,
00234                                   TRUE, TRUE,
00235                                   LEXTREE_TYPE_UNIGRAM);
00236 
00237         if (tm_build)
00238             ptmr_stop(tm_build);
00239 
00240         if (lextree[j] == NULL) {
00241             int i;
00242             E_INFO
00243                 ("Failed to allocate lexical tree for lm %s and lextree %d\n",
00244                  lmname, j);
00245 
00246             for (i = j - 1; i >= 0; --i)
00247                 lextree_free(lextree[i]);
00248             ckd_free(lextree);
00249 
00250             return NULL;
00251         }
00252         E_INFO("Lextree (%d) for lm \"%s\" has %d nodes(ug)\n",
00253                j, lmname, lextree_n_node(lextree[j]));
00254     }
00255 
00256     lextree_report(lextree[0]);
00257 
00258     return lextree;
00259 }
00260 
00261 static int
00262 tst_search_reinit(ps_search_t *search)
00263 {
00264     /* set_lm() code goes here. */
00265     return -1;
00266 }
00267 
00268 ps_search_t *
00269 tst_search_init(cmd_ln_t *config,
00270                 acmod_t *acmod,
00271                 s3dict_t *dict,
00272                 dict2pid_t *d2p)
00273 {
00274     tst_search_t *tstg;
00275     char const *path;
00276     int32 n_ltree;
00277     int32 i, j;
00278     ptmr_t tm_build;
00279     ngram_model_set_iter_t *lmset_iter;
00280     lextree_t **lextree = NULL;
00281 
00282     tstg = ckd_calloc(1, sizeof(*tstg));
00283     ps_search_init(&tstg->base, &tst_funcs, config, acmod, dict, d2p);
00284 
00285     tstg->fillpen = fillpen_init(ps_search_dict(tstg), NULL,
00286                                  cmd_ln_float32_r(config, "-silprob"),
00287                                  cmd_ln_float32_r(config, "-fillprob"),
00288                                  cmd_ln_float32_r(config, "-lw"),
00289                                  cmd_ln_float32_r(config, "-wip"),
00290                                  acmod->lmath);
00291     tstg->beam = beam_init(cmd_ln_float64_r(config, "-beam"),
00292                            cmd_ln_float64_r(config, "-pbeam"),
00293                            cmd_ln_float64_r(config, "-wbeam"),
00294                            cmd_ln_float64_r(config, "-wend_beam"),
00295                            0, bin_mdef_n_ciphone(acmod->mdef),
00296                            acmod->lmath);
00297     beam_report(tstg->beam);
00298 
00299     tstg->ssid_active = bitvec_alloc(bin_mdef_n_sseq(acmod->mdef));
00300     tstg->comssid_active = bitvec_alloc(dict2pid_n_comsseq(ps_search_dict2pid(tstg)));
00301     tstg->composite_senone_scores = ckd_calloc(dict2pid_n_comstate(ps_search_dict2pid(tstg)),
00302                                                sizeof(*tstg->composite_senone_scores));
00303 
00304     ptmr_init(&(tm_build));
00305 
00306     tstg->epl = cmd_ln_int32_r(config, "-epl");
00307     tstg->n_lextree = cmd_ln_int32_r(config, "-Nlextree");
00308     n_ltree = tstg->n_lextree;
00309 
00310     /* Initialize language model set (this is done for us in Sphinx3,
00311      * but not in PocketSphinx) */
00312     if ((path = cmd_ln_str_r(config, "-lmctl"))) {
00313         tstg->lmset = ngram_model_set_read(config, path, acmod->lmath);
00314         if (tstg->lmset == NULL) {
00315             E_ERROR("Failed to read language model control file: %s\n",
00316                     path);
00317             goto error_out;
00318         }
00319         /* Set the default language model if needed. */
00320         if ((path = cmd_ln_str_r(config, "-lmname"))) {
00321             ngram_model_set_select(tstg->lmset, path);
00322         }
00323     }
00324     else if ((path = cmd_ln_str_r(config, "-lm"))) {
00325         static const char *name = "default";
00326         ngram_model_t *lm;
00327 
00328         lm = ngram_model_read(config, path, NGRAM_AUTO, acmod->lmath);
00329         if (lm == NULL) {
00330             E_ERROR("Failed to read language model file: %s\n", path);
00331             goto error_out;
00332         }
00333         tstg->lmset = ngram_model_set_init(config,
00334                                           &lm, (char **)&name,
00335                                           NULL, 1);
00336         if (tstg->lmset == NULL) {
00337             E_ERROR("Failed to initialize language model set\n");
00338             goto error_out;
00339         }
00340     }
00341 
00342     /* STRUCTURE and REPORT: Initialize lexical tree. Filler tree's
00343        initialization is followed.  */
00344     tstg->ugtree =
00345         hash_table_new(ngram_model_set_count(tstg->lmset), HASH_CASE_YES);
00346 
00347     /* curugtree is a pointer pointing the current unigram tree which
00348        were being used. */
00349 
00350     tstg->curugtree =
00351         (lextree_t **) ckd_calloc(n_ltree, sizeof(lextree_t *));
00352 
00353     /* Just allocate pointers */
00354 
00355     ptmr_reset(&(tm_build));
00356     /*
00357      * Only create the lextree for the entire language model set
00358      * specific ones will be created in srch_TST_set_lm()
00359      */
00360     if ((lextree = create_lextree(tstg, "lmset", &tm_build)) == NULL) {
00361         goto error_out;
00362     }
00363     for (j = 0; j < n_ltree; ++j)
00364         tstg->curugtree[j] = lextree[j];
00365 
00366     E_INFO("Time for building trees, %4.4f CPU %4.4f Clk\n",
00367            tm_build.t_cpu, tm_build.t_elapsed);
00368 
00369     /* STRUCTURE: Create filler lextrees */
00370     /* ARCHAN : only one filler tree is supposed to be built even for dynamic LMs */
00371     tstg->fillertree =
00372         (lextree_t **) ckd_calloc(n_ltree, sizeof(lextree_t *));
00373 
00374     for (i = 0; i < n_ltree; i++) {
00375         if ((tstg->fillertree[i] = fillertree_init(acmod->mdef, acmod->tmat,
00376                                                    ps_search_dict(tstg), ps_search_dict2pid(tstg),
00377                                                    tstg->fillpen)) == NULL) {
00378             E_INFO("Fail to allocate filler tree  %d\n", i);
00379             goto error_out;
00380         }
00381         E_INFO("Lextrees(%d), %d nodes(filler)\n",
00382                i, lextree_n_node(tstg->fillertree[0]));
00383     }
00384 
00385     if (cmd_ln_int32_r(config, "-lextreedump")) {
00386         for (lmset_iter = ngram_model_set_iter(tstg->lmset);
00387              lmset_iter; lmset_iter = ngram_model_set_iter_next(lmset_iter)) {
00388             const char *model_name;
00389             ngram_model_set_iter_model(lmset_iter, &model_name);
00390             hash_table_lookup(tstg->ugtree, model_name, (void*)&lextree);
00391             for (j = 0; j < n_ltree; j++) {
00392                 E_INFO("LM name: \'%s\' UGTREE: %d\n",
00393                         model_name, j);
00394                 lextree_dump(lextree[j], stderr,
00395                              cmd_ln_int32_r(config, "-lextreedump"));
00396             }
00397         }
00398         ngram_model_set_iter_free(lmset_iter);
00399         for (i = 0; i < n_ltree; i++) {
00400             E_INFO("FILLERTREE %d\n", i);
00401             lextree_dump(tstg->fillertree[i], stderr,
00402                          cmd_ln_int32_r(config, "-lextreedump"));
00403         }
00404     }
00405 
00406     tstg->histprune = histprune_init(cmd_ln_int32_r(config, "-maxhmmpf"),
00407                                      cmd_ln_int32_r(config, "-maxhistpf"),
00408                                      cmd_ln_int32_r(config, "-maxwpf"),
00409                                      cmd_ln_int32_r(config, "-hmmhistbinsize"),
00410                                      (tstg->curugtree[0]->n_node + tstg->fillertree[0]->n_node) *
00411                                      tstg->n_lextree);
00412     histprune_report(tstg->histprune);
00413 
00414     /* Viterbi history structure */
00415     tstg->vithist = vithist_init(ngram_model_get_counts(tstg->lmset)[0],
00416                                  bin_mdef_n_ciphone(acmod->mdef),
00417                                  logmath_log(acmod->lmath, cmd_ln_float64_r(config, "-vhbeam")),
00418                                  cmd_ln_int32_r(config, "-bghist"), TRUE);
00419 
00420 
00421     return (ps_search_t *)tstg;
00422 
00423 error_out:
00424     tst_search_free(ps_search_base(tstg));
00425     return NULL;
00426 }
00427 
00428 void
00429 tst_search_free(ps_search_t *search)
00430 {
00431     tst_search_t *tstg = (tst_search_t *)search;
00432 
00433     if (tstg == NULL)
00434         return;
00435 
00436     if (tstg->ugtree) {
00437         hash_iter_t *hiter = hash_table_iter(tstg->ugtree);
00438         if (hiter)
00439             do {
00440                 lextree_t **lextree = (lextree_t**)hash_entry_val(hiter->ent);
00441                 if (lextree) {
00442                     int j;
00443                     for (j = 0; j < tstg->n_lextree; ++j)
00444                         lextree_free(lextree[j]);
00445                 }
00446             } while ((hiter = hash_table_iter_next(hiter)));
00447         hash_table_free(tstg->ugtree);
00448     }
00449 
00450     ckd_free(tstg->curugtree);
00451     if (tstg->fillertree) {
00452         int32 j;
00453         for (j = 0; j < tstg->n_lextree; ++j)
00454             lextree_free(tstg->fillertree[j]);
00455         ckd_free(tstg->fillertree);
00456     }
00457 
00458     if (tstg->vithist)
00459         vithist_free(tstg->vithist);
00460     if (tstg->histprune)
00461         histprune_free(tstg->histprune);
00462     if (tstg->fillpen)
00463         fillpen_free(tstg->fillpen);
00464     if (tstg->beam)
00465         beam_free(tstg->beam);
00466     bitvec_free(tstg->ssid_active);
00467     bitvec_free(tstg->comssid_active);
00468     ckd_free(tstg->composite_senone_scores);
00469     ps_search_deinit(search);
00470     ckd_free(tstg);
00471 }
00472 
00473 static int
00474 tst_search_start(ps_search_t *search)
00475 {
00476     tst_search_t *tstg = (tst_search_t *)search;
00477     int32 n, pred;
00478     int32 i;
00479 
00480     /* Clean up any previous viterbi history */
00481     vithist_utt_reset(tstg->vithist);
00482     histprune_zero_histbin(tstg->histprune);
00483 
00484     /* Reset statistics */
00485     memset(&tstg->st, 0, sizeof(tstg->st));
00486     tstg->n_frame = 0;
00487 
00488     /* Insert initial <s> into vithist structure */
00489     pred = vithist_utt_begin(tstg->vithist,
00490                              s3dict_startwid(ps_search_dict(tstg)),
00491                              ngram_wid(tstg->lmset, "<s>"));
00492     assert(pred == 0);          /* Vithist entry ID for <s> */
00493 
00494     /* Need to reinitialize GMMs, things like that? */
00495 
00496     /* Enter into unigram lextree[0] */
00497     n = lextree_n_next_active(tstg->curugtree[0]);
00498     assert(n == 0);
00499     lextree_enter(tstg->curugtree[0],
00500                   bin_mdef_silphone(ps_search_acmod(tstg)->mdef),
00501                   -1, 0, pred, tstg->beam->hmm);
00502 
00503     /* Enter into filler lextree */
00504     n = lextree_n_next_active(tstg->fillertree[0]);
00505     assert(n == 0);
00506     lextree_enter(tstg->fillertree[0], BAD_S3CIPID, -1, 0, pred, tstg->beam->hmm);
00507 
00508     tstg->n_lextrans = 1;
00509 
00510     tstg->exit_id = -1;
00511 
00512     for (i = 0; i < tstg->n_lextree; i++) {
00513         lextree_active_swap(tstg->curugtree[i]);
00514         lextree_active_swap(tstg->fillertree[i]);
00515     }
00516 
00517     return 0;
00518 }
00519 
00520 static int
00521 tst_search_finish(ps_search_t *search)
00522 {
00523     tst_search_t *tstg = (tst_search_t *)search;
00524     int32 i, cf;
00525 
00526     /* This is the number of frames processed. */
00527     cf = ps_search_acmod(search)->output_frame;
00528 
00529     /* Find the exit word and wrap up Viterbi history (but don't reset
00530      * it yet!) */
00531     tstg->exit_id = vithist_utt_end(tstg->vithist,
00532                                     tstg->lmset, ps_search_dict(tstg),
00533                                     ps_search_dict2pid(tstg), tstg->fillpen);
00534 
00535     /* Not sure hwo to get the uttid. */
00536     histprune_showhistbin(tstg->histprune, cf, "histbin");
00537 
00538     for (i = 0; i < tstg->n_lextree; i++) {
00539         lextree_utt_end(tstg->curugtree[i]);
00540         lextree_utt_end(tstg->fillertree[i]);
00541     }
00542 
00543     /* Print out some statistics. */
00544     if (cf > 0) {
00545         E_INFO("%8d words recognized (%d/fr)\n",
00546                vithist_n_entry(tstg->vithist),
00547                (vithist_n_entry(tstg->vithist) + (cf >> 1)) / (cf + 1));
00548         E_INFO("%8d senones evaluated (%d/fr)\n", tstg->st.n_senone_active_utt,
00549                (tstg->st.n_senone_active_utt + (cf >> 1)) / (cf + 1));
00550         E_INFO("%8d channels searched (%d/fr)\n",
00551                tstg->st.n_hmm_eval, tstg->st.n_hmm_eval / (cf + 1));
00552     }
00553 
00554     if (tstg->exit_id >= 0)
00555         return 0;
00556     else
00557         return -1;
00558 }
00559 
00560 static int
00561 srch_TST_hmm_compute_lv2(tst_search_t *tstg, int32 frmno)
00562 {
00563     /* This is local to this codebase */
00564 
00565     int32 i, j;
00566     lextree_t *lextree;
00567     beam_t *bm;
00568     histprune_t *hp;
00569 
00570     int32 besthmmscr, bestwordscr;
00571     int32 frm_nhmm, hb, pb, wb;
00572     int32 n_ltree;              /* Local version of number of lexical trees used */
00573     int32 maxwpf;               /* Local version of Max words per frame, don't expect it to change */
00574     int32 maxhistpf;            /* Local version of Max histories per frame, don't expect it to change */
00575     int32 maxhmmpf;             /* Local version of Max active HMMs per frame, don't expect it to change  */
00576     int32 histbinsize;          /* Local version of histogram bin size, don't expect it to change */
00577     int32 numhistbins;          /* Local version of number of histogram bins, don't expect it to change */
00578     int32 hmmbeam;              /* Local version of hmm beam, don't expect it to change. */
00579     int32 pbeam;                /* Local version of phone beam, don't expect it to change. */
00580     int32 wbeam;                /* Local version of word beam , don't expect it to change */
00581     int32 *hmm_hist;            /* local version of histogram bins. */
00582 
00583     n_ltree = tstg->n_lextree;
00584     hp = tstg->histprune;
00585     bm = tstg->beam;
00586     hmm_hist = hp->hmm_hist;
00587 
00588     maxwpf = hp->maxwpf;
00589     maxhistpf = hp->maxhistpf;
00590     maxhmmpf = hp->maxhmmpf;
00591     histbinsize = hp->hmm_hist_binsize;
00592     numhistbins = hp->hmm_hist_bins;
00593 
00594     hmmbeam = bm->hmm;
00595     pbeam = bm->ptrans;
00596     wbeam = bm->word;
00597 
00598     /* Evaluate active HMMs in each lextree; note best HMM state score */
00599     besthmmscr = MAX_NEG_INT32;
00600     bestwordscr = MAX_NEG_INT32;
00601     frm_nhmm = 0;
00602 
00603     for (i = 0; i < (n_ltree << 1); i++) {
00604         lextree =
00605             (i < n_ltree) ? tstg->curugtree[i] : tstg->fillertree[i - n_ltree];
00606         if (tstg->hmmdumpfp != NULL)
00607             fprintf(tstg->hmmdumpfp, "Fr %d Lextree %d #HMM %d\n", frmno, i,
00608                     lextree->n_active);
00609         lextree_hmm_eval(lextree,
00610                          ps_search_acmod(tstg)->senone_scores,
00611                          tstg->composite_senone_scores,
00612                          frmno, tstg->hmmdumpfp);
00613 
00614         if (besthmmscr < lextree->best)
00615             besthmmscr = lextree->best;
00616         if (bestwordscr < lextree->wbest)
00617             bestwordscr = lextree->wbest;
00618 
00619         tstg->st.n_hmm_eval += lextree->n_active;
00620         frm_nhmm += lextree->n_active;
00621     }
00622     if (besthmmscr > 0) {
00623         E_ERROR
00624             ("***ERROR*** Fr %d, best HMM score > 0 (%d); int32 wraparound?\n",
00625              frmno, besthmmscr);
00626     }
00627 
00628 
00629     /* Hack! similar to the one in mode 5. The reason though is because
00630        dynamic allocation of node cause the histroyt array need to be
00631        allocated too.  I skipped this step by just making simple
00632        assumption here.
00633      */
00634     if (frm_nhmm / histbinsize > hp->hmm_hist_bins - 1)
00635         hmm_hist[hp->hmm_hist_bins - 1]++;
00636     else
00637         hmm_hist[frm_nhmm / histbinsize]++;
00638 
00639     /* Set pruning threshold depending on whether number of active HMMs 
00640      * is within limit 
00641      */
00642     /* ARCHAN: MAGIC */
00643     if (maxhmmpf != -1 && frm_nhmm > (maxhmmpf + (maxhmmpf >> 1))) {
00644         int32 *bin, nbin, bw;
00645 
00646         /* Use histogram pruning */
00647         nbin = 1000;
00648         bw = -(hmmbeam) / nbin;
00649         bin = (int32 *) ckd_calloc(nbin, sizeof(int32));
00650 
00651         for (i = 0; i < (n_ltree << 1); i++) {
00652             lextree = (i < n_ltree) ?
00653                 tstg->curugtree[i] : tstg->fillertree[i - n_ltree];
00654 
00655             lextree_hmm_histbin(lextree, besthmmscr, bin, nbin, bw);
00656         }
00657 
00658         for (i = 0, j = 0; (i < nbin) && (j < maxhmmpf); i++, j += bin[i]);
00659         ckd_free((void *) bin);
00660 
00661         /* Determine hmm, phone, word beams */
00662         hb = -(i * bw);
00663         pb = (hb > pbeam) ? hb : pbeam;
00664         wb = (hb > wbeam) ? hb : wbeam;
00665     }
00666     else {
00667         hb = hmmbeam;
00668         pb = pbeam;
00669         wb = wbeam;
00670     }
00671 
00672     bm->bestscore = besthmmscr;
00673     bm->bestwordscore = bestwordscr;
00674 
00675     bm->thres = bm->bestscore + hb;     /* HMM survival threshold */
00676     bm->phone_thres = bm->bestscore + pb;       /* Cross-HMM transition threshold */
00677     bm->word_thres = bm->bestwordscore + wb;    /* Word exit threshold */
00678 
00679     return 0;
00680 }
00681 
00682 static int
00683 srch_TST_propagate_graph_ph_lv2(tst_search_t *tstg, int32 frmno)
00684 {
00685     int32 i;
00686     int32 n_ltree;              /* Local version of number of lexical trees used */
00687 
00688     lextree_t *lextree;
00689 
00690     n_ltree = tstg->n_lextree;
00691 
00692     for (i = 0; i < (n_ltree << 1); i++) {
00693         lextree = (i < n_ltree)
00694             ? tstg->curugtree[i]
00695             : tstg->fillertree[i - tstg-> n_lextree];
00696 
00697         if (lextree_hmm_propagate_non_leaves(lextree, frmno,
00698                                              tstg->beam->thres,
00699                                              tstg->beam->phone_thres,
00700                                              tstg->beam->word_thres)
00701             != LEXTREE_OPERATION_SUCCESS) {
00702             E_ERROR
00703                 ("Propagation Failed for lextree_hmm_propagate_non_leave at tree %d\n",
00704                  i);
00705             lextree_utt_end(lextree);
00706             return -1;
00707         }
00708     }
00709 
00710     return 0;
00711 }
00712 
00713 static void
00714 mdef_sseq2sen_active(bin_mdef_t * mdef, bitvec_t * sseq, bitvec_t * sen)
00715 {
00716     int32 ss, i;
00717     s3senid_t *sp;
00718 
00719     for (ss = 0; ss < bin_mdef_n_sseq(mdef); ss++) {
00720         if (bitvec_is_set(sseq,ss)) {
00721             sp = mdef->sseq[ss];
00722             for (i = 0; i < mdef_n_emit_state(mdef); i++)
00723                 bitvec_set(sen, sp[i]);
00724         }
00725     }
00726 }
00727 
00728 static int
00729 srch_TST_select_active_gmm(tst_search_t *tstg)
00730 {
00731     int32 n_ltree;              /* Local version of number of lexical trees used */
00732     dict2pid_t *d2p;
00733     bin_mdef_t *mdef;
00734     lextree_t *lextree;
00735     int32 i;
00736 
00737     n_ltree = tstg->n_lextree;
00738     mdef = ps_search_acmod(tstg)->mdef;
00739     d2p = ps_search_dict2pid(tstg);
00740 
00741     bitvec_clear_all(tstg->ssid_active, bin_mdef_n_sseq(mdef));
00742     bitvec_clear_all(tstg->comssid_active, dict2pid_n_comsseq(d2p));
00743 
00744     /* Find active senone-sequence IDs (including composite ones) */
00745     for (i = 0; i < (n_ltree << 1); i++) {
00746         lextree = (i < n_ltree) ? tstg->curugtree[i] :
00747             tstg->fillertree[i - n_ltree];
00748         lextree_ssid_active(lextree, tstg->ssid_active,
00749                             tstg->comssid_active);
00750     }
00751 
00752     /* Find active senones from active senone-sequences */
00753     acmod_clear_active(ps_search_acmod(tstg));
00754     mdef_sseq2sen_active(mdef, tstg->ssid_active,
00755                          ps_search_acmod(tstg)->senone_active_vec);
00756 
00757     /* Add in senones needed for active composite senone-sequences */
00758     dict2pid_comsseq2sen_active(d2p, mdef, tstg->comssid_active,
00759                                 ps_search_acmod(tstg)->senone_active_vec);
00760 
00761     return 0;
00762 }
00763 
00764 static int
00765 srch_TST_rescoring(tst_search_t *tstg, int32 frmno)
00766 {
00767     int32 i;
00768     int32 n_ltree;              /* Local version of number of lexical trees used */
00769     lextree_t *lextree;
00770     vithist_t *vh;
00771 
00772     vh = tstg->vithist;
00773 
00774     n_ltree = tstg->n_lextree;
00775 
00776     for (i = 0; i < (n_ltree * 2); i++) {
00777         lextree = (i < n_ltree)
00778             ? tstg->curugtree[i]
00779             : tstg->fillertree[i - tstg->n_lextree];
00780 
00781         E_DEBUG(1,("Propagating words from lextree %d\n", i));
00782         if (lextree_hmm_propagate_leaves
00783             (lextree, vh, frmno,
00784              tstg->beam->word_thres) != LEXTREE_OPERATION_SUCCESS) {
00785             E_ERROR
00786                 ("Propagation Failed for lextree_hmm_propagate_leave at tree %d\n",
00787                  i);
00788             lextree_utt_end(lextree);
00789             return -1;
00790         }
00791     }
00792 
00793     return 0;
00794 }
00795 
00796 static void
00797 srch_utt_word_trans(tst_search_t * tstg, int32 cf)
00798 {
00799     int32 k, th;
00800     vithist_t *vh;
00801     vithist_entry_t *ve;
00802     int32 vhid, le, n_ci, score;
00803     int32 maxpscore;
00804     int32 *bs = NULL, *bv = NULL, epl;
00805     beam_t *bm;
00806     s3wid_t wid;
00807     int32 p;
00808     s3dict_t *dict;
00809     bin_mdef_t *mdef;
00810 
00811     /* Call the rescoring routines at all word end */
00812     maxpscore = MAX_NEG_INT32;
00813     bm = tstg->beam;
00814     vh = tstg->vithist;
00815     th = bm->bestscore + bm->hmm;       /* Pruning threshold */
00816 
00817     if (vh->bestvh[cf] < 0)
00818         return;
00819 
00820     dict = ps_search_dict(tstg);
00821     mdef = ps_search_acmod(tstg)->mdef;
00822     n_ci = bin_mdef_n_ciphone(mdef);
00823 
00824     /* Initialize best exit for each distinct word-final CI phone to NONE */
00825 
00826     bs = bm->wordbestscores;
00827     bv = bm->wordbestexits;
00828     epl = tstg->epl;
00829 
00830     for (p = 0; p < n_ci; p++) {
00831         bs[p] = MAX_NEG_INT32;
00832         bv[p] = -1;
00833     }
00834 
00835     /* Find best word exit in this frame for each distinct word-final CI phone */
00836     vhid = vithist_first_entry(vh, cf);
00837     le = vithist_n_entry(vh) - 1;
00838     for (; vhid <= le; vhid++) {
00839         ve = vithist_id2entry(vh, vhid);
00840         if (!vithist_entry_valid(ve))
00841             continue;
00842 
00843         wid = vithist_entry_wid(ve);
00844         p = s3dict_last_phone(dict, wid);
00845         if (bin_mdef_is_fillerphone(mdef, p))
00846             p = bin_mdef_silphone(mdef);
00847 
00848         score = vithist_entry_score(ve);
00849         if (score > bs[p]) {
00850             bs[p] = score;
00851             bv[p] = vhid;
00852             if (maxpscore < score) {
00853                 maxpscore = score;
00854                 /*    E_INFO("maxscore = %d\n", maxpscore); */
00855             }
00856         }
00857     }
00858 
00859     /* Find lextree instance to be entered */
00860     k = tstg->n_lextrans++;
00861     k = (k % (tstg->n_lextree * epl)) / epl;
00862 
00863     /* Transition to unigram lextrees */
00864     for (p = 0; p < n_ci; p++) {
00865         if (bv[p] >= 0) {
00866             if (tstg->beam->wordend == 0
00867                 || bs[p] > tstg->beam->wordend + maxpscore) {
00868                 /* RAH, typecast p to (s3cipid_t) to make compiler happy */
00869                 lextree_enter(tstg->curugtree[k], (s3cipid_t) p, cf, bs[p],
00870                               bv[p], th);
00871             }
00872         }
00873 
00874     }
00875 
00876     /* Transition to filler lextrees */
00877     lextree_enter(tstg->fillertree[k], BAD_S3CIPID, cf, vh->bestscore[cf],
00878                   vh->bestvh[cf], th);
00879 }
00880 
00881 static int
00882 srch_TST_propagate_graph_wd_lv2(tst_search_t *tstg, int32 frmno)
00883 {
00884     s3dict_t *dict;
00885     vithist_t *vh;
00886     histprune_t *hp;
00887     int32 maxwpf;               /* Local version of Max words per frame, don't expect it to change */
00888     int32 maxhistpf;            /* Local version of Max histories per frame, don't expect it to change */
00889     int32 maxhmmpf;             /* Local version of Max active HMMs per frame, don't expect it to change  */
00890 
00891 
00892     hp = tstg->histprune;
00893     vh = tstg->vithist;
00894     dict = ps_search_dict(tstg);
00895 
00896     maxwpf = hp->maxwpf;
00897     maxhistpf = hp->maxhistpf;
00898     maxhmmpf = hp->maxhmmpf;
00899 
00900     srch_TST_rescoring(tstg, frmno);
00901 
00902     vithist_prune(vh, dict, frmno, maxwpf, maxhistpf,
00903                   tstg->beam->word_thres - tstg->beam->bestwordscore);
00904 
00905     srch_utt_word_trans(tstg, frmno);
00906 
00907     return 0;
00908 }
00909 
00910 
00911 static int
00912 srch_TST_frame_windup(tst_search_t *tstg, int32 frmno)
00913 {
00914     vithist_t *vh;
00915     int32 i;
00916 
00917     vh = tstg->vithist;
00918 
00919     /* Wind up this frame */
00920     vithist_frame_windup(vh, frmno, NULL, tstg->lmset, ps_search_dict(tstg));
00921 
00922     for (i = 0; i < tstg->n_lextree; i++) {
00923         lextree_active_swap(tstg->curugtree[i]);
00924         lextree_active_swap(tstg->fillertree[i]);
00925     }
00926     return 0;
00927 }
00928 
00929 static int
00930 tst_search_step(ps_search_t *search, int frame_idx)
00931 {
00932     tst_search_t *tstg = (tst_search_t *)search;
00933     int16 const *senscr;
00934 
00935     /* Select active senones for the current frame. */
00936     srch_TST_select_active_gmm(tstg);
00937 
00938     /* Compute GMM scores for the current frame. */
00939     if ((senscr = acmod_score(ps_search_acmod(search), &frame_idx)) == NULL)
00940         return 0;
00941     tstg->st.n_senone_active_utt += ps_search_acmod(search)->n_senone_active;
00942 
00943     /* Evaluate composite senone scores from senone scores */
00944     memset(tstg->composite_senone_scores, 0,
00945            dict2pid_n_comstate(ps_search_dict2pid(tstg)) * sizeof(*tstg->composite_senone_scores));
00946     dict2pid_comsenscr(ps_search_dict2pid(tstg), senscr, tstg->composite_senone_scores);
00947 
00948     /* Compute HMMs, propagate phone and word exits, etc, etc. */
00949     srch_TST_hmm_compute_lv2(tstg, frame_idx);
00950     srch_TST_propagate_graph_ph_lv2(tstg, frame_idx);
00951     srch_TST_propagate_graph_wd_lv2(tstg, frame_idx);
00952     srch_TST_frame_windup(tstg, frame_idx);
00953 
00954     /* FIXME: Renormalization? */
00955     ++tstg->n_frame;
00956 
00957     /* Return the number of frames processed. */
00958     return 1;
00959 }
00960 
00961 static ps_lattice_t *
00962 tst_search_lattice(ps_search_t *search)
00963 {
00964     tst_search_t *tstg = (tst_search_t *)search;
00965     vithist_t *vh;
00966     glist_t *sfwid;             /* To maintain <start-frame, word-id> pair dagnodes */
00967     gnode_t *gn, *gn2, *gn3;
00968     int32 min_ef_range;
00969     int32 sf, ef, n_node;
00970     int32 f, i;
00971     ps_lattice_t *dag;
00972     ps_latnode_t *dn;
00973     int32 exit_id, id;
00974 
00975     vh = tstg->vithist;
00976     if (tstg->exit_id == -1) /* Search not finished */
00977         exit_id = vithist_partialutt_end(vh, tstg->lmset, ps_search_dict(tstg));
00978     else
00979         exit_id = tstg->exit_id;
00980 
00981     if (exit_id < 0) {
00982         E_WARN("Failed to retrieve viterbi history.\n");
00983         return NULL;
00984     }
00985 
00986     /* Check to see if a lattice has previously been created over the
00987      * same number of frames, and reuse it if so. */
00988     if (search->dag && search->dag->n_frames == tstg->n_frame)
00989         return search->dag;
00990 
00991     /* Nope, create a new one. */
00992     ps_lattice_free(search->dag);
00993     search->dag = NULL;
00994     dag = ps_lattice_init_search(search, tstg->n_frame);
00995 
00996     /* Track starting frame, word id pairs. */
00997     sfwid = (glist_t *) ckd_calloc(vh->n_frm + 1, sizeof(glist_t));
00998 
00999     /* Min. endframes value that a node must persist for it to be not ignored */
01000     min_ef_range = cmd_ln_int32_r(ps_search_config(search), "-min_endfr");
01001 
01002     n_node = 0;
01003     sf = 0;
01004     for (i = 0; i < vh->n_entry; i++) { /* This range includes the dummy <s> and </s> entries */
01005         ps_latnode_t *dn;
01006         vithist_entry_t *ve, *ve2;
01007 
01008         ve = vithist_id2entry(vh, i);
01009         if (!ve->valid)
01010             continue;
01011         /*
01012          * The initial <s> entry (at 0) is a dummy, with start/end frame = -1.  But the old S3
01013          * code treats it like a real word, so we have to reintroduce it in the dag file with
01014          * a start time of 0.  And shift the start time of words starting at frame 0 up by 1.
01015          * MAJOR HACK!!
01016          */
01017         if (ve->sf == -1) {
01018             assert(ve->ef == -1);
01019             sf = ef = 0;
01020         }
01021         else if (ve->sf == 0) {
01022             assert(ve->ef > 0);
01023             sf = ve->sf + 1;
01024             ef = ve->ef;
01025         }
01026         else {
01027             sf = ve->sf;
01028             ef = ve->ef;
01029         }
01030 
01031         /* Look for other instances of this word starting in the same frame. */
01032         for (gn = sfwid[sf]; gn; gn = gnode_next(gn)) {
01033             dn = (ps_latnode_t *) gnode_ptr(gn);
01034             if (dn->wid == ve->wid)
01035                 break;
01036         }
01037         /* Create a new one if not. */
01038         if (!gn) {
01039             dn = listelem_malloc(dag->latnode_alloc);
01040             memset(dn, 0, sizeof(*dn));
01041             dn->wid = ve->wid;
01042 
01043             dn->sf = sf;
01044             dn->fef = ef;
01045             dn->lef = ef;
01046             dn->id = -1;     /* Initially all invalid, selected ones validated below */
01047             ++n_node;
01048 
01049             sfwid[sf] = glist_add_ptr(sfwid[sf], (void *) dn);
01050         }
01051         else {
01052             dn->lef = ef;
01053         }
01054 
01055         if (i == exit_id)
01056             dag->end = dn;
01057 
01058         /*
01059          * Check if an entry already exists under dn->velist (generated by a different
01060          * LM context; retain only the best scoring one.
01061          */
01062         for (gn = dn->info.velist; gn; gn = gnode_next(gn)) {
01063             ve2 = (vithist_entry_t *) gnode_ptr(gn);
01064             if (ve2->ef == ve->ef)
01065                 break;
01066         }
01067         if (gn) {
01068             if (ve->path.score > ve2->path.score)
01069                 gnode_ptr(gn) = (void *) ve;
01070         }
01071         else
01072             dn->info.velist = glist_add_ptr(dn->info.velist, (void *) ve);
01073     }
01074 
01075     /*
01076      * Validate segments with >=min_endfr end times.
01077      * But keep segments in the original hypothesis, regardless; mark them first.
01078      */
01079     id = exit_id;
01080     while (id >= 0) {
01081         vithist_entry_t *ve = vithist_id2entry(vh, id);
01082         /*
01083          * As long as the above comment about the MAJOR HACK is true
01084          * the start time has to be hacked here too
01085          */
01086         int hacked_sf = vithist_entry_sf(ve);
01087         if (hacked_sf <= 0) ++hacked_sf;
01088         assert(hacked_sf >= 0);
01089         for (gn2 = sfwid[hacked_sf]; gn2; gn2 = gnode_next(gn2)) {
01090             ps_latnode_t *dn = (ps_latnode_t *) gnode_ptr(gn2);
01091             if (vithist_entry_wid(ve) == dn->wid)
01092                 dn->id = 0;  /* Do not discard (prune) this dagnode */
01093         }
01094         id = vithist_entry_pred(ve);
01095     }
01096 
01097     /* Validate startwid and finishwid nodes */
01098     dn = (ps_latnode_t *) gnode_ptr(sfwid[0]);
01099     assert(dn->wid == s3dict_startwid(ps_search_dict(tstg)));
01100     dn->id = 0;
01101     dag->start = dn;
01102 
01103     dn = (ps_latnode_t *) gnode_ptr(sfwid[vh->n_frm]);
01104     assert(dn->wid == s3dict_finishwid(ps_search_dict(tstg)));
01105     dn->id = 0;
01106     /* If for some reason the final node is not the same as the end
01107      * node, make sure it exists and is also marked valid. */
01108     if (dag->end == NULL) {
01109         E_WARN("Final vithist entry %d not found, using </s> node\n", exit_id);
01110         dag->end = dn;
01111     }
01112     dag->end->id = 0;
01113     /* Find the exit score for the end node. */
01114     for (gn = (glist_t)dag->end->info.velist; gn; gn = gnode_next(gn)) {
01115         vithist_entry_t *ve2 = (vithist_entry_t *) gnode_ptr(gn);
01116         if (ve2->ef == vh->n_frm)
01117             dag->final_node_ascr = ve2->ascr;
01118     }
01119 
01120     /* Now prune dagnodes with <min_endfr end frames if not validated above */
01121     i = 0;
01122     for (f = 0; f <= vh->n_frm; ++f) {
01123         for (gn = sfwid[f]; gn; gn = gnode_next(gn)) {
01124             ps_latnode_t *dn = (ps_latnode_t *) gnode_ptr(gn);
01125             if ((dn->lef - dn->fef > min_ef_range) || (dn->id >= 0)) {
01126                 dn->id = i++;
01127                 dn->next = dag->nodes;
01128                 dag->nodes = dn;
01129             }
01130             else
01131                 dn->id = -1; /* Flag: discard */
01132         }
01133     }
01134 
01135     for (f = 0; f < vh->n_frm; ++f) {
01136         for (gn = sfwid[f]; gn; gn = gnode_next(gn)) {
01137             ps_latnode_t *dn = (ps_latnode_t *) gnode_ptr(gn);
01138             /* Look for transitions from this dagnode to later ones, if not discarded */
01139             if (dn->id < 0)
01140                 continue;
01141 
01142             for (gn2 = (glist_t) dn->info.velist; gn2; gn2 = gnode_next(gn2)) {
01143                 vithist_entry_t *ve = (vithist_entry_t *) gnode_ptr(gn2);
01144                 sf = (ve->ef < 0) ? 1 : (ve->ef + 1);
01145                 for (gn3 = sfwid[sf]; gn3; gn3 = gnode_next(gn3)) {
01146                     ps_latnode_t *dn2 = (ps_latnode_t *) gnode_ptr(gn3);
01147                     if (dn2->id >= 0)
01148                         ps_lattice_link(dag, dn, dn2, ve->ascr, sf - 1);
01149                 }
01150             }
01151         }
01152     }
01153 
01154     /* Free dagnodes structure */
01155     for (f = 0; f <= vh->n_frm; f++) {
01156         for (gn = sfwid[f]; gn; gn = gnode_next(gn)) {
01157             ps_latnode_t *dn = (ps_latnode_t *) gnode_ptr(gn);
01158             glist_free((glist_t) dn->info.velist);
01159             dn->info.velist = NULL;
01160             if (dn->id == -1) /* If pruned, free the node too */
01161                 listelem_free(dag->latnode_alloc, dn);
01162         }
01163         glist_free(sfwid[f]);
01164     }
01165     ckd_free((void *)sfwid);
01166 
01167     dag->n_frames = vh->n_frm;
01168 
01169     /* FIXME: We should delete unreachable nodes here. */
01170 
01171     /* Build links around silence and filler words, since they do not
01172      * exist in the language model. */
01173     ps_lattice_bypass_fillers
01174         (dag, logmath_log(ps_search_acmod(search)->lmath, tstg->fillpen->silprob),
01175          logmath_log(ps_search_acmod(search)->lmath, tstg->fillpen->fillerprob));
01176 
01177     search->dag = dag;
01178 
01179     return dag;
01180 }
01181 
01182 static char const *
01183 tst_search_hyp(ps_search_t *base, int32 *out_score)
01184 {
01185     tst_search_t *tstg = (tst_search_t *)base;
01186     vithist_entry_t *ve;
01187     char *c;
01188     size_t len;
01189     int32 exit_id, id;
01190 
01191     if (tstg->exit_id == -1) /* Search not finished */
01192         exit_id = vithist_partialutt_end(tstg->vithist, tstg->lmset, ps_search_dict(tstg));
01193     else
01194         exit_id = tstg->exit_id;
01195 
01196     if (exit_id < 0) {
01197         E_WARN("Failed to retrieve viterbi history.\n");
01198         return NULL;
01199     }
01200 
01201     ve = vithist_id2entry(tstg->vithist, exit_id);
01202     *out_score = ve->ascr + ve->lscr;
01203 
01204     id = exit_id;
01205     len = 0;
01206     while (id >= 0) {
01207         s3wid_t wid;
01208         ve = vithist_id2entry(tstg->vithist, id);
01209         assert(ve);
01210         wid = vithist_entry_wid(ve);
01211         id = ve->path.pred;
01212         if (s3dict_filler_word(ps_search_dict(tstg), wid)
01213             || wid == s3dict_startwid(ps_search_dict(tstg))
01214             || wid == s3dict_finishwid(ps_search_dict(tstg)))
01215             continue;
01216         len += strlen(s3dict_wordstr(ps_search_dict(tstg), s3dict_basewid(ps_search_dict(tstg), wid))) + 1;
01217     }
01218 
01219     ckd_free(base->hyp_str);
01220     base->hyp_str = ckd_calloc(1, len);
01221     id = exit_id;
01222     c = base->hyp_str + len - 1;
01223     while (id >= 0) {
01224         s3wid_t wid;
01225         ve = vithist_id2entry(tstg->vithist, id);
01226         assert(ve);
01227         wid = vithist_entry_wid(ve);
01228         id = ve->path.pred;
01229         if (s3dict_filler_word(ps_search_dict(tstg), wid)
01230             || wid == s3dict_startwid(ps_search_dict(tstg))
01231             || wid == s3dict_finishwid(ps_search_dict(tstg)))
01232             continue;
01233         len = strlen(s3dict_wordstr(ps_search_dict(tstg), s3dict_basewid(ps_search_dict(tstg), wid)));
01234         c -= len;
01235         memcpy(c, s3dict_wordstr(ps_search_dict(tstg), s3dict_basewid(ps_search_dict(tstg), wid)), len);
01236         if (c > base->hyp_str) {
01237             --c;
01238             *c = ' ';
01239         }
01240     }
01241 
01242     return base->hyp_str;
01243 }
01244 
01245 static int32
01246 tst_search_prob(ps_search_t *search)
01247 {
01248     /* Bogus out-of-band value for now. */
01249     return 1;
01250 }
01251 
01255 typedef struct tst_seg_s {
01256     ps_seg_t base;  
01257     int32 *bpidx;   
01258     int16 n_bpidx;  
01259     int16 cur;      
01260 } tst_seg_t;
01261 
01262 static void
01263 tst_search_bp2itor(ps_seg_t *seg, int id)
01264 {
01265     tst_search_t *tstg = (tst_search_t *)seg->search;
01266     vithist_entry_t *ve;
01267 
01268     ve = vithist_id2entry(tstg->vithist, id);
01269     assert(ve);
01270     seg->word = s3dict_wordstr(ps_search_dict(tstg), vithist_entry_wid(ve));
01271     seg->ef = vithist_entry_ef(ve);
01272     seg->sf = vithist_entry_sf(ve);
01273     seg->prob = 0; /* Bogus value... */
01274     seg->ascr = vithist_entry_ascr(ve);
01275     seg->lscr = vithist_entry_lscr(ve);
01276     seg->lback = 0; /* FIXME: Compute this somewhere... */
01277 }
01278 
01279 static void
01280 tst_seg_free(ps_seg_t *seg)
01281 {
01282     tst_seg_t *itor = (tst_seg_t *)seg;
01283     
01284     ckd_free(itor->bpidx);
01285     ckd_free(itor);
01286 }
01287 
01288 static ps_seg_t *
01289 tst_seg_next(ps_seg_t *seg)
01290 {
01291     tst_seg_t *itor = (tst_seg_t *)seg;
01292 
01293     if (++itor->cur == itor->n_bpidx) {
01294         tst_seg_free(seg);
01295         return NULL;
01296     }
01297 
01298     tst_search_bp2itor(seg, itor->bpidx[itor->cur]);
01299     return seg;
01300 }
01301 
01302 static ps_segfuncs_t tst_segfuncs = {
01303     /* seg_next */ tst_seg_next,
01304     /* seg_free */ tst_seg_free
01305 };
01306 
01307 static ps_seg_t *
01308 tst_search_seg_iter(ps_search_t *search, int32 *out_score)
01309 {
01310     tst_search_t *tstg = (tst_search_t *)search;
01311     tst_seg_t *itor;
01312     int exit_id, id, cur;
01313 
01314     if (tstg->exit_id == -1) /* Search not finished */
01315         exit_id = vithist_partialutt_end(tstg->vithist, tstg->lmset, ps_search_dict(tstg));
01316     else
01317         exit_id = tstg->exit_id;
01318     if (exit_id < 0) {
01319         E_WARN("Failed to retrieve viterbi history.\n");
01320         return NULL;
01321     }
01322 
01323     /* Calling this an "iterator" is a bit of a misnomer since we have
01324      * to get the entire backtrace in order to produce it.  On the
01325      * other hand, all we actually need is the vithist IDs, and we can
01326      * allocate a fixed-size array of them. */
01327     itor = ckd_calloc(1, sizeof(*itor));
01328     itor->base.vt = &tst_segfuncs;
01329     itor->base.search = search;
01330     itor->base.lwf = 1.0;
01331     itor->n_bpidx = 0;
01332     id = exit_id;
01333     while (id >= 0) {
01334         vithist_entry_t *ve = vithist_id2entry(tstg->vithist, id);
01335         assert(ve);
01336         id = vithist_entry_pred(ve);
01337         ++itor->n_bpidx;
01338     }
01339     if (itor->n_bpidx == 0) {
01340         ckd_free(itor);
01341         return NULL;
01342     }
01343     itor->bpidx = ckd_calloc(itor->n_bpidx, sizeof(*itor->bpidx));
01344     cur = itor->n_bpidx - 1;
01345     id = exit_id;
01346     while (id >= 0) {
01347         vithist_entry_t *ve = vithist_id2entry(tstg->vithist, id);
01348         assert(ve);
01349         itor->bpidx[cur] = id;
01350         id = vithist_entry_pred(ve);
01351         --cur;
01352     }
01353 
01354     /* Fill in relevant fields for first element. */
01355     tst_search_bp2itor((ps_seg_t *)itor, itor->bpidx[0]);
01356 
01357     return (ps_seg_t *)itor;
01358 }

Generated on Mon Jan 24 21:50:16 2011 for PocketSphinx by  doxygen 1.4.7