00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00042
00043 #include <string.h>
00044 #include <assert.h>
00045
00046
00047 #include <ckd_alloc.h>
00048 #include <listelem_alloc.h>
00049 #include <err.h>
00050
00051
00052 #include "pocketsphinx_internal.h"
00053 #include "ps_lattice_internal.h"
00054 #include "ngram_search.h"
00055 #include "ngram_search_fwdtree.h"
00056 #include "ngram_search_fwdflat.h"
00057
00058 static int ngram_search_start(ps_search_t *search);
00059 static int ngram_search_step(ps_search_t *search, int frame_idx);
00060 static int ngram_search_finish(ps_search_t *search);
00061 static int ngram_search_reinit(ps_search_t *search);
00062 static char const *ngram_search_hyp(ps_search_t *search, int32 *out_score);
00063 static int32 ngram_search_prob(ps_search_t *search);
00064 static ps_seg_t *ngram_search_seg_iter(ps_search_t *search, int32 *out_score);
00065
00066 static ps_searchfuncs_t ngram_funcs = {
00067 "ngram",
00068 ngram_search_start,
00069 ngram_search_step,
00070 ngram_search_finish,
00071 ngram_search_reinit,
00072 ngram_search_free,
00073 ngram_search_lattice,
00074 ngram_search_hyp,
00075 ngram_search_prob,
00076 ngram_search_seg_iter,
00077 };
00078
00079 static void
00080 ngram_search_update_widmap(ngram_search_t *ngs)
00081 {
00082 const char **words;
00083 int32 i, n_words;
00084
00085
00086 n_words = ps_search_n_words(ngs);
00087 words = ckd_calloc(n_words, sizeof(*words));
00088
00089 for (i = 0; i < n_words; ++i)
00090 words[i] = (const char *)s3dict_wordstr(ps_search_dict(ngs), i);
00091 ngram_model_set_map_words(ngs->lmset, words, n_words);
00092 ckd_free(words);
00093 }
00094
00095 static void
00096 ngram_search_calc_beams(ngram_search_t *ngs)
00097 {
00098 cmd_ln_t *config;
00099 acmod_t *acmod;
00100
00101 config = ps_search_config(ngs);
00102 acmod = ps_search_acmod(ngs);
00103
00104
00105 ngs->beam = logmath_log(acmod->lmath, cmd_ln_float64_r(config, "-beam"));
00106 ngs->wbeam = logmath_log(acmod->lmath, cmd_ln_float64_r(config, "-wbeam"));
00107 ngs->pbeam = logmath_log(acmod->lmath, cmd_ln_float64_r(config, "-pbeam"));
00108 ngs->lpbeam = logmath_log(acmod->lmath, cmd_ln_float64_r(config, "-lpbeam"));
00109 ngs->lponlybeam = logmath_log(acmod->lmath, cmd_ln_float64_r(config, "-lponlybeam"));
00110 ngs->fwdflatbeam = logmath_log(acmod->lmath, cmd_ln_float64_r(config, "-fwdflatbeam"));
00111 ngs->fwdflatwbeam = logmath_log(acmod->lmath, cmd_ln_float64_r(config, "-fwdflatwbeam"));
00112
00113
00114 ngs->maxwpf = cmd_ln_int32_r(config, "-maxwpf");
00115 ngs->maxhmmpf = cmd_ln_int32_r(config, "-maxhmmpf");
00116
00117
00118 ngs->wip = logmath_log(acmod->lmath, cmd_ln_float32_r(config, "-wip"));
00119 ngs->nwpen = logmath_log(acmod->lmath, cmd_ln_float32_r(config, "-nwpen"));
00120 ngs->pip = logmath_log(acmod->lmath, cmd_ln_float32_r(config, "-pip"));
00121 ngs->silpen = ngs->pip
00122 + logmath_log(acmod->lmath, cmd_ln_float32_r(config, "-silprob"));
00123 ngs->fillpen = ngs->pip
00124 + logmath_log(acmod->lmath, cmd_ln_float32_r(config, "-fillprob"));
00125
00126
00127 ngs->fwdflat_fwdtree_lw_ratio =
00128 cmd_ln_float32_r(config, "-fwdflatlw")
00129 / cmd_ln_float32_r(config, "-lw");
00130 ngs->bestpath_fwdtree_lw_ratio =
00131 cmd_ln_float32_r(config, "-bestpathlw")
00132 / cmd_ln_float32_r(config, "-lw");
00133
00134
00135 ngs->ascale = 1.0 / cmd_ln_float32_r(config, "-ascale");
00136 }
00137
00138 ps_search_t *
00139 ngram_search_init(cmd_ln_t *config,
00140 acmod_t *acmod,
00141 s3dict_t *dict,
00142 dict2pid_t *d2p)
00143 {
00144 ngram_search_t *ngs;
00145 const char *path;
00146
00147 ngs = ckd_calloc(1, sizeof(*ngs));
00148 ps_search_init(&ngs->base, &ngram_funcs, config, acmod, dict, d2p);
00149 ngs->hmmctx = hmm_context_init(bin_mdef_n_emit_state(acmod->mdef),
00150 acmod->tmat->tp, NULL, acmod->mdef->sseq);
00151 if (ngs->hmmctx == NULL) {
00152 ps_search_free(ps_search_base(ngs));
00153 return NULL;
00154 }
00155 ngs->chan_alloc = listelem_alloc_init(sizeof(chan_t));
00156 ngs->root_chan_alloc = listelem_alloc_init(sizeof(root_chan_t));
00157 ngs->latnode_alloc = listelem_alloc_init(sizeof(ps_latnode_t));
00158
00159
00160 ngram_search_calc_beams(ngs);
00161
00162
00163 ngs->word_chan = ckd_calloc(s3dict_size(dict),
00164 sizeof(*ngs->word_chan));
00165 ngs->word_lat_idx = ckd_calloc(s3dict_size(dict),
00166 sizeof(*ngs->word_lat_idx));
00167 ngs->zeroPermTab = ckd_calloc(bin_mdef_n_ciphone(acmod->mdef),
00168 sizeof(*ngs->zeroPermTab));
00169 ngs->word_active = bitvec_alloc(s3dict_size(dict));
00170 ngs->last_ltrans = ckd_calloc(s3dict_size(dict),
00171 sizeof(*ngs->last_ltrans));
00172
00173
00174
00175 ngs->bp_table_size = cmd_ln_int32_r(config, "-latsize");
00176 ngs->bp_table = ckd_calloc(ngs->bp_table_size,
00177 sizeof(*ngs->bp_table));
00178
00179 ngs->bscore_stack_size = ngs->bp_table_size * 20;
00180 ngs->bscore_stack = ckd_calloc(ngs->bscore_stack_size,
00181 sizeof(*ngs->bscore_stack));
00182 ngs->n_frame_alloc = 256;
00183 ngs->bp_table_idx = ckd_calloc(ngs->n_frame_alloc + 1,
00184 sizeof(*ngs->bp_table_idx));
00185 ++ngs->bp_table_idx;
00186
00187
00188 ngs->active_word_list = ckd_calloc_2d(2, s3dict_size(dict),
00189 sizeof(**ngs->active_word_list));
00190
00191
00192 if ((path = cmd_ln_str_r(config, "-lmctl"))) {
00193 ngs->lmset = ngram_model_set_read(config, path, acmod->lmath);
00194 if (ngs->lmset == NULL) {
00195 E_ERROR("Failed to read language model control file: %s\n",
00196 path);
00197 goto error_out;
00198 }
00199
00200 if ((path = cmd_ln_str_r(config, "-lmname"))) {
00201 ngram_model_set_select(ngs->lmset, path);
00202 }
00203 }
00204 else if ((path = cmd_ln_str_r(config, "-lm"))) {
00205 static const char *name = "default";
00206 ngram_model_t *lm;
00207
00208 lm = ngram_model_read(config, path, NGRAM_AUTO, acmod->lmath);
00209 if (lm == NULL) {
00210 E_ERROR("Failed to read language model file: %s\n", path);
00211 goto error_out;
00212 }
00213 ngs->lmset = ngram_model_set_init(config,
00214 &lm, (char **)&name,
00215 NULL, 1);
00216 if (ngs->lmset == NULL) {
00217 E_ERROR("Failed to initialize language model set\n");
00218 goto error_out;
00219 }
00220 }
00221
00222
00223 ngram_search_update_widmap(ngs);
00224
00225
00226 if (cmd_ln_boolean_r(config, "-fwdtree")) {
00227 ngram_fwdtree_init(ngs);
00228 ngs->fwdtree = TRUE;
00229 }
00230 if (cmd_ln_boolean_r(config, "-fwdflat")) {
00231 ngram_fwdflat_init(ngs);
00232 ngs->fwdflat = TRUE;
00233 }
00234 if (cmd_ln_boolean_r(config, "-bestpath")) {
00235 ngs->bestpath = TRUE;
00236 }
00237 return (ps_search_t *)ngs;
00238
00239 error_out:
00240 ngram_search_free((ps_search_t *)ngs);
00241 return NULL;
00242 }
00243
00244 static int
00245 ngram_search_reinit(ps_search_t *search)
00246 {
00247 ngram_search_t *ngs = (ngram_search_t *)search;
00248 int rv = 0;
00249
00250
00251
00252
00253
00254
00255
00256 ngram_search_calc_beams(ngs);
00257
00258
00259 ngram_search_update_widmap(ngs);
00260
00261
00262 if (ngs->fwdtree) {
00263 if ((rv = ngram_fwdtree_reinit(ngs)) < 0)
00264 return rv;
00265 }
00266 if (ngs->fwdflat) {
00267 if ((rv = ngram_fwdflat_reinit(ngs)) < 0)
00268 return rv;
00269 }
00270
00271 return rv;
00272 }
00273
00274 void
00275 ngram_search_free(ps_search_t *search)
00276 {
00277 ngram_search_t *ngs = (ngram_search_t *)search;
00278
00279 ps_search_deinit(search);
00280 if (ngs->fwdtree)
00281 ngram_fwdtree_deinit(ngs);
00282 if (ngs->fwdflat)
00283 ngram_fwdflat_deinit(ngs);
00284
00285 hmm_context_free(ngs->hmmctx);
00286 listelem_alloc_free(ngs->chan_alloc);
00287 listelem_alloc_free(ngs->root_chan_alloc);
00288 listelem_alloc_free(ngs->latnode_alloc);
00289 ngram_model_free(ngs->lmset);
00290
00291 ckd_free(ngs->word_chan);
00292 ckd_free(ngs->word_lat_idx);
00293 ckd_free(ngs->zeroPermTab);
00294 bitvec_free(ngs->word_active);
00295 ckd_free(ngs->bp_table);
00296 ckd_free(ngs->bscore_stack);
00297 if (ngs->bp_table_idx != NULL)
00298 ckd_free(ngs->bp_table_idx - 1);
00299 ckd_free_2d(ngs->active_word_list);
00300 ckd_free(ngs->last_ltrans);
00301 ckd_free(ngs);
00302 }
00303
00304 int
00305 ngram_search_mark_bptable(ngram_search_t *ngs, int frame_idx)
00306 {
00307 if (frame_idx >= ngs->n_frame_alloc) {
00308 ngs->n_frame_alloc *= 2;
00309 ngs->bp_table_idx = ckd_realloc(ngs->bp_table_idx - 1,
00310 (ngs->n_frame_alloc + 1)
00311 * sizeof(*ngs->bp_table_idx));
00312 if (ngs->frm_wordlist) {
00313 ngs->frm_wordlist = ckd_realloc(ngs->frm_wordlist,
00314 ngs->n_frame_alloc
00315 * sizeof(*ngs->frm_wordlist));
00316 }
00317 ++ngs->bp_table_idx;
00318 }
00319 ngs->bp_table_idx[frame_idx] = ngs->bpidx;
00320 return ngs->bpidx;
00321 }
00322
00326 static void
00327 cache_bptable_paths(ngram_search_t *ngs, int32 bp)
00328 {
00329 int32 w, prev_bp;
00330 bptbl_t *be;
00331
00332 be = &(ngs->bp_table[bp]);
00333 prev_bp = bp;
00334 w = be->wid;
00335
00336 while (s3dict_filler_word(ps_search_dict(ngs), w)) {
00337 prev_bp = ngs->bp_table[prev_bp].bp;
00338 w = ngs->bp_table[prev_bp].wid;
00339 }
00340
00341 be->real_wid = s3dict_basewid(ps_search_dict(ngs), w);
00342
00343 prev_bp = ngs->bp_table[prev_bp].bp;
00344 be->prev_real_wid =
00345 (prev_bp != NO_BP) ? ngs->bp_table[prev_bp].real_wid : -1;
00346 }
00347
00348 void
00349 ngram_search_save_bp(ngram_search_t *ngs, int frame_idx,
00350 int32 w, int32 score, int32 path, int32 rc)
00351 {
00352 int32 _bp_;
00353
00354
00355 _bp_ = ngs->word_lat_idx[w];
00356 if (_bp_ != NO_BP) {
00357
00358
00359 if (ngs->bp_table[_bp_].score WORSE_THAN score) {
00360 if (ngs->bp_table[_bp_].bp != path) {
00361 ngs->bp_table[_bp_].bp = path;
00362 cache_bptable_paths(ngs, _bp_);
00363 }
00364 ngs->bp_table[_bp_].score = score;
00365 }
00366
00367
00368
00369 ngs->bscore_stack[ngs->bp_table[_bp_].s_idx + rc] = score;
00370 }
00371 else {
00372 int32 i, rcsize, *bss;
00373 bptbl_t *be;
00374
00375
00376 if (ngs->bpidx >= ngs->bp_table_size) {
00377 ngs->bp_table_size *= 2;
00378 ngs->bp_table = ckd_realloc(ngs->bp_table,
00379 ngs->bp_table_size
00380 * sizeof(*ngs->bp_table));
00381 E_INFO("Resized backpointer table to %d entries\n", ngs->bp_table_size);
00382 }
00383 if (ngs->bss_head >= ngs->bscore_stack_size
00384 - bin_mdef_n_ciphone(ps_search_acmod(ngs)->mdef)) {
00385 ngs->bscore_stack_size *= 2;
00386 ngs->bscore_stack = ckd_realloc(ngs->bscore_stack,
00387 ngs->bscore_stack_size
00388 * sizeof(*ngs->bscore_stack));
00389 E_INFO("Resized score stack to %d entries\n", ngs->bscore_stack_size);
00390 }
00391
00392 ngs->word_lat_idx[w] = ngs->bpidx;
00393 be = &(ngs->bp_table[ngs->bpidx]);
00394 be->wid = w;
00395 be->frame = frame_idx;
00396 be->bp = path;
00397 be->score = score;
00398 be->s_idx = ngs->bss_head;
00399 be->valid = TRUE;
00400
00401
00402
00403 be->last_phone = s3dict_last_phone(ps_search_dict(ngs),w);
00404 if (s3dict_pronlen(ps_search_dict(ngs), w) != 1) {
00405 be->last2_phone = s3dict_second_last_phone(ps_search_dict(ngs),w);
00406 rcsize = dict2pid_rssid(ps_search_dict2pid(ngs),
00407 be->last_phone, be->last2_phone)->n_ssid;
00408 }
00409 else {
00410 be->last2_phone = -1;
00411 rcsize = 1;
00412 }
00413
00414 for (i = rcsize, bss = ngs->bscore_stack + ngs->bss_head; i > 0; --i, bss++)
00415 *bss = WORST_SCORE;
00416 ngs->bscore_stack[ngs->bss_head + rc] = score;
00417 cache_bptable_paths(ngs, ngs->bpidx);
00418
00419 ngs->bpidx++;
00420 ngs->bss_head += rcsize;
00421 }
00422 }
00423
00424 int
00425 ngram_search_find_exit(ngram_search_t *ngs, int frame_idx, int32 *out_best_score)
00426 {
00427
00428 int end_bpidx;
00429 int best_exit, bp;
00430 int32 best_score;
00431
00432
00433 if (ngs->n_frame == 0)
00434 return NO_BP;
00435
00436 if (frame_idx == -1 || frame_idx >= ngs->n_frame)
00437 frame_idx = ngs->n_frame - 1;
00438 end_bpidx = ngs->bp_table_idx[frame_idx];
00439
00440 best_score = WORST_SCORE;
00441 best_exit = NO_BP;
00442
00443
00444 while (frame_idx >= 0 && ngs->bp_table_idx[frame_idx] == end_bpidx)
00445 --frame_idx;
00446
00447 if (frame_idx < 0)
00448 return NO_BP;
00449
00450
00451 assert(end_bpidx < ngs->bp_table_size);
00452 for (bp = ngs->bp_table_idx[frame_idx]; bp < end_bpidx; ++bp) {
00453 if (ngs->bp_table[bp].wid == ps_search_finish_wid(ngs)
00454 || ngs->bp_table[bp].score BETTER_THAN best_score) {
00455 best_score = ngs->bp_table[bp].score;
00456 best_exit = bp;
00457 }
00458 if (ngs->bp_table[bp].wid == ps_search_finish_wid(ngs))
00459 break;
00460 }
00461
00462 if (out_best_score) *out_best_score = best_score;
00463 return best_exit;
00464 }
00465
00466 char const *
00467 ngram_search_bp_hyp(ngram_search_t *ngs, int bpidx)
00468 {
00469 ps_search_t *base = ps_search_base(ngs);
00470 char *c;
00471 size_t len;
00472 int bp;
00473
00474 if (bpidx == NO_BP)
00475 return NULL;
00476
00477 bp = bpidx;
00478 len = 0;
00479 while (bp != NO_BP) {
00480 bptbl_t *be = &ngs->bp_table[bp];
00481 bp = be->bp;
00482 if (s3dict_real_word(ps_search_dict(ngs), be->wid))
00483 len += strlen(s3dict_basestr(ps_search_dict(ngs), be->wid)) + 1;
00484 }
00485
00486 ckd_free(base->hyp_str);
00487 base->hyp_str = ckd_calloc(1, len);
00488 bp = bpidx;
00489 c = base->hyp_str + len - 1;
00490 while (bp != NO_BP) {
00491 bptbl_t *be = &ngs->bp_table[bp];
00492 size_t len;
00493
00494 bp = be->bp;
00495 if (s3dict_real_word(ps_search_dict(ngs), be->wid)) {
00496 len = strlen(s3dict_basestr(ps_search_dict(ngs), be->wid));
00497 c -= len;
00498 memcpy(c, s3dict_basestr(ps_search_dict(ngs), be->wid), len);
00499 if (c > base->hyp_str) {
00500 --c;
00501 *c = ' ';
00502 }
00503 }
00504 }
00505
00506 return base->hyp_str;
00507 }
00508
00509 void
00510 ngram_search_alloc_all_rc(ngram_search_t *ngs, int32 w)
00511 {
00512 chan_t *hmm, *thmm;
00513 xwdssid_t *rssid;
00514 int32 i;
00515
00516
00517
00518 assert(s3dict_pronlen(ps_search_dict(ngs), w) > 1);
00519 rssid = dict2pid_rssid(ps_search_dict2pid(ngs),
00520 s3dict_last_phone(ps_search_dict(ngs),w),
00521 s3dict_second_last_phone(ps_search_dict(ngs),w));
00522 hmm = ngs->word_chan[w];
00523 if ((hmm == NULL) || (hmm_nonmpx_ssid(&hmm->hmm) != rssid->ssid[0])) {
00524 hmm = listelem_malloc(ngs->chan_alloc);
00525 hmm->next = ngs->word_chan[w];
00526 ngs->word_chan[w] = hmm;
00527
00528 hmm->info.rc_id = 0;
00529 hmm->ciphone = s3dict_last_phone(ps_search_dict(ngs),w);
00530 hmm_init(ngs->hmmctx, &hmm->hmm, FALSE, rssid->ssid[0], hmm->ciphone);
00531 E_DEBUG(3,("allocated rc_id 0 ssid %d ciphone %d lc %d word %s\n",
00532 rssid->ssid[0], hmm->ciphone,
00533 s3dict_second_last_phone(ps_search_dict(ngs),w),
00534 s3dict_wordstr(ps_search_dict(ngs),w)));
00535 }
00536 for (i = 1; i < rssid->n_ssid; ++i) {
00537 if ((hmm->next == NULL) || (hmm_nonmpx_ssid(&hmm->next->hmm) != rssid->ssid[i])) {
00538 thmm = listelem_malloc(ngs->chan_alloc);
00539 thmm->next = hmm->next;
00540 hmm->next = thmm;
00541 hmm = thmm;
00542
00543 hmm->info.rc_id = i;
00544 hmm->ciphone = s3dict_last_phone(ps_search_dict(ngs),w);
00545 hmm_init(ngs->hmmctx, &hmm->hmm, FALSE, rssid->ssid[i], hmm->ciphone);
00546 E_DEBUG(3,("allocated rc_id %d ssid %d ciphone %d lc %d word %s\n",
00547 i, rssid->ssid[i], hmm->ciphone,
00548 s3dict_second_last_phone(ps_search_dict(ngs),w),
00549 s3dict_wordstr(ps_search_dict(ngs),w)));
00550 }
00551 else
00552 hmm = hmm->next;
00553 }
00554 }
00555
00556 void
00557 ngram_search_free_all_rc(ngram_search_t *ngs, int32 w)
00558 {
00559 chan_t *hmm, *thmm;
00560
00561 for (hmm = ngs->word_chan[w]; hmm; hmm = thmm) {
00562 thmm = hmm->next;
00563 hmm_deinit(&hmm->hmm);
00564 listelem_free(ngs->chan_alloc, hmm);
00565 }
00566 ngs->word_chan[w] = NULL;
00567 }
00568
00569 int32
00570 ngram_search_exit_score(ngram_search_t *ngs, bptbl_t *pbe, int rcphone)
00571 {
00572
00573
00574
00575 if (pbe->last2_phone == -1) {
00576
00577 return ngs->bscore_stack[pbe->s_idx];
00578 }
00579 else {
00580 xwdssid_t *rssid;
00581
00582
00583 rssid = dict2pid_rssid(ps_search_dict2pid(ngs),
00584 pbe->last_phone, pbe->last2_phone);
00585 return ngs->bscore_stack[pbe->s_idx + rssid->cimap[rcphone]];
00586 }
00587 }
00588
00589
00590
00591
00592 void
00593 ngram_compute_seg_score(ngram_search_t *ngs, bptbl_t *be, float32 lwf,
00594 int32 *out_ascr, int32 *out_lscr)
00595 {
00596 bptbl_t *pbe;
00597 int32 start_score;
00598
00599
00600 if (be->bp == NO_BP) {
00601 *out_ascr = be->score;
00602 *out_lscr = 0;
00603 return;
00604 }
00605
00606
00607 pbe = ngs->bp_table + be->bp;
00608 start_score = ngram_search_exit_score(ngs, pbe,
00609 s3dict_first_phone(ps_search_dict(ngs),be->wid));
00610
00611
00612
00613
00614
00615 if (start_score == WORST_SCORE)
00616 start_score = 0;
00617
00618
00619
00620
00621
00622 if (be->wid == ps_search_silence_wid(ngs)) {
00623 *out_lscr = ngs->silpen;
00624 }
00625 else if (s3dict_filler_word(ps_search_dict(ngs), be->wid)) {
00626 *out_lscr = ngs->fillpen;
00627 }
00628 else {
00629 int32 n_used;
00630 *out_lscr = ngram_tg_score(ngs->lmset,
00631 be->real_wid,
00632 pbe->real_wid,
00633 pbe->prev_real_wid, &n_used);
00634 *out_lscr = *out_lscr * lwf;
00635 }
00636 *out_ascr = be->score - start_score - *out_lscr;
00637 }
00638
00639 static int
00640 ngram_search_start(ps_search_t *search)
00641 {
00642 ngram_search_t *ngs = (ngram_search_t *)search;
00643
00644 ngs->done = FALSE;
00645 ngram_model_flush(ngs->lmset);
00646 if (ngs->fwdtree)
00647 ngram_fwdtree_start(ngs);
00648 else if (ngs->fwdflat)
00649 ngram_fwdflat_start(ngs);
00650 else
00651 return -1;
00652 return 0;
00653 }
00654
00655 static int
00656 ngram_search_step(ps_search_t *search, int frame_idx)
00657 {
00658 ngram_search_t *ngs = (ngram_search_t *)search;
00659
00660 if (ngs->fwdtree)
00661 return ngram_fwdtree_search(ngs, frame_idx);
00662 else if (ngs->fwdflat)
00663 return ngram_fwdflat_search(ngs, frame_idx);
00664 else
00665 return -1;
00666 }
00667
00668 static void
00669 dump_bptable(ngram_search_t *ngs)
00670 {
00671 int i;
00672 E_INFO("Backpointer table (%d entries):\n", ngs->bpidx);
00673 for (i = 0; i < ngs->bpidx; ++i) {
00674 E_INFO_NOFN("%-5d %-10s start %-3d end %-3d score %-8d bp\n",
00675 i, s3dict_wordstr(ps_search_dict(ngs), ngs->bp_table[i].wid),
00676 ngs->bp_table[i].bp == -1 ? 0 :
00677 ngs->bp_table[ngs->bp_table[i].bp].frame + 1,
00678 ngs->bp_table[i].frame,
00679 ngs->bp_table[i].score,
00680 ngs->bp_table[i].bp);
00681
00682 }
00683 }
00684
00685 static int
00686 ngram_search_finish(ps_search_t *search)
00687 {
00688 ngram_search_t *ngs = (ngram_search_t *)search;
00689
00690 if (ngs->fwdtree) {
00691 ngram_fwdtree_finish(ngs);
00692
00693
00694
00695 if (ngs->fwdflat) {
00696 int i;
00697
00698 if (acmod_rewind(ps_search_acmod(ngs)) < 0)
00699 return -1;
00700
00701 ngram_fwdflat_start(ngs);
00702 i = 0;
00703 while (ps_search_acmod(ngs)->n_feat_frame > 0) {
00704 int nfr;
00705 if ((nfr = ngram_fwdflat_search(ngs, i)) < 0)
00706 return nfr;
00707 acmod_advance(ps_search_acmod(ngs));
00708 ++i;
00709 }
00710 ngram_fwdflat_finish(ngs);
00711
00712
00713 }
00714 }
00715 else if (ngs->fwdflat) {
00716 ngram_fwdflat_finish(ngs);
00717 }
00718
00719
00720 ngs->done = TRUE;
00721 return 0;
00722 }
00723
00724 static ps_latlink_t *
00725 ngram_search_bestpath(ps_search_t *search, int32 *out_score, int backward)
00726 {
00727 ngram_search_t *ngs = (ngram_search_t *)search;
00728
00729 if (search->last_link == NULL) {
00730 search->last_link = ps_lattice_bestpath(search->dag, ngs->lmset,
00731 ngs->bestpath_fwdtree_lw_ratio,
00732 ngs->ascale);
00733 if (search->last_link == NULL)
00734 return NULL;
00735
00736
00737 if (search->post == 0)
00738 search->post = ps_lattice_posterior(search->dag, ngs->lmset,
00739 ngs->ascale);
00740 }
00741 if (out_score)
00742 *out_score = search->last_link->path_scr + search->dag->final_node_ascr;
00743 return search->last_link;
00744 }
00745
00746 static char const *
00747 ngram_search_hyp(ps_search_t *search, int32 *out_score)
00748 {
00749 ngram_search_t *ngs = (ngram_search_t *)search;
00750
00751
00752 if (ngs->bestpath && ngs->done) {
00753 ps_lattice_t *dag;
00754 ps_latlink_t *link;
00755
00756 if ((dag = ngram_search_lattice(search)) == NULL)
00757 return NULL;
00758 if ((link = ngram_search_bestpath(search, out_score, FALSE)) == NULL)
00759 return NULL;
00760 return ps_lattice_hyp(dag, link);
00761 }
00762 else {
00763 int32 bpidx;
00764
00765
00766 bpidx = ngram_search_find_exit(ngs, -1, out_score);
00767 if (bpidx != NO_BP)
00768 return ngram_search_bp_hyp(ngs, bpidx);
00769 }
00770
00771 return NULL;
00772 }
00773
00774 static void
00775 ngram_search_bp2itor(ps_seg_t *seg, int bp)
00776 {
00777 ngram_search_t *ngs = (ngram_search_t *)seg->search;
00778 bptbl_t *be, *pbe;
00779
00780 be = &ngs->bp_table[bp];
00781 pbe = be->bp == -1 ? NULL : &ngs->bp_table[be->bp];
00782 seg->word = s3dict_wordstr(ps_search_dict(ngs), be->wid);
00783 seg->ef = be->frame;
00784 seg->sf = pbe ? pbe->frame + 1 : 0;
00785 seg->prob = 0;
00786
00787 if (pbe == NULL) {
00788 seg->ascr = be->score;
00789 seg->lscr = 0;
00790 seg->lback = 0;
00791 }
00792 else {
00793 int32 start_score;
00794
00795
00796 start_score = ngram_search_exit_score(ngs, pbe,
00797 s3dict_first_phone(ps_search_dict(ngs), be->wid));
00798 if (be->wid == ps_search_silence_wid(ngs)) {
00799 seg->lscr = ngs->silpen;
00800 }
00801 else if (s3dict_filler_word(ps_search_dict(ngs), be->wid)) {
00802 seg->lscr = ngs->fillpen;
00803 }
00804 else {
00805 seg->lscr = ngram_tg_score(ngs->lmset,
00806 be->real_wid,
00807 pbe->real_wid,
00808 pbe->prev_real_wid, &seg->lback);
00809 seg->lscr = (int32)(seg->lscr * seg->lwf);
00810 }
00811 seg->ascr = be->score - start_score - seg->lscr;
00812 }
00813 }
00814
00815 static void
00816 ngram_bp_seg_free(ps_seg_t *seg)
00817 {
00818 bptbl_seg_t *itor = (bptbl_seg_t *)seg;
00819
00820 ckd_free(itor->bpidx);
00821 ckd_free(itor);
00822 }
00823
00824 static ps_seg_t *
00825 ngram_bp_seg_next(ps_seg_t *seg)
00826 {
00827 bptbl_seg_t *itor = (bptbl_seg_t *)seg;
00828
00829 if (++itor->cur == itor->n_bpidx) {
00830 ngram_bp_seg_free(seg);
00831 return NULL;
00832 }
00833
00834 ngram_search_bp2itor(seg, itor->bpidx[itor->cur]);
00835 return seg;
00836 }
00837
00838 static ps_segfuncs_t ngram_bp_segfuncs = {
00839 ngram_bp_seg_next,
00840 ngram_bp_seg_free
00841 };
00842
00843 static ps_seg_t *
00844 ngram_search_bp_iter(ngram_search_t *ngs, int bpidx, float32 lwf)
00845 {
00846 bptbl_seg_t *itor;
00847 int bp, cur;
00848
00849
00850
00851
00852
00853 itor = ckd_calloc(1, sizeof(*itor));
00854 itor->base.vt = &ngram_bp_segfuncs;
00855 itor->base.search = ps_search_base(ngs);
00856 itor->base.lwf = lwf;
00857 itor->n_bpidx = 0;
00858 bp = bpidx;
00859 while (bp != NO_BP) {
00860 bptbl_t *be = &ngs->bp_table[bp];
00861 bp = be->bp;
00862 ++itor->n_bpidx;
00863 }
00864 if (itor->n_bpidx == 0) {
00865 ckd_free(itor);
00866 return NULL;
00867 }
00868 itor->bpidx = ckd_calloc(itor->n_bpidx, sizeof(*itor->bpidx));
00869 cur = itor->n_bpidx - 1;
00870 bp = bpidx;
00871 while (bp != NO_BP) {
00872 bptbl_t *be = &ngs->bp_table[bp];
00873 itor->bpidx[cur] = bp;
00874 bp = be->bp;
00875 --cur;
00876 }
00877
00878
00879 ngram_search_bp2itor((ps_seg_t *)itor, itor->bpidx[0]);
00880
00881 return (ps_seg_t *)itor;
00882 }
00883
00884 static ps_seg_t *
00885 ngram_search_seg_iter(ps_search_t *search, int32 *out_score)
00886 {
00887 ngram_search_t *ngs = (ngram_search_t *)search;
00888
00889
00890 if (ngs->bestpath && ngs->done) {
00891 ps_lattice_t *dag;
00892 ps_latlink_t *link;
00893
00894 if ((dag = ngram_search_lattice(search)) == NULL)
00895 return NULL;
00896 if ((link = ngram_search_bestpath(search, out_score, TRUE)) == NULL)
00897 return NULL;
00898 return ps_lattice_seg_iter(dag, link,
00899 ngs->bestpath_fwdtree_lw_ratio);
00900 }
00901 else {
00902 int32 bpidx;
00903
00904
00905 bpidx = ngram_search_find_exit(ngs, -1, out_score);
00906 return ngram_search_bp_iter(ngs, bpidx,
00907
00908 (ngs->done && ngs->fwdflat)
00909 ? ngs->fwdflat_fwdtree_lw_ratio : 1.0);
00910 }
00911
00912 return NULL;
00913 }
00914
00915 static int32
00916 ngram_search_prob(ps_search_t *search)
00917 {
00918 ngram_search_t *ngs = (ngram_search_t *)search;
00919
00920
00921 if (ngs->bestpath && ngs->done) {
00922 ps_lattice_t *dag;
00923 ps_latlink_t *link;
00924
00925 if ((dag = ngram_search_lattice(search)) == NULL)
00926 return 0;
00927 if ((link = ngram_search_bestpath(search, NULL, TRUE)) == NULL)
00928 return 0;
00929 return search->post;
00930 }
00931 else {
00932
00933 return 0;
00934 }
00935 }
00936
00937 static void
00938 create_dag_nodes(ngram_search_t *ngs, ps_lattice_t *dag)
00939 {
00940 bptbl_t *bp_ptr;
00941 int32 i;
00942
00943 for (i = 0, bp_ptr = ngs->bp_table; i < ngs->bpidx; ++i, ++bp_ptr) {
00944 int32 sf, ef, wid;
00945 ps_latnode_t *node;
00946
00947
00948 if (!bp_ptr->valid)
00949 continue;
00950
00951 sf = (bp_ptr->bp < 0) ? 0 : ngs->bp_table[bp_ptr->bp].frame + 1;
00952 ef = bp_ptr->frame;
00953 wid = bp_ptr->wid;
00954
00955 assert(ef < dag->n_frames);
00956
00957 if ((wid == ps_search_finish_wid(ngs)) && (ef < dag->n_frames - 1))
00958 continue;
00959
00960
00961 if ((!s3dict_filler_word(ps_search_dict(ngs), wid))
00962 && (!ngram_model_set_known_wid(ngs->lmset,
00963 s3dict_basewid(ps_search_dict(ngs), wid))))
00964 continue;
00965
00966
00967 for (node = dag->nodes; node; node = node->next) {
00968 if ((node->wid == wid) && (node->sf == sf))
00969 break;
00970 }
00971
00972
00973 if (node)
00974 node->lef = i;
00975 else {
00976
00977 node = listelem_malloc(dag->latnode_alloc);
00978 node->wid = wid;
00979 node->sf = sf;
00980 node->fef = node->lef = i;
00981 node->reachable = FALSE;
00982 node->entries = NULL;
00983 node->exits = NULL;
00984
00985 node->next = dag->nodes;
00986 dag->nodes = node;
00987 }
00988 }
00989 }
00990
00991 static ps_latnode_t *
00992 find_start_node(ngram_search_t *ngs, ps_lattice_t *dag)
00993 {
00994 ps_latnode_t *node;
00995
00996
00997 for (node = dag->nodes; node; node = node->next) {
00998 if ((node->wid == ps_search_start_wid(ngs)) && (node->sf == 0))
00999 break;
01000 }
01001 if (!node) {
01002
01003 E_ERROR("Couldn't find <s> in first frame\n");
01004 return NULL;
01005 }
01006 return node;
01007 }
01008
01009 static ps_latnode_t *
01010 find_end_node(ngram_search_t *ngs, ps_lattice_t *dag, float32 lwf)
01011 {
01012 ps_latnode_t *node;
01013 int32 ef, bestbp, bp, bestscore;
01014
01015
01016 for (node = dag->nodes; node; node = node->next) {
01017 int32 lef = ngs->bp_table[node->lef].frame;
01018 if ((node->wid == ps_search_finish_wid(ngs))
01019 && (lef == dag->n_frames - 1))
01020 break;
01021 }
01022 if (node != NULL)
01023 return node;
01024
01025
01026
01027
01028 for (ef = dag->n_frames - 1;
01029 ef >= 0 && ngs->bp_table_idx[ef] == ngs->bpidx;
01030 --ef);
01031 if (ef < 0) {
01032 E_ERROR("Empty backpointer table: can not build DAG.\n");
01033 return NULL;
01034 }
01035
01036
01037 bestscore = WORST_SCORE;
01038 bestbp = NO_BP;
01039 for (bp = ngs->bp_table_idx[ef]; bp < ngs->bp_table_idx[ef + 1]; ++bp) {
01040 int32 n_used, l_scr;
01041 l_scr = ngram_tg_score(ngs->lmset, ps_search_finish_wid(ngs),
01042 ngs->bp_table[bp].real_wid,
01043 ngs->bp_table[bp].prev_real_wid,
01044 &n_used);
01045 l_scr = l_scr * lwf;
01046
01047 if (ngs->bp_table[bp].score + l_scr BETTER_THAN bestscore) {
01048 bestscore = ngs->bp_table[bp].score + l_scr;
01049 bestbp = bp;
01050 }
01051 }
01052 if (bestbp == NO_BP) {
01053 E_ERROR("No word exits found in last frame, assuming no recognition\n");
01054 return NULL;
01055 }
01056 E_WARN("</s> not found in last frame, using %s instead\n",
01057 s3dict_basestr(ps_search_dict(ngs), ngs->bp_table[bestbp].wid));
01058
01059
01060 for (node = dag->nodes; node; node = node->next) {
01061 if (node->lef == bestbp)
01062 return node;
01063 }
01064
01065
01066 E_ERROR("Failed to find DAG node corresponding to %s\n",
01067 s3dict_basestr(ps_search_dict(ngs), ngs->bp_table[bestbp].wid));
01068 return NULL;
01069 }
01070
01071
01072
01073
01074 ps_lattice_t *
01075 ngram_search_lattice(ps_search_t *search)
01076 {
01077 int32 i, ef, lef, score, ascr, lscr;
01078 ps_latnode_t *node, *from, *to;
01079 ngram_search_t *ngs;
01080 ps_lattice_t *dag;
01081 float lwf;
01082
01083 ngs = (ngram_search_t *)search;
01084
01085
01086
01087 if (search->dag && search->dag->n_frames == ngs->n_frame)
01088 return search->dag;
01089
01090
01091 ps_lattice_free(search->dag);
01092 search->dag = NULL;
01093 dag = ps_lattice_init_search(search, ngs->n_frame);
01094
01095 lwf = ngs->fwdflat ? ngs->fwdflat_fwdtree_lw_ratio : 1.0;
01096 create_dag_nodes(ngs, dag);
01097 if ((dag->start = find_start_node(ngs, dag)) == NULL)
01098 goto error_out;
01099 if ((dag->end = find_end_node(ngs, dag, ngs->bestpath_fwdtree_lw_ratio)) == NULL)
01100 goto error_out;
01101 E_INFO("lattice start node %s.%d end node %s.%d\n",
01102 s3dict_wordstr(search->dict, dag->start->wid), dag->start->sf,
01103 s3dict_wordstr(search->dict, dag->end->wid), dag->end->sf);
01104
01105 ngram_compute_seg_score(ngs, ngs->bp_table + dag->end->lef, lwf,
01106 &dag->final_node_ascr, &lscr);
01107
01108
01109
01110
01111
01112
01113
01114
01115 dag->end->reachable = TRUE;
01116 for (to = dag->end; to; to = to->next) {
01117
01118 if (!to->reachable)
01119 continue;
01120
01121
01122 for (from = to->next; from; from = from->next) {
01123 bptbl_t *bp_ptr;
01124
01125 ef = ngs->bp_table[from->fef].frame;
01126 lef = ngs->bp_table[from->lef].frame;
01127
01128 if ((to->sf <= ef) || (to->sf > lef + 1))
01129 continue;
01130
01131
01132 i = from->fef;
01133 bp_ptr = ngs->bp_table + i;
01134 for (; i <= from->lef; i++, bp_ptr++) {
01135 if (bp_ptr->wid != from->wid)
01136 continue;
01137 if (bp_ptr->frame >= to->sf - 1)
01138 break;
01139 }
01140
01141 if ((i > from->lef) || (bp_ptr->frame != to->sf - 1))
01142 continue;
01143
01144
01145 ngram_compute_seg_score(ngs, bp_ptr, lwf,
01146 &ascr, &lscr);
01147
01148 score = (ngram_search_exit_score(ngs, bp_ptr,
01149 s3dict_first_phone(ps_search_dict(ngs), to->wid))
01150 - bp_ptr->score + ascr);
01151 if (score BETTER_THAN 0) {
01152
01153
01154
01155
01156
01157 ps_lattice_link(dag, from, to, -424242, bp_ptr->frame);
01158 from->reachable = TRUE;
01159 }
01160 else if (score BETTER_THAN WORST_SCORE) {
01161 ps_lattice_link(dag, from, to, score, bp_ptr->frame);
01162 from->reachable = TRUE;
01163 }
01164 }
01165 }
01166
01167
01168 if (!dag->start->reachable) {
01169 E_ERROR("End node of lattice isolated; unreachable\n");
01170 goto error_out;
01171 }
01172
01173 for (node = dag->nodes; node; node = node->next) {
01174
01175 node->fef = ngs->bp_table[node->fef].frame;
01176 node->lef = ngs->bp_table[node->lef].frame;
01177
01178 node->basewid = s3dict_basewid(search->dict, node->wid);
01179 }
01180
01181
01182 for (node = dag->nodes; node; node = node->next) {
01183 ps_latnode_t *alt;
01184
01185 for (alt = node->next; alt && alt->sf == node->sf; alt = alt->next) {
01186 if (alt->basewid == node->basewid) {
01187 alt->alt = node->alt;
01188 node->alt = alt;
01189 break;
01190 }
01191 }
01192 }
01193
01194
01195
01196
01197 if (s3dict_filler_word(ps_search_dict(ngs), dag->end->wid))
01198 dag->end->basewid = ps_search_finish_wid(ngs);
01199
01200
01201 ps_lattice_delete_unreachable(dag);
01202
01203
01204
01205 ps_lattice_bypass_fillers(dag, ngs->silpen, ngs->fillpen);
01206
01207 search->dag = dag;
01208 return dag;
01209
01210 error_out:
01211 ps_lattice_free(dag);
01212 return NULL;
01213 }