Julius 4.2
libjulius/src/search_bestfirst_v2.c
説明を見る。
00001 
00054 /*
00055  * Copyright (c) 1991-2011 Kawahara Lab., Kyoto University
00056  * Copyright (c) 2000-2005 Shikano Lab., Nara Institute of Science and Technology
00057  * Copyright (c) 2005-2011 Julius project team, Nagoya Institute of Technology
00058  * All rights reserved
00059  */
00060 
00061 /* By "fast" setting (default), search_bestfirst_v1.c is used for faster
00062    decoding.  Please specify option "--enable-setup=standard" or
00063    "--enable-strict-iwcd2" at "./configure" to activate this. */
00064 
00065 #include <julius/julius.h>
00066 
00067 #ifdef PASS2_STRICT_IWCD
00068 
00069 #undef TCD                      ///< Define if want triphone debug messages
00070 
00071 
00072 /**********************************************************************/
00073 /************ 仮説ノードの基本操作                         ************/
00074 /************ Basic functions for hypothesis node handling ************/
00075 /**********************************************************************/
00076 
00077 #undef STOCKER_DEBUG
00078 
00079 #ifdef STOCKER_DEBUG
00080 static int stocked_num = 0;
00081 static int reused_num = 0;
00082 static int new_num = 0;
00083 static int request_num = 0;
00084 #endif
00085 
00098 static void
00099 free_node_exec(NODE *node)
00100 {
00101   if (node == NULL) return;
00102   free(node->g);
00103 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00104   if (node->region->graphout) {
00105     free(node->wordend_frame);
00106     free(node->wordend_gscore);
00107   }
00108 #endif
00109   free(node);
00110 }
00111 
00126 void
00127 free_node(NODE *node)
00128 {
00129   if (node == NULL) return;
00130 
00131   if (node->region->graphout) {
00132     if (node->prevgraph != NULL && node->prevgraph->saved == FALSE) {
00133       wordgraph_free(node->prevgraph);
00134     }
00135   }
00136 
00137   /* save to stocker */
00138   node->next = node->region->pass2.stocker_root;
00139   node->region->pass2.stocker_root = node;
00140 
00141 #ifdef STOCKER_DEBUG
00142   stocked_num++;
00143 #endif
00144 }
00145 
00162 void
00163 clear_stocker(StackDecode *s)
00164 {
00165   NODE *node, *tmp;
00166   node = s->stocker_root;
00167   while(node) {
00168     tmp = node->next;
00169     free_node_exec(node);
00170     node = tmp;
00171   }
00172   s->stocker_root = NULL;
00173 
00174 #ifdef STOCKER_DEBUG
00175   jlog("DEBUG: %d times requested, %d times newly allocated, %d times reused\n", request_num, new_num, reused_num);
00176   stocked_num = 0;
00177   reused_num = 0;
00178   new_num = 0;
00179   request_num = 0;
00180 #endif
00181 }
00182 
00203 NODE *
00204 cpy_node(NODE *dst, NODE *src)
00205 {
00206   int peseqlen;
00207 
00208   peseqlen = src->region->peseqlen;
00209   
00210   dst->next = src->next;
00211   dst->prev = src->prev;
00212   memcpy(dst->g, src->g, sizeof(LOGPROB) * peseqlen);
00213   memcpy(dst->seq, src->seq, sizeof(WORD_ID) * MAXSEQNUM);
00214 #ifdef CM_SEARCH
00215 #ifdef CM_MULTIPLE_ALPHA
00216   {
00217     int w;
00218     for(w=0;w<src->seqnum;w++) {
00219       memcpy(dst->cmscore[w], src->cmscore[w], sizeof(LOGPROB) * src->region->config->annotate.cm_alpha_num);
00220     }
00221   }     
00222 #else
00223   memcpy(dst->cmscore, src->cmscore, sizeof(LOGPROB) * MAXSEQNUM);
00224 #endif
00225 #endif /* CM_SEARCH */
00226   dst->seqnum = src->seqnum;
00227   dst->score = src->score;
00228   dst->bestt = src->bestt;
00229   dst->estimated_next_t = src->estimated_next_t;
00230   dst->endflag = src->endflag;
00231   dst->state = src->state;
00232   dst->tre = src->tre;
00233   if (src->region->ccd_flag) {
00234     dst->last_ph = src->last_ph;
00235     dst->last_ph_sp_attached = src->last_ph_sp_attached;
00236   }
00237   dst->totallscore = src->totallscore;
00238   dst->final_g = src->final_g;
00239 #ifdef VISUALIZE
00240   dst->popnode = src->popnode;
00241 #endif
00242 
00243   if (src->region->graphout) {
00244 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00245     memcpy(dst->wordend_frame, src->wordend_frame, sizeof(short) * peseqlen);
00246     memcpy(dst->wordend_gscore, src->wordend_gscore, sizeof(LOGPROB) * peseqlen);
00247 #endif
00248     dst->prevgraph = src->prevgraph;
00249     dst->lastcontext = src->lastcontext;
00250 #ifndef GRAPHOUT_PRECISE_BOUNDARY
00251     dst->tail_g_score = src->tail_g_score;
00252 #endif
00253   }
00254   return(dst);
00255 }
00256 
00277 NODE *
00278 newnode(RecogProcess *r)
00279 {
00280   NODE *tmp;
00281   int i;
00282   int peseqlen;
00283 
00284   peseqlen = r->peseqlen;
00285 
00286 #ifdef STOCKER_DEBUG
00287   request_num++;
00288 #endif
00289   if ((tmp = r->pass2.stocker_root) != NULL) {
00290     /* re-use ones in the stocker */
00291     r->pass2.stocker_root = tmp->next;
00292 #ifdef STOCKER_DEBUG
00293     stocked_num--;
00294     reused_num++;
00295 #endif
00296   } else {
00297     /* allocate new */
00298     tmp = (NODE *)mymalloc(sizeof(NODE));
00299     tmp->g = (LOGPROB *)mymalloc(sizeof(LOGPROB) * peseqlen);
00300 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00301     if (r->graphout) {
00302       tmp->wordend_frame = (short *)mymalloc(sizeof(short) * peseqlen);
00303       tmp->wordend_gscore = (LOGPROB *)mymalloc(sizeof(LOGPROB) * peseqlen);
00304     }
00305 #endif
00306 #ifdef STOCKER_DEBUG
00307     new_num++;
00308 #endif
00309   }
00310 
00311   /* clear the data */
00312   /*bzero(tmp,sizeof(NODE));*/
00313   tmp->next=NULL;
00314   tmp->prev=NULL;
00315   tmp->last_ph = NULL;
00316   tmp->last_ph_sp_attached = FALSE;
00317   if (r->ccd_flag) {
00318     tmp->totallscore = LOG_ZERO;
00319   }
00320   tmp->endflag = FALSE;
00321   tmp->seqnum = 0;
00322   for(i = 0; i < peseqlen; i++) {
00323     tmp->g[i] = LOG_ZERO;
00324   }
00325   tmp->final_g = LOG_ZERO;
00326 #ifdef VISUALIZE
00327   tmp->popnode = NULL;
00328 #endif
00329   if (r->graphout) {
00330     tmp->prevgraph = NULL;
00331     tmp->lastcontext = NULL;
00332   }
00333 
00334   tmp->region = r;
00335 
00336   return(tmp);
00337 }
00338 
00339 
00340 /**********************************************************************/
00341 /************ 前向きトレリス展開と尤度計算             ****************/
00342 /************ Expand trellis and update forward score *****************/
00343 /**********************************************************************/
00344 
00361 void
00362 malloc_wordtrellis(RecogProcess *r)
00363 {
00364   int maxwn;
00365   StackDecode *dwrk;
00366 
00367   maxwn = r->lm->winfo->maxwn + 10;     /* CCDによる変動を考慮 */
00368   dwrk = &(r->pass2);
00369 
00370   dwrk->wordtrellis[0] = (LOGPROB *)mymalloc(sizeof(LOGPROB) * maxwn);
00371   dwrk->wordtrellis[1] = (LOGPROB *)mymalloc(sizeof(LOGPROB) * maxwn);
00372 
00373   dwrk->g = (LOGPROB *)mymalloc(sizeof(LOGPROB) * r->peseqlen);
00374 
00375   dwrk->phmmlen_max = r->lm->winfo->maxwlen + 2;
00376   dwrk->phmmseq = (HMM_Logical **)mymalloc(sizeof(HMM_Logical *) * dwrk->phmmlen_max);
00377   if (r->lm->config->enable_iwsp && r->am->hmminfo->multipath) {
00378     dwrk->has_sp = (boolean *)mymalloc(sizeof(boolean) * dwrk->phmmlen_max);
00379   } else {
00380     dwrk->has_sp = NULL;
00381   }
00382 
00383   dwrk->wef = NULL;
00384   dwrk->wes = NULL;
00385   dwrk->wend_token_frame[0] = NULL;
00386   dwrk->wend_token_frame[1] = NULL;
00387   dwrk->wend_token_gscore[0] = NULL;
00388   dwrk->wend_token_gscore[1] = NULL;
00389 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00390   if (r->graphout) {
00391     dwrk->wef = (short *)mymalloc(sizeof(short) * r->peseqlen);
00392     dwrk->wes = (LOGPROB *)mymalloc(sizeof(LOGPROB) * r->peseqlen);
00393     dwrk->wend_token_frame[0] = (short *)mymalloc(sizeof(short) * maxwn);
00394     dwrk->wend_token_frame[1] = (short *)mymalloc(sizeof(short) * maxwn);
00395     dwrk->wend_token_gscore[0] = (LOGPROB *)mymalloc(sizeof(LOGPROB) * maxwn);
00396     dwrk->wend_token_gscore[1] = (LOGPROB *)mymalloc(sizeof(LOGPROB) * maxwn);
00397   }
00398 #endif
00399 }
00400 
00413 void
00414 free_wordtrellis(StackDecode *dwrk)
00415 {
00416   free(dwrk->wordtrellis[0]);
00417   free(dwrk->wordtrellis[1]);
00418   free(dwrk->g);
00419   free(dwrk->phmmseq);
00420   if (dwrk->has_sp) {
00421     free(dwrk->has_sp);
00422     dwrk->has_sp = NULL;
00423   }
00424 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00425   if (dwrk->wef) {
00426     free(dwrk->wef);
00427     free(dwrk->wes);
00428     free(dwrk->wend_token_frame[0]);
00429     free(dwrk->wend_token_frame[1]);
00430     free(dwrk->wend_token_gscore[0]);
00431     free(dwrk->wend_token_gscore[1]);
00432     dwrk->wef = NULL;
00433   }
00434 #endif
00435 }
00436 
00437 
00438 /**********************************************************************/
00439 /************ 仮説の前向き尤度計算                  *******************/
00440 /************ Compute forward score of a hypothesis *******************/
00441 /**********************************************************************/
00442 
00443 /* 与えられた音素のならび phmmseq[0..phmmlen-1]に対してviterbi計算を行う. 
00444    g[0..framelen-1] のスコアを初期値として g_new[0..framelen-1]に更新値を代入. 
00445    最低 least_frame まではscanする. */
00446 /* Viterbi computation for the given phoneme sequence 'phmmseq[0..phmmlen-1]'
00447    with g[0..framelen-1] as initial values.  The results are stored in
00448    g_new[0..framelen-1].  Scan should not terminate at least it reaches
00449    'least_frame'. */
00491 static void
00492 do_viterbi(LOGPROB *g, LOGPROB *g_new, HMM_Logical **phmmseq, boolean *has_sp, int phmmlen, HTK_Param *param, int framelen, int least_frame, LOGPROB *final_g, short *wordend_frame_src, short *wordend_frame_dst, LOGPROB *wordend_gscore_src, LOGPROB *wordend_gscore_dst, RecogProcess *r) /* has_sp and final_g is for multipath only */
00493 {
00494   HMM *whmm;                    /* HMM */
00495   int wordhmmnum;               /* length of above */
00496   int startt;                   /* scan start frame */
00497   LOGPROB tmpmax,tmpscore;      /* variables for Viterbi process */
00498   A_CELL *ac;
00499   int t,i,j;
00500   boolean node_exist_p;
00501   int tn;                      
00502   int tl;                      
00503 
00504   /* store global values to local for rapid access */
00505   StackDecode *dwrk;
00506   WORD_INFO *winfo;
00507   HTK_HMM_INFO *hmminfo;
00508   LOGPROB *framemaxscore;
00509 #ifdef SCAN_BEAM
00510   LOGPROB scan_beam_thres;
00511 #endif
00512 
00513   dwrk = &(r->pass2);
00514   winfo = r->lm->winfo;
00515   hmminfo = r->am->hmminfo;
00516   framemaxscore = r->pass2.framemaxscore;
00517 #ifdef SCAN_BEAM
00518   scan_beam_thres = r->config->pass2.scan_beam_thres;
00519 #endif
00520 
00521 
00522 #ifdef TCD
00523   jlog("DEBUG: scan for:");
00524   for (i=0;i<phmmlen;i++) {
00525     jlog(" %s", phmmseq[i]->name);
00526   }
00527   jlog("\n");
00528 #endif
00529   
00530   /* 単語HMMを作る */
00531   /* make word HMM */
00532   whmm = new_make_word_hmm(hmminfo, phmmseq, phmmlen, has_sp);
00533   if (whmm == NULL) {
00534     j_internal_error("Error: failed to make word hmm\n");
00535   }
00536   wordhmmnum = whmm->len;
00537   if (wordhmmnum >= winfo->maxwn + 10) {
00538     j_internal_error("do_viterbi: word too long (>%d)\n", winfo->maxwn + 10);
00539   }
00540 
00541   /* scan開始点を検索 -> starttへ*/
00542   /* search for the start frame -> set to startt */
00543   for(t = framelen-1; t >=0 ; t--) {
00544     if (
00545 #ifdef SCAN_BEAM
00546         g[t] > framemaxscore[t] - scan_beam_thres &&
00547 #endif
00548         g[t] > LOG_ZERO) {
00549       break;
00550     }
00551   }
00552   if (t < 0) {                  /* no node has score > LOG_ZERO */
00553     /* reset all scores and end */
00554     for(t=0;t<framelen;t++) {
00555       g_new[t] = LOG_ZERO;
00556 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00557       if (r->graphout) {
00558         wordend_frame_dst[t] = -1;
00559         wordend_gscore_dst[t] = LOG_ZERO;
00560       }
00561 #endif
00562     }
00563     free_hmm(whmm);
00564     return;
00565   }
00566   startt = t;
00567   
00568   /* 開始点以降[startt+1..framelen-1] の g_new[] をリセット */
00569   /* clear g_new[] for [startt+1..framelen-1] */
00570   for(t=framelen-1;t>startt;t--) {
00571     g_new[t] = LOG_ZERO;
00572 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00573     if (r->graphout) {
00574       wordend_frame_dst[t] = -1;
00575       wordend_gscore_dst[t] = LOG_ZERO;
00576     }
00577 #endif
00578   }
00579 
00580   /*****************/
00581   /* viterbi start */
00582   /*****************/
00583 
00584   /* set initial swap buffer */
00585   tn = 0; tl = 1;
00586 
00587 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00588   if (r->graphout) {
00589     for(i=0;i<wordhmmnum;i++) {
00590       dwrk->wend_token_frame[tn][i] = -1;
00591       dwrk->wend_token_gscore[tn][i] = LOG_ZERO;
00592     }
00593   }
00594 #endif
00595 
00596   if (! hmminfo->multipath) {
00597     /* 時間 [startt] 上の値を初期化 */
00598     /* initialize scores on frame [startt] */
00599     for(i=0;i<wordhmmnum-1;i++) dwrk->wordtrellis[tn][i] = LOG_ZERO;
00600     dwrk->wordtrellis[tn][wordhmmnum-1] = g[startt] + outprob(&(r->am->hmmwrk), startt, &(whmm->state[wordhmmnum-1]), param);
00601     g_new[startt] = dwrk->wordtrellis[tn][0];
00602 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00603     if (r->graphout) {
00604       dwrk->wend_token_frame[tn][wordhmmnum-1] = wordend_frame_src[startt];
00605       dwrk->wend_token_gscore[tn][wordhmmnum-1] = wordend_gscore_src[startt];
00606       wordend_frame_dst[startt] = dwrk->wend_token_frame[tn][0];
00607       wordend_gscore_dst[startt] = dwrk->wend_token_gscore[tn][0];
00608     }
00609 #endif
00610   }
00611   
00612   /* メインループ: startt から始まり 0 に向かって Viterbi 計算 */
00613   /* main loop: start from [startt], and compute Viterbi toward [0] */
00614   for(t = hmminfo->multipath ? startt : startt - 1; t >= 0; t--) {
00615     
00616     /* wordtrellisのワークエリアをスワップ */
00617     /* swap workarea of wordtrellis */
00618     i = tn; tn = tl; tl = i;
00619 
00620     node_exist_p = FALSE;       /* TRUE if there is at least 1 survived node in this frame */
00621 
00622     if (! hmminfo->multipath) {
00623     
00624       /* 端のノード [t][wordhmmnum-1]は,内部遷移 か g[]の高い方になる */
00625       /* the edge node [t][wordhmmnum-1] is either internal transitin or g[] */
00626       tmpscore = LOG_ZERO;
00627       for (ac=whmm->state[wordhmmnum-1].ac;ac;ac=ac->next) {
00628         if (tmpscore < dwrk->wordtrellis[tl][ac->arc] + ac->a) {
00629           j = ac->arc;
00630           tmpscore = dwrk->wordtrellis[tl][ac->arc] + ac->a;
00631         }
00632       }
00633       if (g[t] > tmpscore) {
00634         tmpmax = g[t];
00635 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00636         if (r->graphout) {
00637           dwrk->wend_token_frame[tn][wordhmmnum-1] = wordend_frame_src[t];
00638           dwrk->wend_token_gscore[tn][wordhmmnum-1] = wordend_gscore_src[t];
00639         }
00640 #endif
00641       } else {
00642         tmpmax = tmpscore;
00643 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00644         if (r->graphout) {
00645           dwrk->wend_token_frame[tn][wordhmmnum-1] = dwrk->wend_token_frame[tl][j];
00646           dwrk->wend_token_gscore[tn][wordhmmnum-1] = dwrk->wend_token_gscore[tl][j];
00647         }
00648 #endif
00649       }
00650       
00651       /* 端のノードのスコアエンベロープチェック: 一定幅外なら落とす */
00652       /* check if the edge node is within score envelope */
00653       if (
00654 #ifdef SCAN_BEAM
00655           tmpmax <= framemaxscore[t] - scan_beam_thres ||
00656 #endif
00657           tmpmax <= LOG_ZERO
00658           ) {
00659         dwrk->wordtrellis[tn][wordhmmnum-1] = LOG_ZERO;
00660 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00661         if (r->graphout) {
00662           dwrk->wend_token_frame[tn][wordhmmnum-1] = -1;
00663           dwrk->wend_token_gscore[tn][wordhmmnum-1] = LOG_ZERO;
00664         }
00665 #endif
00666       } else {
00667         node_exist_p = TRUE;
00668         dwrk->wordtrellis[tn][wordhmmnum-1] = tmpmax + outprob(&(r->am->hmmwrk), t, &(whmm->state[wordhmmnum-1]), param);
00669       }
00670 
00671     }
00672 
00673     /* node[wordhmmnum-2..0]についてトレリスを展開 */
00674     /* expand trellis for node [t][wordhmmnum-2..0] */
00675     for(i=wordhmmnum-2;i>=0;i--) {
00676       
00677       /* 最尤パスと最尤スコア tmpmax を見つける */
00678       /* find most likely path and the max score 'tmpmax' */
00679       tmpmax = LOG_ZERO;
00680       for (ac=whmm->state[i].ac;ac;ac=ac->next) {
00681         if (hmminfo->multipath) {
00682           if (ac->arc == wordhmmnum-1) tmpscore = g[t];
00683           else if (t + 1 > startt) tmpscore = LOG_ZERO;
00684           else tmpscore = dwrk->wordtrellis[tl][ac->arc];
00685           tmpscore += ac->a;
00686         } else {
00687           tmpscore = dwrk->wordtrellis[tl][ac->arc] + ac->a;
00688         }
00689         if (tmpmax < tmpscore) {
00690           tmpmax = tmpscore;
00691           j = ac->arc;
00692         }
00693       }
00694       
00695       /* スコアエンベロープチェック: 一定幅外なら落とす */
00696       /* check if score of this node is within the score envelope */
00697       if (
00698 #ifdef SCAN_BEAM
00699           tmpmax <= framemaxscore[t] - scan_beam_thres ||
00700 #endif
00701           tmpmax <= LOG_ZERO
00702           ) {
00703         /* invalid node */
00704         dwrk->wordtrellis[tn][i] = LOG_ZERO;
00705 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00706         if (r->graphout) {
00707           dwrk->wend_token_frame[tn][i] = -1;
00708           dwrk->wend_token_gscore[tn][i] = LOG_ZERO;
00709         }
00710 #endif
00711       } else {
00712         /* survived node */
00713         node_exist_p = TRUE;
00714         dwrk->wordtrellis[tn][i] = tmpmax;
00715         if (! hmminfo->multipath || i > 0) {
00716           dwrk->wordtrellis[tn][i] += outprob(&(r->am->hmmwrk), t, &(whmm->state[i]), param);
00717         }
00718 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00719         if (r->graphout) {
00720           if (hmminfo->multipath) {
00721             if (j == wordhmmnum-1) {
00722               dwrk->wend_token_frame[tn][i] = wordend_frame_src[t];
00723               dwrk->wend_token_gscore[tn][i] = wordend_gscore_src[t];
00724             } else {
00725               dwrk->wend_token_frame[tn][i] = dwrk->wend_token_frame[tl][j];
00726               dwrk->wend_token_gscore[tn][i] = dwrk->wend_token_gscore[tl][j];
00727             }
00728           } else {
00729             dwrk->wend_token_frame[tn][i] = dwrk->wend_token_frame[tl][j];
00730             dwrk->wend_token_gscore[tn][i] = dwrk->wend_token_gscore[tl][j];
00731           }
00732         }
00733 #endif
00734       }
00735     } /* end of node loop */
00736 
00737     /* 時間 t のViterbi計算終了. 新たな前向きスコア g_new[t] をセット */
00738     /* Viterbi end for frame [t].  set the new forward score g_new[t] */
00739     g_new[t] = dwrk->wordtrellis[tn][0];
00740 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00741     if (r->graphout) {
00742     /* new wordend */
00743       wordend_frame_dst[t] = dwrk->wend_token_frame[tn][0];
00744       wordend_gscore_dst[t] = dwrk->wend_token_gscore[tn][0];
00745     }
00746 #endif
00747     /* 指定された least_frame より先まで t が進んでおり,かつこの t において
00748        スコアエンベロープによって生き残ったノードが一つも無かった場合,
00749        このフレームで計算を打ち切りそれ以上先([0..t-1])は計算しない */
00750     /* if frame 't' already reached the 'least_frame' and no node was
00751        survived in this frame (all nodes pruned by score envelope),
00752        terminate computation at this frame and do not computer further
00753        frame ([0..t-1]). */
00754     if (t < least_frame && (!node_exist_p)) {
00755       /* crear the rest scores */
00756       for (i=t-1;i>=0;i--) {
00757         g_new[i] = LOG_ZERO;
00758 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00759         if (r->graphout) {
00760           wordend_frame_dst[i] = -1;
00761           wordend_gscore_dst[i] = LOG_ZERO;
00762         }
00763 #endif
00764       }
00765       /* terminate loop */
00766       break;
00767     }
00768     
00769   } /* end of time loop */
00770 
00771   if (hmminfo->multipath) {
00772     /* 前向きスコアの最終値を計算 (状態 0 から時間 0 への遷移) */
00773     /* compute the total forward score (transition from state 0 to frame 0 */
00774     if (t < 0) {                        /* computed till the end */
00775       tmpmax = LOG_ZERO;
00776       for(ac=whmm->state[0].ac;ac;ac=ac->next) {
00777         tmpscore = dwrk->wordtrellis[tn][ac->arc] + ac->a;
00778         if (tmpmax < tmpscore) tmpmax = tmpscore;
00779       }
00780       *final_g = tmpmax;
00781     } else {
00782       *final_g = LOG_ZERO;
00783     }
00784   }
00785 
00786   /* free work area */
00787   free_hmm(whmm);
00788 }
00789 
00813 static void
00814 do_viterbi_next_word(NODE *now, NODE *new, HMM_Logical *lastphone, boolean sp, HTK_Param *param, RecogProcess *r) /* sp is for multipath only */
00815 {
00816   int t, n;
00817   LOGPROB a_value;              /* for non multi-path */
00818   int peseqlen;
00819   boolean multipath;
00820   StackDecode *dwrk;
00821 
00822   dwrk = &(r->pass2);
00823 
00824   multipath = r->am->hmminfo->multipath;
00825 
00826   peseqlen = r->peseqlen;
00827   
00828   if (! multipath) {
00829 
00830     /* もし展開元仮説の最後の単語の音素長が 1 であれば,その音素は
00831        直前の scan_word で計算されていない. この場合, now->g[] に以前の
00832        初期値が格納されている. 
00833        もし音素長が1以上であれば,now->g[] はその手前まで計算した状態
00834        のスコアが入っているので,now->g[t] から初期値を設定する必要がある */
00835     /* If the length of last word is 1, it means the last phone was not
00836        scanned in the last call of scan_word().  In this case, now->g[]
00837        keeps the previous initial value, so start viterbi with the old scores.
00838        If the length is more than 1, the now->g[] keeps the values of the
00839        scan result till the previous phone, so make initial value
00840        considering last transition probability. */
00841     if (r->lm->winfo->wlen[now->seq[now->seqnum-1]] > 1) {
00842       n = hmm_logical_state_num(lastphone);
00843       a_value = (hmm_logical_trans(lastphone))->a[n-2][n-1];
00844       for(t=0; t<peseqlen-1; t++) dwrk->g[t] = now->g[t+1] + a_value;
00845       dwrk->g[peseqlen-1] = LOG_ZERO;
00846     } else {
00847       for(t=0; t<peseqlen; t++) dwrk->g[t] = now->g[t];
00848     }
00849 
00850   } else {
00851   
00852     for(t=0; t<peseqlen; t++) dwrk->g[t] = now->g[t];
00853     dwrk->phmmseq[0] = lastphone;
00854     if (r->lm->config->enable_iwsp) dwrk->has_sp[0] = sp;
00855 
00856   }
00857   
00858   do_viterbi(dwrk->g, new->g,
00859              multipath ? dwrk->phmmseq : &lastphone,
00860              (r->lm->config->enable_iwsp && multipath) ? dwrk->has_sp : NULL,
00861              1, param, peseqlen, now->estimated_next_t, &(new->final_g)
00862 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00863              , now->wordend_frame, new->wordend_frame
00864              , now->wordend_gscore, new->wordend_gscore
00865 #else
00866              , NULL, NULL
00867              , NULL, NULL
00868 #endif
00869              , r
00870              );
00871 
00872 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00873   if (! multipath) {
00874     if (r->graphout) {
00875       /* 次回の next_word 用に境界情報を調整 */
00876       /* proceed word boundary for one step for next_word */
00877       new->wordend_frame[r->peseqlen-1] = new->wordend_frame[0];
00878       new->wordend_gscore[r->peseqlen-1] = new->wordend_gscore[0];
00879       for (t=0;t<r->peseqlen-1;t++) {
00880         new->wordend_frame[t] = new->wordend_frame[t+1];
00881         new->wordend_gscore[t] = new->wordend_gscore[t+1];
00882       }
00883     }
00884   }
00885 #endif
00886 }
00887 
00907 void
00908 scan_word(NODE *now, HTK_Param *param, RecogProcess *r)
00909 {
00910   int   i,t;
00911   WORD_ID word;
00912   int phmmlen;
00913   HMM_Logical *tailph;
00914 
00915   /* store global values to local for rapid access */
00916   WORD_INFO *winfo;
00917   HTK_HMM_INFO *hmminfo;
00918   int peseqlen;
00919   boolean ccd_flag;
00920   boolean enable_iwsp;          /* multipath */
00921   StackDecode *dwrk;
00922 
00923   dwrk = &(r->pass2);
00924   winfo = r->lm->winfo;
00925   hmminfo = r->am->hmminfo;
00926   peseqlen = r->peseqlen;
00927   ccd_flag = r->ccd_flag;
00928   if (hmminfo->multipath) {
00929     enable_iwsp = r->lm->config->enable_iwsp;
00930   }
00931   
00932 #ifndef GRAPHOUT_PRECISE_BOUNDARY
00933   if (r->graphout) {
00934     if (ccd_flag) {
00935       now->tail_g_score = now->g[now->bestt];
00936     }
00937   }
00938 #endif
00939 
00940   /* ----------------------- prepare phoneme sequence ------------------ */
00941   /* triphoneなら先頭の1音素はここでは対象外(あとでnext_wordでやる) */
00942   /*             末尾の1音素はコンテキストにしたがって置換 */
00943   /* with triphone, modify the tail phone of the last word according to the
00944      previous word, and do not compute the head phone here (that will be
00945      computed later in next_word() */
00946   word = now->seq[now->seqnum-1];
00947   
00948 #ifdef TCD
00949     jlog("DEBUG: w=");
00950     for(i=0;i<winfo->wlen[word];i++) {
00951       jlog(" %s",(winfo->wseq[word][i])->name);
00952     }
00953     if (ccd_flag) {
00954       if (now->last_ph != NULL) {
00955         jlog(" | %s", (now->last_ph)->name);
00956       }
00957     }
00958     jlog("\n");
00959 #endif /* TCD */
00960     
00961   if (ccd_flag) {
00962     
00963     /* the tail triphone of the last word varies by context */
00964     if (now->last_ph != NULL) {
00965       tailph = get_right_context_HMM(winfo->wseq[word][winfo->wlen[word]-1], now->last_ph->name, hmminfo);
00966       if (tailph == NULL) {
00967         /* fallback to the original bi/mono-phone */
00968         /* error if the original is pseudo phone (not explicitly defined
00969            in hmmdefs/hmmlist) */
00970         /* exception: word with 1 phone (triphone may exist in the next expansion */
00971         if (winfo->wlen[word] > 1 && winfo->wseq[word][winfo->wlen[word]-1]->is_pseudo){
00972           error_missing_right_triphone(winfo->wseq[word][winfo->wlen[word]-1], now->last_ph->name);
00973         }
00974 
00975         tailph = winfo->wseq[word][winfo->wlen[word]-1];
00976       }
00977     } else {
00978       tailph = winfo->wseq[word][winfo->wlen[word]-1];
00979     }
00980     /* 長さ1の単語は次のnextwordでさらに変化するのでここではscanしない */
00981     /* do not scan word if the length is 1, as it further varies in the
00982        following next_word() */
00983     if (winfo->wlen[word] == 1) {
00984       now->last_ph = tailph;
00985       if (enable_iwsp && hmminfo->multipath) now->last_ph_sp_attached = TRUE;
00986 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00987       if (r->graphout) {
00988         /* 単語境界伝搬情報を初期化 */
00989         /* initialize word boundary propagation info */
00990         for (t=0;t<peseqlen;t++) {
00991           now->wordend_frame[t] = t;
00992           now->wordend_gscore[t] = now->g[t];
00993         }
00994       }
00995 #endif
00996 #ifdef TCD
00997       jlog("DEBUG: suspended as %s\n", (now->last_ph)->name);
00998 #endif
00999       return;
01000     }
01001 
01002     /* scan範囲の音素列を準備 */
01003     /* prepare HMM of the scan range */
01004     phmmlen = winfo->wlen[word] - 1;
01005     if (phmmlen > dwrk->phmmlen_max) {
01006       j_internal_error("scan_word: num of phonemes in a word exceed phmmlenmax (%d) ?\n", dwrk->phmmlen_max);
01007     }
01008     for (i=0;i<phmmlen-1;i++) {
01009       dwrk->phmmseq[i] = winfo->wseq[word][i+1];
01010     }
01011     dwrk->phmmseq[phmmlen-1] = tailph;
01012     if (enable_iwsp && hmminfo->multipath) {
01013       for (i=0;i<phmmlen-1;i++) dwrk->has_sp[i] = FALSE;
01014       dwrk->has_sp[phmmlen-1] = TRUE;
01015     }
01016 
01017   } else {                      /* ~ccd_flag */
01018 
01019     phmmlen = winfo->wlen[word];
01020     for (i=0;i<phmmlen;i++) dwrk->phmmseq[i] = winfo->wseq[word][i];
01021     if (enable_iwsp && hmminfo->multipath) {
01022       for (i=0;i<phmmlen;i++) dwrk->has_sp[i] = FALSE;
01023       dwrk->has_sp[phmmlen-1] = TRUE;
01024     }
01025 
01026   }
01027 
01028   /* 元のg[]をいったん待避しておく */
01029   /* temporally keeps the original g[] */
01030   for (t=0;t<peseqlen;t++) dwrk->g[t] = now->g[t];
01031 
01032 #ifdef GRAPHOUT_PRECISE_BOUNDARY
01033   if (r->graphout) {
01034     /* 単語境界伝搬情報を初期化 */
01035     /* initialize word boundary propagation info */
01036     for (t=0;t<peseqlen;t++) {
01037       dwrk->wef[t] = t;
01038       dwrk->wes[t] = now->g[t];
01039     }
01040   }
01041 #endif
01042 
01043   /* viterbiを実行して g[] から now->g[] を更新する */
01044   /* do viterbi computation for phmmseq from g[] to now->g[] */
01045   do_viterbi(dwrk->g, now->g, dwrk->phmmseq, (enable_iwsp && hmminfo->multipath) ? dwrk->has_sp : NULL, 
01046              phmmlen, param, peseqlen, now->estimated_next_t, &(now->final_g)
01047 #ifdef GRAPHOUT_PRECISE_BOUNDARY
01048              /* 単語境界情報 we[] から now->wordend_frame[] を更新する */
01049              /* propagate word boundary info from we[] to now->wordend_frame[] */
01050              , dwrk->wef, now->wordend_frame
01051              , dwrk->wes, now->wordend_gscore
01052 #else
01053              , NULL, NULL
01054              , NULL, NULL
01055 #endif
01056              , r
01057              );
01058 #ifdef GRAPHOUT_PRECISE_BOUNDARY
01059   if (! hmminfo->multipath) {
01060     if (r->graphout) {
01061       /* 次回の next_word 用に境界情報を調整 */
01062       /* proceed word boundary for one step for next_word */
01063       now->wordend_frame[peseqlen-1] = now->wordend_frame[0];
01064       now->wordend_gscore[peseqlen-1] = now->wordend_gscore[0];
01065       for (t=0;t<peseqlen-1;t++) {
01066         now->wordend_frame[t] = now->wordend_frame[t+1];
01067         now->wordend_gscore[t] = now->wordend_gscore[t+1];
01068       }
01069     }
01070   }
01071 #endif
01072 
01073   if (ccd_flag) {
01074     /* 次回のために now->last_ph を更新 */
01075     /* update 'now->last_ph' for future scan_word() */
01076     now->last_ph = winfo->wseq[word][0];
01077     if (enable_iwsp && hmminfo->multipath) now->last_ph_sp_attached = FALSE; /* wlen > 1 here */
01078 #ifdef TCD
01079     jlog("DEBUG: last_ph = %s\n", (now->last_ph)->name);
01080 #endif
01081   }
01082 }
01083 
01084 
01085 /**************************************************************************/
01086 /*** 新仮説の展開とヒューリスティックを繋いだ全体スコアを計算           ***/
01087 /*** Expand new hypothesis and compute the total score (with heuristic) ***/
01088 /**************************************************************************/
01089 
01115 void
01116 next_word(NODE *now, NODE *new, NEXTWORD *nword, HTK_Param *param, RecogProcess *r)
01117 {
01118   HMM_Logical *lastphone, *newphone;
01119   LOGPROB *g_src;
01120   int   t;
01121   int lastword;
01122   int   i;
01123   LOGPROB a_value;
01124   LOGPROB tmpp;
01125   int   startt;
01126   int word;
01127   TRELLIS_ATOM *tre;
01128   LOGPROB totalscore;
01129   BACKTRELLIS *backtrellis;
01130   WORD_INFO *winfo;
01131   HTK_HMM_INFO *hmminfo;
01132   int peseqlen;
01133   boolean ccd_flag;
01134   StackDecode *dwrk;
01135 
01136   dwrk = &(r->pass2);
01137   backtrellis = r->backtrellis;
01138   winfo = r->lm->winfo;
01139   hmminfo = r->am->hmminfo;
01140   peseqlen = r->peseqlen;
01141   ccd_flag = r->ccd_flag;
01142 
01143   word = nword->id;
01144   lastword = now->seq[now->seqnum-1];
01145 
01146   /* lastphone (直前単語の先頭音素) を準備 */
01147   /* prepare lastphone (head phone of previous word) */
01148   if (ccd_flag) {
01149     /* 最終音素 triphone を接続単語に会わせて変化 */
01150     /* modify triphone of last phone according to the next word */
01151     lastphone = get_left_context_HMM(now->last_ph, winfo->wseq[word][winfo->wlen[word]-1]->name, hmminfo);
01152     if (lastphone == NULL) {
01153       /* fallback to the original bi/mono-phone */
01154       /* error if the original is pseudo phone (not explicitly defined
01155          in hmmdefs/hmmlist) */
01156       /* exception: word with 1 phone (triphone may exist in the next expansion */
01157       if (now->last_ph->is_pseudo){
01158         error_missing_left_triphone(now->last_ph, winfo->wseq[word][winfo->wlen[word]-1]->name);
01159       }
01160       lastphone = now->last_ph;
01161     }
01162   }
01163 
01164   /* newphone (接続単語の末尾音素) を準備 */
01165   /* prepare newphone (tail phone of next word) */
01166   if (ccd_flag) {
01167     newphone = get_right_context_HMM(winfo->wseq[word][winfo->wlen[word]-1], now->last_ph->name, hmminfo);
01168     if (newphone == NULL) {
01169       /* fallback to the original bi/mono-phone */
01170       /* error if the original is pseudo phone (not explicitly defined
01171          in hmmdefs/hmmlist) */
01172       /* exception: word with 1 phone (triphone may exist in the next expansion */
01173       if (winfo->wlen[word] > 1 && winfo->wseq[word][winfo->wlen[word]-1]->is_pseudo){
01174         error_missing_right_triphone(winfo->wseq[word][winfo->wlen[word]-1], now->last_ph->name);
01175       }
01176       newphone = winfo->wseq[word][winfo->wlen[word]-1];
01177     }
01178   } else {
01179     newphone = winfo->wseq[word][winfo->wlen[word]-1];
01180   }
01181   
01182   /* 単語並び、DFA状態番号、言語スコアを new へ継承・更新 */
01183   /* inherit and update word sequence, DFA state and total LM score to 'new' */
01184   new->score = LOG_ZERO;
01185   for (i=0;i< now->seqnum;i++){
01186     new->seq[i] = now->seq[i];
01187 #ifdef CM_SEARCH
01188 #ifdef CM_MULTIPLE_ALPHA
01189     memcpy(new->cmscore[i], now->cmscore[i], sizeof(LOGPROB) * r->config->annotate.cm_alpha_num);
01190 #else
01191     new->cmscore[i] = now->cmscore[i];
01192 #endif
01193 #endif /* CM_SEARCH */
01194   }
01195   new->seq[i] = word;
01196   new->seqnum = now->seqnum+1;
01197   new->state = nword->next_state;
01198   new->totallscore = now->totallscore + nword->lscore;
01199   if (ccd_flag) {
01200     /* 次仮説の履歴情報として保存 */
01201     /* keep the lastphone for next scan_word() */
01202     new->last_ph = lastphone;
01203     new->last_ph_sp_attached = now->last_ph_sp_attached;
01204   }
01205 
01206   if (ccd_flag) {
01207     /* 最後の1音素(lastphone)分をscanし,更新したスコアを new に保存 */
01208     /* scan the lastphone and set the updated score to new->g[] */
01209     do_viterbi_next_word(now, new, lastphone,
01210                          hmminfo->multipath ? now->last_ph_sp_attached : FALSE,
01211                          param, r);
01212     g_src = new->g;
01213   } else {
01214     g_src = now->g;
01215 #ifdef GRAPHOUT_PRECISE_BOUNDARY
01216     if (r->graphout) {
01217       memcpy(new->wordend_frame, now->wordend_frame, sizeof(short)*peseqlen);
01218       memcpy(new->wordend_gscore, now->wordend_gscore, sizeof(LOGPROB)*peseqlen);
01219     }
01220 #endif
01221   }
01222       
01223   /* 次回の scan_word に備えて new->g[] を変更しておく */
01224   /* prepare new->g[] for next scan_word() */
01225   if (hmminfo->multipath) {
01226     startt = peseqlen-1;
01227   } else {
01228     startt = peseqlen-2;
01229   }
01230   i = hmm_logical_state_num(newphone);
01231   a_value = (hmm_logical_trans(newphone))->a[i-2][i-1];
01232   if (hmminfo->multipath) {
01233     for(t=0; t <= startt; t++) {
01234       new->g[t] = g_src[t] + nword->lscore;
01235     }
01236   } else {
01237     for(t=0; t <= startt; t++) {
01238       new->g[t] = g_src[t+1] + a_value + nword->lscore;
01239     }
01240   }
01241 
01242   /***************************************************************************/
01243   /* 前向き(第2パス),後ろ向き(第1パス)トレリスを接続し最尤接続点を見つける */
01244   /* connect forward/backward trellis to look for the best connection time   */
01245   /***************************************************************************/
01246   /*-----------------------------------------------------------------*/
01247   /* 単語トレリスを探して, 次単語の最尤接続点を発見する */
01248   /* determine the best connection time of the new word, seeking the word
01249      trellis */
01250   /*-----------------------------------------------------------------*/
01251 
01252   if (r->lmtype == LM_DFA && !r->config->pass2.looktrellis_flag) {
01253     /* すべてのフレームにわたって最尤を探す */
01254     /* search for best trellis word throughout all frame */
01255     for(t = startt; t >= 0; t--) {
01256       tre = bt_binsearch_atom(backtrellis, t, (WORD_ID) word);
01257       if (tre == NULL) continue;
01258       totalscore = new->g[t] + tre->backscore;
01259       if (! hmminfo->multipath) {
01260         if (newphone->is_pseudo) {
01261           tmpp = outprob_cd(&(r->am->hmmwrk), t, &(newphone->body.pseudo->stateset[newphone->body.pseudo->state_num-2]), param);
01262         } else {
01263           tmpp = outprob_state(&(r->am->hmmwrk), t, newphone->body.defined->s[newphone->body.defined->state_num-2], param);
01264         }
01265         totalscore += tmpp;
01266       }
01267       if (new->score < totalscore) {
01268         new->score = totalscore;
01269         new->bestt = t;
01270         new->estimated_next_t = tre->begintime - 1;
01271         new->tre = tre;
01272       }
01273     }
01274 
01275     return;
01276   }
01277 
01278   /* 最後に参照したTRELLIS_ATOMの終端時間の前後 */
01279   /* newの推定時間は,上記で採用したTRELLIS_ATOMの始端時間 */
01280 
01281   /* この展開単語のトレリス上の終端時間の前後のみスキャンする
01282      前後に連続して存在するフレームについてのみ計算 */
01283   /* search for best trellis word only around the estimated time */
01284   /* 1. search forward */
01285   for(t = (nword->tre)->endtime; t >= 0; t--) {
01286     tre = bt_binsearch_atom(backtrellis, t, (WORD_ID) word);
01287     if (tre == NULL) break;     /* go to 2 if the trellis word disappear */
01288     totalscore = new->g[t] + tre->backscore;
01289     if (! hmminfo->multipath) {
01290       if (newphone->is_pseudo) {
01291         tmpp = outprob_cd(&(r->am->hmmwrk), t, &(newphone->body.pseudo->stateset[newphone->body.pseudo->state_num-2]), param);
01292       } else {
01293         tmpp = outprob_state(&(r->am->hmmwrk), t, newphone->body.defined->s[newphone->body.defined->state_num-2], param);
01294       }
01295       totalscore += tmpp;
01296     }
01297     if (new->score < totalscore) {
01298       new->score = totalscore;
01299       new->bestt = t;
01300       new->estimated_next_t = tre->begintime - 1;
01301       new->tre = tre;
01302     }
01303   }
01304   /* 2. search bckward */
01305   for(t = (nword->tre)->endtime + 1; t <= startt; t++) {
01306     tre = bt_binsearch_atom(backtrellis, t, (WORD_ID) word);
01307     if (tre == NULL) break;     /* end if the trellis word disapper */
01308     totalscore = new->g[t] + tre->backscore;
01309     if (! hmminfo->multipath) {
01310       if (newphone->is_pseudo) {
01311         tmpp = outprob_cd(&(r->am->hmmwrk), t, &(newphone->body.pseudo->stateset[newphone->body.pseudo->state_num-2]), param);
01312       } else {
01313         tmpp = outprob_state(&(r->am->hmmwrk), t, newphone->body.defined->s[newphone->body.defined->state_num-2], param);
01314       }
01315       totalscore += tmpp;
01316     }
01317     if (new->score < totalscore) {
01318       new->score = totalscore;
01319       new->bestt = t;
01320       new->estimated_next_t = tre->begintime - 1;
01321       new->tre = tre;
01322     }
01323   }
01324 
01325   /* set current LM score */
01326   new->lscore = nword->lscore;
01327   
01328 }
01329 
01330 
01331 /**********************************************************************/
01332 /********** 初期仮説の生成                 ****************************/
01333 /********** Generate an initial hypothesis ****************************/
01334 /**********************************************************************/
01335 
01357 void
01358 start_word(NODE *new, NEXTWORD *nword, HTK_Param *param, RecogProcess *r)
01359 {
01360   HMM_Logical *newphone;
01361   WORD_ID word;
01362   TRELLIS_ATOM *tre = NULL;
01363   LOGPROB tmpp;
01364   int t;
01365 
01366   BACKTRELLIS *backtrellis;
01367   WORD_INFO *winfo;
01368 
01369   int peseqlen;
01370   boolean ccd_flag;
01371   boolean multipath;
01372 
01373   backtrellis = r->backtrellis;
01374   winfo = r->lm->winfo;
01375   peseqlen = r->peseqlen;
01376   ccd_flag = r->ccd_flag;
01377   multipath = r->am->hmminfo->multipath;
01378 
01379   /* initialize data */
01380   word = nword->id;
01381   new->score = LOG_ZERO;
01382   new->seqnum = 1;
01383   new->seq[0] = word;
01384 
01385   new->state = nword->next_state;
01386   new->totallscore = nword->lscore;
01387 
01388   /* set current LM score */
01389   new->lscore = nword->lscore;
01390 
01391   /* cross-word triphone need not be handled on startup */
01392   newphone = winfo->wseq[word][winfo->wlen[word]-1];
01393   if (ccd_flag) {
01394     new->last_ph = NULL;
01395   }
01396   
01397   new->g[peseqlen-1] = nword->lscore;
01398   
01399   for (t=peseqlen-1; t>=0; t--) {
01400     tre = bt_binsearch_atom(backtrellis, t, word);
01401     if (tre != NULL) {
01402       if (r->graphout) {
01403         new->bestt = peseqlen-1;
01404       } else {
01405         new->bestt = t;
01406       }
01407       new->score = new->g[peseqlen-1] + tre->backscore;
01408       if (! multipath) {
01409         if (newphone->is_pseudo) {
01410           tmpp = outprob_cd(&(r->am->hmmwrk), peseqlen-1, &(newphone->body.pseudo->stateset[newphone->body.pseudo->state_num-2]), param);
01411         } else {
01412           tmpp = outprob_state(&(r->am->hmmwrk), peseqlen-1, newphone->body.defined->s[newphone->body.defined->state_num-2], param);
01413         }
01414         new->score += tmpp;
01415       }
01416       new->estimated_next_t = tre->begintime - 1;
01417       new->tre = tre;
01418       break;
01419     }
01420   }
01421   if (tre == NULL) {            /* no word in backtrellis */
01422     new->score = LOG_ZERO;
01423   }
01424 }
01425 
01447 void
01448 last_next_word(NODE *now, NODE *new, HTK_Param *param, RecogProcess *r)
01449 {
01450   cpy_node(new, now);
01451   if (r->ccd_flag) {
01452     /* 最終音素分を viterbi して最終スコアを設定 */
01453     /* scan the last phone and update the final score */
01454     if (r->am->hmminfo->multipath) {
01455       do_viterbi_next_word(now, new, now->last_ph, now->last_ph_sp_attached, param, r);
01456       new->score = new->final_g;
01457     } else {
01458       do_viterbi_next_word(now, new, now->last_ph, FALSE, param, r);
01459       new->score = new->g[0];
01460     }
01461   } else {
01462     if (r->am->hmminfo->multipath) {
01463       new->score = now->final_g;
01464     } else {
01465       new->score = now->g[0];
01466     }
01467 #ifdef GRAPHOUT_PRECISE_BOUNDARY
01468     if (r->graphout) {
01469       /* last boundary has moved to [peseqlen-1] in last scan_word() */
01470       memcpy(new->wordend_frame, now->wordend_frame, sizeof(short)*r->peseqlen);
01471       memcpy(new->wordend_gscore, now->wordend_gscore, sizeof(LOGPROB)*r->peseqlen);
01472     }
01473 #endif
01474   }
01475 }
01476 
01477 #endif /* PASS2_STRICT_IWCD */
01478 
01479 /* end of file */