• Main Page
  • Related Pages
  • Data Structures
  • Files
  • File List
  • Globals

src/libsphinxbase/lm/fsg_model.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 /* System headers. */
00036 #ifdef _WIN32_WCE
00037 /*MC in a debug build it's implicitly included by assert.h
00038      but you need this in a release build */
00039 #include <windows.h>
00040 #else
00041 #include <time.h>
00042 #endif /* _WIN32_WCE */
00043 #include <stdio.h>
00044 #include <string.h>
00045 #include <assert.h>
00046 
00047 /* SphinxBase headers. */
00048 #include "err.h"
00049 #include "pio.h"
00050 #include "ckd_alloc.h"
00051 #include "prim_type.h"
00052 #include "strfuncs.h"
00053 #include "hash_table.h"
00054 
00055 #include "fsg_model.h"
00056 
00057 
00058 #define FSG_MODEL_BEGIN_DECL            "FSG_BEGIN"
00059 #define FSG_MODEL_END_DECL              "FSG_END"
00060 #define FSG_MODEL_N_DECL                        "N"
00061 #define FSG_MODEL_NUM_STATES_DECL       "NUM_STATES"
00062 #define FSG_MODEL_S_DECL                        "S"
00063 #define FSG_MODEL_START_STATE_DECL      "START_STATE"
00064 #define FSG_MODEL_F_DECL                        "F"
00065 #define FSG_MODEL_FINAL_STATE_DECL      "FINAL_STATE"
00066 #define FSG_MODEL_T_DECL                        "T"
00067 #define FSG_MODEL_TRANSITION_DECL       "TRANSITION"
00068 #define FSG_MODEL_COMMENT_CHAR          '#'
00069 
00070 
00071 static int32
00072 nextline_str2words(FILE * fp, int32 * lineno,
00073                    char **lineptr, char ***wordptr)
00074 {
00075     for (;;) {
00076         size_t len;
00077         int32 n;
00078 
00079         ckd_free(*lineptr);
00080         if ((*lineptr = fread_line(fp, &len)) == NULL)
00081             return -1;
00082 
00083         (*lineno)++;
00084 
00085         if ((*lineptr)[0] == FSG_MODEL_COMMENT_CHAR)
00086             continue; /* Skip comment lines */
00087         
00088         n = str2words(*lineptr, NULL, 0);
00089         if (n == 0)
00090             continue; /* Skip blank lines */
00091 
00092         /* Abuse of realloc(), but this doesn't have to be fast. */
00093         if (*wordptr == NULL)
00094             *wordptr = ckd_calloc(n, sizeof(**wordptr));
00095         else
00096             *wordptr = ckd_realloc(*wordptr, n * sizeof(**wordptr));
00097         return str2words(*lineptr, *wordptr, n);
00098     }
00099 }
00100 
00101 void
00102 fsg_model_trans_add(fsg_model_t * fsg,
00103                    int32 from, int32 to, int32 logp, int32 wid)
00104 {
00105     fsg_link_t *link;
00106     gnode_t *gn;
00107 
00108     /* Check for duplicate link (i.e., link already exists with label=wid) */
00109     for (gn = fsg->trans[from][to]; gn; gn = gnode_next(gn)) {
00110         link = (fsg_link_t *) gnode_ptr(gn);
00111 
00112         if (link->wid == wid) {
00113             if (link->logs2prob < logp)
00114                 link->logs2prob = logp;
00115             return;
00116         }
00117     }
00118 
00119     /* Create transition object */
00120     link = listelem_malloc(fsg->link_alloc);
00121     link->from_state = from;
00122     link->to_state = to;
00123     link->logs2prob = logp;
00124     link->wid = wid;
00125 
00126     fsg->trans[from][to] =
00127         glist_add_ptr(fsg->trans[from][to], (void *) link);
00128 }
00129 
00130 int32
00131 fsg_model_null_trans_add(fsg_model_t * fsg, int32 from, int32 to, int32 logp)
00132 {
00133     fsg_link_t *link;
00134 
00135     /* Check for transition probability */
00136     if (logp > 0) {
00137         E_FATAL("Null transition prob must be <= 1.0 (state %d -> %d)\n",
00138                 from, to);
00139     }
00140 
00141     /* Self-loop null transitions (with prob <= 1.0) are redundant */
00142     if (from == to)
00143         return -1;
00144 
00145     /* Check for a duplicate link; if found, keep the higher prob */
00146     link = fsg->null_trans[from][to];
00147     if (link) {
00148         assert(link->wid < 0);
00149         if (link->logs2prob < logp) {
00150             link->logs2prob = logp;
00151             return 0;
00152         }
00153         else
00154             return -1;
00155     }
00156 
00157     /* Create null transition object */
00158     link = listelem_malloc(fsg->link_alloc);
00159     link->from_state = from;
00160     link->to_state = to;
00161     link->logs2prob = logp;
00162     link->wid = -1;
00163 
00164     fsg->null_trans[from][to] = link;
00165 
00166     return 1;
00167 }
00168 
00169 glist_t
00170 fsg_model_null_trans_closure(fsg_model_t * fsg, glist_t nulls)
00171 {
00172     gnode_t *gn1, *gn2;
00173     int updated;
00174     fsg_link_t *tl1, *tl2;
00175     int32 k, n;
00176 
00177     E_INFO("Computing transitive closure for null transitions\n");
00178 
00179     if (nulls == NULL) {
00180         int i, j;
00181         
00182         for (i = 0; i < fsg->n_state; ++i) {
00183             for (j = 0; j < fsg->n_state; ++j) {
00184                 if (fsg->null_trans[i][j])
00185                     nulls = glist_add_ptr(nulls, fsg->null_trans[i][j]);
00186             }
00187         }
00188     }
00189 
00190     /*
00191      * Probably not the most efficient closure implementation, in general, but
00192      * probably reasonably efficient for a sparse null transition matrix.
00193      */
00194     n = 0;
00195     do {
00196         updated = FALSE;
00197 
00198         for (gn1 = nulls; gn1; gn1 = gnode_next(gn1)) {
00199             tl1 = (fsg_link_t *) gnode_ptr(gn1);
00200             assert(tl1->wid < 0);
00201 
00202             for (gn2 = nulls; gn2; gn2 = gnode_next(gn2)) {
00203                 tl2 = (fsg_link_t *) gnode_ptr(gn2);
00204 
00205                 if (tl1->to_state == tl2->from_state) {
00206                     k = fsg_model_null_trans_add(fsg,
00207                                                 tl1->from_state,
00208                                                 tl2->to_state,
00209                                                 tl1->logs2prob +
00210                                                 tl2->logs2prob);
00211                     if (k >= 0) {
00212                         updated = TRUE;
00213                         if (k > 0) {
00214                             nulls =
00215                                 glist_add_ptr(nulls,
00216                                               (void *) fsg->
00217                                               null_trans[tl1->
00218                                                          from_state][tl2->
00219                                                                      to_state]);
00220                             n++;
00221                         }
00222                     }
00223                 }
00224             }
00225         }
00226     } while (updated);
00227 
00228     E_INFO("%d null transitions added\n", n);
00229 
00230     return nulls;
00231 }
00232 
00233 int
00234 fsg_model_word_id(fsg_model_t *fsg, char const *word)
00235 {
00236     int wid;
00237 
00238     /* Search for an existing word matching this. */
00239     for (wid = 0; wid < fsg->n_word; ++wid) {
00240         if (0 == strcmp(fsg->vocab[wid], word))
00241             break;
00242     }
00243     /* If not found, add this to the vocab. */
00244     if (wid == fsg->n_word)
00245         return -1;
00246     return wid;
00247 }
00248 
00249 int
00250 fsg_model_word_add(fsg_model_t *fsg, char const *word)
00251 {
00252     int wid;
00253 
00254     /* Search for an existing word matching this. */
00255     wid = fsg_model_word_id(fsg, word);
00256     /* If not found, add this to the vocab. */
00257     if (wid == -1) {
00258         wid = fsg->n_word;
00259         if (fsg->n_word == fsg->n_word_alloc) {
00260             fsg->n_word_alloc += 10;
00261             fsg->vocab = ckd_realloc(fsg->vocab,
00262                                      fsg->n_word_alloc * sizeof(*fsg->vocab));
00263             if (fsg->silwords)
00264                 fsg->silwords = bitvec_realloc(fsg->silwords, fsg->n_word_alloc);
00265             if (fsg->altwords)
00266                 fsg->altwords = bitvec_realloc(fsg->altwords, fsg->n_word_alloc);
00267         }
00268         ++fsg->n_word;
00269         fsg->vocab[wid] = ckd_salloc(word);
00270     }
00271     return wid;
00272 }
00273 
00274 int
00275 fsg_model_add_silence(fsg_model_t * fsg, char const *silword,
00276                       int state, float32 silprob)
00277 {
00278     int32 logsilp;
00279     int n_trans, silwid, src;
00280 
00281     E_INFO("Adding silence transitions for %s to FSG\n", silword);
00282 
00283     silwid = fsg_model_word_add(fsg, silword);
00284     logsilp = (int32) (logmath_log(fsg->lmath, silprob) * fsg->lw);
00285     if (fsg->silwords == NULL)
00286         fsg->silwords = bitvec_alloc(fsg->n_word_alloc);
00287     bitvec_set(fsg->silwords, silwid);
00288 
00289     n_trans = 0;
00290     if (state == -1) {
00291         for (src = 0; src < fsg->n_state; src++) {
00292             fsg_model_trans_add(fsg, src, src, logsilp, silwid);
00293             ++n_trans;
00294         }
00295     }
00296     else {
00297         fsg_model_trans_add(fsg, state, state, logsilp, silwid);
00298         ++n_trans;
00299     }
00300 
00301     E_INFO("Added %d silence word transitions\n", n_trans);
00302     return n_trans;
00303 }
00304 
00305 int
00306 fsg_model_add_alt(fsg_model_t * fsg, char const *baseword,
00307                   char const *altword)
00308 {
00309     int i, j, basewid, altwid;
00310     int ntrans;
00311 
00312     /* FIXME: This will get slow, eventually... */
00313     for (basewid = 0; basewid < fsg->n_word; ++basewid)
00314         if (0 == strcmp(fsg->vocab[basewid], baseword))
00315             break;
00316     if (basewid == fsg->n_word) {
00317         E_ERROR("Base word %s not present in FSG vocabulary!\n", baseword);
00318         return -1;
00319     }
00320     altwid = fsg_model_word_add(fsg, altword);
00321     if (fsg->altwords == NULL)
00322         fsg->altwords = bitvec_alloc(fsg->n_word_alloc);
00323     bitvec_set(fsg->altwords, altwid);
00324 
00325     E_INFO("Adding alternate word transitions (%s,%s) to FSG\n",
00326            baseword, altword);
00327 
00328     /* Look for all transitions involving baseword and duplicate them. */
00329     /* FIXME: This will also get slow, eventually... */
00330     ntrans = 0;
00331     for (i = 0; i < fsg->n_state; ++i) {
00332         for (j = 0; j < fsg->n_state; ++j) {
00333             glist_t trans;
00334             gnode_t *gn;
00335 
00336             trans = fsg->trans[i][j];
00337             for (gn = trans; gn; gn = gnode_next(gn)) {
00338                 fsg_link_t *fl = gnode_ptr(gn);
00339                 if (fl->wid == basewid) {
00340                     fsg_link_t *link;
00341 
00342                     /* Create transition object */
00343                     link = listelem_malloc(fsg->link_alloc);
00344                     link->from_state = i;
00345                     link->to_state = j;
00346                     link->logs2prob = fl->logs2prob; /* FIXME!!!??? */
00347                     link->wid = altwid;
00348 
00349                     trans =
00350                         glist_add_ptr(trans, (void *) link);
00351                     ++ntrans;
00352                 }
00353             }
00354             fsg->trans[i][j] = trans;
00355         }
00356     }
00357 
00358     E_INFO("Added %d alternate word transitions\n", ntrans);
00359     return ntrans;
00360 }
00361 
00362 
00363 fsg_model_t *
00364 fsg_model_init(char const *name, logmath_t *lmath, float32 lw, int32 n_state)
00365 {
00366     fsg_model_t *fsg;
00367 
00368     /* Allocate basic stuff. */
00369     fsg = ckd_calloc(1, sizeof(*fsg));
00370     fsg->refcount = 1;
00371     fsg->link_alloc = listelem_alloc_init(sizeof(fsg_link_t));
00372     fsg->lmath = lmath;
00373     fsg->name = name ? ckd_salloc(name) : NULL;
00374     fsg->n_state = n_state;
00375     fsg->lw = lw;
00376 
00377     /* Allocate non-epsilon transition matrix array */
00378     fsg->trans = ckd_calloc_2d(fsg->n_state, fsg->n_state,
00379                                sizeof(glist_t));
00380     /* Allocate epsilon transition matrix array */
00381     fsg->null_trans = ckd_calloc_2d(fsg->n_state, fsg->n_state,
00382                                     sizeof(fsg_link_t *));
00383     return fsg;
00384 }
00385 
00386 fsg_model_t *
00387 fsg_model_read(FILE * fp, logmath_t *lmath, float32 lw)
00388 {
00389     fsg_model_t *fsg;
00390     hash_table_t *vocab;
00391     hash_iter_t *itor;
00392     int32 lastwid;
00393     char **wordptr;
00394     char *lineptr;
00395     char *fsgname;
00396     int32 lineno;
00397     int32 n, i, j;
00398     int n_state, n_trans, n_null_trans;
00399     glist_t nulls;
00400     float32 p;
00401 
00402     lineno = 0;
00403     vocab = hash_table_new(32, FALSE);
00404     wordptr = NULL;
00405     lineptr = NULL;
00406     nulls = NULL;
00407     fsgname = NULL;
00408     fsg = NULL;
00409 
00410     /* Scan upto FSG_BEGIN header */
00411     for (;;) {
00412         n = nextline_str2words(fp, &lineno, &lineptr, &wordptr);
00413         if (n < 0) {
00414             E_ERROR("%s declaration missing\n", FSG_MODEL_BEGIN_DECL);
00415             goto parse_error;
00416         }
00417 
00418         if ((strcmp(wordptr[0], FSG_MODEL_BEGIN_DECL) == 0)) {
00419             if (n > 2) {
00420                 E_ERROR("Line[%d]: malformed FSG_BEGIN declaration\n",
00421                         lineno);
00422                 goto parse_error;
00423             }
00424             break;
00425         }
00426     }
00427     /* Save FSG name, or it will get clobbered below :(.
00428      * If name is missing, try the default.
00429      */
00430     if (n == 2) {
00431         fsgname = ckd_salloc(wordptr[1]);
00432     } else {
00433         E_WARN ("FSG name is missing\n");
00434         fsgname = ckd_salloc("unknown");
00435     }
00436 
00437     /* Read #states */
00438     n = nextline_str2words(fp, &lineno, &lineptr, &wordptr);
00439     if ((n != 2)
00440         || ((strcmp(wordptr[0], FSG_MODEL_N_DECL) != 0)
00441             && (strcmp(wordptr[0], FSG_MODEL_NUM_STATES_DECL) != 0))
00442         || (sscanf(wordptr[1], "%d", &n_state) != 1)
00443         || (n_state <= 0)) {
00444         E_ERROR
00445             ("Line[%d]: #states declaration line missing or malformed\n",
00446              lineno);
00447         goto parse_error;
00448     }
00449 
00450     /* Now create the FSG. */
00451     fsg = fsg_model_init(fsgname, lmath, lw, n_state);
00452     ckd_free(fsgname);
00453     fsgname = NULL;
00454 
00455     /* Read start state */
00456     n = nextline_str2words(fp, &lineno, &lineptr, &wordptr);
00457     if ((n != 2)
00458         || ((strcmp(wordptr[0], FSG_MODEL_S_DECL) != 0)
00459             && (strcmp(wordptr[0], FSG_MODEL_START_STATE_DECL) != 0))
00460         || (sscanf(wordptr[1], "%d", &(fsg->start_state)) != 1)
00461         || (fsg->start_state < 0)
00462         || (fsg->start_state >= fsg->n_state)) {
00463         E_ERROR
00464             ("Line[%d]: start state declaration line missing or malformed\n",
00465              lineno);
00466         goto parse_error;
00467     }
00468 
00469     /* Read final state */
00470     n = nextline_str2words(fp, &lineno, &lineptr, &wordptr);
00471     if ((n != 2)
00472         || ((strcmp(wordptr[0], FSG_MODEL_F_DECL) != 0)
00473             && (strcmp(wordptr[0], FSG_MODEL_FINAL_STATE_DECL) != 0))
00474         || (sscanf(wordptr[1], "%d", &(fsg->final_state)) != 1)
00475         || (fsg->final_state < 0)
00476         || (fsg->final_state >= fsg->n_state)) {
00477         E_ERROR
00478             ("Line[%d]: final state declaration line missing or malformed\n",
00479              lineno);
00480         goto parse_error;
00481     }
00482 
00483     /* Read transitions */
00484     lastwid = 0;
00485     n_trans = n_null_trans = 0;
00486     for (;;) {
00487         int32 wid, tprob;
00488 
00489         n = nextline_str2words(fp, &lineno, &lineptr, &wordptr);
00490         if (n <= 0) {
00491             E_ERROR("Line[%d]: transition or FSG_END statement expected\n",
00492                     lineno);
00493             goto parse_error;
00494         }
00495 
00496         if ((strcmp(wordptr[0], FSG_MODEL_END_DECL) == 0)) {
00497             break;
00498         }
00499 
00500         if ((strcmp(wordptr[0], FSG_MODEL_T_DECL) == 0)
00501             || (strcmp(wordptr[0], FSG_MODEL_TRANSITION_DECL) == 0)) {
00502 
00503 
00504             if (((n != 4) && (n != 5))
00505                 || (sscanf(wordptr[1], "%d", &i) != 1)
00506                 || (sscanf(wordptr[2], "%d", &j) != 1)
00507                 || (i < 0) || (i >= fsg->n_state)
00508                 || (j < 0) || (j >= fsg->n_state)) {
00509                 E_ERROR
00510                     ("Line[%d]: transition spec malformed; Expecting: from-state to-state trans-prob [word]\n",
00511                      lineno);
00512                 goto parse_error;
00513             }
00514 
00515             p = atof_c(wordptr[3]);
00516             if ((p <= 0.0) || (p > 1.0)) {
00517                 E_ERROR
00518                     ("Line[%d]: transition spec malformed; Expecting float as transition probability\n",
00519                      lineno);
00520                 goto parse_error;
00521             }
00522         }
00523         else {
00524             E_ERROR("Line[%d]: transition or FSG_END statement expected\n",
00525                     lineno);
00526             goto parse_error;
00527         }
00528 
00529         tprob = (int32)(logmath_log(lmath, p) * fsg->lw);
00530         /* Add word to "dictionary". */
00531         if (n > 4) {
00532             if (hash_table_lookup_int32(vocab, wordptr[4], &wid) < 0) {
00533                 (void)hash_table_enter_int32(vocab, ckd_salloc(wordptr[4]), lastwid);
00534                 wid = lastwid;
00535                 ++lastwid;
00536             }
00537             fsg_model_trans_add(fsg, i, j, tprob, wid);
00538             ++n_trans;
00539         }
00540         else {
00541             if (fsg_model_null_trans_add(fsg, i, j, tprob) == 1) {
00542                 ++n_null_trans;
00543                 nulls = glist_add_ptr(nulls, fsg->null_trans[i][j]);
00544             }
00545         }
00546     }
00547 
00548     E_INFO("FSG: %d states, %d unique words, %d transitions (%d null)\n",
00549            fsg->n_state, hash_table_inuse(vocab), n_trans, n_null_trans);
00550 
00551     /* Do transitive closure on null transitions */
00552     nulls = fsg_model_null_trans_closure(fsg, nulls);
00553     glist_free(nulls);
00554 
00555     /* Now create a string table from the "dictionary" */
00556     fsg->n_word = hash_table_inuse(vocab);
00557     fsg->n_word_alloc = fsg->n_word + 10; /* Pad it a bit. */
00558     fsg->vocab = ckd_calloc(fsg->n_word_alloc, sizeof(*fsg->vocab));
00559     for (itor = hash_table_iter(vocab); itor; itor = hash_table_iter_next(itor)) {
00560         char const *word = hash_entry_key(itor->ent);
00561         int32 wid = (int32)(long)hash_entry_val(itor->ent);
00562         fsg->vocab[wid] = (char *)word;
00563     }
00564     hash_table_free(vocab);
00565     ckd_free(lineptr);
00566     ckd_free(wordptr);
00567 
00568     return fsg;
00569 
00570   parse_error:
00571     for (itor = hash_table_iter(vocab); itor; itor = hash_table_iter_next(itor))
00572         ckd_free((char *)hash_entry_key(itor->ent));
00573     glist_free(nulls);
00574     hash_table_free(vocab);
00575     ckd_free(fsgname);
00576     ckd_free(lineptr);
00577     ckd_free(wordptr);
00578     fsg_model_free(fsg);
00579     return NULL;
00580 }
00581 
00582 
00583 fsg_model_t *
00584 fsg_model_readfile(const char *file, logmath_t *lmath, float32 lw)
00585 {
00586     FILE *fp;
00587     fsg_model_t *fsg;
00588 
00589     if ((fp = fopen(file, "r")) == NULL) {
00590         E_ERROR("fopen(%s,r) failed\n", file);
00591         return NULL;
00592     }
00593     fsg = fsg_model_read(fp, lmath, lw);
00594     fclose(fp);
00595     return fsg;
00596 }
00597 
00598 fsg_model_t *
00599 fsg_model_retain(fsg_model_t *fsg)
00600 {
00601     ++fsg->refcount;
00602     return fsg;
00603 }
00604 
00605 int
00606 fsg_model_free(fsg_model_t * fsg)
00607 {
00608     int i, j;
00609 
00610     if (fsg == NULL)
00611         return 0;
00612 
00613     if (--fsg->refcount > 0)
00614         return fsg->refcount;
00615 
00616     for (i = 0; i < fsg->n_word; ++i)
00617         ckd_free(fsg->vocab[i]);
00618     for (i = 0; i < fsg->n_state; ++i)
00619         for (j = 0; j < fsg->n_state; ++j)
00620             glist_free(fsg->trans[i][j]);
00621     ckd_free(fsg->vocab);
00622     listelem_alloc_free(fsg->link_alloc);
00623     bitvec_free(fsg->silwords);
00624     bitvec_free(fsg->altwords);
00625     ckd_free_2d(fsg->trans);
00626     ckd_free_2d(fsg->null_trans);
00627     ckd_free(fsg->name);
00628     ckd_free(fsg);
00629     return 0;
00630 }
00631 
00632 
00633 void
00634 fsg_model_write(fsg_model_t * fsg, FILE * fp)
00635 {
00636     int32 i, j;
00637     gnode_t *gn;
00638     fsg_link_t *tl;
00639 
00640     fprintf(fp, "%s %s\n", FSG_MODEL_BEGIN_DECL, fsg->name ? fsg->name : "");
00641     fprintf(fp, "%s %d\n", FSG_MODEL_NUM_STATES_DECL, fsg->n_state);
00642     fprintf(fp, "%s %d\n", FSG_MODEL_START_STATE_DECL, fsg->start_state);
00643     fprintf(fp, "%s %d\n", FSG_MODEL_FINAL_STATE_DECL, fsg->final_state);
00644 
00645     for (i = 0; i < fsg->n_state; i++) {
00646         for (j = 0; j < fsg->n_state; j++) {
00647             /* Print non-null transitions */
00648             for (gn = fsg->trans[i][j]; gn; gn = gnode_next(gn)) {
00649                 tl = (fsg_link_t *) gnode_ptr(gn);
00650 
00651                 fprintf(fp, "%s %d %d %f %s\n", FSG_MODEL_TRANSITION_DECL,
00652                         tl->from_state, tl->to_state,
00653                         logmath_exp(fsg->lmath, (int32)(tl->logs2prob / fsg->lw)),
00654                         (tl->wid < 0) ? "" : fsg_model_word_str(fsg, tl->wid));
00655             }
00656 
00657             /* Print null transitions */
00658             tl = fsg->null_trans[i][j];
00659             if (tl) {
00660                 fprintf(fp, "%s %d %d %f\n",
00661                         FSG_MODEL_TRANSITION_DECL,
00662                         tl->from_state, tl->to_state,
00663                         logmath_exp(fsg->lmath, (int32)(tl->logs2prob / fsg->lw)));
00664             }
00665         }
00666     }
00667 
00668     fprintf(fp, "%s\n", FSG_MODEL_END_DECL);
00669 
00670     fflush(fp);
00671 }
00672 
00673 void
00674 fsg_model_writefile(fsg_model_t *fsg, char const *file)
00675 {
00676     FILE *fp;
00677 
00678     assert(fsg);
00679 
00680     E_INFO("Writing FSG file '%s'\n", file);
00681 
00682     if ((fp = fopen(file, "w")) == NULL) {
00683         E_ERROR("fopen(%s,r) failed\n", file);
00684         return;
00685     }
00686 
00687     fsg_model_write(fsg, fp);
00688 
00689     fclose(fp);
00690 }
00691 
00692 static void
00693 fsg_model_write_fsm_trans(fsg_model_t *fsg, int i, FILE *fp)
00694 {
00695     int j;
00696 
00697     for (j = 0; j < fsg->n_state; j++) {
00698         gnode_t *gn;
00699         fsg_link_t *tl;
00700 
00701         /* Print non-null transitions */
00702         for (gn = fsg->trans[i][j]; gn; gn = gnode_next(gn)) {
00703             tl = (fsg_link_t *) gnode_ptr(gn);
00704 
00705             fprintf(fp, "%d %d %s %f\n",
00706                     tl->from_state, tl->to_state,
00707                     (tl->wid < 0) ? "<eps>" : fsg_model_word_str(fsg, tl->wid),
00708                     -logmath_log_to_ln(fsg->lmath, tl->logs2prob / fsg->lw));
00709         }
00710 
00711         /* Print null transitions */
00712         tl = fsg->null_trans[i][j];
00713         if (tl) {
00714             fprintf(fp, "%d %d <eps> %f\n",
00715                     tl->from_state, tl->to_state,
00716                     -logmath_log_to_ln(fsg->lmath, tl->logs2prob / fsg->lw));
00717         }
00718     }
00719 }
00720 
00721 void
00722 fsg_model_write_fsm(fsg_model_t * fsg, FILE * fp)
00723 {
00724     int i;
00725 
00726     /* Write transitions from initial state first. */
00727     fsg_model_write_fsm_trans(fsg, fsg_model_start_state(fsg), fp);
00728 
00729     /* Other states. */
00730     for (i = 0; i < fsg->n_state; i++) {
00731         if (i == fsg_model_start_state(fsg))
00732             continue;
00733         fsg_model_write_fsm_trans(fsg, i, fp);
00734     }
00735 
00736     /* Final state. */
00737     fprintf(fp, "%d 0\n", fsg_model_final_state(fsg));
00738 
00739     fflush(fp);
00740 }
00741 
00742 void
00743 fsg_model_writefile_fsm(fsg_model_t *fsg, char const *file)
00744 {
00745     FILE *fp;
00746 
00747     assert(fsg);
00748 
00749     E_INFO("Writing FSM file '%s'\n", file);
00750 
00751     if ((fp = fopen(file, "w")) == NULL) {
00752         E_ERROR("fopen(%s,r) failed\n", file);
00753         return;
00754     }
00755 
00756     fsg_model_write_fsm(fsg, fp);
00757 
00758     fclose(fp);
00759 }
00760 
00761 void
00762 fsg_model_write_symtab(fsg_model_t *fsg, FILE *file)
00763 {
00764     int i;
00765 
00766     fprintf(file, "<eps> 0\n");
00767     for (i = 0; i < fsg_model_n_word(fsg); ++i) {
00768         fprintf(file, "%s %d\n", fsg_model_word_str(fsg, i), i + 1);
00769     }
00770     fflush(file);
00771 }
00772 
00773 void
00774 fsg_model_writefile_symtab(fsg_model_t *fsg, char const *file)
00775 {
00776     FILE *fp;
00777 
00778     assert(fsg);
00779 
00780     E_INFO("Writing FSM symbol table '%s'\n", file);
00781 
00782     if ((fp = fopen(file, "w")) == NULL) {
00783         E_ERROR("fopen(%s,r) failed\n", file);
00784         return;
00785     }
00786 
00787     fsg_model_write_symtab(fsg, fp);
00788 
00789     fclose(fp);
00790 }

Generated on Mon Aug 29 2011 for SphinxBase by  doxygen 1.7.1