47 #include <sphinxbase/ckd_alloc.h>
48 #include <sphinxbase/listelem_alloc.h>
49 #include <sphinxbase/err.h>
59 static int ngram_search_step(
ps_search_t *search,
int frame_idx);
60 static int ngram_search_finish(
ps_search_t *search);
62 static char const *ngram_search_hyp(
ps_search_t *search, int32 *out_score);
63 static int32 ngram_search_prob(
ps_search_t *search);
76 ngram_search_seg_iter,
86 n_words = ps_search_n_words(ngs);
87 words = ckd_calloc(n_words,
sizeof(*words));
89 for (i = 0; i < n_words; ++i)
90 words[i] = (
const char *)dict_wordstr(ps_search_dict(ngs), i);
91 ngram_model_set_map_words(ngs->
lmset, words, n_words);
101 config = ps_search_config(ngs);
102 acmod = ps_search_acmod(ngs);
105 ngs->beam = logmath_log(acmod->
lmath, cmd_ln_float64_r(config,
"-beam"))>>
SENSCR_SHIFT;
106 ngs->wbeam = logmath_log(acmod->
lmath, cmd_ln_float64_r(config,
"-wbeam"))>>
SENSCR_SHIFT;
107 ngs->pbeam = logmath_log(acmod->
lmath, cmd_ln_float64_r(config,
"-pbeam"))>>
SENSCR_SHIFT;
108 ngs->lpbeam = logmath_log(acmod->
lmath, cmd_ln_float64_r(config,
"-lpbeam"))>>
SENSCR_SHIFT;
109 ngs->lponlybeam = logmath_log(acmod->
lmath, cmd_ln_float64_r(config,
"-lponlybeam"))>>
SENSCR_SHIFT;
110 ngs->fwdflatbeam = logmath_log(acmod->
lmath, cmd_ln_float64_r(config,
"-fwdflatbeam"))>>
SENSCR_SHIFT;
111 ngs->fwdflatwbeam = logmath_log(acmod->
lmath, cmd_ln_float64_r(config,
"-fwdflatwbeam"))>>
SENSCR_SHIFT;
114 ngs->maxwpf = cmd_ln_int32_r(config,
"-maxwpf");
115 ngs->maxhmmpf = cmd_ln_int32_r(config,
"-maxhmmpf");
118 ngs->wip = logmath_log(acmod->
lmath, cmd_ln_float32_r(config,
"-wip")) >>
SENSCR_SHIFT;
119 ngs->nwpen = logmath_log(acmod->
lmath, cmd_ln_float32_r(config,
"-nwpen")) >>
SENSCR_SHIFT;
120 ngs->pip = logmath_log(acmod->
lmath, cmd_ln_float32_r(config,
"-pip")) >>
SENSCR_SHIFT;
121 ngs->silpen = ngs->pip
122 + (logmath_log(acmod->
lmath, cmd_ln_float32_r(config,
"-silprob"))>>
SENSCR_SHIFT);
123 ngs->fillpen = ngs->pip
124 + (logmath_log(acmod->
lmath, cmd_ln_float32_r(config,
"-fillprob"))>>
SENSCR_SHIFT);
127 ngs->fwdflat_fwdtree_lw_ratio =
128 cmd_ln_float32_r(config,
"-fwdflatlw")
129 / cmd_ln_float32_r(config,
"-lw");
130 ngs->bestpath_fwdtree_lw_ratio =
131 cmd_ln_float32_r(config,
"-bestpathlw")
132 / cmd_ln_float32_r(config,
"-lw");
135 ngs->
ascale = 1.0 / cmd_ln_float32_r(config,
"-ascale");
147 ngs = ckd_calloc(1,
sizeof(*ngs));
148 ps_search_init(&ngs->base, &ngram_funcs, config, acmod, dict, d2p);
149 ngs->
hmmctx = hmm_context_init(bin_mdef_n_emit_state(acmod->
mdef),
151 if (ngs->
hmmctx == NULL) {
152 ps_search_free(ps_search_base(ngs));
160 ngram_search_calc_beams(ngs);
165 ngs->word_lat_idx = ckd_calloc(
dict_size(dict),
166 sizeof(*ngs->word_lat_idx));
168 ngs->last_ltrans = ckd_calloc(
dict_size(dict),
169 sizeof(*ngs->last_ltrans));
173 ngs->bp_table_size = cmd_ln_int32_r(config,
"-latsize");
174 ngs->bp_table = ckd_calloc(ngs->bp_table_size,
175 sizeof(*ngs->bp_table));
177 ngs->bscore_stack_size = ngs->bp_table_size * 20;
178 ngs->bscore_stack = ckd_calloc(ngs->bscore_stack_size,
179 sizeof(*ngs->bscore_stack));
182 sizeof(*ngs->bp_table_idx));
190 if ((path = cmd_ln_str_r(config,
"-lmctl"))) {
191 ngs->
lmset = ngram_model_set_read(config, path, acmod->
lmath);
192 if (ngs->
lmset == NULL) {
193 E_ERROR(
"Failed to read language model control file: %s\n",
198 if ((path = cmd_ln_str_r(config,
"-lmname"))) {
199 ngram_model_set_select(ngs->
lmset, path);
202 else if ((path = cmd_ln_str_r(config,
"-lm"))) {
203 static const char *name =
"default";
206 lm = ngram_model_read(config, path, NGRAM_AUTO, acmod->
lmath);
208 E_ERROR(
"Failed to read language model file: %s\n", path);
211 ngs->
lmset = ngram_model_set_init(config,
214 if (ngs->
lmset == NULL) {
215 E_ERROR(
"Failed to initialize language model set\n");
219 if (ngs->
lmset != NULL
220 && ngram_wid(ngs->
lmset, S3_FINISH_WORD) == ngram_unknown_wid(ngs->
lmset)) {
221 E_ERROR(
"Language model/set does not contain </s>, recognition will fail\n");
226 ngram_search_update_widmap(ngs);
229 if (cmd_ln_boolean_r(config,
"-fwdtree")) {
232 ngs->fwdtree_perf.name =
"fwdtree";
233 ptmr_init(&ngs->fwdtree_perf);
235 if (cmd_ln_boolean_r(config,
"-fwdflat")) {
238 ngs->fwdflat_perf.name =
"fwdflat";
239 ptmr_init(&ngs->fwdflat_perf);
241 if (cmd_ln_boolean_r(config,
"-bestpath")) {
242 ngs->bestpath = TRUE;
243 ngs->bestpath_perf.name =
"bestpath";
244 ptmr_init(&ngs->bestpath_perf);
266 ckd_free(ngs->word_lat_idx);
268 ckd_free(ngs->last_ltrans);
270 ngs->word_lat_idx = ckd_calloc(search->
n_words,
sizeof(*ngs->word_lat_idx));
272 ngs->last_ltrans = ckd_calloc(search->
n_words,
sizeof(*ngs->last_ltrans));
274 = ckd_calloc_2d(2, search->
n_words,
279 ps_search_base_reinit(search, dict, d2p);
281 if (ngs->
lmset == NULL)
285 ngram_search_calc_beams(ngs);
288 ngram_search_update_widmap(ngs);
308 ps_search_deinit(search);
314 double n_speech = (double)ngs->n_tot_frame
315 / cmd_ln_int32_r(ps_search_config(ngs),
"-frate");
317 E_INFO(
"TOTAL bestpath %.2f CPU %.3f xRT\n",
318 ngs->bestpath_perf.t_tot_cpu,
319 ngs->bestpath_perf.t_tot_cpu / n_speech);
320 E_INFO(
"TOTAL bestpath %.2f wall %.3f xRT\n",
321 ngs->bestpath_perf.t_tot_elapsed,
322 ngs->bestpath_perf.t_tot_elapsed / n_speech);
325 hmm_context_free(ngs->
hmmctx);
329 ngram_model_free(ngs->
lmset);
332 ckd_free(ngs->word_lat_idx);
334 ckd_free(ngs->bp_table);
335 ckd_free(ngs->bscore_stack);
336 if (ngs->bp_table_idx != NULL)
337 ckd_free(ngs->bp_table_idx - 1);
339 ckd_free(ngs->last_ltrans);
348 ngs->bp_table_idx = ckd_realloc(ngs->bp_table_idx - 1,
350 *
sizeof(*ngs->bp_table_idx));
358 ngs->bp_table_idx[frame_idx] = ngs->bpidx;
368 ent = ngs->bp_table + bp;
369 if (ent->
bp == NO_BP)
372 prev = ngs->bp_table + ent->
bp;
375 if (dict_filler_word(ps_search_dict(ngs), ent->
wid)) {
381 ent->
real_wid = dict_basewid(ps_search_dict(ngs),
387 ent->
real_wid = dict_basewid(ps_search_dict(ngs), ent->
wid);
397 int32 w, int32 score, int32 path, int32 rc)
404 bp = ngs->word_lat_idx[w];
411 if (ngs->bp_table[bp].
bp != path) {
412 int32 bplh[2], newlh[2];
416 E_DEBUG(2,(
"Updating path history %d => %d frame %d\n",
417 ngs->bp_table[bp].
bp, path, frame_idx));
418 bplh[0] = ngs->bp_table[bp].
bp == -1
420 bplh[1] = ngs->bp_table[bp].
bp == -1
421 ? -1 : ngs->bp_table[ngs->bp_table[bp].
bp].
real_wid;
422 newlh[0] = path == -1
424 newlh[1] = path == -1
425 ? -1 : ngs->bp_table[path].
real_wid;
428 if (bplh[0] != newlh[0] || bplh[1] != newlh[1]) {
432 E_DEBUG(1, (
"Updating language model state %s,%s => %s,%s frame %d\n",
433 dict_wordstr(ps_search_dict(ngs), bplh[0]),
434 dict_wordstr(ps_search_dict(ngs), bplh[1]),
435 dict_wordstr(ps_search_dict(ngs), newlh[0]),
436 dict_wordstr(ps_search_dict(ngs), newlh[1]),
438 set_real_wid(ngs, bp);
440 ngs->bp_table[bp].
bp = path;
442 ngs->bp_table[bp].
score = score;
447 if (ngs->bp_table[bp].
s_idx != -1)
448 ngs->bscore_stack[ngs->bp_table[bp].
s_idx + rc] = score;
455 if (ngs->bpidx == NO_BP) {
456 E_ERROR(
"No entries in backpointer table!");
461 if (ngs->bpidx >= ngs->bp_table_size) {
462 ngs->bp_table_size *= 2;
463 ngs->bp_table = ckd_realloc(ngs->bp_table,
465 *
sizeof(*ngs->bp_table));
466 E_INFO(
"Resized backpointer table to %d entries\n", ngs->bp_table_size);
468 if (ngs->bss_head >= ngs->bscore_stack_size
469 - bin_mdef_n_ciphone(ps_search_acmod(ngs)->mdef)) {
470 ngs->bscore_stack_size *= 2;
471 ngs->bscore_stack = ckd_realloc(ngs->bscore_stack,
472 ngs->bscore_stack_size
473 *
sizeof(*ngs->bscore_stack));
474 E_INFO(
"Resized score stack to %d entries\n", ngs->bscore_stack_size);
477 ngs->word_lat_idx[w] = ngs->bpidx;
478 be = &(ngs->bp_table[ngs->bpidx]);
480 be->
frame = frame_idx;
483 be->
s_idx = ngs->bss_head;
485 assert(path != ngs->bpidx);
489 be->
last_phone = dict_last_phone(ps_search_dict(ngs),w);
490 if (dict_is_single_phone(ps_search_dict(ngs), w)) {
496 be->
last2_phone = dict_second_last_phone(ps_search_dict(ngs),w);
501 for (i = 0; i < rcsize; ++i)
502 ngs->bscore_stack[ngs->bss_head + i] =
WORST_SCORE;
504 ngs->bscore_stack[ngs->bss_head + rc] = score;
505 set_real_wid(ngs, ngs->bpidx);
508 ngs->bss_head += rcsize;
524 if (frame_idx == -1 || frame_idx >= ngs->
n_frame)
526 end_bpidx = ngs->bp_table_idx[frame_idx];
532 while (frame_idx >= 0 && ngs->bp_table_idx[frame_idx] == end_bpidx)
539 assert(end_bpidx < ngs->bp_table_size);
540 for (bp = ngs->bp_table_idx[frame_idx]; bp < end_bpidx; ++bp) {
541 if (ngs->bp_table[bp].
wid == ps_search_finish_wid(ngs)
543 best_score = ngs->bp_table[bp].
score;
546 if (ngs->bp_table[bp].
wid == ps_search_finish_wid(ngs))
550 if (out_best_score) *out_best_score = best_score;
567 while (bp != NO_BP) {
568 bptbl_t *be = &ngs->bp_table[bp];
570 if (dict_real_word(ps_search_dict(ngs), be->
wid))
571 len += strlen(dict_basestr(ps_search_dict(ngs), be->
wid)) + 1;
579 base->
hyp_str = ckd_calloc(1, len);
583 while (bp != NO_BP) {
584 bptbl_t *be = &ngs->bp_table[bp];
588 if (dict_real_word(ps_search_dict(ngs), be->
wid)) {
589 len = strlen(dict_basestr(ps_search_dict(ngs), be->
wid));
591 memcpy(c, dict_basestr(ps_search_dict(ngs), be->
wid), len);
607 int32 i, tmatid, ciphone;
611 assert(!dict_is_single_phone(ps_search_dict(ngs), w));
612 ciphone = dict_last_phone(ps_search_dict(ngs),w);
615 dict_second_last_phone(ps_search_dict(ngs),w));
616 tmatid = bin_mdef_pid2tmatid(ps_search_acmod(ngs)->mdef, ciphone);
618 if ((hmm == NULL) || (hmm_nonmpx_ssid(&hmm->
hmm) != rssid->
ssid[0])) {
625 hmm_init(ngs->
hmmctx, &hmm->
hmm, FALSE, rssid->
ssid[0], tmatid);
626 E_DEBUG(3,(
"allocated rc_id 0 ssid %d ciphone %d lc %d word %s\n",
628 dict_second_last_phone(ps_search_dict(ngs),w),
629 dict_wordstr(ps_search_dict(ngs),w)));
631 for (i = 1; i < rssid->
n_ssid; ++i) {
632 if ((hmm->
next == NULL) || (hmm_nonmpx_ssid(&hmm->
next->
hmm) != rssid->
ssid[i])) {
640 hmm_init(ngs->
hmmctx, &hmm->
hmm, FALSE, rssid->
ssid[i], tmatid);
641 E_DEBUG(3,(
"allocated rc_id %d ssid %d ciphone %d lc %d word %s\n",
643 dict_second_last_phone(ps_search_dict(ngs),w),
644 dict_wordstr(ps_search_dict(ngs),w)));
656 for (hmm = ngs->
word_chan[w]; hmm; hmm = thmm) {
658 hmm_deinit(&hmm->
hmm);
682 return ngs->bscore_stack[pbe->
s_idx + rssid->
cimap[rcphone]];
691 int32 *out_ascr, int32 *out_lscr)
697 if (be->
bp == NO_BP) {
698 *out_ascr = be->
score;
704 pbe = ngs->bp_table + be->
bp;
706 dict_first_phone(ps_search_dict(ngs),be->
wid));
713 if (be->
wid == ps_search_silence_wid(ngs)) {
714 *out_lscr = ngs->silpen;
716 else if (dict_filler_word(ps_search_dict(ngs), be->
wid)) {
717 *out_lscr = ngs->fillpen;
721 *out_lscr = ngram_tg_score(ngs->
lmset,
726 *out_lscr = *out_lscr * lwf;
728 *out_ascr = be->
score - start_score - *out_lscr;
737 ngram_model_flush(ngs->
lmset);
740 else if (ngs->fwdflat)
748 ngram_search_step(
ps_search_t *search,
int frame_idx)
754 else if (ngs->fwdflat)
764 E_INFO(
"Backpointer table (%d entries):\n", ngs->bpidx);
765 for (i = 0; i < ngs->bpidx; ++i) {
766 bptbl_t *bpe = ngs->bp_table + i;
769 E_INFO_NOFN(
"%-5d %-10s start %-3d end %-3d score %-8d bp %-3d real_wid %-5d prev_real_wid %-5d",
770 i, dict_wordstr(ps_search_dict(ngs), bpe->
wid),
772 ? 0 : ngs->bp_table[bpe->
bp].
frame + 1),
783 for (j = 0; j < rcsize; ++j)
785 E_INFOCONT(
" %d", bpe->
score - ngs->bscore_stack[bpe->
s_idx + j]);
796 ngs->n_tot_frame += ngs->
n_frame;
810 while (ps_search_acmod(ngs)->n_feat_frame > 0) {
822 else if (ngs->fwdflat) {
832 ngram_search_bestpath(
ps_search_t *search, int32 *out_score,
int backward)
838 ngs->bestpath_fwdtree_lw_ratio,
844 if (search->
post == 0)
854 ngram_search_hyp(
ps_search_t *search, int32 *out_score)
859 if (ngs->bestpath && ngs->done) {
865 ptmr_reset(&ngs->bestpath_perf);
866 ptmr_start(&ngs->bestpath_perf);
869 if ((link = ngram_search_bestpath(search, out_score, FALSE)) == NULL)
872 ptmr_stop(&ngs->bestpath_perf);
874 / cmd_ln_int32_r(ps_search_config(ngs),
"-frate");
875 E_INFO(
"bestpath %.2f CPU %.3f xRT\n",
876 ngs->bestpath_perf.t_cpu,
877 ngs->bestpath_perf.t_cpu / n_speech);
878 E_INFO(
"bestpath %.2f wall %.3f xRT\n",
879 ngs->bestpath_perf.t_elapsed,
880 ngs->bestpath_perf.t_elapsed / n_speech);
896 ngram_search_bp2itor(
ps_seg_t *seg,
int bp)
901 be = &ngs->bp_table[bp];
902 pbe = be->
bp == -1 ? NULL : &ngs->bp_table[be->
bp];
903 seg->
word = dict_wordstr(ps_search_dict(ngs), be->
wid);
905 seg->
sf = pbe ? pbe->
frame + 1 : 0;
918 dict_first_phone(ps_search_dict(ngs), be->
wid));
920 if (be->
wid == ps_search_silence_wid(ngs)) {
921 seg->
lscr = ngs->silpen;
923 else if (dict_filler_word(ps_search_dict(ngs), be->
wid)) {
924 seg->
lscr = ngs->fillpen;
943 ckd_free(itor->
bpidx);
953 ngram_bp_seg_free(seg);
957 ngram_search_bp2itor(seg, itor->
bpidx[itor->
cur]);
976 itor = ckd_calloc(1,
sizeof(*itor));
977 itor->
base.
vt = &ngram_bp_segfuncs;
982 while (bp != NO_BP) {
983 bptbl_t *be = &ngs->bp_table[bp];
994 while (bp != NO_BP) {
995 bptbl_t *be = &ngs->bp_table[bp];
996 itor->
bpidx[cur] = bp;
1008 ngram_search_seg_iter(
ps_search_t *search, int32 *out_score)
1013 if (ngs->bestpath && ngs->done) {
1019 ptmr_reset(&ngs->bestpath_perf);
1020 ptmr_start(&ngs->bestpath_perf);
1023 if ((link = ngram_search_bestpath(search, out_score, TRUE)) == NULL)
1026 ngs->bestpath_fwdtree_lw_ratio);
1027 ptmr_stop(&ngs->bestpath_perf);
1029 / cmd_ln_int32_r(ps_search_config(ngs),
"-frate");
1030 E_INFO(
"bestpath %.2f CPU %.3f xRT\n",
1031 ngs->bestpath_perf.t_cpu,
1032 ngs->bestpath_perf.t_cpu / n_speech);
1033 E_INFO(
"bestpath %.2f wall %.3f xRT\n",
1034 ngs->bestpath_perf.t_elapsed,
1035 ngs->bestpath_perf.t_elapsed / n_speech);
1043 return ngram_search_bp_iter(ngs, bpidx,
1045 (ngs->done && ngs->fwdflat)
1046 ? ngs->fwdflat_fwdtree_lw_ratio : 1.0);
1058 if (ngs->bestpath && ngs->done) {
1064 if ((link = ngram_search_bestpath(search, NULL, TRUE)) == NULL)
1066 return search->
post;
1080 for (i = 0, bp_ptr = ngs->bp_table; i < ngs->bpidx; ++i, ++bp_ptr) {
1088 sf = (bp_ptr->
bp < 0) ? 0 : ngs->bp_table[bp_ptr->
bp].
frame + 1;
1092 assert(ef < dag->n_frames);
1094 if ((wid == ps_search_finish_wid(ngs)) && (ef < dag->
n_frames - 1))
1098 if ((!dict_filler_word(ps_search_dict(ngs), wid))
1099 && (!ngram_model_set_known_wid(ngs->
lmset,
1100 dict_basewid(ps_search_dict(ngs), wid))))
1104 for (node = dag->
nodes; node; node = node->
next) {
1105 if ((node->
wid == wid) && (node->
sf == sf))
1117 node->
fef = node->
lef = i;
1138 for (node = dag->
nodes; node; node = node->
next) {
1139 if ((node->
wid == ps_search_start_wid(ngs)) && (node->
sf == 0))
1144 E_ERROR(
"Couldn't find <s> in first frame\n");
1154 int32 ef, bestbp, bp, bestscore;
1157 for (node = dag->
nodes; node; node = node->
next) {
1158 int32 lef = ngs->bp_table[node->
lef].
frame;
1159 if ((node->
wid == ps_search_finish_wid(ngs))
1170 ef >= 0 && ngs->bp_table_idx[ef] == ngs->bpidx;
1173 E_ERROR(
"Empty backpointer table: can not build DAG.\n");
1180 for (bp = ngs->bp_table_idx[ef]; bp < ngs->bp_table_idx[ef + 1]; ++bp) {
1181 int32 n_used, l_scr, wid, prev_wid;
1185 if (wid == ps_search_finish_wid(ngs)) {
1189 l_scr = ngram_tg_score(ngs->
lmset, ps_search_finish_wid(ngs),
1191 l_scr = l_scr * lwf;
1193 bestscore = ngs->bp_table[bp].
score + l_scr;
1197 if (bestbp == NO_BP) {
1198 E_ERROR(
"No word exits found in last frame (%d), assuming no recognition\n", ef);
1201 E_INFO(
"</s> not found in last frame, using %s.%d instead\n",
1202 dict_basestr(ps_search_dict(ngs), ngs->bp_table[bestbp].
wid), ef);
1205 for (node = dag->
nodes; node; node = node->
next) {
1206 if (node->
lef == bestbp)
1211 E_ERROR(
"Failed to find DAG node corresponding to %s\n",
1212 dict_basestr(ps_search_dict(ngs), ngs->bp_table[bestbp].
wid));
1222 int32 i, score, ascr, lscr;
1226 int min_endfr, nlink;
1230 min_endfr = cmd_ln_int32_r(ps_search_config(search),
"-min_endfr");
1247 lwf = ngs->fwdflat ? ngs->fwdflat_fwdtree_lw_ratio : 1.0;
1248 create_dag_nodes(ngs, dag);
1249 if ((dag->
start = find_start_node(ngs, dag)) == NULL)
1251 if ((dag->
end = find_end_node(ngs, dag, ngs->bestpath_fwdtree_lw_ratio)) == NULL)
1253 E_INFO(
"lattice start node %s.%d end node %s.%d\n",
1257 ngram_compute_seg_score(ngs, ngs->bp_table + dag->
end->
lef, lwf,
1281 E_INFO(
"Eliminated %d nodes before end node\n", i);
1284 for (to = dag->
end; to; to = to->
next) {
1293 fef = ngs->bp_table[to->
fef].
frame;
1294 lef = ngs->bp_table[to->
lef].
frame;
1295 if (to != dag->
end && lef - fef < min_endfr) {
1301 for (from = to->
next; from; from = from->
next) {
1304 fef = ngs->bp_table[from->
fef].
frame;
1305 lef = ngs->bp_table[from->
lef].
frame;
1307 if ((to->
sf <= fef) || (to->
sf > lef + 1))
1309 if (lef - fef < min_endfr) {
1316 from_bpe = ngs->bp_table + i;
1317 for (; i <= from->
lef; i++, from_bpe++) {
1318 if (from_bpe->
wid != from->
wid)
1320 if (from_bpe->
frame >= to->
sf - 1)
1324 if ((i > from->
lef) || (from_bpe->
frame != to->
sf - 1))
1329 ngram_compute_seg_score(ngs, from_bpe, lwf,
1335 dict_first_phone(ps_search_dict(ngs), to->
wid));
1337 if (score == WORST_SCORE)
1341 score = ascr + (score - from_bpe->
score);
1352 else if (score BETTER_THAN WORST_SCORE) {
1362 E_ERROR(
"End node of lattice isolated; unreachable\n");
1366 for (node = dag->
nodes; node; node = node->
next) {
1375 for (node = dag->
nodes; node; node = node->
next) {
1378 for (alt = node->
next; alt && alt->
sf == node->
sf; alt = alt->
next) {
1386 E_INFO(
"Lattice has %d nodes, %d links\n", dag->
n_nodes, nlink);
1391 if (dict_filler_word(ps_search_dict(ngs), dag->
end->
wid))
1392 dag->
end->
basewid = ps_search_finish_wid(ngs);