src/libpocketsphinx/lextree.c

00001 /* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */
00002 /* ====================================================================
00003  * Copyright (c) 1999-2004 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 /*
00038  * lextree.c -- 
00039  * 
00040  * **********************************************
00041  * CMU ARPA Speech Project
00042  *
00043  * Copyright (c) 1999 Carnegie Mellon University.
00044  * ALL RIGHTS RESERVED.
00045  * **********************************************
00046  * 
00047  * HISTORY
00048  * $Log$
00049  * Revision 1.11  2006/02/24  12:42:43  arthchan2003
00050  * Removed warnings in srch_flat_fwd.c and lextree.c
00051  * 
00052  * Revision 1.10  2006/02/23 15:08:24  arthchan2003
00053  * Merged from the branch SPHINX3_5_2_RCI_IRII_BRANCH:
00054  *
00055  * 1, Fixed memory leaks.
00056  * 2, Add logic for full triphone expansion.  At this point, the
00057  * propagation of scores in word end is still incorrect. So composite
00058  * triphone should still be used by default.
00059  * 3, Removed lextree_copies_hmm_propagate.
00060  *
00061  * Revision 1.9.4.10  2005/11/17 06:28:50  arthchan2003
00062  * Changed the code to used compressed triphones. Not yet correct at this point
00063  *
00064  * Revision 1.9.4.9  2005/10/17 04:53:44  arthchan2003
00065  * Shrub the trees so that the run-time memory could be controlled.
00066  *
00067  * Revision 1.9.4.8  2005/10/07 19:34:29  arthchan2003
00068  * In full cross-word triphones expansion, the previous implementation has several flaws, e.g, 1, it didn't consider the phone beam on cross word triphones. 2, Also, when the cross word triphone phone is used, children of the last phones will be regarded as cross word triphone. So, the last phone should not be evaluated at all.  Last implementation has not safe-guaded that. 3, The rescoring for language model is not done correctly.  What we still need to do: a, test the algorithm in more databases. b,  implement some speed up schemes.
00069  *
00070  * Revision 1.9.4.7  2005/09/25 19:27:04  arthchan2003
00071  * (Change for Comment) 1, Added lexical tree reporting. 2, Added a function for getting the number of links. 3, Added support for doing full triphone expansion. 4, In lextree_dump separate hmm evaluation and hmm dumping.
00072  *
00073  * Revision 1.9.4.6  2005/09/25 19:23:55  arthchan2003
00074  * 1, Added arguments for turning on/off LTS rules. 2, Added arguments for turning on/off composite triphones. 3, Moved dict2pid deallocation back to dict2pid. 4, Tidying up the clean up code.
00075  *
00076  * Revision 1.9.4.5  2005/09/18 01:36:47  arthchan2003
00077  * Add implementation for lextree_report.
00078  *
00079  * Revision 1.9.4.4  2005/08/02 21:35:05  arthchan2003
00080  * Change sen to senscr.
00081  *
00082  * Revision 1.9.4.3  2005/07/17 05:44:32  arthchan2003
00083  * Added dag_write_header so that DAG header writer could be shared between 3.x and 3.0. However, because the backtrack pointer structure is different in 3.x and 3.0. The DAG writer still can't be shared yet.
00084  *
00085  * Revision 1.9.4.2  2005/07/07 02:34:36  arthchan2003
00086  * Remove empty lextree_tree_copies_hmm_propagate
00087  *
00088  * Revision 1.9.4.1  2005/06/27 05:37:05  arthchan2003
00089  * Incorporated several fixes to the search. 1, If a tree is empty, it will be removed and put back to the pool of tree, so number of trees will not be always increasing.  2, In the previous search, the answer is always "STOP P I T G S B U R G H </s>"and filler words never occurred in the search.  The reason is very simple, fillers was not properly propagated in the search at all <**exculamation**>  This version fixed this problem.  The current search will give <sil> P I T T S B U R G H </sil> </s> to me.  This I think it looks much better now.
00090  *
00091  * Revision 1.9  2005/06/21 23:32:58  arthchan2003
00092  * Log. Introduced lextree_init and filler_init to wrap up lextree_build
00093  * process. Split the hmm propagation to propagation for leaves and
00094  * non-leaves node.  This allows an easier time for turning off the
00095  * rescoring stage. However, the implementation is not clever enough. One
00096  * should split the array to leave array and non-leave array.
00097  *
00098  * Revision 1.11  2005/06/16 04:59:10  archan
00099  * Sphinx3 to s3.generic, a gentle-refactored version of Dave's change in senone scale.
00100  *
00101  * Revision 1.10  2005/06/11 00:15:14  archan
00102  * Add an assert that could save lives
00103  *
00104  * Revision 1.9  2005/05/03 06:57:43  archan
00105  * Finally. The word switching tree code is completed. Of course, the reporting routine largely duplicate with time switching tree code.  Also, there has to be some bugs in the filler treatment.  But, hey! These stuffs we can work on it.
00106  *
00107  * Revision 1.8  2005/05/03 04:09:09  archan
00108  * Implemented the heart of word copy search. For every ci-phone, every word end, a tree will be allocated to preserve its pathscore.  This is different from 3.5 or below, only the best score for a particular ci-phone, regardless of the word-ends will be preserved at every frame.  The graph propagation will not collect unused word tree at this point. srch_WST_propagate_wd_lv2 is also as the most stupid in the century.  But well, after all, everything needs a start.  I will then really get the results from the search and see how it looks.
00109  *
00110  * Revision 1.7  2005/04/25 23:53:35  archan
00111  * 1, Some minor modification of vithist_t, vithist_rescore can now support optional LM rescoring, vithist also has its own reporting routine. A new argument -lmrescore is also added in decode and livepretend.  This can switch on and off the rescoring procedure. 2, I am reaching the final difficulty of mode 5 implementation.  That is, to implement an algorithm which dynamically decide which tree copies should be entered.  However, stuffs like score propagation in the leave nodes and non-leaves nodes are already done. 3, As briefly mentioned in 2, implementation of rescoring , which used to happened at leave nodes are now separated. The current implementation is not the most clever one. Wish I have time to change it before check-in to the canonical.
00112  *
00113  * Revision 1.6  2005/04/25 19:22:47  archan
00114  * Refactor out the code of rescoring from lexical tree. Potentially we want to turn off the rescoring if we need.
00115  *
00116  * Revision 1.5  2005/04/21 23:50:26  archan
00117  * Some more refactoring on the how reporting of structures inside kbcore_t is done, it is now 50% nice. Also added class-based LM test case into test-decode.sh.in.  At this moment, everything in search mode 5 is already done.  It is time to test the idea whether the search can really be used.
00118  *
00119  * Revision 1.4  2005/03/30 01:22:47  archan
00120  * Fixed mistakes in last updates. Add
00121  *
00122  * 
00123  * 29-Feb-2000  M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University
00124  *              Modified some functions to be able to deal with HMMs with any number
00125  *              of states.  Modified lextree_hmm_eval() to dynamically call the
00126  *              appropriate hmm_vit_eval routine.
00127  * 
00128  * 07-Jul-1999  M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University
00129  *              Added lextree_node_t.ci and lextree_ci_active().
00130  * 
00131  * 30-Apr-1999  M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University
00132  *              Started.
00133  */
00134 
00135 #include "lextree.h"
00136 #include "fillpen.h"
00137 
00138 /*
00139  * Lextree nodes, and the HMMs contained within, are cleared upon creation, and whenever
00140  * they become active during search.  Thus, when activated during search, they are always
00141  * "ready-to-use".  And, when cleaning up after an utterance, only the active nodes need
00142  * be cleaned up.
00143  */
00144 
00151 static lextree_t * lextree_build(bin_mdef_t *mdef,
00152                                  tmat_t *tmat,
00153                                  s3dict_t *dict,
00154                                  dict2pid_t *dict2pid,
00155                                  wordprob_t *wordprob,  
00156                                  int32 n_word,          
00157                                  s3cipid_t *lc,         
00159                                  int32 type              
00160     );
00161 
00162 
00163 static lextree_node_t *
00164 lextree_node_alloc(lextree_t *lextree, int32 wid, int32 prob,
00165                    int32 comp, int32 ssid, s3cipid_t ci, s3cipid_t rc,
00166                    s3tmatid_t tmat)
00167 {
00168     lextree_node_t *ln;
00169 
00170     ln = (lextree_node_t *) ckd_calloc(1, sizeof(lextree_node_t));
00171     ln->children = NULL;
00172     ln->wid = wid;
00173     ln->prob = prob;
00174     ln->ssid = ssid;
00175     ln->ci = (s3cipid_t) ci;
00176     ln->rc = rc;
00177     ln->composite = comp;
00178     hmm_init((comp ? lextree->comctx : lextree->ctx), (hmm_t *)ln, FALSE, ssid, tmat);
00179 
00180     return ln;
00181 }
00182 
00183 static void
00184 lextree_node_free(lextree_node_t * ln)
00185 {
00186     if (ln) {
00187         hmm_deinit((hmm_t *)ln);
00188         ckd_free(ln);
00189     }
00190 }
00191 
00192 /* This create a mapping from either the unigram or words in a class*/
00193 static int32
00194 lextree_ug_wordprob(ngram_model_t * lm, s3dict_t * dict, wordprob_t * wp)
00195 {
00196     int32 i, j, n;
00197     int32 unk, startwid, endwid;
00198 
00199     n = s3dict_size(dict);
00200     unk = ngram_unknown_wid(lm);
00201     startwid = ngram_wid(lm, S3_START_WORD);
00202     endwid = ngram_wid(lm, S3_FINISH_WORD);
00203 
00204     /* Iterate over dictionary words rather than LM words since we
00205      * don't have a reverse mapping.  (FIXME: might change this
00206      * totally in the near future to take advantage of ngram_model_t
00207      * word mapping) */
00208     for (i = 0, j = 0; i < n; i++) {
00209         int32 lmwid, nbo;
00210 
00211         if (s3dict_basewid(dict, i) != i)
00212             continue;
00213         lmwid = ngram_wid(lm, s3dict_wordstr(dict, s3dict_basewid(dict, i)));
00214         if (lmwid == unk || lmwid == startwid || lmwid == endwid)
00215             continue;
00216         wp[j].prob = ngram_ng_score(lm, lmwid, NULL, 0, &nbo);
00217         wp[j].wid = i;
00218         ++j;
00219     }
00220 
00221     return j;
00222 }
00223 
00224 
00225 static int32
00226 wid_wordprob2alt(s3dict_t * dict, wordprob_t * wp, int32 n)
00227 {
00228     int32 i, j;
00229     s3wid_t w;
00230 
00231     for (i = 0, j = n; i < n; i++) {
00232         w = wp[i].wid;
00233         for (w = s3dict_nextalt(dict, w); IS_S3WID(w);
00234              w = s3dict_nextalt(dict, w)) {
00235             /*      E_INFO("i %d, j %d n %d\n",i,j,n); */
00236             wp[j].wid = w;
00237             wp[j].prob = wp[i].prob;
00238             j++;
00239         }
00240     }
00241 
00242     return j;
00243 }
00244 
00245 lextree_t *
00246 lextree_init(bin_mdef_t *mdef, tmat_t *tmat, s3dict_t *dict, dict2pid_t *dict2pid,
00247              fillpen_t *fp, ngram_model_t * lm, const char *lmname, int32 istreeUgProb,
00248              int32 bReport, int32 type)
00249 {
00250     s3cipid_t *lc;
00251     s3cipid_t ci;
00252     bitvec_t *lc_active;
00253     s3wid_t w;
00254     int32 n, n_lc;
00255     int32 i, j;
00256     wordprob_t *wp;
00257     lextree_t *ltree;
00258 
00259     /* Build set of all possible left contexts */
00260     lc = (s3cipid_t *) ckd_calloc(bin_mdef_n_ciphone(mdef) + 1,
00261                                   sizeof(s3cipid_t));
00262     lc_active = bitvec_alloc(bin_mdef_n_ciphone(mdef));
00263     wp = (wordprob_t *) ckd_calloc(s3dict_size(dict), sizeof(wordprob_t));
00264 
00265     for (w = 0; w < s3dict_size(dict); w++) {
00266         ci = s3dict_pron(dict, w, s3dict_pronlen(dict, w) - 1);
00267         if (!bin_mdef_is_fillerphone(mdef, (int) ci))
00268             bitvec_set(lc_active, ci);
00269     }
00270     ci = bin_mdef_silphone(mdef);
00271     bitvec_set(lc_active, ci);
00272 
00273     for (ci = 0, n_lc = 0; ci < bin_mdef_n_ciphone(mdef); ci++) {
00274         if (bitvec_is_set(lc_active, ci))
00275             lc[n_lc++] = ci;
00276     }
00277     lc[n_lc] = BAD_S3CIPID;
00278 
00279     if (bReport)
00280         E_INFO("Creating Unigram Table for lm (name: %s)\n", lmname);
00281 
00282     /* Build active word list */
00283 
00284     n = 0;
00285     /*try to be very careful again */
00286     for (j = 0; j < s3dict_size(dict); j++) {
00287         wp[j].wid = -1;
00288         wp[j].prob = -1;
00289     }
00290     n = lextree_ug_wordprob(lm, dict, wp);
00291 
00292     if (bReport)
00293         E_INFO("Size of word table after unigram + words in class: %d.\n",
00294                n);
00295     if (n < 1)
00296         E_FATAL("%d active words in %s\n", n, lmname);
00297 
00298     n = wid_wordprob2alt(dict, wp, n);
00299 
00300     if (bReport)
00301         E_INFO("Size of word table after adding alternative prons: %d.\n",
00302                n);
00303     if (istreeUgProb == 0) {
00304         for (i = 0; i < n; i++) {
00305             wp[i].prob = -1;    /* Flatten all initial probabilities */
00306         }
00307     }
00308     ltree = lextree_build(mdef, tmat, dict, dict2pid,
00309                           wp, n, lc, type);
00310     ltree->dict = dict;
00311     ltree->mdef = mdef;
00312     ltree->tmat = tmat;
00313     ltree->dict2pid = dict2pid;
00314     ltree->fp = fp;
00315     ltree->lm = ngram_model_retain(lm);
00316 
00317     ckd_free((void *) wp);
00318     ckd_free((void *) lc);
00319     bitvec_free(lc_active);
00320 
00321     strcpy(ltree->prev_word, "");
00322     return ltree;
00323 }
00324 
00325 lextree_t *
00326 fillertree_init(bin_mdef_t *mdef, tmat_t *tmat, s3dict_t *dict,
00327                 dict2pid_t *dict2pid, fillpen_t *fp)
00328 {
00329     int32 n;
00330     int32 i;
00331     wordprob_t *wp;
00332     lextree_t *ltree;
00333 
00334     n = 0;
00335 
00336     wp = (wordprob_t *) ckd_calloc(s3dict_size(dict), sizeof(wordprob_t));
00337 
00338     for (i = s3dict_filler_start(dict); i <= s3dict_filler_end(dict); i++) {
00339         if (s3dict_filler_word(dict, i)) {
00340             E_DEBUG(1,("Filler word %s prob %d\n",
00341                        s3dict_wordstr(dict, i), fillpen(fp, i)));
00342             wp[n].wid = i;
00343             wp[n].prob = fillpen(fp, i);
00344             n++;
00345         }
00346     }
00347 
00348     ltree = lextree_build(mdef, tmat, dict, dict2pid, wp, n, NULL, LEXTREE_TYPE_FILLER);
00349     ltree->mdef = mdef;
00350     ltree->tmat = tmat;
00351     ltree->dict = dict;
00352     ltree->fp = fp;
00353     ltree->dict2pid = dict2pid;
00354 
00355     ckd_free(wp);
00356     return ltree;
00357 }
00358 
00359 void
00360 lextree_report(lextree_t * ltree)
00361 {
00362     E_INFO_NOFN("lextree_t, report:\n");
00363     E_INFO_NOFN("Parameters of the lexical tree. \n");
00364     E_INFO_NOFN("Type of the tree %d (0:unigram, 1: 2g, 2: 3g etc.)\n",
00365                 ltree->type);
00366     E_INFO_NOFN("Number of left contexts %d \n", ltree->n_lc);
00367     E_INFO_NOFN("Number of root nodes %d\n", glist_count(ltree->root));
00368     E_INFO_NOFN("Number of nodes %d \n", ltree->n_node);
00369     E_INFO_NOFN("Number of links in the tree %d\n",
00370                 num_lextree_links(ltree));
00371     /*
00372        E_INFO_NOFN("Number of active node in this frame %d \n",ltree->n_active);
00373        E_INFO_NOFN("Number of active node in next frame %d \n",ltree->n_next_active);
00374        E_INFO_NOFN("Best HMM score of the current frame %d \n",ltree->best);
00375        E_INFO_NOFN("Best Word score of the current frame %d \n",ltree->wbest);
00376      */
00377     if (ltree->prev_word)
00378         E_INFO_NOFN("The previous word for this tree %s \n",
00379                     ltree->prev_word);
00380 
00381     E_INFO_NOFN("The size of a node of the lexical tree %d \n",
00382                 sizeof(lextree_node_t));
00383     E_INFO_NOFN("The size of a gnode_t %d \n", sizeof(gnode_t));
00384     E_INFO_NOFN("\n");
00385 
00386 }
00387 
00388 int32
00389 lextree_subtree_num_links(lextree_node_t * ln)
00390 {
00391     gnode_t *gn;
00392     int32 numlink = 0;
00393     if (ln == NULL) {
00394         return 0;
00395     }
00396     else {
00397         for (gn = ln->children; gn; gn = gnode_next(gn)) {
00398             ln = (lextree_node_t *) gnode_ptr(gn);
00399             numlink += 1 + lextree_subtree_num_links(ln);
00400         }
00401         return numlink;
00402     }
00403 }
00404 
00405 int32
00406 num_lextree_links(lextree_t * ltree)
00407 {
00408     gnode_t *gn;
00409     int32 numlink = 0;
00410     lextree_node_t *ln;
00411 
00412     for (gn = ltree->root; gn; gn = gnode_next(gn)) {
00413         ln = (lextree_node_t *) gnode_ptr(gn);
00414         numlink += 1 + lextree_subtree_num_links(ln);
00415     }
00416 
00417     return numlink;
00418 
00419 }
00420 
00421 
00422 lextree_t *
00423 lextree_build(bin_mdef_t *mdef, tmat_t *tmat,
00424               s3dict_t *dict, dict2pid_t *d2p,
00425               wordprob_t * wordprob, int32 n_word,
00426               s3cipid_t * lc, int32 type)
00427 {
00428     s3ssid_t *ldiph_lc;
00429     lextree_t *lextree;
00430     lextree_lcroot_t *lcroot;
00431     int32 n_lc, n_node, n_ci, n_sseq, pronlen, ssid, prob, ci, rc, wid, np,
00432         n_st;
00433     lextree_node_t *ln = 0, **parent, **ssid2ln;
00434     gnode_t *gn = 0;
00435     bitvec_t **ssid_lc;
00436     int32 i, j, k, p;
00437 
00438     n_ci = bin_mdef_n_ciphone(mdef);
00439     n_sseq = bin_mdef_n_sseq(mdef);
00440     n_st = bin_mdef_n_emit_state(mdef);
00441 
00442     lextree = (lextree_t *) ckd_calloc(1, sizeof(lextree_t));
00443     lextree->root = NULL;
00444     lextree_type(lextree) = type;
00445 
00446     /* HMM contexts for regular and composite triphones */
00447     lextree->ctx = hmm_context_init(n_st,
00448                                     tmat->tp, NULL,
00449                                     mdef->sseq);
00450     lextree->comctx = hmm_context_init(n_st,
00451                                        tmat->tp, NULL,
00452                                        d2p->comsseq);
00453 
00454     /* Table mapping from root level ssid to lexnode (temporary) */
00455     ssid2ln =
00456         (lextree_node_t **) ckd_calloc(n_sseq, sizeof(lextree_node_t *));
00457 
00458     /* ssid_lc[ssid] = bitvec indicating which lc's this (root) ssid is entered under */
00459     ssid_lc = (bitvec_t **) ckd_calloc(n_sseq, sizeof(bitvec_t *));
00460     for (i = 0; i < n_sseq; i++)
00461         ssid_lc[i] = bitvec_alloc(n_ci);
00462 
00463     n_node = 0;
00464 
00465     /* Create top-level structures pointing to (shared) lextrees for each left context */
00466     n_lc = 0;
00467     lcroot = NULL;
00468     if (!lc) {
00469         lextree->n_lc = 0;
00470         lextree->lcroot = NULL;
00471 
00472         parent =
00473             (lextree_node_t **) ckd_calloc(1, sizeof(lextree_node_t *));
00474     }
00475     else {
00476         for (n_lc = 0; IS_S3CIPID(lc[n_lc]); n_lc++);
00477         assert(n_lc > 0);
00478 
00479         lextree->n_lc = n_lc;
00480         lcroot =
00481             (lextree_lcroot_t *) ckd_calloc(n_lc,
00482                                             sizeof(lextree_lcroot_t));
00483         lextree->lcroot = lcroot;
00484 
00485         for (i = 0; i < n_lc; i++) {
00486             lcroot[i].lc = lc[i];
00487             lcroot[i].root = NULL;
00488         }
00489 
00490         parent =
00491             (lextree_node_t **) ckd_calloc(n_lc, sizeof(lextree_node_t *));
00492     }
00493 
00494     /*
00495      * Build up lextree for each word.  For each word:
00496      *   for each phone position {
00497      *     see if node already exists in lextree built so far;
00498      *     if so, share it, otherwise create one (this becomes the parent whose subtree will be
00499      *       searched for the next phone position);
00500      *   }
00501      * 
00502      * parent[]: A temporary structure during the addition of one word W to the lextree.
00503      * Normally, when a phone position p of W is added to the lextree, it has one parent node.
00504      * But when the parent is at the root level, there can actually be several parents, for the
00505      * different left contexts.  (Hence, parent[] instead of a scalar parent.  Beyond the root
00506      * level, only parent[0] is useful.)  Furthermore, root parents may share nodes (with same
00507      * ssid).  Maintain only the unique set.
00508      * 
00509      * Other points worth mentioning:
00510      * - Leaf nodes are not shared among words
00511      * - (LM) prob at any node is the max of the probs of words reachable from that node
00512      */
00513     for (i = 0; i < n_word; i++) {
00514         wid = wordprob[i].wid;
00515         prob = wordprob[i].prob;
00516         E_DEBUG(2,("%s wid %d prob %d\n",
00517                    s3dict_wordstr(dict, wid), wid, prob));
00518 
00519         pronlen = s3dict_pronlen(dict, wid);
00520 
00521         if (pronlen == 1) {
00522             /* Single phone word; node(s) not shared with any other word */
00523             ci = s3dict_pron(dict, wid, 0);
00524             if (!lc) {
00525 
00526                 if (d2p->is_composite)
00527                     ssid = d2p->internal[wid][0];
00528                 else            /* MAJOR HACK! use the phone filler tree */
00529                     ssid = bin_mdef_pid2ssid(mdef, ci);
00530 
00531                 ln = lextree_node_alloc(lextree,
00532                                         wid, prob, d2p->is_composite, ssid,
00533                                         s3dict_pron(dict, wid, 0),
00534                                         BAD_S3CIPID,
00535                                         bin_mdef_pid2tmatid(mdef, ci));
00536 
00537                 lextree->root = glist_add_ptr(lextree->root, (void *) ln);
00538                 n_node++;
00539             }
00540             else {
00541                 np = 0;
00542                 for (j = 0; j < n_lc; j++) {
00543 
00544                     if (d2p->is_composite) {    /* In composite triphone */
00545                         ssid = d2p->single_lc[ci][(int) lc[j]]; /* This is a composite triphone */
00546                     }
00547                     else {      /* Use approximation to get the SSID */
00548                         ssid = d2p->lrdiph_rc[ci][(int) lc[j]][bin_mdef_silphone(mdef)];   /* HACK, always assume right context is silence */
00549                     }
00550 
00551                     /* Check if this ssid already allocated for another lc */
00552                     for (k = 0; (k < np) && (parent[k]->ssid != ssid);
00553                          k++);
00554                     if (k >= np) {      /* Not found; allocate new node */
00556                         ln = lextree_node_alloc(lextree,
00557                                                 wid, prob,
00558                                                 d2p->is_composite, ssid,
00559                                                 ci, BAD_S3CIPID,
00560                                                 bin_mdef_pid2tmatid(mdef, ci));
00561 
00562                         lextree->root =
00563                             glist_add_ptr(lextree->root, (void *) ln);
00564                         n_node++;
00565 
00566                         lcroot[j].root =
00567                             glist_add_ptr(lcroot[j].root, (void *) ln);
00568                         parent[np++] = ln;
00569                     }
00570                     else {      /* Already exists; link to lcroot[j] */
00571                         lcroot[j].root =
00572                             glist_add_ptr(lcroot[j].root,
00573                                           (void *) parent[k]);
00574                     }
00575                 }
00576             }
00577         }
00578         else {
00579             assert(pronlen > 1);
00580 
00581             /* Multi-phone word; allocate root node(s) first, if not already present */
00582             if (!lc) {
00583                 ssid = d2p->internal[wid][0];
00584                 ci = s3dict_pron(dict, wid, 0);
00585 
00586                 /* Check if this ssid already allocated for another word */
00587                 for (gn = lextree->root; gn; gn = gnode_next(gn)) {
00588                     ln = (lextree_node_t *) gnode_ptr(gn);
00589                     if ((ln->ssid == ssid) && ln->composite
00590                         && NOT_S3WID(ln->wid))
00591                         break;
00592                 }
00593                 if (!gn) {
00594                     ln = lextree_node_alloc(lextree, BAD_S3WID, prob,
00595                                             d2p->is_composite, ssid, ci, BAD_S3CIPID,
00596                                             bin_mdef_pid2tmatid(mdef, ci));
00597 
00598                     lextree->root =
00599                         glist_add_ptr(lextree->root, (void *) ln);
00600                     n_node++;
00601                 }
00602                 else {
00603                     if (ln->prob < prob)
00604                         ln->prob = prob;
00605                 }
00606                 parent[0] = ln;
00607                 np = 1;
00608             }
00609             else {
00610                 ci = s3dict_pron(dict, wid, 0);
00611                 rc = s3dict_pron(dict, wid, 1);
00612                 ldiph_lc = d2p->ldiph_lc[ci][rc];
00613 
00614                 np = 0;
00615                 for (j = 0; j < n_lc; j++) {
00616                     ssid = ldiph_lc[(int) lc[j]];
00617 
00618                     /* Check if ssid already allocated */
00619                     ln = ssid2ln[ssid];
00620                     if (!ln) {
00621                         ln = lextree_node_alloc(lextree,
00622                                                 BAD_S3WID, prob,
00623                                                 NOT_COMPOSITE, ssid,
00624                                                 ci, BAD_S3CIPID,
00625                                                 bin_mdef_pid2tmatid(mdef, ci));
00626                         lextree->root =
00627                             glist_add_ptr(lextree->root, (void *) ln);
00628                         n_node++;
00629 
00630                         ssid2ln[ssid] = ln;
00631                     }
00632                     else if (ln->prob < prob)
00633                         ln->prob = prob;
00634 
00635                     /* Check if lexnode already entered under lcroot[lc] */
00636                     if (bitvec_is_clear(ssid_lc[ssid], lc[j])) {
00637                         lcroot[j].root =
00638                             glist_add_ptr(lcroot[j].root, (void *) ln);
00639                         bitvec_set(ssid_lc[ssid], lc[j]);
00640                     }
00641 
00642                     /* Add to parent_list if not already there */
00643                     for (k = 0; (k < np) && (parent[k]->ssid != ssid);
00644                          k++);
00645                     if (k >= np)
00646                         parent[np++] = ln;
00647                 }
00648             }
00649 
00650             /* Rest of the pronunciation except the final one */
00651             for (p = 1; p < pronlen - 1; p++) {
00652                 ssid = d2p->internal[wid][p];
00653                 ci = s3dict_pron(dict, wid, p);
00654 
00655                 /* Check for ssid under each parent (#parents(np) > 1 only when p==1) */
00656                 for (j = 0; j < np; j++) {
00657                     for (gn = parent[j]->children; gn; gn = gnode_next(gn)) {
00658                         ln = (lextree_node_t *) gnode_ptr(gn);
00659 
00660                         if ((ln->ssid == ssid) && (!ln->composite)) {
00661                             assert(NOT_S3WID(ln->wid));
00662                             break;
00663                         }
00664                     }
00665                     if (gn)
00666                         break;
00667                 }
00668 
00669                 if (!gn) {      /* Not found under any parent; allocate new node */
00670                     ln = lextree_node_alloc(lextree, BAD_S3WID,
00671                                             prob, NOT_COMPOSITE,
00672                                             ssid, ci, BAD_S3CIPID,
00673                                             bin_mdef_pid2tmatid(mdef, ci));
00674 
00675                     for (j = 0; j < np; j++)
00676                         parent[j]->children =
00677                             glist_add_ptr(parent[j]->children,
00678                                           (void *) ln);
00679                     n_node++;
00680                 }
00681                 else {          /* Already exists under parent[j] */
00682                     if (ln->prob < prob)
00683                         ln->prob = prob;
00684 
00685                     k = j;
00686 
00687                     /* Child was not found under parent[0..k-1]; add */
00688                     for (j = 0; j < k; j++)
00689                         parent[j]->children =
00690                             glist_add_ptr(parent[j]->children,
00691                                           (void *) ln);
00692 
00693                     /* Parents beyond k have not been checked; add if not present */
00694                     for (j = k + 1; j < np; j++) {
00695                         gnode_t *gn;
00696                         for (gn = parent[j]->children; gn; gn = gnode_next(gn))
00697                             if (gnode_ptr(gn) == ln)
00698                                 break;
00699                         if (gn == NULL)
00700                             parent[j]->children =
00701                                 glist_add_ptr(parent[j]->children,
00702                                               (void *) ln);
00703                     }
00704                 }
00705 
00706                 parent[0] = ln;
00707                 np = 1;
00708             }
00709 
00710             /* Final (leaf) node, no sharing */
00711             ssid = d2p->internal[wid][p];
00712             ci = s3dict_pron(dict, wid, p);
00713             ln = lextree_node_alloc(lextree, wid, prob,
00714                                     d2p->is_composite, ssid,
00715                                     ci, BAD_S3CIPID,
00716                                     bin_mdef_pid2tmatid(mdef, ci));
00717 
00718             for (j = 0; j < np; j++)
00719                 parent[j]->children =
00720                     glist_add_ptr(parent[j]->children, (void *) ln);
00721             n_node++;
00722         }
00723     }
00724 
00725     lextree->n_node = n_node;
00726     lextree->n_alloc_node = n_node;     /* dynamically allocated. */
00727 
00728     /* Assuming each time, when re-allocation of active, next_active
00729        need to be done only one eighth of all possible cross word
00730        expansion is needed to be allocated. That would mean in the
00731        worst case, for a time moment, that can be a possibility for 8
00732        allocations. 
00733      */
00734     lextree->n_alloc_blk_sz = ((n_word * bin_mdef_n_ciphone(mdef)) >> 3);
00735 
00736     lextree->active =
00737         (lextree_node_t **) ckd_calloc(n_node +
00738                                        n_word * bin_mdef_n_ciphone(mdef),
00739                                        sizeof(lextree_node_t *));
00740     lextree->next_active =
00741         (lextree_node_t **) ckd_calloc(n_node +
00742                                        n_word * bin_mdef_n_ciphone(mdef),
00743                                        sizeof(lextree_node_t *));
00744 
00745     /*    lextree->active = (lextree_node_t **) ckd_calloc (n_node, sizeof(lextree_node_t *));
00746        lextree->next_active = (lextree_node_t **) ckd_calloc (n_node, sizeof(lextree_node_t *)); */
00747 
00748 
00749     lextree->n_active = 0;
00750     lextree->n_next_active = 0;
00751 
00752     ckd_free((void *) ssid2ln);
00753     for (i = 0; i < n_sseq; i++)
00754         bitvec_free(ssid_lc[i]);
00755     ckd_free((void *) ssid_lc);
00756     ckd_free(parent);
00757 
00758     return lextree;
00759 }
00760 
00761 
00762 /* Also work for the case where triphone is allocated */
00763 static int32
00764 lextree_subtree_free(lextree_node_t * ln, int32 level)
00765 {
00766     gnode_t *gn;
00767     lextree_node_t *ln2;
00768     int32 k;
00769 
00770     k = 0;
00771 
00772     /* Free subtrees below this node */
00773     for (gn = ln->children; gn; gn = gnode_next(gn)) {
00774         ln2 = (lextree_node_t *) gnode_ptr(gn);
00775         k += lextree_subtree_free(ln2, level + 1);
00776     }
00777     glist_free(ln->children);
00778     ln->children = NULL;
00779 
00780     /* Free this node, but for level-1 nodes only if reference count drops to 0 */
00781     if ((level != 1) || (--ln->ssid == 0)) {
00782         /*        myfree ((void *) ln, sizeof(lextree_node_t)); */
00783 
00784         lextree_node_free((void *) ln);
00785         k++;
00786     }
00787 
00788     return k;
00789 }
00790 
00791 static int32
00792 lextree_shrub_subtree_cw_leaves(lextree_node_t * ln, int32 level)
00793 {
00794     gnode_t *gn;
00795     lextree_node_t *ln2;
00796     int32 k;
00797     k = 0;
00798 
00799     /* If it is a leave and it is a WID and it has not SSID, then, it is
00800        a mother of the list of cross-word triphones.
00801      */
00802 
00803     if (IS_S3WID(ln->wid) && !IS_S3SSID(ln->ssid)) {
00804 
00805         /* If it is a node with WID and have bad senone sequence */
00806 
00807         if (ln->children != NULL) {
00808 
00809 #if 0
00810             E_INFO
00811                 ("Free Cross word is carried out  for wid %d, ln->children %d\n",
00812                  ln->wid, ln->children);
00813 #endif
00814 
00815             for (gn = ln->children; gn; gn = gnode_next(gn)) {
00816                 ln2 = (lextree_node_t *) gnode_ptr(gn);
00817                 /*      E_INFO("I am freeing something! WID, %d, rc %d\n",ln->wid,ln2->rc); */
00818 
00819                 /* Free this node, but for level-1 nodes only if reference count drops to 0 */
00820 
00821                 lextree_node_free(ln2);
00822                 k++;
00823             }
00824             glist_free(ln->children);
00825             ln->children = NULL;
00826         }
00827 
00828     }
00829     else {
00830         /* Free subtrees below this node */
00831         for (gn = ln->children; gn; gn = gnode_next(gn)) {
00832             ln2 = (lextree_node_t *) gnode_ptr(gn);
00833             k += lextree_shrub_subtree_cw_leaves(ln2, level + 1);
00834         }
00835     }
00836 
00837 
00838     return k;
00839 }
00840 
00841 void
00842 lextree_shrub_cw_leaves(lextree_t * lextree)
00843 {
00844     gnode_t *gn, *cwgn;
00845     glist_t root;
00846     lextree_node_t *ln;
00847     lextree_node_t *cwln;
00848     int32 k, i;
00849 
00850     /* Free lextree */
00851     k = 0;
00852 
00853     if (lextree->n_lc > 0) {
00854         for (i = 0; i < lextree->n_lc; i++) {
00855             root = lextree->lcroot[i].root;
00856 
00857             if (root != NULL) {
00858                 for (gn = root; gn; gn = gnode_next(gn)) {
00859 
00860                     ln = (lextree_node_t *) gnode_ptr(gn);
00861 
00862                     if (IS_S3WID(ln->wid) && ln->children != NULL) {
00863 
00864 #if 0
00865                         E_INFO
00866                             ("Tree %d, lc %d, Free Cross word is carried out  for wid %d, ln->children %d\n",
00867                              lextree, lextree->lcroot[i].lc, ln->wid,
00868                              ln->children);
00869 #endif
00870                         for (cwgn = ln->children; cwgn;
00871                              cwgn = gnode_next(cwgn)) {
00872                             cwln = (lextree_node_t *) gnode_ptr(cwgn);
00873                             lextree_node_free(cwln);
00874                         }
00875                         glist_free(ln->children);
00876                         ln->children = NULL;
00877                     }
00878                 }
00879             }
00880         }
00881     }
00882 
00883     for (gn = lextree->root; gn; gn = gnode_next(gn)) {
00884         ln = (lextree_node_t *) gnode_ptr(gn);
00885         k += lextree_shrub_subtree_cw_leaves(ln, 0);
00886     }
00887     lextree_n_node(lextree) -= k;
00888 }
00889 
00890 /*
00891  * This is a bit tricky because of the replication of root nodes for different left-contexts.
00892  * A node just below the root can have more than one parent.  Use reference counts to know how
00893  * many parents refer to such a node.  Use the lextree_node_t.ssid field for such counts.
00894  */
00895 void
00896 lextree_free(lextree_t * lextree)
00897 {
00898     gnode_t *gn, *gn2;
00899     lextree_node_t *ln, *ln2;
00900     int32 i, k;
00901 
00902     if (lextree->n_lc > 0) {
00903         for (i = 0; i < lextree->n_lc; i++) {
00904             glist_free(lextree->lcroot[i].root);
00905             lextree->lcroot[i].root = NULL;
00906         }
00907 
00908         ckd_free(lextree->lcroot);
00909     }
00910 
00911     /* Build reference counts for level-1 nodes (nodes just below root) */
00912     for (gn = lextree->root; gn; gn = gnode_next(gn)) {
00913         ln = (lextree_node_t *) gnode_ptr(gn);
00914         for (gn2 = ln->children; gn2; gn2 = gnode_next(gn2)) {
00915             ln2 = (lextree_node_t *) gnode_ptr(gn2);
00916             if (ln2->composite >= 0) {  /* First visit to this node */
00917                 ln2->composite = -1;
00918                 ln2->ssid = 1;  /* Ref count = 1 */
00919             }
00920             else
00921                 ln2->ssid++;    /* Increment ref count */
00922         }
00923     }
00924 
00925     /* Free lextree */
00926     k = 0;
00927     for (gn = lextree->root; gn; gn = gnode_next(gn)) {
00928         ln = (lextree_node_t *) gnode_ptr(gn);
00929         k += lextree_subtree_free(ln, 0);
00930     }
00931     glist_free(lextree->root);
00932 
00933     ckd_free((void *) lextree->active);
00934     ckd_free((void *) lextree->next_active);
00935 
00936     /*    E_INFO("%d %d\n",k,lextree->n_node); */
00937     if (k != lextree->n_node)
00938         E_ERROR("#Nodes allocated(%d) != #nodes freed(%d)\n",
00939                 lextree->n_node, k);
00940 
00941     hmm_context_free(lextree->ctx);
00942     hmm_context_free(lextree->comctx);
00943 
00944     ngram_model_free(lextree->lm);
00945 
00946     ckd_free(lextree);
00947 }
00948 
00949 /* Not full triphone expansion aware */
00950 void
00951 lextree_ci_active(lextree_t * lextree, bitvec_t *ci_active)
00952 {
00953     lextree_node_t **list, *ln;
00954     int32 i;
00955 
00956     list = lextree->active;
00957 
00958     for (i = 0; i < lextree->n_active; i++) {
00959         ln = list[i];
00960         bitvec_set(ci_active, ln->ci);
00961     }
00962 }
00963 
00964 
00965 void
00966 lextree_ssid_active(lextree_t * lextree, bitvec_t * ssid, bitvec_t * comssid)
00967 {
00968     lextree_node_t **list, *ln;
00969     int32 i;
00970 
00971     list = lextree->active;
00972 
00973     for (i = 0; i < lextree->n_active; i++) {
00974         ln = list[i];
00975 
00976 
00977         /*      if(IS_S3WID(ln->wid)){
00978            E_INFO("Is WID %d,  ln->ssid %d, Do I have children %d?\n",ln ->wid, ln->ssid, (ln->children!=NULL));
00979 
00980            assert(ln->ssid!=BAD_S3SSID);
00981            } */
00982 
00983         if (ln->composite)
00984             bitvec_set(comssid, ln->ssid);
00985         else
00986             bitvec_set(ssid, ln->ssid);
00987     }
00988 }
00989 
00990 
00991 void
00992 lextree_utt_end(lextree_t * l)
00993 {
00994     lextree_node_t *ln;
00995     int32 i;
00996 
00997     for (i = 0; i < l->n_active; i++) { /* The inactive ones should already be reset */
00998         ln = l->active[i];
00999         hmm_clear((hmm_t *)ln);
01000     }
01001 
01002     l->n_active = 0;
01003     l->n_next_active = 0;
01004 
01005     strcpy(l->prev_word, "");
01006 
01007     /* If the tree has crossword triphone, shrub them off at the end
01008        of the utterance */
01009 
01010 
01011     if (!dict2pid_is_composite(l->dict2pid)) {
01012         lextree_shrub_cw_leaves(l);
01013     }
01014 }
01015 
01016 
01017 static void
01018 lextree_node_print(lextree_node_t * ln, s3dict_t * dict, FILE * fp)
01019 {
01020     fprintf(fp, "wid(%d)pr(%d)com(%d)ss(%d)rc(%d)", ln->wid, ln->prob,
01021             ln->composite, ln->ssid, ln->rc);
01022     if (IS_S3WID(ln->wid))
01023         fprintf(fp, "%s", s3dict_wordstr(dict, ln->wid));
01024     fprintf(fp, "\n");
01025 }
01026 
01027 
01028 
01029 static void
01030 lextree_subtree_print(lextree_node_t * ln, int32 level, s3dict_t * dict,
01031                       FILE * fp)
01032 {
01033     int32 i;
01034     gnode_t *gn;
01035 
01036     for (i = 0; i < level; i++)
01037         fprintf(fp, "    ");
01038     lextree_node_print(ln, dict, fp);
01039 
01040     for (gn = ln->children; gn; gn = gnode_next(gn)) {
01041         ln = (lextree_node_t *) gnode_ptr(gn);
01042         lextree_subtree_print(ln, level + 1, dict, fp);
01043     }
01044 }
01045 
01046 static void
01047 lextree_subtree_print_dot(lextree_node_t * ln, int32 level, s3dict_t * dict,
01048                           bin_mdef_t * mdef, FILE * fp)
01049 {
01050     gnode_t *gn;
01051 
01052 
01053     if (IS_S3WID(ln->wid)) {
01054         fprintf(fp, "\"%s\";\n", s3dict_wordstr(dict, ln->wid));
01055     }
01056     else {
01057         for (gn = ln->children; gn; gn = gnode_next(gn)) {
01058             ln = (lextree_node_t *) gnode_ptr(gn);
01059             fprintf(fp, " \"%s\" -> ", bin_mdef_ciphone_str(mdef, ln->ci));
01060             lextree_subtree_print_dot(ln, level + 1, dict, mdef, fp);
01061         }
01062     }
01063 }
01064 
01065 #define GRAPH_RAVIFMT 1
01066 #define GRAPH_DOTFMT 2
01067 
01068 void
01069 lextree_dump(lextree_t * lextree, FILE * fp, int32 fmt)
01070 {
01071     gnode_t *gn;
01072     lextree_node_t *ln;
01073 
01074     if (fmt > 2) {
01075         fmt = GRAPH_RAVIFMT;
01076     }
01077     if (fmt == GRAPH_RAVIFMT) { /*Ravi's format */
01078         for (gn = lextree->root; gn; gn = gnode_next(gn)) {
01079             ln = (lextree_node_t *) gnode_ptr(gn);
01080             lextree_subtree_print(ln, 0, lextree->dict, fp);
01081         }
01082 
01083         if (lextree->n_lc > 0) {
01084             int32 i;
01085             for (i = 0; i < lextree->n_lc; i++) {
01086                 fprintf(fp, "lcroot %d\n", lextree->lcroot[i].lc);
01087                 for (gn = lextree->lcroot[i].root; gn; gn = gnode_next(gn)) {
01088                     ln = (lextree_node_t *) gnode_ptr(gn);
01089                     lextree_node_print(ln, lextree->dict, fp);
01090                 }
01091             }
01092         }
01093     }
01094     else if (fmt == GRAPH_DOTFMT) {
01095         fprintf(fp, "digraph G {\n");
01096         fprintf(fp, "rankdir=LR \n");
01097         for (gn = lextree->root; gn; gn = gnode_next(gn)) {
01098             ln = (lextree_node_t *) gnode_ptr(gn);
01099 
01100             fprintf(fp, " \"%s\" -> ", bin_mdef_ciphone_str(lextree->mdef, ln->ci));
01101 
01102             lextree_subtree_print_dot(ln, 0, lextree->dict, lextree->mdef, fp);
01103         }
01104         fprintf(fp, "}\n");
01105     }
01106     fflush(fp);
01107 }
01108 
01109 /*
01110   Hmm. For some reason, it doesn't really work yet. 
01111  */
01112 static void
01113 lextree_realloc_active_list(lextree_t * lt, int32 num_active)
01114 {
01115     if (num_active >= lt->n_alloc_node && lt->type != LEXTREE_TYPE_FILLER) {
01116         E_INFO("num_active %d, n_alloc_node %d, n_node %d\n", num_active,
01117                lt->n_alloc_node, lt->n_node);
01118         lextree_n_alloc_node(lt) = lextree_n_node(lt);
01119         lt->active =
01120             (lextree_node_t **) ckd_realloc(lt->active,
01121                                             lextree_n_alloc_node(lt) *
01122                                             sizeof(lextree_node_t *));
01123         if (lt->active == NULL) {
01124             E_INFO("help.\n");
01125         }
01126         lt->next_active =
01127             (lextree_node_t **) ckd_realloc(lt->next_active,
01128                                             lextree_n_alloc_node(lt) *
01129                                             sizeof(lextree_node_t *));
01130         if (lt->next_active == NULL) {
01131             E_INFO("help.\n");
01132         }
01133 
01134         E_INFO("Reallocating more memory, now has node %d\n",
01135                lextree_n_alloc_node(lt));
01136     }
01137 }
01138 
01139 
01140 void
01141 lextree_enter(lextree_t * lextree, s3cipid_t lc, int32 cf,
01142               int32 inscore, int32 inhist, int32 thresh)
01143 {
01144     glist_t root;
01145     gnode_t *gn, *cwgn;
01146     lextree_node_t *ln, *cwln;
01147     int32 nf, scr;
01148     int32 i, n;
01149     int32 rc;
01150     int32 n_ci, n_st, n_rc;
01151     /*    int32 tmp_lc; */
01152     tmat_t *tmat;
01153     s3ssid_t *rmap;
01154 
01155     nf = cf + 1;
01156 
01157     n_ci = bin_mdef_n_ciphone(lextree->mdef);
01158     n_st = bin_mdef_n_emit_state(lextree->mdef);
01159     tmat = lextree->tmat;
01160     rc = 0;
01161 
01162     assert(lextree);
01163     /* Locate root nodes list */
01164     if (lextree->n_lc == 0) {
01165         assert(NOT_S3CIPID(lc));
01166         root = lextree->root;
01167     }
01168     else {
01169         for (i = 0; (i < lextree->n_lc) && (lextree->lcroot[i].lc != lc);
01170              i++);
01171         /*      E_INFO("i=%d, lextree->n_lc %d\n",i,lextree->n_lc); */
01172         assert(i < lextree->n_lc);
01173 
01174         root = lextree->lcroot[i].root;
01175     }
01176 
01177     /* Enter root nodes */
01178     n = lextree->n_next_active;
01179 
01180 
01181     for (gn = root; gn; gn = gnode_next(gn)) {
01182         ln = (lextree_node_t *) gnode_ptr(gn);
01183 
01184         if (NOT_S3WID(ln->wid) ||       /* If the first node we see it a non leave */
01185             (IS_S3WID(ln->wid)
01186              && dict2pid_is_composite(lextree->dict2pid)) /* Or it is a leave but we are using composite triphone */
01187             ) {
01188             scr = inscore + ln->prob;
01189             if ((scr >= thresh) && (hmm_in_score(&ln->hmm) < scr)) {
01190                 E_DEBUG(4,("entering non-leaf root node with %d + %d >= (thresh %d score %d)\n",
01191                            inscore, ln->prob, thresh, hmm_in_score(&ln->hmm)));
01192                 hmm_in_score(&ln->hmm) = scr;
01193                 hmm_in_history(&ln->hmm) = inhist;
01194 
01195                 if (hmm_frame(&ln->hmm) != nf) {
01196                     hmm_frame(&ln->hmm) = nf;
01197                     lextree->next_active[n++] = ln;
01198                 }
01199             }                   /* else it is activated separately */
01200         }
01201         else {                  /* It is a leave node, so we consider all possible contexts */
01202 
01203             /* FIX ME! To allow extra flexibility, one should allow 
01204                optionally composite single phone */
01205 
01206             assert(IS_S3WID(ln->wid));
01207             if (ln->children == NULL) {
01208                 n_ci = bin_mdef_n_ciphone(lextree->mdef);
01209                 rmap = lextree->dict2pid->lrssid[ln->ci][0].ssid;
01210                 n_rc = get_rc_nssid(lextree->dict2pid, ln->wid, lextree->dict);
01211 
01212                 if (!s3dict_filler_word(lextree->dict, ln->wid)) {
01213 
01214                     for (rc = 0; rc < n_rc; rc++) {
01215                         cwln =
01216                             lextree_node_alloc(lextree,
01217                                                ln->wid, ln->prob,
01218                                                NOT_COMPOSITE, rmap[rc],
01219                                                ln->ci, rc,
01220                                                bin_mdef_pid2tmatid(lextree->mdef, ln->ci));
01221                         ln->children =
01222                             glist_add_ptr(ln->children, (void *) cwln);
01223                     }
01224 
01225                 }
01226                 else {
01227                     /* Assume there is no context when filler. Still expands to keep the program
01228                        consistency. */
01229 
01230                     cwln =
01231                         lextree_node_alloc(lextree,
01232                                            ln->wid, ln->prob,
01233                                            NOT_COMPOSITE, rmap[0],
01234                                            ln->ci, 0,
01235                                            bin_mdef_pid2tmatid(lextree->mdef, ln->ci));
01236                     lextree_n_node(lextree) += 1;
01237 
01238                     ln->children =
01239                         glist_add_ptr(ln->children, (void *) cwln);
01240                 }
01241 
01242             }
01243 
01244             /* This part should be moved to a function */
01245             for (cwgn = ln->children; cwgn; cwgn = gnode_next(cwgn)) {
01246                 cwln = (lextree_node_t *) gnode_ptr(cwgn);
01247                 scr = inscore + cwln->prob;
01248                 if ((scr >= thresh) && (hmm_in_score(&cwln->hmm) < scr)) {
01249                     hmm_in_score(&cwln->hmm) = scr;
01250                     hmm_in_history(&cwln->hmm) = inhist;
01251 
01252                     if (hmm_frame(&cwln->hmm) != nf) {
01253                         hmm_frame(&cwln->hmm) = nf;
01254                         lextree->next_active[n++] = cwln;
01255                     }
01256                 }
01257             }
01258         }
01259 
01260     }
01261     lextree->n_next_active = n;
01262 }
01263 
01264 
01265 void
01266 lextree_active_swap(lextree_t * lextree)
01267 {
01268     lextree_node_t **t;
01269 
01270     t = lextree->active;
01271     lextree->active = lextree->next_active;
01272     lextree->next_active = t;
01273     lextree->n_active = lextree->n_next_active;
01274     lextree->n_next_active = 0;
01275 }
01276 
01277 
01278 int32
01279 lextree_hmm_eval(lextree_t * lextree, int16 *senscr, int16 *comsen, int32 frm, FILE * fp)
01280 {
01281     int32 best, wbest, n_st;
01282     int32 i, k;
01283     lextree_node_t **list, *ln;
01284     bin_mdef_t *mdef;
01285     dict2pid_t *d2p;
01286 
01287     mdef = lextree->mdef;
01288     d2p = lextree->dict2pid;
01289     n_st = bin_mdef_n_emit_state(mdef);
01290 
01291     list = lextree->active;
01292     best = MAX_NEG_INT32;
01293     wbest = MAX_NEG_INT32;
01294 
01295     hmm_context_set_senscore(lextree->ctx, senscr);
01296     hmm_context_set_senscore(lextree->comctx, comsen);
01297 
01298     for (i = 0; i < lextree->n_active; i++) {
01299         ln = list[i];
01300 
01301         if (IS_S3WID(ln->wid)) {
01302             /*      E_INFO("Frm %d, Is WID %d, wdstr %s, ln->ssid %d\n",frm, ln->wid,s3dict_wordstr(dict,ln->wid), ln->ssid); */
01303         }
01304 
01305         assert(hmm_frame(&ln->hmm) == frm);
01306         assert(ln->ssid >= 0);
01307 
01308         if (fp) {
01309             /*      lextree_node_print (ln, dict, fp); */
01310             hmm_dump((hmm_t *)ln, fp);
01311         }
01312 
01313         k = hmm_vit_eval((hmm_t *)ln);
01314 
01315         if (best < k)
01316             best = k;
01317 
01318         if (IS_S3WID(ln->wid)) {
01319             if (wbest < k)
01320                 wbest = k;
01321         }
01322 
01323     }
01324 
01325     lextree->best = best;
01326     lextree->wbest = wbest;
01327 
01328     if (fp) {
01329         fprintf(fp, "Fr %d  #active %d  best %d  wbest %d\n",
01330                 frm, lextree->n_active, best, wbest);
01331         fflush(fp);
01332     }
01333 
01334     return best;
01335 }
01336 
01337 
01338 void
01339 lextree_hmm_histbin(lextree_t * lextree, int32 bestscr, int32 * bin,
01340                     int32 nbin, int32 bw)
01341 {
01342     lextree_node_t **list, *ln;
01343     int32 i, k;
01344     glist_t *binln;
01345     gnode_t *gn;
01346 
01347     binln = (glist_t *) ckd_calloc(nbin, sizeof(glist_t));
01348 
01349     list = lextree->active;
01350 
01351     for (i = 0; i < lextree->n_active; i++) {
01352         ln = list[i];
01353 
01354         if (IS_S3WID(ln->wid)) {
01355             assert(ln->ssid != BAD_S3SSID);
01356         }
01357 
01358         /*      if(IS_S3WID(ln->wid)){
01359            E_INFO("Is WID\n");
01360            } */
01361 
01362         k = (bestscr - hmm_bestscore(&ln->hmm)) / bw;
01363         if (k >= nbin)
01364             k = nbin - 1;
01365         assert(k >= 0);
01366 
01367         bin[k]++;
01368         binln[k] = glist_add_ptr(binln[k], (void *) ln);
01369     }
01370 
01371     /* Reorder the active lexnodes in APPROXIMATELY descending scores */
01372     k = 0;
01373     for (i = 0; i < nbin; i++) {
01374         for (gn = binln[i]; gn; gn = gnode_next(gn)) {
01375             ln = (lextree_node_t *) gnode_ptr(gn);
01376             list[k++] = ln;
01377         }
01378         glist_free(binln[i]);
01379     }
01380     assert(k == lextree->n_active);
01381 
01382     ckd_free((void *) binln);
01383 }
01384 
01385 
01386 
01387 
01388 
01389 int32
01390 lextree_hmm_propagate_non_leaves(lextree_t * lextree,
01391                                  int32 cf, int32 th, int32 pth, int32 wth)
01392 {
01393     bin_mdef_t *mdef;
01394     dict2pid_t *d2p;
01395     s3dict_t *dict;
01396     int32 nf, newscore;
01397     lextree_node_t **list, *ln, *ln2;
01398     lextree_node_t *cwln;
01399     tmat_t *tmat;
01400     gnode_t *gn, *gn2;
01401     int32 i, n, lastfrm;
01402     int32 hth;
01403     int32 rc;
01404     int32 n_ci, n_st, n_rc;
01405     s3ssid_t *rmap;
01406 
01407     lastfrm = -1;
01408     hth = 0;
01409     mdef = lextree->mdef;
01410     n_ci = bin_mdef_n_ciphone(mdef);
01411     n_st = bin_mdef_n_emit_state(mdef);
01412     d2p = lextree->dict2pid;
01413     dict = lextree->dict;
01414     tmat = lextree->tmat;
01415 
01416     nf = cf + 1;
01417 
01418     list = lextree->active;
01419 
01420     E_DEBUG(1, ("lextree_hmm_propagate_non_leaves: cf %d th %d pth %d wth %d\n",
01421                 cf, th, pth, wth)); 
01422     n = lextree->n_next_active;
01423     assert(n == 0);
01424 
01425     E_DEBUG(1,("No. of active node within the lexical tree: %d\n",lextree->n_active));
01426 
01427     for (i = 0; i < lextree->n_active; i++) {
01428         E_DEBUG(3,("Looking at node %d of %d\n", i,  lextree->n_alloc_node));
01429         ln = list[i];
01430 
01431         if (IS_S3WID(ln->wid)) {
01432             E_DEBUG(3,("Is WID %d = %s, ln->rc %d, ln->ssid %d\n",
01433                        ln->wid, s3dict_wordstr(dict, ln->wid), ln->rc, ln->ssid));
01434             assert(ln->ssid != BAD_S3SSID);
01435         }
01436 
01437         /* This if will activate nodes */
01438         if (hmm_frame(&ln->hmm) < nf) {
01439             if (hmm_bestscore(&ln->hmm) >= th) { /* Active in next frm */
01440                 E_DEBUG(4,("Activating (%d >= %d)\n", hmm_bestscore(&ln->hmm), th));
01441                 hmm_frame(&ln->hmm) = nf;
01442                 lextree->next_active[n++] = ln;
01443             }
01444             else {              /* Deactivate */
01445                 E_DEBUG(4,("Deactivating (%d < %d)\n", hmm_bestscore(&ln->hmm), th));
01446                 hmm_clear((hmm_t *)ln);
01447             }
01448         }
01449 
01450         if (NOT_S3WID(ln->wid)) {       /* Not a leaf node */
01451             if (hmm_out_score(&ln->hmm) < pth)
01452                 continue;       /* HMM exit score not good enough */
01453             E_DEBUG(4,("Propagating (%d >= %d)\n", hmm_out_score(&ln->hmm), pth));
01454             /* Transition to each child */
01455             for (gn = ln->children; gn; gn = gnode_next(gn)) {
01456 
01457                 ln2 = gnode_ptr(gn);
01458                 /*Sorry, code of composite triphone mode and full expansion mode are mixed 
01459                    If not, it could run on. 
01460                  */
01461                 if (dict2pid_is_composite(d2p) ||
01462                     (!dict2pid_is_composite(d2p) && NOT_S3WID(ln2->wid))) {
01463                     /* If we use composite triphone mode. Or If we are 
01464                        not using composite triphone mode but the next node
01465                        is not a leave node .
01466                        Just enter like it is a simple triphone. 
01467                     */
01468                     newscore = hmm_out_score(&ln->hmm) + (ln2->prob - ln->prob);
01469 
01470                     E_DEBUG(4,("  newscore %d + %d - %d = %d\n",
01471                                hmm_out_score(&ln->hmm), ln2->prob, ln->prob, newscore));
01472                     if ((newscore >= th) &&     /*If the score is smaller than the
01473                                                    phone score, prune away */
01474                         (hmm_in_score(&ln2->hmm) < newscore)) {
01475                         hmm_in_score(&ln2->hmm) = newscore;
01476                         hmm_in_history(&ln2->hmm) = hmm_out_history(&ln->hmm);
01477 
01478                         if (hmm_frame(&ln2->hmm) != nf) {
01479                             E_DEBUG(4,("  entering this node\n"));
01480                             hmm_frame(&ln2->hmm) = nf;
01481                             /*                  lextree_realloc_active_list(lextree,n+1); */
01482                             lextree->next_active[n++] = ln2;
01483                         }
01484                     }
01485                 }
01486                 else {
01487                     assert(IS_S3WID(ln2->wid));
01488                     assert(ln2->ssid == BAD_S3SSID && ln2->rc == BAD_S3CIPID);  /* Make sure that the another indication is 
01489                                                                                    proved. */
01490                     assert(!dict2pid_is_composite(d2p));
01491 
01492                     /* If the node doens't has children */
01493                     if (ln2->children == NULL) {        /*Is children not allocated, then allocate it first. */
01494                         assert(s3dict_pronlen(dict, ln2->wid) > 1);       /* Because word enter should have already taken care 
01495                                                                            expansion of single word case. 
01496                                                                          */
01497                         assert(ln2->ssid == BAD_S3SSID);        /*First timer of being expanded */
01498                         n_ci = bin_mdef_n_ciphone(mdef);
01499 
01500 
01501                         E_DEBUG(3,
01502                             ("Tree %d, Cross word expansion is carried out at cf %d for wid %d, wstr %s, ln->children %d\n",
01503                              lextree, cf, ln2->wid, s3dict_wordstr(lextree->dict, ln2->wid),
01504                              ln2->children));
01505 
01506                         rmap = d2p->rssid[ln2->ci][ln->ci].ssid;
01507                         n_rc =
01508                             d2p->rssid[ln2->ci][ln->ci].n_ssid;
01509 
01510                         assert(n_rc ==
01511                                get_rc_nssid(d2p, ln2->wid,
01512                                             dict));
01513 
01514                         for (rc = 0; rc < n_rc; rc++) {
01515                             cwln =
01516                                 lextree_node_alloc(lextree,
01517                                                    ln2->wid, ln2->prob,
01518                                                    NOT_COMPOSITE, rmap[rc],
01519                                                    ln2->ci, rc,
01520                                                    bin_mdef_pid2tmatid(mdef, ln2->ci));
01521                             lextree_n_node(lextree) += 1;
01522 
01523                             ln2->children =
01524                                 glist_add_ptr(ln2->children,
01525                                               (void *) cwln);
01526                         }
01527                     }
01528 
01529                     /* For each of them sum of the scores and decide which one should be enter */
01530                     for (gn2 = ln2->children; gn2; gn2 = gnode_next(gn2)) {
01531                         cwln = gnode_ptr(gn2);
01532                         /* The following two can actually be saved. However, there is a possiblity
01533                            that one might want to use different lookahead probability for different
01534                            cw triphone */
01535 
01536                         newscore = hmm_out_score(&ln->hmm)
01537                             + (cwln->prob - ln->prob);    /*< This is correct! because ln->prob
01538                                                             is directly
01539                                                             feed into the cross word */
01540                         if ((newscore >= th) && /*If the score is smaller than the
01541                                                    phone score, prune away */
01542                             (hmm_in_score(&cwln->hmm) < newscore)) {
01543                             hmm_in_score(&cwln->hmm) = newscore;
01544                             hmm_in_history(&cwln->hmm) = hmm_out_history(&ln->hmm);
01545 
01546                             if (hmm_frame(&cwln->hmm) != nf) {
01547                                 hmm_frame(&cwln->hmm) = nf;
01548                                 /*                        lextree_realloc_active_list(lextree,n+1); */
01549                                 lextree->next_active[n++] = cwln;
01550                             }
01551                         }
01552                     }
01553                     assert(ln2->ssid == BAD_S3SSID && ln2->rc == BAD_S3CIPID);  /* Make sure that the mother of all cross-word expansion
01554                                                                                    is not touched */
01555                 }
01556             }
01557         }
01558     }
01559 
01560     lextree->n_next_active = n;
01561 #ifdef SPHINX_DEBUG
01562     E_DEBUG(3,("Debugging.\n"));
01563     for (i = 0; i < lextree->n_next_active; i++) {
01564         ln = lextree->next_active[i];
01565 
01566         E_DEBUG(3,(" ln->wid %d, str %s, ln->ssid %d, ln->rc %d,\n", ln->wid,
01567                    s3dict_wordstr(dict, ln->wid), ln->ssid, ln->rc));
01568     }
01569 #endif
01570     E_DEBUG(1,("lextree->n_next_active %d\n",    lextree->n_next_active));
01571     return LEXTREE_OPERATION_SUCCESS;
01572 }
01573 
01574 int32
01575 lextree_hmm_propagate_leaves(lextree_t * lextree,
01576                              vithist_t * vh, int32 cf, int32 wth)
01577 {
01578 
01579     lextree_node_t **list, *ln;
01580 #ifdef SPHINX_DEBUG
01581     int32 n_active_word_end;
01582 #endif
01583     int32 i;
01584 
01585     /* Code for heursitic score */
01586     list = lextree->active;
01587 
01588     E_DEBUG(1, ("lextree_hmm_propagate_leaves: cf %d wth %d\n", cf, wth)); 
01589     for (i = 0; i < lextree->n_active; i++) {
01590         ln = list[i];
01591 
01592         if (IS_S3WID(ln->wid)) {        /* Leaf node; word exit */
01593 
01594             if (hmm_out_score(&ln->hmm) < wth)
01595                 continue;       /* Word exit score not good enough */
01596 
01597             if (hmm_out_history(&ln->hmm) == -1) { /* This is a case where continue
01598                                                              subsituting out.history into
01599                                                              vithist_rescore will cause
01600                                                              core-dump */
01601                 E_ERROR("out.history==-1, error\n");
01602                 return LEXTREE_OPERATION_FAILURE;
01603             }
01604 
01605 
01606             /* Rescore the LM prob for this word wrt all possible predecessors */
01607             E_DEBUG(2,("Rescoring exit %s with score %d\n",
01608                        s3dict_wordstr(lextree->dict, ln->wid),
01609                        hmm_out_score(&ln->hmm) - ln->prob));
01610             if (dict2pid_is_composite(lextree->dict2pid)) {
01611                 vithist_rescore(vh, lextree->lm, lextree->dict,
01612                                 lextree->dict2pid, lextree->fp, ln->wid, cf,
01613                                 hmm_out_score(&ln->hmm) - ln->prob,
01614                                 hmm_out_history(&ln->hmm), lextree->type, -1);
01615             }
01616             else {
01617                 /*              lextree_node_print(ln,dict,stdout); */
01618                 assert(ln->ssid != BAD_S3SSID); /*This make we are not using the mother of cross-word triphone */
01619                 assert(ln->rc != BAD_S3CIPID);
01620 
01621                 vithist_rescore(vh, lextree->lm, lextree->dict,
01622                                 lextree->dict2pid, lextree->fp, ln->wid, cf,
01623                                 hmm_out_score(&ln->hmm) - ln->prob,
01624                                 hmm_out_history(&ln->hmm), lextree->type, ln->rc);
01625 
01626             }
01627 
01628 
01629 #ifdef SPHINX_DEBUG
01630             n_active_word_end++;
01631 #endif
01632         }
01633     }
01634 
01635     E_DEBUG(1,("number of active leaf nodes %d\n",n_active_word_end));
01636     return LEXTREE_OPERATION_SUCCESS;
01637 }

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