libjulius/src/search_bestfirst_v1.c

Go to the documentation of this file.
00001 
00098 /*
00099  * Copyright (c) 1991-2007 Kawahara Lab., Kyoto University
00100  * Copyright (c) 2000-2005 Shikano Lab., Nara Institute of Science and Technology
00101  * Copyright (c) 2005-2007 Julius project team, Nagoya Institute of Technology
00102  * All rights reserved
00103  */
00104 
00105 #include <julius/julius.h>
00106 
00107 #ifndef PASS2_STRICT_IWCD
00108 
00109 #undef TCD                      
00110 
00111 /**********************************************************************/
00112 /************ 仮説ノードの基本操作                         ************/
00113 /************ Basic functions for hypothesis node handling ************/
00114 /**********************************************************************/
00115 
00116 #undef STOCKER_DEBUG
00117 
00118 #ifdef STOCKER_DEBUG
00119 static int stocked_num = 0;
00120 static int reused_num = 0;
00121 static int new_num = 0;
00122 static int request_num = 0;
00123 #endif
00124 
00137 static void
00138 free_node_exec(NODE *node)
00139 {
00140   if (node == NULL) return;
00141 
00142   free(node->g);
00143   if (node->g_prev != NULL) free(node->g_prev);
00144 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00145   if (node->region->graphout) {
00146     free(node->wordend_frame);
00147     free(node->wordend_gscore);
00148   }
00149 #endif
00150 
00151   free(node);
00152 }
00153 
00169 void
00170 free_node(NODE *node)
00171 {
00172   if (node == NULL) return;
00173 
00174   if (node->region->graphout) {
00175     if (node->prevgraph != NULL && node->prevgraph->saved == FALSE) {
00176       wordgraph_free(node->prevgraph);
00177     }
00178   }
00179 
00180   /* save to stocker */
00181   node->next = node->region->pass2.stocker_root;
00182   node->region->pass2.stocker_root = node;
00183 
00184 #ifdef STOCKER_DEBUG
00185   stocked_num++;
00186 #endif
00187 }
00188 
00205 void
00206 clear_stocker(StackDecode *s)
00207 {
00208   NODE *node, *tmp;
00209   node = s->stocker_root;
00210   while(node) {
00211     tmp = node->next;
00212     free_node_exec(node);
00213     node = tmp;
00214   }
00215   s->stocker_root = NULL;
00216 
00217 #ifdef STOCKER_DEBUG
00218   jlog("DEBUG: %d times requested, %d times newly allocated, %d times reused\n", request_num, new_num, reused_num);
00219   stocked_num = 0;
00220   reused_num = 0;
00221   new_num = 0;
00222   request_num = 0;
00223 #endif
00224 }
00225 
00246 NODE *
00247 cpy_node(NODE *dst, NODE *src)
00248 {
00249   int peseqlen;
00250 
00251   peseqlen = src->region->peseqlen;
00252   
00253   dst->next = src->next;
00254   dst->prev = src->prev;
00255   memcpy(dst->g, src->g, sizeof(LOGPROB) * peseqlen);
00256   memcpy(dst->seq, src->seq, sizeof(WORD_ID) * MAXSEQNUM);
00257 #ifdef CM_SEARCH
00258 #ifdef CM_MULTIPLE_ALPHA
00259   {
00260     int w;
00261     for(w=0;w<src->seqnum;w++) {
00262       memcpy(dst->cmscore[w], src->cmscore[w], sizeof(LOGPROB) * src->region->config->annotate.cm_alpha_num);
00263     }
00264   }     
00265 #else
00266   memcpy(dst->cmscore, src->cmscore, sizeof(LOGPROB) * MAXSEQNUM);
00267 #endif
00268 #endif /* CM_SEARCH */
00269   dst->seqnum = src->seqnum;
00270   dst->score = src->score;
00271   dst->bestt = src->bestt;
00272   dst->estimated_next_t = src->estimated_next_t;
00273   dst->endflag = src->endflag;
00274   dst->state = src->state;
00275   dst->tre = src->tre;
00276   if (src->g_prev != NULL) { // ccd_flag == TRUE
00277     memcpy(dst->g_prev, src->g_prev, sizeof(LOGPROB) * peseqlen);
00278     dst->last_ph = src->last_ph;
00279     dst->last_ph_sp_attached = src->last_ph_sp_attached;
00280     dst->lscore = src->lscore;
00281   }
00282   dst->totallscore = src->totallscore;
00283   dst->final_g = src->final_g;
00284 #ifdef VISUALIZE
00285   dst->popnode = src->popnode;
00286 #endif
00287 
00288   if (src->region->graphout) {
00289 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00290     memcpy(dst->wordend_frame, src->wordend_frame, sizeof(short) * peseqlen);
00291     memcpy(dst->wordend_gscore, src->wordend_gscore, sizeof(LOGPROB) * peseqlen);
00292 #endif
00293     dst->prevgraph = src->prevgraph;
00294     dst->lastcontext = src->lastcontext;
00295 #ifndef GRAPHOUT_PRECISE_BOUNDARY
00296     dst->tail_g_score = src->tail_g_score;
00297 #endif
00298   }
00299 
00300   return(dst);
00301 }
00302 
00323 NODE *
00324 newnode(RecogProcess *r)
00325 {
00326   NODE *tmp;
00327   int i;
00328   int peseqlen;
00329 
00330   peseqlen = r->peseqlen;
00331 
00332 #ifdef STOCKER_DEBUG
00333   request_num++;
00334 #endif
00335   if ((tmp = r->pass2.stocker_root) != NULL) {
00336     /* re-use ones in the stocker */
00337     r->pass2.stocker_root = tmp->next;
00338 #ifdef STOCKER_DEBUG
00339     stocked_num--;
00340     reused_num++;
00341 #endif
00342   } else {
00343     /* allocate new */
00344     tmp =(NODE *)mymalloc(sizeof(NODE));
00345     tmp->g = (LOGPROB *)mymalloc(sizeof(LOGPROB) * peseqlen);
00346     if (r->ccd_flag) {
00347       tmp->g_prev = (LOGPROB *)mymalloc(sizeof(LOGPROB) * peseqlen);
00348     } else {
00349       tmp->g_prev = NULL;
00350     }
00351 
00352 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00353     if (r->graphout) {
00354       tmp->wordend_frame = (short *)mymalloc(sizeof(short) * peseqlen);
00355       tmp->wordend_gscore = (LOGPROB *)mymalloc(sizeof(LOGPROB) * peseqlen);
00356     }
00357 #endif
00358 #ifdef STOCKER_DEBUG
00359     new_num++;
00360 #endif
00361   }
00362 
00363   /* clear the data */
00364   /*bzero(tmp,sizeof(NODE));*/
00365   tmp->next=NULL;
00366   tmp->prev=NULL;
00367   tmp->last_ph = NULL;
00368   tmp->last_ph_sp_attached = FALSE;
00369   if (r->ccd_flag) {
00370     if (r->lmtype == LM_PROB) {
00371       tmp->lscore = LOG_ZERO;
00372       tmp->totallscore = LOG_ZERO;
00373     } else if (r->lmtype == LM_DFA) {
00374       tmp->lscore = 0.0;
00375       tmp->totallscore = 0.0;
00376     }
00377   }
00378   tmp->endflag = FALSE;
00379   tmp->seqnum = 0;
00380   for(i=0;i<peseqlen;i++) {
00381     tmp->g[i] = LOG_ZERO;
00382   }
00383   if (r->ccd_flag) {
00384     for(i=0;i<peseqlen;i++) {
00385       tmp->g_prev[i] = LOG_ZERO;
00386     }
00387   }
00388   tmp->final_g = LOG_ZERO;
00389 #ifdef VISUALIZE
00390   tmp->popnode = NULL;
00391 #endif
00392   tmp->tre = NULL;
00393 
00394   if (r->graphout) {
00395     tmp->prevgraph = NULL;
00396     tmp->lastcontext = NULL;
00397   }
00398 
00399   tmp->region = r;
00400 
00401   return(tmp);
00402 }
00403 
00404 
00405 /**********************************************************************/
00406 /************ 前向きトレリス展開と尤度計算              ***************/
00407 /************ Expand trellis and update forward viterbi ***************/
00408 /**********************************************************************/
00409 
00410 static LOGPROB *wordtrellis[2]; 
00411 static int tn;                 
00412 static int tl;                 
00413 static LOGPROB *g;              
00414 static HMM_Logical **phmmseq;   
00415 static int phmmlen_max;         
00416 static boolean *has_sp;         
00417 
00418 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00419 static short *wend_token_frame[2]; 
00420 static LOGPROB *wend_token_gscore[2]; 
00421 #endif
00422 
00439 void
00440 malloc_wordtrellis(RecogProcess *r)
00441 {
00442   int maxwn;
00443 
00444   maxwn = r->lm->winfo->maxwn + 10;
00445   wordtrellis[0] = (LOGPROB *)mymalloc(sizeof(LOGPROB) * maxwn);
00446   wordtrellis[1] = (LOGPROB *)mymalloc(sizeof(LOGPROB) * maxwn);
00447 
00448   g = (LOGPROB *)mymalloc(sizeof(LOGPROB) * r->peseqlen);
00449 
00450   phmmlen_max = r->lm->winfo->maxwlen + 2;
00451   phmmseq = (HMM_Logical **)mymalloc(sizeof(HMM_Logical *) * phmmlen_max);
00452   if (r->am->hmminfo->multipath) {
00453     has_sp = (boolean *)mymalloc(sizeof(boolean) * phmmlen_max);
00454   } else {
00455     has_sp = NULL;
00456   }
00457 
00458   wend_token_frame[0] = NULL;
00459   wend_token_frame[1] = NULL;
00460   wend_token_gscore[0] = NULL;
00461   wend_token_gscore[1] = NULL;
00462 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00463   if (r->graphout) {
00464     wend_token_frame[0] = (short *)mymalloc(sizeof(short) * maxwn);
00465     wend_token_frame[1] = (short *)mymalloc(sizeof(short) * maxwn);
00466     wend_token_gscore[0] = (LOGPROB *)mymalloc(sizeof(LOGPROB) * maxwn);
00467     wend_token_gscore[1] = (LOGPROB *)mymalloc(sizeof(LOGPROB) * maxwn);
00468   }
00469 #endif
00470   
00471 }
00472 
00485 void
00486 free_wordtrellis()
00487 {
00488   int i;
00489 
00490   free(wordtrellis[0]);
00491   free(wordtrellis[1]);
00492   free(g);
00493   free(phmmseq);
00494   if (has_sp) {
00495     free(has_sp);
00496     has_sp = NULL;
00497   }
00498 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00499   for(i=0;i<2;i++) {
00500     if (wend_token_frame[i]) {
00501       free(wend_token_frame[i]);
00502       wend_token_frame[i] = NULL;
00503     }
00504     if (wend_token_gscore[i]) {
00505       free(wend_token_gscore[i]);
00506       wend_token_gscore[i] = NULL;
00507     }
00508   }
00509 #endif
00510 }
00511 
00512 
00513 /**********************************************************************/
00514 /************ 仮説の前向き尤度計算                  *******************/
00515 /************ Compute forward score of a hypothesis *******************/
00516 /**********************************************************************/
00517 
00536 static LOGPROB
00537 get_max_out_arc(HTK_HMM_Trans *tr, int state_num)
00538 {
00539   LOGPROB max_a;
00540   int afrom;
00541   LOGPROB a;
00542   
00543   max_a = LOG_ZERO;
00544   for (afrom = 0; afrom < state_num - 1; afrom++) {
00545     a = tr->a[afrom][state_num-1];
00546     if (max_a < a) max_a = a;
00547   }
00548   return(max_a);
00549 }
00550 
00567 static LOGPROB
00568 max_out_arc(HMM_Logical *l)
00569 {
00570   return(get_max_out_arc(hmm_logical_trans(l), hmm_logical_state_num(l)));
00571 }
00572 
00594 void
00595 scan_word(NODE *now, HTK_Param *param, RecogProcess *r)
00596 {
00597   int   i,t, j;
00598   HMM *whmm;
00599   A_CELL *ac;
00600   WORD_ID word;
00601   LOGPROB tmpmax, tmptmp, score1;
00602   int startt = 0, endt;
00603   int wordhmmnum;
00604   LOGPROB tmpmax_store, store_point_maxarc; /* multipath */
00605   LOGPROB tmpmax2 = LOG_ZERO;
00606   int phmmlen;
00607   HMM_Logical *ret, *wend;
00608   int store_point;
00609   int crossword_point = 0;
00610   boolean back_rescan = FALSE;
00611   boolean node_exist_p;
00612 
00613   /* store global values to local for rapid access */
00614   WORD_INFO *winfo;
00615   HTK_HMM_INFO *hmminfo;
00616   LOGPROB *framemaxscore;
00617   int peseqlen;
00618   boolean ccd_flag;
00619   boolean enable_iwsp;
00620 #ifdef SCAN_BEAM
00621   LOGPROB scan_beam_thres;
00622 #endif
00623 
00624   winfo = r->lm->winfo;
00625   hmminfo = r->am->hmminfo;
00626   peseqlen = r->peseqlen;
00627   framemaxscore = r->pass2.framemaxscore;
00628   ccd_flag = r->ccd_flag;
00629   enable_iwsp = r->lm->config->enable_iwsp; /* multipath */
00630 #ifdef SCAN_BEAM
00631   scan_beam_thres = r->config->pass2.scan_beam_thres;
00632 #endif
00633 
00634   if (hmminfo->multipath) {
00635     store_point = -1;
00636   } else {
00637     store_point = 0;
00638   }
00639   
00640   /* ----------------------- prepare HMM ----------------------- */
00641 
00642   if (ccd_flag) {
00643     /* 直前の音素があれば,そこまでさかのぼって scan する */
00644     /* if there are any last phone, enable backscan */
00645     if (now->last_ph == NULL) {
00646       /* initial score: now->g[] */
00647       /* scan range: phones in now->seq[now->seqnum-1] */
00648       back_rescan = FALSE;
00649     } else {
00650       /* initial score: now->g_prev[] (1-phone before)*/
00651       /* scan range: phones in now->seq[now->seqnum-1] + now->last_ph */
00652       back_rescan = TRUE;
00653     }
00654   }
00655 #ifdef TCD
00656   if (now->last_ph != NULL) {
00657     jlog("DEBUG: inherited last_ph: %s\n", (now->last_ph)->name);
00658     if (now->last_ph_sp_attached) jlog("DEBUG: (sp attached)\n"); /* multipath */
00659   } else {
00660     jlog("DEBUG: no last_ph inherited\n");
00661   }
00662 #endif
00663 
00664   /* scan 範囲分のHMMを準備 */
00665   /* prepare HMM of the scan range */
00666   word = now->seq[now->seqnum-1];
00667 
00668   if (ccd_flag) {
00669 
00670     if (back_rescan) {
00671       
00672       /* scan range: phones in now->seq[now->seqnum-1] + now->last_ph */
00673       
00674       phmmlen = winfo->wlen[word] + 1;
00675       if (phmmlen > phmmlen_max) {
00676         j_internal_error("scan_word: num of phonemes in a word exceed phmmlenmax (%d) ?\n", phmmlen_max);
00677       }
00678       for (i=0;i<phmmlen - 2;i++) phmmseq[i] = winfo->wseq[word][i];
00679       if (hmminfo->multipath) {
00680         for (i=0;i<phmmlen - 2;i++) has_sp[i] = FALSE;
00681       }
00682 
00683       /* 最終単語と last_ph 間の単語間triphoneを考慮 */
00684       /* consider cross-word context dependency between the last word and now->last_ph */
00685       wend = winfo->wseq[word][winfo->wlen[word]-1];
00686       ret = get_right_context_HMM(wend, now->last_ph->name, hmminfo);
00687       if (ret == NULL) {        /* triphone not found */
00688         /* fallback to the original bi/mono-phone */
00689         /* error if the original is pseudo phone (not explicitly defined
00690            in hmmdefs/hmmlist) */
00691         /* exception: word with 1 phone (triphone may exist in the next expansion */
00692         if (winfo->wlen[word] > 1 && wend->is_pseudo) {
00693           error_missing_right_triphone(wend, now->last_ph->name);
00694         }
00695         phmmseq[phmmlen-2] = wend;
00696       } else {
00697         phmmseq[phmmlen-2] = ret;
00698       }
00699       ret = get_left_context_HMM(now->last_ph, wend->name, hmminfo);
00700       if (ret == NULL) {
00701         /* fallback to the original bi/mono-phone */
00702         /* error if the original is pseudo phone (not explicitly defined
00703            in hmmdefs/hmmlist) */
00704         if (now->last_ph->is_pseudo) {
00705           error_missing_left_triphone(now->last_ph, wend->name);
00706         }
00707         phmmseq[phmmlen-1] = now->last_ph;
00708       } else {
00709         phmmseq[phmmlen-1] = ret;
00710       }
00711 
00712       if (hmminfo->multipath) {
00713         has_sp[phmmlen-2] = has_sp[phmmlen-1] = FALSE;
00714         if (enable_iwsp) {
00715           has_sp[phmmlen-2] = TRUE;
00716           if (now->last_ph_sp_attached) {
00717             has_sp[phmmlen-1] = TRUE;
00718           }
00719         }
00720       }
00721  
00722 #ifdef TCD
00723       jlog("DEBUG: w=");
00724       for(i=0;i<winfo->wlen[word];i++) {
00725         jlog(" %s",(winfo->wseq[word][i])->name);
00726         if (hmminfo->multipath && has_sp[i]) jlog("(sp)");
00727       }
00728       jlog(" | %s\n", (now->last_ph)->name);
00729       if (hmminfo->multipath && now->last_ph_sp_attached) jlog("DEBUG:   (sp)\n");
00730       jlog("DEBUG: scan for:");
00731       
00732       for (i=0;i<phmmlen;i++) {
00733         jlog(" %s", phmmseq[i]->name);
00734         if (hmminfo->multipath && has_sp[i]) jlog("(sp)");
00735       }
00736       jlog("\n");
00737 #endif
00738 
00739       /* 単語HMMを作る */
00740       /* make word HMM */
00741       whmm = new_make_word_hmm(hmminfo, phmmseq, phmmlen, hmminfo->multipath ? has_sp : NULL);
00742       if (whmm == NULL) {
00743         j_internal_error("Error: failed to make word hmm for word #%d \"%s [%s]\"\n", word, winfo->wname[word], winfo->woutput[word]);
00744       }
00745       
00746       /* backscan なので,計算前の g[] 初期値は now->g_prev[] を使用 */
00747       /* As backscan enabled, the initial forward score g[] is set by
00748          now->g_prev[] */
00749       for (t=0;t<peseqlen;t++) {
00750         g[t]=now->g_prev[t];
00751 
00752       }
00753       
00754       /* 次段用のg_prevを格納するノード位置を設定 */
00755       /* set where to store scores as new g_prev[] for the next backscan
00756          in the HMM */
00757       if (hmminfo->multipath) {
00758         store_point = hmm_logical_state_num(phmmseq[0]) - 2;
00759         store_point_maxarc = max_out_arc(phmmseq[0]);
00760         if (enable_iwsp && has_sp[0]) {
00761           store_point += hmm_logical_state_num(hmminfo->sp) - 2;
00762           if (store_point_maxarc < max_out_arc(hmminfo->sp)) {
00763             store_point_maxarc = max_out_arc(hmminfo->sp);
00764           }
00765         }
00766       } else {
00767         store_point = hmm_logical_state_num(phmmseq[0]) - 2 - 1;
00768       }
00769       /* scan中に直前単語とこの単語をまたぐ場所を設定 */
00770       /* set where is the connection point of the last word in the HMM */
00771       if (hmminfo->multipath) {
00772         crossword_point = whmm->len - hmm_logical_state_num(phmmseq[phmmlen-1]);
00773         if (enable_iwsp && has_sp[phmmlen-1]) {
00774           crossword_point -= hmm_logical_state_num(hmminfo->sp) - 2;
00775         }
00776       } else {
00777         crossword_point = whmm->len - (hmm_logical_state_num(phmmseq[phmmlen-1]) - 2) - 1;
00778       }
00779       
00780     } else {                    /* not backscan mode */
00781       
00782       /* scan range: phones in now->seq[now->seqnum-1] */
00783       
00784 #ifdef TCD
00785       jlog("DEBUG: scan(org):");
00786       for (i=0;i<winfo->wlen[word];i++) {
00787         jlog(" %s", (winfo->wseq[word][i])->name);
00788       }
00789       jlog("\n");
00790 #endif
00791 
00792       if (hmminfo->multipath) {
00793         /* 必要ならばショートポーズを挟み込む位置を指定する */
00794         for(i=0;i<winfo->wlen[word];i++) {
00795           has_sp[i] = FALSE;
00796         }
00797         if (enable_iwsp) {
00798           has_sp[winfo->wlen[word]-1] = TRUE;
00799         }
00800       }
00801       
00802       /* 単語HMMを作る */
00803       /* make word HMM */
00804       whmm = new_make_word_hmm(hmminfo, winfo->wseq[word], winfo->wlen[word], hmminfo->multipath ? has_sp : NULL);
00805       if (whmm == NULL) {
00806         j_internal_error("Error: failed to make word hmm for word #%d \"%s [%s]\"\n", word, winfo->wname[word], winfo->woutput[word]);
00807       }
00808       
00809       /* 計算前の g[] 初期値は now->g[] を使用 */
00810       /* the initial forward score g[] is set by now->g[] */
00811       for (t=0;t<peseqlen;t++) {
00812         g[t]=now->g[t];
00813       }
00814       
00815       /* 次段用のg_prevを格納するノード位置を設定 */
00816       /* set where to store scores as new g_prev[] for the next backscan
00817          in the HMM */
00818       if (hmminfo->multipath) {
00819         store_point = hmm_logical_state_num(winfo->wseq[word][0]) - 2;
00820         store_point_maxarc = max_out_arc(winfo->wseq[word][0]);
00821         if (enable_iwsp && has_sp[0]) {
00822           store_point += hmm_logical_state_num(hmminfo->sp) - 2;
00823           if (store_point_maxarc < max_out_arc(hmminfo->sp)) {
00824             store_point_maxarc = max_out_arc(hmminfo->sp);
00825           }
00826         }
00827       } else {
00828         store_point = hmm_logical_state_num(winfo->wseq[word][0]) - 2 - 1;
00829       }
00830 
00831       /* scan中に直前単語とこの単語をまたぐ場所は,なし */
00832       /* the connection point of the last word is not exist in the HMM */
00833       crossword_point = -1;
00834     }
00835     
00836   } else {                      /* ccd_flag == FALSE */
00837 
00838     if (hmminfo->multipath) {
00839       /* 必要ならばショートポーズを挟み込む位置を指定する */
00840       for(i=0;i<winfo->wlen[word];i++) {
00841         has_sp[i] = FALSE;
00842       }
00843       if (enable_iwsp) {
00844         has_sp[winfo->wlen[word]-1] = TRUE;
00845       }
00846     }
00847 
00848     /* 音素環境非依存の場合は単純に最終単語分の HMM を作成 */
00849     /* for monophone: simple make HMM for the last word */
00850     whmm = new_make_word_hmm(hmminfo, winfo->wseq[word], winfo->wlen[word], hmminfo->multipath ? has_sp : NULL);
00851     if (whmm == NULL) {
00852       j_internal_error("Error: failed to make word hmm for word #%d \"%s [%s]\"\n", word, winfo->wname[word], winfo->woutput[word]);
00853     }
00854 
00855     /* 計算前の g[] 初期値は now->g[] を使用 */
00856     /* the initial forward score g[] is set by now->g[] */
00857     for (t=0;t<peseqlen;t++) {
00858       g[t]=now->g[t];
00859     }
00860     
00861   }
00862 
00863 #ifdef TCD
00864   jlog("DEBUG: whmm len   = %d\n",whmm->len);
00865   jlog("DEBUG: crossword_point = %d\n", crossword_point);
00866   jlog("DEBUG: g[] store point = %d\n", store_point);
00867 #endif
00868 
00869   wordhmmnum = whmm->len;
00870   if (wordhmmnum >= winfo->maxwn + 10) {
00871     j_internal_error("scan_word: word too long (>%d)\n", winfo->maxwn + 10);
00872   }
00873 
00874 #ifndef GRAPHOUT_PRECISE_BOUNDARY
00875   if (r->graphout) {
00876     if (ccd_flag) {
00877       now->tail_g_score = now->g[now->bestt];
00878     }
00879   }
00880 #endif
00881 
00882   /* ----------------------- do scan ----------------------- */
00883   
00884   /* scan開始点を検索 -> starttへ*/
00885   /* search for the start frame -> set to startt */
00886   for(t = peseqlen-1; t >=0 ; t--) {
00887     if (
00888 #ifdef SCAN_BEAM
00889         g[t] > framemaxscore[t] - scan_beam_thres &&
00890 #endif
00891         g[t] > LOG_ZERO) {
00892       break;
00893     }
00894   }
00895   if (t < 0) {                  /* no node has score > LOG_ZERO */
00896     for(t=0;t<peseqlen;t++) {
00897       if (ccd_flag) now->g_prev[t] = LOG_ZERO;
00898       now->g[t] = LOG_ZERO;
00899     }
00900 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00901     if (r->graphout) {
00902       for(t=0;t<peseqlen;t++) {
00903         now->wordend_frame[t] = -1;
00904         now->wordend_gscore[t] = LOG_ZERO;
00905       }
00906     }
00907 #endif
00908     goto end_of_scan;
00909   }
00910   startt = t;
00911   
00912   /* clear [startt+1..peseqlen-1] */
00913   for(t=peseqlen-1;t>startt;t--) {
00914     if (ccd_flag) now->g_prev[t] = LOG_ZERO;
00915     now->g[t] = LOG_ZERO;
00916 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00917     if (r->graphout) {
00918       now->wordend_frame[t] = -1;
00919       now->wordend_gscore[t] = LOG_ZERO;
00920     }
00921 #endif
00922   }
00923 
00924   /* バッファポインタ初期化 */
00925   tn = 0; tl = 1;
00926 
00927 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00928   if (r->graphout) {
00929     for(i=0;i<wordhmmnum;i++) {
00930       wend_token_frame[tn][i] = -1;
00931       wend_token_gscore[tn][i] = LOG_ZERO;
00932     }
00933   }
00934 #endif
00935   
00936   if (! hmminfo->multipath) {
00937     /* Below initialization is not needed on multipath version, since
00938        the actual viterbi will begin at frame 0 in multipath mode in main loop */
00939     
00940     /* 時間 [startt] 上の値を初期化 */
00941     /* initialize scores on frame [startt] */
00942     for(i=0;i<wordhmmnum-1;i++) wordtrellis[tn][i] = LOG_ZERO;
00943     wordtrellis[tn][wordhmmnum-1] = g[startt] + outprob(&(r->am->hmmwrk), startt, &(whmm->state[wordhmmnum-1]), param);
00944     if (ccd_flag) {
00945       now->g_prev[startt] = wordtrellis[tn][store_point];
00946     }
00947     now->g[startt] = wordtrellis[tn][0];
00948     
00949 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00950     if (r->graphout) {
00951       if (ccd_flag) {
00952         if (back_rescan) {
00953           if (wordhmmnum-1 == crossword_point) {
00954             wend_token_frame[tn][wordhmmnum-1] = startt;
00955             wend_token_gscore[tn][wordhmmnum-1] = g[startt];
00956           } else {
00957             wend_token_frame[tn][wordhmmnum-1] = -1;
00958             wend_token_gscore[tn][wordhmmnum-1] = LOG_ZERO;
00959           }
00960         } else {
00961           wend_token_frame[tn][wordhmmnum-1] = startt;
00962           wend_token_gscore[tn][wordhmmnum-1] = g[startt];
00963         }
00964       } else {
00965         wend_token_frame[tn][wordhmmnum-1] = startt;
00966         wend_token_gscore[tn][wordhmmnum-1] = g[startt];
00967       }
00968       now->wordend_frame[startt] = wend_token_frame[tn][0];
00969       now->wordend_gscore[startt] = wend_token_gscore[tn][0];
00970     }
00971 #endif
00972   } /* end of hmminfo->multipath */
00973   
00974   endt = startt;
00975 
00976   /* メインループ: startt から始まり 0 に向かって Viterbi 計算 */
00977   /* main loop: start from [startt], and compute Viterbi toward [0] */
00978   for(t = hmminfo->multipath ? startt : startt - 1; t >= 0; t--) {
00979     
00980     /* wordtrellisのワークエリアをスワップ */
00981     i = tn; tn = tl; tl = i;
00982     
00983     node_exist_p = FALSE;       /* TRUE if there is at least 1 survived node in this frame */
00984 
00985     if (hmminfo->multipath) {
00986 
00987       /* 端のノード [t][wordhmmnum-1]は g[] を参照する */
00988       /* the edge node [t][wordhmmnum-1] is equal to g[] */
00989 
00990       /* ノード [t][wordhmmnum-2..0] についてトレリスを計算 */
00991       /* expand trellis for node [t][wordhmmnum-2..0] */
00992       tmpmax_store = LOG_ZERO;
00993 
00994     } else {
00995     
00996       /* 端のノード [t][wordhmmnum-1]は,内部遷移 か g[]の高い方になる */
00997       /* the edge node [t][wordhmmnum-1] is either internal transitin or g[] */
00998       tmptmp = LOG_ZERO;
00999       for (ac=whmm->state[wordhmmnum-1].ac;ac;ac=ac->next) {
01000         score1 = wordtrellis[tl][ac->arc] + ac->a;
01001         if (tmptmp < score1) {
01002           j = ac->arc;
01003           tmptmp = score1;
01004         }
01005       }
01006       if (g[t] > tmptmp) {
01007         tmpmax = g[t];
01008 #ifdef GRAPHOUT_PRECISE_BOUNDARY
01009         if (r->graphout) {
01010           if (!back_rescan || wordhmmnum-1 == crossword_point) {
01011             wend_token_frame[tn][wordhmmnum-1] = t;
01012             wend_token_gscore[tn][wordhmmnum-1] = g[t];
01013           } else {
01014             wend_token_frame[tn][wordhmmnum-1] = wend_token_frame[tl][j];
01015             wend_token_gscore[tn][wordhmmnum-1] = wend_token_gscore[tl][j];
01016           }
01017         }
01018 #endif
01019       } else {
01020         tmpmax = tmptmp;
01021 #ifdef GRAPHOUT_PRECISE_BOUNDARY
01022         if (r->graphout) {
01023           wend_token_frame[tn][wordhmmnum-1] = wend_token_frame[tl][j];
01024           wend_token_gscore[tn][wordhmmnum-1] = wend_token_gscore[tl][j];
01025         }
01026 #endif
01027       }
01028 
01029       /* 端のノードのスコアエンベロープチェック: 一定幅外なら落とす */
01030       /* check if the edge node is within score envelope */
01031       if (
01032 #ifdef SCAN_BEAM
01033           tmpmax <= framemaxscore[t] - scan_beam_thres ||
01034 #endif
01035           tmpmax <= LOG_ZERO
01036           ) {
01037         wordtrellis[tn][wordhmmnum-1] = LOG_ZERO;
01038 #ifdef GRAPHOUT_PRECISE_BOUNDARY
01039         if (r->graphout) {
01040           wend_token_frame[tn][wordhmmnum-1] = -1;
01041           wend_token_gscore[tn][wordhmmnum-1] = LOG_ZERO;
01042         }
01043 #endif
01044       } else {
01045         node_exist_p = TRUE;
01046         wordtrellis[tn][wordhmmnum-1] = tmpmax + outprob(&(r->am->hmmwrk), t, &(whmm->state[wordhmmnum-1]), param);
01047       }
01048 
01049     } /* end of ~multipath */
01050 
01051     /* ノード [t][wordhmmnum-2..0] についてトレリスを計算 */
01052     /* expand trellis for node [t][wordhmmnum-2..0] */
01053     for(i=wordhmmnum-2;i>=0;i--) {
01054 
01055       if (ccd_flag) {
01056 
01057         /* 最尤パスと最尤スコア tmpmax を見つける */
01058         /* tmpmax2 は次回用 g_prev[] のための最大値(自己遷移を除いた最大値) */
01059         /* find most likely path and the max score 'tmpmax' */
01060         /* 'tmpmax2' is max score excluding self transition, for next g_prev[] */
01061         if (! hmminfo->multipath) {
01062           if (i == store_point) {
01063             tmpmax2 = LOG_ZERO;
01064           }
01065         }
01066         tmpmax = LOG_ZERO;
01067         for (ac=whmm->state[i].ac;ac;ac=ac->next) {
01068           if (hmminfo->multipath) {
01069             if (ac->arc == wordhmmnum-1) score1 = g[t];
01070             else if (t + 1 > startt) score1 = LOG_ZERO;
01071             else score1 = wordtrellis[tl][ac->arc];
01072             score1 += ac->a;
01073           } else {
01074             score1 = wordtrellis[tl][ac->arc] + ac->a;
01075           }
01076           if (i <= crossword_point && ac->arc > crossword_point) {
01077             /* これは単語を越える遷移 (backscan 実行時) */
01078             /* this is a transition across word (when backscan is enabled) */
01079             score1 += now->lscore; /* add LM score */
01080           }
01081 
01082           if (hmminfo->multipath) {
01083             if (i <= store_point && ac->arc > store_point) {
01084               if (tmpmax_store < score1) tmpmax_store = score1;
01085             }
01086           } else {
01087             if (i == store_point && i != ac->arc) {
01088               if (tmpmax2 < score1) tmpmax2 = score1;
01089             }
01090           }
01091 
01092           if (tmpmax < score1) {
01093             tmpmax = score1;
01094             j = ac->arc;
01095           }
01096         }
01097 
01098         /* スコアエンベロープチェック: 一定幅外なら落とす */
01099         /* check if score of this node is within the score envelope */
01100         if (
01101 #ifdef SCAN_BEAM
01102             tmpmax <= framemaxscore[t] - scan_beam_thres ||
01103 #endif
01104             tmpmax <= LOG_ZERO
01105             ) {  /* invalid node */
01106           wordtrellis[tn][i] = LOG_ZERO;
01107 #ifdef GRAPHOUT_PRECISE_BOUNDARY
01108           if (r->graphout) {
01109             wend_token_frame[tn][i] = -1;
01110             wend_token_gscore[tn][i] = LOG_ZERO;
01111           }
01112 #endif
01113           if (! hmminfo->multipath) {
01114             if (i == store_point) now->g_prev[t] = LOG_ZERO;
01115           }
01116         } else { /* survived node */
01117           if (! hmminfo->multipath) {
01118             if (i == store_point) now->g_prev[t] = tmpmax2;
01119           }
01120 #ifdef GRAPHOUT_PRECISE_BOUNDARY
01121           if (r->graphout) {
01122 
01123             if (hmminfo->multipath) {
01124               if ((back_rescan && i <= crossword_point && j > crossword_point)
01125                   || j == wordhmmnum-1) {
01126                 wend_token_frame[tn][i] = t;
01127                 wend_token_gscore[tn][i] = tmpmax;
01128               } else {
01129                 wend_token_frame[tn][i] = wend_token_frame[tl][j];
01130                 wend_token_gscore[tn][i] = wend_token_gscore[tl][j];
01131               }
01132             } else {
01133               if (i <= crossword_point && j > crossword_point) {
01134                 wend_token_frame[tn][i] = t;
01135                 wend_token_gscore[tn][i] = tmpmax;
01136               } else {
01137                 wend_token_frame[tn][i] = wend_token_frame[tl][j];
01138                 wend_token_gscore[tn][i] = wend_token_gscore[tl][j];
01139               }
01140             }
01141           }
01142 #endif
01143           node_exist_p = TRUE;  /* at least one node survive in this frame */
01144 
01145           wordtrellis[tn][i] = tmpmax;
01146           if (! hmminfo->multipath || i > 0) {
01147             /* compute output probability */
01148             wordtrellis[tn][i] += outprob(&(r->am->hmmwrk), t, &(whmm->state[i]), param);
01149           }
01150         }
01151         
01152       } else {                  /* not triphone */
01153 
01154         /* backscan 無し: store_point, crossword_point は無関係 */
01155         /* no backscan: store_point, crossword_point ignored */
01156         tmpmax = LOG_ZERO;
01157         if (hmminfo->multipath) {
01158           for (ac=whmm->state[i].ac;ac;ac=ac->next) {
01159             if (ac->arc == wordhmmnum-1) score1 = g[t];
01160             else if (t + 1 > startt) score1 = LOG_ZERO;
01161             else score1 = wordtrellis[tl][ac->arc];
01162             score1 += ac->a;
01163             if (tmpmax < score1) {
01164               tmpmax = score1;
01165               j = ac->arc;
01166             }
01167           }
01168         } else {
01169           for (ac=whmm->state[i].ac;ac;ac=ac->next) {
01170             score1 = wordtrellis[tl][ac->arc] + ac->a;
01171             if (tmpmax < score1) {
01172               tmpmax = score1;
01173               j = ac->arc;
01174             }
01175           }
01176         }
01177 
01178         /* スコアエンベロープチェック: 一定幅外なら落とす */
01179         /* check if score of this node is within the score envelope */
01180         if (
01181 #ifdef SCAN_BEAM
01182             tmpmax <= framemaxscore[t] - scan_beam_thres ||
01183 #endif
01184             tmpmax <= LOG_ZERO
01185             ) {
01186           /* invalid node */
01187           wordtrellis[tn][i] = LOG_ZERO;
01188 #ifdef GRAPHOUT_PRECISE_BOUNDARY
01189           if (r->graphout) {
01190             wend_token_frame[tn][i] = -1;
01191             wend_token_gscore[tn][i] = LOG_ZERO;
01192           }
01193 #endif
01194         } else {
01195           /* survived node */
01196           node_exist_p = TRUE;
01197 #ifdef GRAPHOUT_PRECISE_BOUNDARY
01198           if (r->graphout) {
01199             if (hmminfo->multipath) {
01200               if (j == wordhmmnum-1) {
01201                 wend_token_frame[tn][i] = t;
01202                 wend_token_gscore[tn][i] = tmpmax;
01203               } else {
01204                 wend_token_frame[tn][i] = wend_token_frame[tl][j];
01205                 wend_token_gscore[tn][i] = wend_token_gscore[tl][j];
01206               }
01207             } else {
01208               wend_token_frame[tn][i] = wend_token_frame[tl][j];
01209               wend_token_gscore[tn][i] = wend_token_gscore[tl][j];
01210             }
01211           }
01212 #endif
01213           /* score of node [t][i] has been determined here */
01214           wordtrellis[tn][i] = tmpmax;
01215           if (! hmminfo->multipath || i > 0) {
01216             wordtrellis[tn][i] += outprob(&(r->am->hmmwrk), t, &(whmm->state[i]), param);
01217           }
01218         }
01219         
01220       }
01221     } /* end of node loop */
01222 
01223     /* 時間 t のViterbi計算終了. 前向きスコアはscanした単語の始端 */
01224     /* Viterbi end for frame [t].  the forward score is the score of word
01225        beginning scanned */
01226     now->g[t] = wordtrellis[tn][0];
01227 #ifdef GRAPHOUT_PRECISE_BOUNDARY
01228     if (r->graphout) {
01229       now->wordend_frame[t] = wend_token_frame[tn][0];
01230       now->wordend_gscore[t] = wend_token_gscore[tn][0];
01231     }
01232 #endif
01233 
01234     if (hmminfo->multipath) {
01235       /* triphone 時, 次段のために store_point のデータをg_prevに保存 */
01236       /* store the scores crossing the store_point to g_prev, for next scan */
01237       if (ccd_flag) {
01238         /* the max arc crossing the store_point always selected as tmpmax_score */ 
01239         tmpmax_store -= store_point_maxarc;
01240         if (tmpmax_store < LOG_ZERO) tmpmax_store = LOG_ZERO;
01241         now->g_prev[t] = tmpmax_store;
01242       }
01243     }
01244 
01245     /* store the number of last computed frame */
01246     if (node_exist_p) endt = t;
01247     
01248     /* scanした単語の第1パスでの始端時刻より先まで t が進んでおり,かつ
01249        この t においてスコアエンベロープによって生き残ったノードが一つも
01250        無かったならば,このフレームで計算を打ち切りそれ以上先([0..t-1])は
01251        計算しない */
01252     /* if frame 't' already reached the beginning frame of scanned word
01253        in 1st pass and no node was survived in this frame (all nodes pruned
01254        by score envelope), terminate computation at this frame and
01255        do not computer further frame ([0..t-1]). */
01256     if (t < now->estimated_next_t && (!node_exist_p)) {
01257       /* clear the rest scores */
01258       for (i=t-1;i>=0;i--) {
01259         now->g[i] = LOG_ZERO;
01260 #ifdef GRAPHOUT_PRECISE_BOUNDARY
01261         if (r->graphout) {
01262           now->wordend_frame[i] = -1;
01263           now->wordend_gscore[i] = LOG_ZERO;
01264         }
01265 #endif
01266         if (ccd_flag) now->g_prev[i] = LOG_ZERO;
01267       }
01268       /* terminate loop */
01269       break;
01270     }
01271     
01272   } /* end of time loop */
01273   
01274   if (debug2_flag) jlog("DEBUG: scanned: [%3d-%3d]\n", endt, startt);
01275 
01276  end_of_scan:
01277 
01278   if (hmminfo->multipath) {
01279     /* 前向きスコアの最終値を計算 (状態 0 から時間 0 への遷移) */
01280     /* compute the total forward score (transition from state 0 to frame 0 */
01281     if (endt == 0) {
01282       tmpmax = LOG_ZERO;
01283       for(ac=whmm->state[0].ac;ac;ac=ac->next) {
01284         score1 = wordtrellis[tn][ac->arc] + ac->a;
01285         if (tmpmax < score1) tmpmax = score1;
01286       }
01287       now->final_g = score1;
01288     } else {
01289       now->final_g = LOG_ZERO;
01290     }
01291   }
01292   
01293   /* 次回 backscan のための情報格納 */
01294   /* store data for next backscan */
01295   if (ccd_flag) {
01296     if (store_point == (hmminfo->multipath ? wordhmmnum - 2 : wordhmmnum - 1)) {
01297       /* last_ph無し,かつ単語の音素長=1の場合、次回の scan_word() で
01298          単語全体がもう一度再計算される. この場合,
01299          g_prev は,このscan_wordを開始する前のスコアを入れておく必要がある */
01300       /* if there was no 'last_ph' and the scanned word consists of only
01301          1 phone, the whole word should be re-computed in the future scan_word().
01302          So the next 'g_prev[]' should be the initial forward scores
01303          before we begin Viterbi (= g[t]). */
01304       for (t = startt; t>=0; t--) {
01305         now->g_prev[t] = g[t];
01306       }
01307     }
01308 #ifndef GRAPHOUT_PRECISE_BOUNDARY
01309     if (r->graphout) {
01310       if (now->tail_g_score != LOG_ZERO) {
01311         if (now->prevgraph != NULL) {
01312           (now->prevgraph)->leftscore = now->tail_g_score;
01313         }
01314       }
01315     }
01316 #endif
01317     /* 次回のために now->last_ph を更新 */
01318     /* update 'now->last_ph' for future scan_word() */
01319     if (back_rescan) {
01320       now->last_ph = phmmseq[0];
01321     } else {
01322       now->last_ph = winfo->wseq[word][0];
01323     }
01324     if (hmminfo->multipath) {
01325       now->last_ph_sp_attached = has_sp[0];
01326     }
01327   }
01328 
01329 #ifdef GRAPHOUT_PRECISE_BOUNDARY
01330   if (! hmminfo->multipath) {
01331     if (r->graphout) {
01332       /* 次回の next_word 用に境界情報を調整 */
01333       /* proceed word boundary for one step for next_word */
01334       now->wordend_frame[peseqlen-1] = now->wordend_frame[0];
01335       now->wordend_gscore[peseqlen-1] = now->wordend_gscore[0];
01336       for (t=0;t<peseqlen-1;t++) {
01337         now->wordend_frame[t] = now->wordend_frame[t+1];
01338         now->wordend_gscore[t] = now->wordend_gscore[t+1];
01339       }
01340     }
01341   }
01342 #endif
01343 
01344   /* free work area */
01345   free_hmm(whmm);
01346 #ifdef TCD
01347   if (hmminfo->multipath) {
01348     if (ccd_flag) {
01349       jlog("DEBUG: last_ph = %s", (now->last_ph)->name);
01350       if (now->last_ph_sp_attached) jlog(" (sp attached)");
01351       jlog("\n");
01352     }
01353   } else {
01354     jlog("DEBUG: last_ph = %s\n", (now->last_ph)->name);
01355   }
01356 #endif
01357 }
01358 
01359 
01360 /**************************************************************************/
01361 /*** 新仮説の展開とヒューリスティックを繋いだ全体スコアを計算           ***/
01362 /*** Expand new hypothesis and compute the total score (with heuristic) ***/
01363 /**************************************************************************/
01364 
01392 void
01393 next_word(NODE *now, NODE *new, NEXTWORD *nword, HTK_Param *param, RecogProcess *r)
01394 {
01395   int   t;
01396   HMM_Logical *newphone;
01397   int lastword;
01398   int   i;
01399   LOGPROB tmpp;
01400   LOGPROB a_value;
01401   int   startt;
01402   int word;
01403   LOGPROB totalscore;
01404   TRELLIS_ATOM *tre;
01405 
01406   BACKTRELLIS *backtrellis;
01407   WORD_INFO *winfo;
01408   HTK_HMM_INFO *hmminfo;
01409   int peseqlen;
01410   boolean ccd_flag;
01411 
01412   backtrellis = r->backtrellis;
01413   winfo = r->lm->winfo;
01414   hmminfo = r->am->hmminfo;
01415   peseqlen = r->peseqlen;
01416   ccd_flag = r->ccd_flag;
01417 
01418   new->score = LOG_ZERO;
01419 
01420   word = nword->id;
01421   lastword=now->seq[now->seqnum-1];
01422 
01423   /* 単語並び、DFA状態番号、言語スコアを継承・更新 */
01424   /* inherit and update word sequence, DFA state and total LM score */
01425   for (i=0;i< now->seqnum;i++){ 
01426     new->seq[i] = now->seq[i];
01427 #ifdef CM_SEARCH
01428 #ifdef CM_MULTIPLE_ALPHA
01429     memcpy(new->cmscore[i], now->cmscore[i], sizeof(LOGPROB) * r->config->annotate.cm_alpha_num);
01430 #else
01431     new->cmscore[i] = now->cmscore[i];
01432 #endif
01433 #endif /* CM_SEARCH */
01434   }
01435   new->seq[i] = word;
01436   new->seqnum = now->seqnum+1;
01437   new->state = nword->next_state;
01438   new->totallscore = now->totallscore + nword->lscore;
01439   if (hmminfo->multipath) new->final_g = now->final_g;
01440   
01441   if (ccd_flag) {
01442     
01443     /* 展開単語の接続点の音素HMMをnewphoneにセットする. 
01444        元仮説 now との単語間の音素環境依存性を考慮する */
01445     /* set the triphone at the connection point to 'newphone', considering
01446        cross-word context dependency to 'now' */
01447     newphone = get_right_context_HMM(winfo->wseq[word][winfo->wlen[word]-1], now->last_ph->name, hmminfo);
01448     if (newphone == NULL) {     /* triphone not found */
01449       /* fallback to the original bi/mono-phone */
01450       /* error if the original is pseudo phone (not explicitly defined
01451          in hmmdefs/hmmlist) */
01452       /* exception: word with 1 phone (triphone may exist in the next expansion */
01453       if (winfo->wlen[word] > 1 && winfo->wseq[word][winfo->wlen[word]-1]->is_pseudo){
01454         error_missing_right_triphone(winfo->wseq[word][winfo->wlen[word]-1], now->last_ph->name);
01455       }
01456       newphone = winfo->wseq[word][winfo->wlen[word]-1];
01457     }
01458     
01459     /* 元仮説をscanした時の末端音素HMM -> 新仮説の直前音素HMM */
01460     /* inherit last_ph */
01461     new->last_ph = now->last_ph;
01462     if (hmminfo->multipath) {
01463       new->last_ph_sp_attached = now->last_ph_sp_attached;
01464     }
01465     
01466     /* backscan用接続ポイントのスコア g_prev[] をコピー */
01467     /* copy g_prev[] that are scores at backscan connection point */
01468     for (t=0;t<peseqlen;t++) {
01469       new->g_prev[t] = now->g_prev[t];
01470     }
01471     
01472   } else {                      /* not triphone */
01473     
01474     /* 展開単語の接続(=終端)の音素HMMをnewphoneにセット */
01475     /* set the phone at the connection point to 'newphone' */
01476     newphone = winfo->wseq[word][winfo->wlen[word]-1];
01477   }
01478 
01479 
01480   if (r->lmtype == LM_PROB) {
01481     new->lscore = nword->lscore;
01482   } else if (r->lmtype == LM_DFA) {
01483     new->lscore = 0.0;
01484   }
01485 
01486   if (! hmminfo->multipath) {
01487     /* a_value: 接続点の遷移確率 */
01488     /* a_value: transition probability of connection point */
01489     i = hmm_logical_state_num(newphone);
01490     a_value = (hmm_logical_trans(newphone))->a[i-2][i-1];
01491   }
01492 
01493   /***************************************************************************/
01494   /* 前向き(第2パス),後ろ向き(第1パス)トレリスを接続し最尤接続点を見つける */
01495   /* connect forward/backward trellis to look for the best connection time   */
01496   /***************************************************************************/
01497 
01498   if (hmminfo->multipath) {
01499     startt = peseqlen-1;
01500   } else {
01501     startt = peseqlen-2;
01502     new->g[startt+1] = LOG_ZERO;
01503   }
01504 
01505   /*-----------------------------------------------------------------*/
01506   /* 単語トレリスを探して, 次単語の最尤接続点を発見する */
01507   /* determine the best connection time of the new word, seeking the word
01508      trellis */
01509   /*-----------------------------------------------------------------*/
01510 
01511   /* update new->g[t] */
01512   if (hmminfo->multipath) {
01513     for(t=startt;t>=0;t--) {
01514       new->g[t] = now->g[t] + nword->lscore;
01515     }
01516   } else {
01517     for(t=startt;t>=0;t--) {
01518       new->g[t] = now->g[t+1] + a_value + nword->lscore;
01519     }
01520   }
01521 
01522   new->tre = NULL;
01523 
01524   if (r->lmtype == LM_DFA && !r->config->pass2.looktrellis_flag) {
01525     /* すべてのフレームにわたって最尤を探す */
01526     /* search for best trellis word throughout all frame */
01527     for(t = startt; t >= 0; t--) {
01528       tre = bt_binsearch_atom(backtrellis, t, (WORD_ID) word);
01529       if (tre == NULL) continue;
01530       totalscore = new->g[t] + tre->backscore;
01531       if (! hmminfo->multipath) {
01532         if (newphone->is_pseudo) {
01533           tmpp = outprob_cd(&(r->am->hmmwrk), t, &(newphone->body.pseudo->stateset[newphone->body.pseudo->state_num-2]), param);
01534         } else {
01535           tmpp = outprob_state(&(r->am->hmmwrk), t, newphone->body.defined->s[newphone->body.defined->state_num-2], param);
01536         }
01537         totalscore += tmpp;
01538       }
01539       if (new->score < totalscore) {
01540         new->score = totalscore;
01541         new->bestt = t;
01542         new->estimated_next_t = tre->begintime - 1;
01543         new->tre  =  tre;
01544       }
01545     }
01546 
01547     return;
01548 
01549   }
01550       
01551   /* この展開単語のトレリス上の終端時間の前後のみスキャンする
01552      前後に連続して存在するフレームについてのみ計算 */
01553   /* search for best trellis word only around the estimated time */
01554   /* 1. search forward */
01555   for(t = (nword->tre)->endtime; t >= 0; t--) {
01556     tre = bt_binsearch_atom(backtrellis, t, (WORD_ID) word);
01557     if (tre == NULL) break;     /* go to 2 if the trellis word disappear */
01558     totalscore = new->g[t] + tre->backscore;
01559     if (! hmminfo->multipath) {
01560       if (newphone->is_pseudo) {
01561         tmpp = outprob_cd(&(r->am->hmmwrk), t, &(newphone->body.pseudo->stateset[newphone->body.pseudo->state_num-2]), param);
01562       } else {
01563         tmpp = outprob_state(&(r->am->hmmwrk), t, newphone->body.defined->s[newphone->body.defined->state_num-2], param);
01564       }
01565       totalscore += tmpp;
01566     }
01567     if (new->score < totalscore) {
01568       new->score = totalscore;
01569       new->bestt = t;
01570       new->estimated_next_t = tre->begintime - 1;
01571       new->tre = tre;
01572     }
01573   }
01574   /* 2. search backward */
01575   for(t = (nword->tre)->endtime + 1; t <= startt; t++) {
01576     tre = bt_binsearch_atom(backtrellis, t, (WORD_ID) word);
01577     if (tre == NULL) break;     /* end if the trellis word disapper */
01578     totalscore = new->g[t] + tre->backscore;
01579     if (! hmminfo->multipath) {
01580       if (newphone->is_pseudo) {
01581         tmpp = outprob_cd(&(r->am->hmmwrk), t, &(newphone->body.pseudo->stateset[newphone->body.pseudo->state_num-2]), param);
01582       } else {
01583         tmpp = outprob_state(&(r->am->hmmwrk), t, newphone->body.defined->s[newphone->body.defined->state_num-2], param);
01584       }
01585       totalscore += tmpp;
01586     }
01587     if (new->score < totalscore) {
01588       new->score = totalscore;
01589       new->bestt = t;
01590       new->estimated_next_t = tre->begintime - 1;
01591       new->tre = tre;
01592     }
01593   }
01594 
01595 }
01596 
01597 /**********************************************************************/
01598 /********** 初期仮説の生成                 ****************************/
01599 /********** Generate an initial hypothesis ****************************/
01600 /**********************************************************************/
01601 
01624 void
01625 start_word(NODE *new, NEXTWORD *nword, HTK_Param *param, RecogProcess *r)
01626 {
01627   HMM_Logical *newphone;
01628   WORD_ID word;
01629   LOGPROB tmpp;
01630   int t;
01631   TRELLIS_ATOM *tre = NULL;
01632 
01633   BACKTRELLIS *backtrellis;
01634   WORD_INFO *winfo;
01635   int peseqlen;
01636   boolean ccd_flag;
01637 
01638   backtrellis = r->backtrellis;
01639   winfo = r->lm->winfo;
01640   peseqlen = r->peseqlen;
01641   ccd_flag = r->ccd_flag;
01642 
01643   /* initialize data */
01644   word = nword->id;
01645   new->score = LOG_ZERO;
01646   new->seqnum = 1;
01647   new->seq[0] = word;
01648 
01649   new->state = nword->next_state;
01650   new->totallscore = nword->lscore;
01651 
01652   /* cross-word triphone handling is not needed on startup */
01653   newphone = winfo->wseq[word][winfo->wlen[word]-1];
01654   if (ccd_flag) {
01655     new->last_ph = NULL;
01656     new->last_ph_sp_attached = FALSE;
01657   }
01658   new->lscore = nword->lscore;
01659 
01660   if (r->lmtype == LM_PROB) {
01661     new->g[peseqlen-1] = nword->lscore;
01662   } else if (r->lmtype == LM_DFA) {
01663     new->g[peseqlen-1] = 0;
01664   }
01665   
01666   for (t=peseqlen-1; t>=0; t--) {
01667     tre = bt_binsearch_atom(backtrellis, t, word);
01668     if (tre != NULL) {
01669       if (r->graphout) {
01670         new->bestt = peseqlen-1;
01671       } else {
01672         new->bestt = t;
01673       }
01674       new->score = new->g[peseqlen-1] + tre->backscore;
01675       if (! r->am->hmminfo->multipath) {
01676         if (newphone->is_pseudo) {
01677           tmpp = outprob_cd(&(r->am->hmmwrk), peseqlen-1, &(newphone->body.pseudo->stateset[newphone->body.pseudo->state_num-2]), param);
01678         } else {
01679           tmpp = outprob_state(&(r->am->hmmwrk), peseqlen-1, newphone->body.defined->s[newphone->body.defined->state_num-2], param);
01680         }
01681         new->score += tmpp;
01682       }
01683       new->estimated_next_t = tre->begintime - 1;
01684       new->tre = tre;
01685       break;
01686     }
01687   }
01688   if (tre == NULL) {            /* no word in backtrellis */
01689     new->score = LOG_ZERO;
01690   }
01691 
01692 }
01693 
01694 
01718 void
01719 last_next_word(NODE *now, NODE *new, HTK_Param *param, RecogProcess *r)
01720 {
01721   cpy_node(new, now);
01722   /* 最終スコアを設定 */
01723   /* update the final score */
01724   if (r->am->hmminfo->multipath) {
01725     new->score = now->final_g;
01726   } else {
01727     new->score = now->g[0];
01728   }
01729 }
01730 
01731 
01732 #endif /* PASS2_STRICT_IWCD */
01733 
01734 /* end of file */

Generated on Tue Dec 18 15:59:53 2007 for Julius by  doxygen 1.5.4