src/libpocketsphinx/fsg_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  *
00019  * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND 
00020  * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
00021  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00022  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY
00023  * NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00024  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
00025  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
00026  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
00027  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
00028  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
00029  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00030  *
00031  * ====================================================================
00032  *
00033  */
00034 /*
00035  * fsg_lextree.c -- The collection of all the lextrees for the entire FSM.
00036  * 
00037  * **********************************************
00038  * CMU ARPA Speech Project
00039  *
00040  * Copyright (c) 2004 Carnegie Mellon University.
00041  * ALL RIGHTS RESERVED.
00042  * **********************************************
00043  * 
00044  * HISTORY
00045  * 
00046  * $Log: fsg_lextree.c,v $
00047  * Revision 1.1.1.1  2006/05/23 18:44:59  dhuggins
00048  * re-importation
00049  *
00050  * Revision 1.1  2004/07/16 00:57:11  egouvea
00051  * Added Ravi's implementation of FSG support.
00052  *
00053  * Revision 1.3  2004/06/23 20:32:16  rkm
00054  * *** empty log message ***
00055  *
00056  * Revision 1.2  2004/05/27 14:22:57  rkm
00057  * FSG cross-word triphones completed (but for single-phone words)
00058  *
00059  * Revision 1.1.1.1  2004/03/01 14:30:30  rkm
00060  *
00061  *
00062  * Revision 1.2  2004/02/27 15:05:21  rkm
00063  * *** empty log message ***
00064  *
00065  * Revision 1.1  2004/02/23 15:53:45  rkm
00066  * Renamed from fst to fsg
00067  *
00068  * Revision 1.2  2004/02/19 21:16:54  rkm
00069  * Added fsg_search.{c,h}
00070  *
00071  * Revision 1.1  2004/02/18 15:02:34  rkm
00072  * Added fsg_lextree.{c,h}
00073  *
00074  * 
00075  * 18-Feb-2004  M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon
00076  *              Started.
00077  */
00078 
00079 /* System headers. */
00080 #include <stdio.h>
00081 #include <string.h>
00082 #include <assert.h>
00083 
00084 /* SphinxBase headers. */
00085 #include <ckd_alloc.h>
00086 #include <err.h>
00087 
00088 /* Local headers. */
00089 #include "fsg_lextree.h"
00090 
00091 #define __FSG_DBG__             0
00092 
00099 static fsg_pnode_t *fsg_psubtree_init(fsg_lextree_t *tree,
00100                                       fsg_model_t *fsg,
00101                                       int32 from_state,
00102                                       fsg_pnode_t **alloc_head);
00103 
00108 static void fsg_psubtree_free(fsg_pnode_t *alloc_head);
00109 
00114 static void fsg_psubtree_dump(fsg_lextree_t *tree, fsg_pnode_t *alloc_head, FILE *fp);
00115 
00119 static void
00120 fsg_lextree_lc_rc(fsg_lextree_t *lextree)
00121 {
00122     int32 s, d, i, j;
00123     int32 n_ci;
00124     gnode_t *gn;
00125     fsg_model_t *fsg;
00126     fsg_link_t *l;
00127     int32 silcipid;
00128     int32 len;
00129 
00130     silcipid = bin_mdef_ciphone_id(lextree->mdef, "SIL");
00131     assert(silcipid >= 0);
00132     n_ci = bin_mdef_n_ciphone(lextree->mdef);
00133 
00134     fsg = lextree->fsg;
00135     /*
00136      * lextree->lc[s] = set of left context CIphones for state s.  Similarly, rc[s]
00137      * for right context CIphones.
00138      */
00139     lextree->lc = ckd_calloc_2d(fsg->n_state, n_ci + 1, sizeof(**lextree->lc));
00140     lextree->rc = ckd_calloc_2d(fsg->n_state, n_ci + 1, sizeof(**lextree->rc));
00141 
00142     for (s = 0; s < fsg->n_state; s++) {
00143         for (d = 0; d < fsg->n_state; d++) {
00144             for (gn = fsg->trans[s][d]; gn; gn = gnode_next(gn)) {
00145                 int32 dictwid; 
00147                 l = (fsg_link_t *) gnode_ptr(gn);
00148                 assert(l->wid >= 0);
00149                 dictwid = s3dict_wordid(lextree->dict,
00150                                         fsg_model_word_str(lextree->fsg, l->wid));
00151 
00152                 /*
00153                  * Add the first CIphone of l->wid to the rclist of state s, and
00154                  * the last CIphone to lclist of state d.
00155                  * (Filler phones are a pain to deal with.  There is no direct
00156                  * marking of a filler phone; but only filler words are supposed to
00157                  * use such phones, so we use that fact.  HACK!!  FRAGILE!!)
00158                  */
00159                 if (fsg_model_is_filler(fsg, l->wid)) {
00160                     /* Filler phone; use silence phone as context */
00161                     lextree->rc[s][silcipid] = 1;
00162                     lextree->lc[d][silcipid] = 1;
00163                 }
00164                 else {
00165                     len = s3dict_pronlen(lextree->dict, dictwid);
00166                     lextree->rc[s][s3dict_pron(lextree->dict, dictwid, 0)] = 1;
00167                     lextree->lc[d][s3dict_pron(lextree->dict, dictwid, len - 1)] = 1;
00168                 }
00169             }
00170         }
00171 
00172         /*
00173          * Add SIL phone to the lclist and rclist of each state.  Strictly
00174          * speaking, only needed at start and final states, respectively, but
00175          * all states considered since the user may change the start and final
00176          * states.  In any case, most applications would have a silence self
00177          * loop at each state, hence these would be needed anyway.
00178          */
00179         lextree->lc[s][silcipid] = 1;
00180         lextree->rc[s][silcipid] = 1;
00181     }
00182 
00183     /*
00184      * Propagate lc and rc lists past null transitions.  (Since FSG contains
00185      * null transitions closure, no need to worry about a chain of successive
00186      * null transitions.  Right??)
00187      */
00188     for (s = 0; s < fsg->n_state; s++) {
00189         for (d = 0; d < fsg->n_state; d++) {
00190             l = fsg->null_trans[s][d];
00191             if (l) {
00192                 /*
00193                  * lclist(d) |= lclist(s), because all the words ending up at s, can
00194                  * now also end at d, becoming the left context for words leaving d.
00195                  */
00196                 for (i = 0; i < n_ci; i++)
00197                     lextree->lc[d][i] |= lextree->lc[s][i];
00198                 /*
00199                  * Similarly, rclist(s) |= rclist(d), because all the words leaving d
00200                  * can equivalently leave s, becoming the right context for words
00201                  * ending up at s.
00202                  */
00203                 for (i = 0; i < n_ci; i++)
00204                     lextree->rc[s][i] |= lextree->rc[d][i];
00205             }
00206         }
00207     }
00208 
00209     /* Convert the bit-vector representation into a list */
00210     for (s = 0; s < fsg->n_state; s++) {
00211         j = 0;
00212         for (i = 0; i < n_ci; i++) {
00213             if (lextree->lc[s][i]) {
00214                 lextree->lc[s][j] = i;
00215                 j++;
00216             }
00217         }
00218         lextree->lc[s][j] = -1;     /* Terminate the list */
00219 
00220         j = 0;
00221         for (i = 0; i < n_ci; i++) {
00222             if (lextree->rc[s][i]) {
00223                 lextree->rc[s][j] = i;
00224                 j++;
00225             }
00226         }
00227         lextree->rc[s][j] = -1;     /* Terminate the list */
00228     }
00229 }
00230 
00231 /*
00232  * For now, allocate the entire lextree statically.
00233  */
00234 fsg_lextree_t *
00235 fsg_lextree_init(fsg_model_t * fsg, s3dict_t *dict, dict2pid_t *d2p,
00236                  bin_mdef_t *mdef, hmm_context_t *ctx,
00237                  int32 wip, int32 pip)
00238 {
00239     int32 s;
00240     fsg_lextree_t *lextree;
00241     fsg_pnode_t *pn;
00242 
00243     lextree = ckd_calloc(1, sizeof(fsg_lextree_t));
00244     lextree->fsg = fsg;
00245     lextree->root = ckd_calloc(fsg_model_n_state(fsg),
00246                                sizeof(fsg_pnode_t *));
00247     lextree->alloc_head = ckd_calloc(fsg_model_n_state(fsg),
00248                                      sizeof(fsg_pnode_t *));
00249     lextree->ctx = ctx;
00250     lextree->dict = dict;
00251     lextree->d2p = d2p;
00252     lextree->mdef = mdef;
00253     lextree->wip = wip;
00254     lextree->pip = pip;
00255 
00256     /* Compute lc and rc for fsg. */
00257     fsg_lextree_lc_rc(lextree);
00258 
00259     /* Create lextree for each state */
00260     lextree->n_pnode = 0;
00261     for (s = 0; s < fsg_model_n_state(fsg); s++) {
00262         lextree->root[s] =
00263             fsg_psubtree_init(lextree, fsg, s, &(lextree->alloc_head[s]));
00264 
00265         for (pn = lextree->alloc_head[s]; pn; pn = pn->alloc_next)
00266             lextree->n_pnode++;
00267     }
00268     E_INFO("%d HMM nodes in lextree\n", lextree->n_pnode);
00269 
00270 #if __FSG_DBG__
00271     fsg_lextree_dump(lextree, stdout);
00272 #endif
00273 
00274     return lextree;
00275 }
00276 
00277 
00278 void
00279 fsg_lextree_dump(fsg_lextree_t * lextree, FILE * fp)
00280 {
00281     int32 s;
00282 
00283     for (s = 0; s < fsg_model_n_state(lextree->fsg); s++) {
00284         fprintf(fp, "State %5d root %p\n", s, lextree->root[s]);
00285         fsg_psubtree_dump(lextree, lextree->alloc_head[s], fp);
00286     }
00287     fflush(fp);
00288 }
00289 
00290 
00291 void
00292 fsg_lextree_free(fsg_lextree_t * lextree)
00293 {
00294     int32 s;
00295 
00296     if (lextree == NULL)
00297         return;
00298 
00299     if (lextree->fsg)
00300         for (s = 0; s < fsg_model_n_state(lextree->fsg); s++)
00301             fsg_psubtree_free(lextree->alloc_head[s]);
00302 
00303     ckd_free_2d(lextree->lc);
00304     ckd_free_2d(lextree->rc);
00305     ckd_free(lextree->root);
00306     ckd_free(lextree->alloc_head);
00307     ckd_free(lextree);
00308 }
00309 
00310 void
00311 fsg_pnode_add_all_ctxt(fsg_pnode_ctxt_t * ctxt)
00312 {
00313     int32 i;
00314 
00315     for (i = 0; i < FSG_PNODE_CTXT_BVSZ; i++)
00316         ctxt->bv[i] = 0xffffffff;
00317 }
00318 
00319 
00320 uint32
00321 fsg_pnode_ctxt_sub(fsg_pnode_ctxt_t * src, fsg_pnode_ctxt_t * sub)
00322 {
00323     int32 i;
00324     uint32 non_zero;
00325 
00326     non_zero = 0;
00327 
00328     for (i = 0; i < FSG_PNODE_CTXT_BVSZ; i++) {
00329         src->bv[i] = ~(sub->bv[i]) & src->bv[i];
00330         non_zero |= src->bv[i];
00331     }
00332 
00333     return non_zero;
00334 }
00335 
00336 
00337 /*
00338  * Add the word emitted by the given transition (fsglink) to the given lextree
00339  * (rooted at root), and return the new lextree root.  (There may actually be
00340  * several root nodes, maintained in a linked list via fsg_pnode_t.sibling.
00341  * "root" is the head of this list.)
00342  * lclist, rclist: sets of left and right context phones for this link.
00343  * alloc_head: head of a linear list of all allocated pnodes for the parent
00344  * FSG state, kept elsewhere and updated by this routine.
00345  * 
00346  * NOTE: No lextree structure for now; using a flat representation.
00347  */
00348 static fsg_pnode_t *
00349 psubtree_add_trans(fsg_lextree_t *lextree, 
00350                    fsg_pnode_t * root,
00351                    fsg_link_t * fsglink,
00352                    int16 *lclist, int16 *rclist,
00353                    fsg_pnode_t ** alloc_head)
00354 {
00355     int32 silcipid;             /* Silence CI phone ID */
00356     int32 pronlen;              /* Pronunciation length */
00357     int32 wid;                  /* FSG (not dictionary!!) word ID */
00358     int32 dictwid;              /* Dictionary (not FSG!!) word ID */
00359     int32 ssid;                 /* Senone Sequence ID */
00360     gnode_t *gn;
00361     fsg_pnode_t *pnode, *pred, *head;
00362     int32 n_ci, p, lc, rc;
00363     glist_t lc_pnodelist;       /* Temp pnodes list for different left contexts */
00364     glist_t rc_pnodelist;       /* Temp pnodes list for different right contexts */
00365     int32 i, j;
00366 
00367     silcipid = bin_mdef_silphone(lextree->mdef);
00368     n_ci = bin_mdef_n_ciphone(lextree->mdef);
00369 
00370     wid = fsg_link_wid(fsglink);
00371     assert(wid >= 0);           /* Cannot be a null transition */
00372     dictwid = s3dict_wordid(lextree->dict,
00373                             fsg_model_word_str(lextree->fsg, wid));
00374     pronlen = s3dict_pronlen(lextree->dict, dictwid);
00375     assert(pronlen >= 1);
00376 
00377     assert(lclist[0] >= 0);     /* At least one phonetic context provided */
00378     assert(rclist[0] >= 0);
00379 
00380     head = *alloc_head;
00381     pred = NULL;
00382 
00383     if (pronlen == 1) {         /* Single-phone word */
00384         int ci = s3dict_first_phone(lextree->dict, dictwid);
00385         /* Only non-filler words are mpx */
00386         if (s3dict_filler_word(lextree->dict, dictwid)) {
00387             /*
00388              * Left diphone ID for single-phone words already assumes SIL is right
00389              * context; only left contexts need to be handled.
00390              */
00391             lc_pnodelist = NULL;
00392 
00393             for (i = 0; lclist[i] >= 0; i++) {
00394                 lc = lclist[i];
00395                 ssid = lextree->d2p->lrdiph_rc[ci][lc][silcipid];
00396                 /* Check if this ssid already allocated for some other context */
00397                 for (gn = lc_pnodelist; gn; gn = gnode_next(gn)) {
00398                     pnode = (fsg_pnode_t *) gnode_ptr(gn);
00399 
00400                     if (hmm_nonmpx_ssid(&pnode->hmm) == ssid) {
00401                         /* already allocated; share it for this context phone */
00402                         fsg_pnode_add_ctxt(pnode, lc);
00403                         break;
00404                     }
00405                 }
00406 
00407                 if (!gn) {      /* ssid not already allocated */
00408                     pnode =
00409                         (fsg_pnode_t *) ckd_calloc(1, sizeof(fsg_pnode_t));
00410                     pnode->ctx = lextree->ctx;
00411                     pnode->next.fsglink = fsglink;
00412                     pnode->logs2prob =
00413                         fsg_link_logs2prob(fsglink) + lextree->wip + lextree->pip;
00414                     pnode->ci_ext = s3dict_first_phone(lextree->dict, dictwid);
00415                     pnode->ppos = 0;
00416                     pnode->leaf = TRUE;
00417                     pnode->sibling = root;      /* All root nodes linked together */
00418                     fsg_pnode_add_ctxt(pnode, lc);      /* Initially zeroed by calloc above */
00419                     pnode->alloc_next = head;
00420                     head = pnode;
00421                     root = pnode;
00422 
00423                     hmm_init(lextree->ctx, &pnode->hmm, FALSE, ssid, pnode->ci_ext);
00424 
00425                     lc_pnodelist =
00426                         glist_add_ptr(lc_pnodelist, (void *) pnode);
00427                 }
00428             }
00429 
00430             glist_free(lc_pnodelist);
00431         }
00432         else {                  /* Filler word; no context modelled */
00433             ssid = bin_mdef_pid2ssid(lextree->mdef, ci); /* probably the same... */
00434 
00435             pnode = (fsg_pnode_t *) ckd_calloc(1, sizeof(fsg_pnode_t));
00436             pnode->ctx = lextree->ctx;
00437             pnode->next.fsglink = fsglink;
00438             pnode->logs2prob = fsg_link_logs2prob(fsglink) + lextree->wip + lextree->pip;
00439             pnode->ci_ext = silcipid;   /* Presents SIL as context to neighbors */
00440             pnode->ppos = 0;
00441             pnode->leaf = TRUE;
00442             pnode->sibling = root;
00443             fsg_pnode_add_all_ctxt(&(pnode->ctxt));
00444             pnode->alloc_next = head;
00445             head = pnode;
00446             root = pnode;
00447 
00448             hmm_init(lextree->ctx, &pnode->hmm, FALSE, ssid, pnode->ci_ext);
00449         }
00450     }
00451     else {                      /* Multi-phone word */
00452         fsg_pnode_t **ssid_pnode_map;       /* Temp array of ssid->pnode mapping */
00453         ssid_pnode_map =
00454             (fsg_pnode_t **) ckd_calloc(n_ci, sizeof(fsg_pnode_t *));
00455         lc_pnodelist = NULL;
00456         rc_pnodelist = NULL;
00457 
00458         for (p = 0; p < pronlen; p++) {
00459             int ci = s3dict_pron(lextree->dict, dictwid, p);
00460             if (p == 0) {       /* Root phone, handle required left contexts */
00461                 rc = s3dict_pron(lextree->dict, dictwid, 1);
00462                 for (i = 0; lclist[i] >= 0; i++) {
00463                     lc = lclist[i];
00464                     ssid = lextree->d2p->ldiph_lc[ci][rc][lc];
00465                     /* Compression is not done by d2p, so we do it
00466                      * here.  This might be slow, but it might not
00467                      * be... we'll see. */
00468                     pnode = ssid_pnode_map[0];
00469                     for (j = 0; j < n_ci && ssid_pnode_map[j] != NULL; ++j) {
00470                         pnode = ssid_pnode_map[j];
00471                         if (hmm_nonmpx_ssid(&pnode->hmm) == ssid)
00472                             break;
00473                     }
00474                     assert(j < n_ci);
00475                     if (!pnode) {       /* Allocate pnode for this new ssid */
00476                         pnode =
00477                             (fsg_pnode_t *) ckd_calloc(1,
00478                                                        sizeof
00479                                                        (fsg_pnode_t));
00480                         pnode->ctx = lextree->ctx;
00481                         pnode->logs2prob =
00482                             fsg_link_logs2prob(fsglink) + lextree->wip + lextree->pip;
00483                         pnode->ci_ext = s3dict_first_phone(lextree->dict, dictwid);
00484                         pnode->ppos = 0;
00485                         pnode->leaf = FALSE;
00486                         pnode->sibling = root;  /* All root nodes linked together */
00487                         pnode->alloc_next = head;
00488                         head = pnode;
00489                         root = pnode;
00490 
00491                         hmm_init(lextree->ctx, &pnode->hmm, FALSE, ssid, pnode->ci_ext);
00492 
00493                         lc_pnodelist =
00494                             glist_add_ptr(lc_pnodelist, (void *) pnode);
00495                         ssid_pnode_map[j] = pnode;
00496                     }
00497                     fsg_pnode_add_ctxt(pnode, lc);
00498                 }
00499             }
00500             else if (p != pronlen - 1) {        /* Word internal phone */
00501                 ssid = lextree->d2p->internal[dictwid][p];
00502                 pnode = (fsg_pnode_t *) ckd_calloc(1, sizeof(fsg_pnode_t));
00503                 pnode->ctx = lextree->ctx;
00504                 pnode->logs2prob = lextree->pip;
00505                 pnode->ci_ext = s3dict_pron(lextree->dict, dictwid, p);
00506                 pnode->ppos = p;
00507                 pnode->leaf = FALSE;
00508                 pnode->sibling = NULL;
00509                 if (p == 1) {   /* Predecessor = set of root nodes for left ctxts */
00510                     for (gn = lc_pnodelist; gn; gn = gnode_next(gn)) {
00511                         pred = (fsg_pnode_t *) gnode_ptr(gn);
00512                         pred->next.succ = pnode;
00513                     }
00514                 }
00515                 else {          /* Predecessor = word internal node */
00516                     pred->next.succ = pnode;
00517                 }
00518                 pnode->alloc_next = head;
00519                 head = pnode;
00520 
00521                 hmm_init(lextree->ctx, &pnode->hmm, FALSE, ssid, pnode->ci_ext);
00522 
00523                 pred = pnode;
00524             }
00525             else {              /* Leaf phone, handle required right contexts */
00526                 xwdssid_t *rssid;
00527                 memset((void *) ssid_pnode_map, 0,
00528                        n_ci * sizeof(fsg_pnode_t *));
00529                 lc = s3dict_pron(lextree->dict, dictwid, p-1);
00530                 rssid = dict2pid_rssid(lextree->d2p, ci, lc);
00531 
00532                 for (i = 0; rclist[i] >= 0; i++) {
00533                     rc = rclist[i];
00534 
00535                     j = rssid->cimap[rc];
00536                     ssid = rssid->ssid[j];
00537                     pnode = ssid_pnode_map[j];
00538 
00539                     if (!pnode) {       /* Allocate pnode for this new ssid */
00540                         pnode =
00541                             (fsg_pnode_t *) ckd_calloc(1,
00542                                                        sizeof
00543                                                        (fsg_pnode_t));
00544                         pnode->ctx = lextree->ctx;
00545                         pnode->logs2prob = lextree->pip;
00546                         pnode->ci_ext = s3dict_pron(lextree->dict, dictwid, p);
00547                         pnode->ppos = p;
00548                         pnode->leaf = TRUE;
00549                         pnode->sibling = rc_pnodelist ?
00550                             (fsg_pnode_t *) gnode_ptr(rc_pnodelist) : NULL;
00551                         pnode->next.fsglink = fsglink;
00552                         pnode->alloc_next = head;
00553                         head = pnode;
00554 
00555                         hmm_init(lextree->ctx, &pnode->hmm, FALSE, ssid, pnode->ci_ext);
00556 
00557                         rc_pnodelist =
00558                             glist_add_ptr(rc_pnodelist, (void *) pnode);
00559                         ssid_pnode_map[j] = pnode;
00560                     }
00561                     else {
00562                         assert(hmm_nonmpx_ssid(&pnode->hmm) == ssid);
00563                     }
00564                     fsg_pnode_add_ctxt(pnode, rc);
00565                 }
00566 
00567                 if (p == 1) {   /* Predecessor = set of root nodes for left ctxts */
00568                     for (gn = lc_pnodelist; gn; gn = gnode_next(gn)) {
00569                         pred = (fsg_pnode_t *) gnode_ptr(gn);
00570                         pred->next.succ =
00571                             (fsg_pnode_t *) gnode_ptr(rc_pnodelist);
00572                     }
00573                 }
00574                 else {          /* Predecessor = word internal node */
00575                     pred->next.succ =
00576                         (fsg_pnode_t *) gnode_ptr(rc_pnodelist);
00577                 }
00578             }
00579         }
00580 
00581         ckd_free((void *) ssid_pnode_map);
00582         glist_free(lc_pnodelist);
00583         glist_free(rc_pnodelist);
00584     }
00585 
00586     *alloc_head = head;
00587 
00588     return root;
00589 }
00590 
00591 
00592 /*
00593  * For now, this "tree" will be "flat"
00594  */
00595 static fsg_pnode_t *
00596 fsg_psubtree_init(fsg_lextree_t *lextree,
00597                   fsg_model_t * fsg, int32 from_state,
00598                   fsg_pnode_t ** alloc_head)
00599 {
00600     int32 dst;
00601     gnode_t *gn;
00602     fsg_link_t *fsglink;
00603     fsg_pnode_t *root;
00604     int32 n_ci;
00605 
00606     root = NULL;
00607     assert(*alloc_head == NULL);
00608 
00609     n_ci = bin_mdef_n_ciphone(lextree->mdef);
00610     if (n_ci > (FSG_PNODE_CTXT_BVSZ * 32)) {
00611         E_FATAL
00612             ("#phones > %d; increase FSG_PNODE_CTXT_BVSZ and recompile\n",
00613              FSG_PNODE_CTXT_BVSZ * 32);
00614     }
00615     for (dst = 0; dst < fsg_model_n_state(fsg); dst++) {
00616         /* Add all links from from_state to dst */
00617         for (gn = fsg_model_trans(fsg, from_state, dst); gn;
00618              gn = gnode_next(gn)) {
00619             /* Add word emitted by this transition (fsglink) to lextree */
00620             fsglink = (fsg_link_t *) gnode_ptr(gn);
00621 
00622             assert(fsg_link_wid(fsglink) >= 0);     /* Cannot be a null trans */
00623 
00624             root = psubtree_add_trans(lextree, root, fsglink,
00625                                       lextree->lc[from_state],
00626                                       lextree->rc[dst],
00627                                       alloc_head);
00628         }
00629     }
00630 
00631     return root;
00632 }
00633 
00634 
00635 static void
00636 fsg_psubtree_free(fsg_pnode_t * head)
00637 {
00638     fsg_pnode_t *next;
00639 
00640     while (head) {
00641         next = head->alloc_next;
00642         hmm_deinit(&head->hmm);
00643         ckd_free(head);
00644         head = next;
00645     }
00646 }
00647 
00648 static void
00649 fsg_psubtree_dump(fsg_lextree_t *tree, fsg_pnode_t * head, FILE * fp)
00650 {
00651     int32 i;
00652     fsg_link_t *tl;
00653 
00654     for (; head; head = head->alloc_next) {
00655         /* Indentation */
00656         for (i = 0; i <= head->ppos; i++)
00657             fprintf(fp, "  ");
00658 
00659         fprintf(fp, "%p.@", head);    /* Pointer used as node ID */
00660         fprintf(fp, " %5d.SS", hmm_nonmpx_ssid(&head->hmm));
00661         fprintf(fp, " %10d.LP", head->logs2prob);
00662         fprintf(fp, " %p.SIB", head->sibling);
00663         fprintf(fp, " %s.%d", bin_mdef_ciphone_str(tree->mdef, head->ci_ext), head->ppos);
00664         if ((head->ppos == 0) || head->leaf) {
00665             fprintf(fp, " [");
00666             for (i = 0; i < FSG_PNODE_CTXT_BVSZ; i++)
00667                 fprintf(fp, "%08x", head->ctxt.bv[i]);
00668             fprintf(fp, "]");
00669         }
00670         if (head->leaf) {
00671             tl = head->next.fsglink;
00672             fprintf(fp, " {%s[%d->%d](%d)}",
00673                     fsg_model_word_str(tree->fsg, tl->wid),
00674                     tl->from_state, tl->to_state, tl->logs2prob);
00675         }
00676         else {
00677             fprintf(fp, " %p.NXT", head->next.succ);
00678         }
00679         fprintf(fp, "\n");
00680     }
00681 
00682     fflush(fp);
00683 }
00684 
00685 
00686 void
00687 fsg_psubtree_pnode_deactivate(fsg_pnode_t * pnode)
00688 {
00689     hmm_clear(&pnode->hmm);
00690 }

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