メインページ | モジュール | データ構造 | Directories | ファイル一覧 | データフィールド | グローバル | 関連ページ

search_bestfirst_v2.c

説明を見る。
00001 
00054 /*
00055  * Copyright (c) 1991-2006 Kawahara Lab., Kyoto University
00056  * Copyright (c) 2000-2005 Shikano Lab., Nara Institute of Science and Technology
00057  * Copyright (c) 2005-2006 Julius project team, Nagoya Institute of Technology, 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.h>
00066 
00067 #ifdef PASS2_STRICT_IWCD
00068 
00069 #undef TCD                      
00070 
00071 
00072 /**********************************************************************/
00073 /************ 仮説ノードの基本操作                         ************/
00074 /************ Basic functions for hypothesis node handling ************/
00075 /**********************************************************************/
00076 
00089 void
00090 free_node(NODE *node)
00091 {
00092   if (node == NULL) return;
00093   free(node->g);
00094 #ifdef GRAPHOUT
00095 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00096   free(node->wordend_frame);
00097   free(node->wordend_gscore);
00098 #endif
00099   if (node->prevgraph != NULL && node->prevgraph->saved == FALSE) {
00100     wordgraph_free(node->prevgraph);
00101   }
00102 #endif
00103   free(node);
00104 }
00105 
00124 NODE *
00125 cpy_node(NODE *dst, NODE *src)
00126 {
00127   
00128   dst->next = src->next;
00129   dst->prev = src->prev;
00130   memcpy(dst->g, src->g, sizeof(LOGPROB) * peseqlen);
00131   memcpy(dst->seq, src->seq, sizeof(WORD_ID) * MAXSEQNUM);
00132 #ifdef CM_SEARCH
00133 #ifdef CM_MULTIPLE_ALPHA
00134   {
00135     int w;
00136     for(w=0;w<src->seqnum;w++) {
00137       memcpy(dst->cmscore[w], src->cmscore[w], sizeof(LOGPROB) * cm_alpha_num);
00138     }
00139   }     
00140 #else
00141   memcpy(dst->cmscore, src->cmscore, sizeof(LOGPROB) * MAXSEQNUM);
00142 #endif
00143 #endif /* CM_SEARCH */
00144   dst->seqnum = src->seqnum;
00145   dst->score = src->score;
00146   dst->bestt = src->bestt;
00147   dst->estimated_next_t = src->estimated_next_t;
00148   dst->endflag = src->endflag;
00149 #ifdef USE_DFA
00150   dst->state = src->state;
00151 #endif
00152   dst->tre = src->tre;
00153   if (ccd_flag) {
00154     dst->last_ph = src->last_ph;
00155 #ifdef MULTIPATH_VERSION
00156     dst->last_ph_sp_attached = src->last_ph_sp_attached;
00157 #endif
00158   }
00159 #ifdef USE_NGRAM
00160   dst->totallscore = src->totallscore;
00161 #endif
00162 #ifdef MULTIPATH_VERSION
00163   dst->final_g = src->final_g;
00164 #endif
00165 #ifdef VISUALIZE
00166   dst->popnode = src->popnode;
00167 #endif
00168 #ifdef GRAPHOUT
00169 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00170   memcpy(dst->wordend_frame, src->wordend_frame, sizeof(short)*peseqlen);
00171   memcpy(dst->wordend_gscore, src->wordend_gscore, sizeof(LOGPROB)*peseqlen);
00172 #endif
00173   dst->prevgraph = src->prevgraph;
00174   dst->lastcontext = src->lastcontext;
00175 #ifndef GRAPHOUT_PRECISE_BOUNDARY
00176   dst->tail_g_score = src->tail_g_score;
00177 #endif
00178 #endif
00179   return(dst);
00180 }
00181 
00194 NODE *
00195 newnode()
00196 {
00197   NODE *tmp;
00198   int i;
00199 
00200   if ((tmp=(NODE *)mymalloc(sizeof(NODE)))==NULL) {
00201     j_error("can't malloc\n");
00202   }
00203   /*bzero(tmp,sizeof(NODE));*/
00204   tmp->next=NULL;
00205   tmp->prev=NULL;
00206   tmp->g = (LOGPROB *)mymalloc(sizeof(LOGPROB)*peseqlen);
00207   tmp->last_ph = NULL;
00208 #ifdef MULTIPATH_VERSION
00209   tmp->last_ph_sp_attached = FALSE;
00210 #endif  
00211   if (ccd_flag) {
00212 #ifdef USE_NGRAM
00213     tmp->totallscore = LOG_ZERO;
00214 #endif
00215   }
00216   tmp->endflag = FALSE;
00217   tmp->seqnum = 0;
00218   for(i=0;i<peseqlen;i++) {
00219     tmp->g[i] = LOG_ZERO;
00220   }
00221 #ifdef MULTIPATH_VERSION
00222   tmp->final_g = LOG_ZERO;
00223 #endif
00224 #ifdef VISUALIZE
00225   tmp->popnode = NULL;
00226 #endif
00227 #ifdef GRAPHOUT
00228 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00229   tmp->wordend_frame = (short *)mymalloc(sizeof(short)*peseqlen);
00230   tmp->wordend_gscore = (LOGPROB *)mymalloc(sizeof(LOGPROB)*peseqlen);
00231 #endif
00232   tmp->prevgraph = NULL;
00233   tmp->lastcontext = NULL;
00234 #endif
00235 
00236   return(tmp);
00237 }
00238 
00239 
00240 /**********************************************************************/
00241 /************ 前向きトレリス展開と尤度計算             ****************/
00242 /************ Expand trellis and update forward score *****************/
00243 /**********************************************************************/
00244 
00245 static LOGPROB *wordtrellis[2]; 
00246 static int tn;                 
00247 static int tl;                 
00248 static LOGPROB *g;              
00249 static HMM_Logical **phmmseq;   
00250 static int phmmlen_max;         
00251 static HMM_Logical *tailph;     
00252 #ifdef MULTIPATH_VERSION
00253 static boolean *has_sp;         
00254 #endif
00255 
00256 #ifdef GRAPHOUT
00257 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00258 static short *wend_token_frame[2]; 
00259 static LOGPROB *wend_token_gscore[2]; 
00260 static short *wef;              
00261 static LOGPROB *wes;            
00262 #endif
00263 #endif
00264 
00275 void
00276 malloc_wordtrellis()
00277 {
00278   int maxwn;
00279 
00280   maxwn = winfo->maxwn + 10;    /* CCDによる変動を考慮 */
00281   wordtrellis[0] = (LOGPROB *)mymalloc(sizeof(LOGPROB) * maxwn);
00282   wordtrellis[1] = (LOGPROB *)mymalloc(sizeof(LOGPROB) * maxwn);
00283 
00284   g = (LOGPROB *)mymalloc(sizeof(LOGPROB) * peseqlen);
00285 
00286   phmmlen_max = winfo->maxwlen + 2;
00287   phmmseq = (HMM_Logical **)mymalloc(sizeof(HMM_Logical *) * phmmlen_max);
00288 #ifdef MULTIPATH_VERSION
00289   has_sp = (boolean *)mymalloc(sizeof(boolean) * phmmlen_max);
00290 #endif
00291 
00292 #ifdef GRAPHOUT
00293 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00294   wef = (short *)mymalloc(sizeof(short) * peseqlen);
00295   wes = (LOGPROB *)mymalloc(sizeof(LOGPROB) * peseqlen);
00296   wend_token_frame[0] = (short *)mymalloc(sizeof(short) * maxwn);
00297   wend_token_frame[1] = (short *)mymalloc(sizeof(short) * maxwn);
00298   wend_token_gscore[0] = (LOGPROB *)mymalloc(sizeof(LOGPROB) * maxwn);
00299   wend_token_gscore[1] = (LOGPROB *)mymalloc(sizeof(LOGPROB) * maxwn);
00300 #endif
00301 #endif
00302 }
00303 
00314 void
00315 free_wordtrellis()
00316 {
00317   free(wordtrellis[0]);
00318   free(wordtrellis[1]);
00319   free(g);
00320   free(phmmseq);
00321 #ifdef MULTIPATH_VERSION
00322   free(has_sp);
00323 #endif
00324 #ifdef GRAPHOUT
00325 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00326   free(wef);
00327   free(wes);
00328   free(wend_token_frame[0]);
00329   free(wend_token_frame[1]);
00330   free(wend_token_gscore[0]);
00331   free(wend_token_gscore[1]);
00332 #endif
00333 #endif
00334 }
00335 
00336 
00337 /**********************************************************************/
00338 /************ 仮説の前向き尤度計算                  *******************/
00339 /************ Compute forward score of a hypothesis *******************/
00340 /**********************************************************************/
00341 
00342 /* 与えられた音素のならび phmmseq[0..phmmlen-1]に対してviterbi計算を行う.
00343    g[0..framelen-1] のスコアを初期値として g_new[0..framelen-1]に更新値を代入.
00344    最低 least_frame まではscanする.*/
00345 /* Viterbi computation for the given phoneme sequence 'phmmseq[0..phmmlen-1]'
00346    with g[0..framelen-1] as initial values.  The results are stored in
00347    g_new[0..framelen-1].  Scan should not terminate at least it reaches
00348    'least_frame'. */
00383 static void
00384 do_viterbi(LOGPROB *g, LOGPROB *g_new, HMM_Logical **phmmseq
00385 #ifdef MULTIPATH_VERSION
00386            , boolean *has_sp
00387 #endif
00388            , int phmmlen, HTK_Param *param, int framelen, int least_frame
00389 #ifdef MULTIPATH_VERSION
00390            , LOGPROB *final_g
00391 #endif
00392 #ifdef GRAPHOUT
00393 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00394            , short *wordend_frame_src, short *wordend_frame_dst
00395            , LOGPROB *wordend_gscore_src, LOGPROB *wordend_gscore_dst
00396 #endif
00397 #endif
00398            )
00399 {
00400   HMM *whmm;                    /* HMM */
00401   int wordhmmnum;               /* length of above */
00402   int startt;                   /* scan start frame */
00403   LOGPROB tmpmax,tmpscore;      /* variables for Viterbi process */
00404   A_CELL *ac;
00405   int t,i,j;
00406   boolean node_exist_p;
00407 
00408 #ifdef TCD
00409   j_printf("scan for:");
00410   for (i=0;i<phmmlen;i++) {
00411     j_printf(" %s", phmmseq[i]->name);
00412   }
00413   j_printf("\n");
00414 #endif
00415   
00416   /* 単語HMMを作る */
00417   /* make word HMM */
00418   whmm = new_make_word_hmm(hmminfo, phmmseq, phmmlen
00419 #ifdef MULTIPATH_VERSION
00420                            , has_sp
00421 #endif
00422                            );
00423   wordhmmnum = whmm->len;
00424   if (wordhmmnum >= winfo->maxwn + 10) {
00425     j_error("scan_word: word too long\n");
00426   }
00427 
00428   /* scan開始点を検索 -> starttへ*/
00429   /* search for the start frame -> set to startt */
00430   for(t = framelen-1; t >=0 ; t--) {
00431     if (
00432 #ifdef SCAN_BEAM
00433         g[t] > framemaxscore[t] - scan_beam_thres &&
00434 #endif
00435         g[t] > LOG_ZERO) {
00436       break;
00437     }
00438   }
00439   if (t < 0) {                  /* no node has score > LOG_ZERO */
00440     /* reset all scores and end */
00441     for(t=0;t<framelen;t++) {
00442       g_new[t] = LOG_ZERO;
00443 #ifdef GRAPHOUT
00444 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00445       wordend_frame_dst[t] = -1;
00446       wordend_gscore_dst[t] = LOG_ZERO;
00447 #endif
00448 #endif
00449     }
00450     free_hmm(whmm);
00451     return;
00452   }
00453   startt = t;
00454   
00455   /* 開始点以降[startt+1..framelen-1] の g_new[] をリセット */
00456   /* clear g_new[] for [startt+1..framelen-1] */
00457   for(t=framelen-1;t>startt;t--) {
00458     g_new[t] = LOG_ZERO;
00459 #ifdef GRAPHOUT
00460 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00461     wordend_frame_dst[t] = -1;
00462     wordend_gscore_dst[t] = LOG_ZERO;
00463 #endif
00464 #endif
00465   }
00466 
00467   /*****************/
00468   /* viterbi start */
00469   /*****************/
00470 
00471   /* set initial swap buffer */
00472   tn = 0; tl = 1;
00473 
00474 #ifdef GRAPHOUT
00475 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00476   for(i=0;i<wordhmmnum;i++) {
00477     wend_token_frame[tn][i] = -1;
00478     wend_token_gscore[tn][i] = LOG_ZERO;
00479   }    
00480 #endif
00481 #endif
00482 
00483 #ifndef MULTIPATH_VERSION
00484   /* 時間 [startt] 上の値を初期化 */
00485   /* initialize scores on frame [startt] */
00486   for(i=0;i<wordhmmnum-1;i++) wordtrellis[tn][i] = LOG_ZERO;
00487   wordtrellis[tn][wordhmmnum-1] = g[startt] + outprob(startt, &(whmm->state[wordhmmnum-1]), param);
00488   g_new[startt] = wordtrellis[tn][0];
00489 #ifdef GRAPHOUT
00490 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00491   wend_token_frame[tn][wordhmmnum-1] = wordend_frame_src[startt];
00492   wend_token_gscore[tn][wordhmmnum-1] = wordend_gscore_src[startt];
00493   wordend_frame_dst[startt] = wend_token_frame[tn][0];
00494   wordend_gscore_dst[startt] = wend_token_gscore[tn][0];
00495 #endif
00496 #endif
00497 #endif /* ~MULTIPATH_VERSION */
00498   
00499   /* メインループ: startt から始まり 0 に向かって Viterbi 計算 */
00500   /* main loop: start from [startt], and compute Viterbi toward [0] */
00501   for(t=
00502 #ifdef MULTIPATH_VERSION
00503         startt
00504 #else
00505         startt-1
00506 #endif
00507         ; t>=0; t--) {
00508     
00509     /* wordtrellisのワークエリアをスワップ */
00510     /* swap workarea of wordtrellis */
00511     i = tn; tn = tl; tl = i;
00512 
00513     node_exist_p = FALSE;       /* TRUE if there is at least 1 survived node in this frame */
00514 
00515 #ifndef MULTIPATH_VERSION
00516     
00517     /* 端のノード [t][wordhmmnum-1]は,内部遷移 か g[]の高い方になる */
00518     /* the edge node [t][wordhmmnum-1] is either internal transitin or g[] */
00519     tmpscore = LOG_ZERO;
00520     for (ac=whmm->state[wordhmmnum-1].ac;ac;ac=ac->next) {
00521       if (tmpscore < wordtrellis[tl][ac->arc] + ac->a)
00522         j = ac->arc;
00523         tmpscore = wordtrellis[tl][ac->arc] + ac->a;
00524     }
00525     if (g[t] > tmpscore) {
00526       tmpmax = g[t];
00527 #ifdef GRAPHOUT
00528 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00529       wend_token_frame[tn][wordhmmnum-1] = wordend_frame_src[t];
00530       wend_token_gscore[tn][wordhmmnum-1] = wordend_gscore_src[t];
00531 #endif
00532 #endif
00533     } else {
00534       tmpmax = tmpscore;
00535 #ifdef GRAPHOUT
00536 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00537       wend_token_frame[tn][wordhmmnum-1] = wend_token_frame[tl][j];
00538       wend_token_gscore[tn][wordhmmnum-1] = wend_token_gscore[tl][j];
00539 #endif
00540 #endif
00541     }
00542 
00543     /* 端のノードのスコアエンベロープチェック: 一定幅外なら落とす */
00544     /* check if the edge node is within score envelope */
00545     if (
00546 #ifdef SCAN_BEAM
00547         tmpmax <= framemaxscore[t] - scan_beam_thres ||
00548 #endif
00549         tmpmax <= LOG_ZERO
00550         ) {
00551       wordtrellis[tn][wordhmmnum-1] = LOG_ZERO;
00552 #ifdef GRAPHOUT
00553 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00554       wend_token_frame[tn][wordhmmnum-1] = -1;
00555       wend_token_gscore[tn][wordhmmnum-1] = LOG_ZERO;
00556 #endif
00557 #endif
00558     } else {
00559       node_exist_p = TRUE;
00560       wordtrellis[tn][wordhmmnum-1] = tmpmax + outprob(t, &(whmm->state[wordhmmnum-1]), param);
00561     }
00562 
00563 #endif /* ~MULTIPATH_VERSION */
00564 
00565     /* node[wordhmmnum-2..0]についてトレリスを展開 */
00566     /* expand trellis for node [t][wordhmmnum-2..0] */
00567     for(i=wordhmmnum-2;i>=0;i--) {
00568       
00569       /* 最尤パスと最尤スコア tmpmax を見つける */
00570       /* find most likely path and the max score 'tmpmax' */
00571       tmpmax = LOG_ZERO;
00572       for (ac=whmm->state[i].ac;ac;ac=ac->next) {
00573 #ifdef MULTIPATH_VERSION
00574         if (ac->arc == wordhmmnum-1) tmpscore = g[t];
00575         else if (t + 1 > startt) tmpscore = LOG_ZERO;
00576         else tmpscore = wordtrellis[tl][ac->arc];
00577         tmpscore += ac->a;
00578 #else
00579         tmpscore = wordtrellis[tl][ac->arc] + ac->a;
00580 #endif
00581         if (tmpmax < tmpscore) {
00582           tmpmax = tmpscore;
00583           j = ac->arc;
00584         }
00585       }
00586       
00587       /* スコアエンベロープチェック: 一定幅外なら落とす */
00588       /* check if score of this node is within the score envelope */
00589       if (
00590 #ifdef SCAN_BEAM
00591           tmpmax <= framemaxscore[t] - scan_beam_thres ||
00592 #endif
00593           tmpmax <= LOG_ZERO
00594           ) {
00595         /* invalid node */
00596         wordtrellis[tn][i] = LOG_ZERO;
00597 #ifdef GRAPHOUT
00598 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00599         wend_token_frame[tn][i] = -1;
00600         wend_token_gscore[tn][i] = LOG_ZERO;
00601 #endif
00602 #endif
00603       } else {
00604         /* survived node */
00605         node_exist_p = TRUE;
00606 #ifdef MULTIPATH_VERSION
00607         wordtrellis[tn][i] = tmpmax;
00608         if (i > 0) wordtrellis[tn][i] += outprob(t, &(whmm->state[i]), param);
00609 #else
00610         wordtrellis[tn][i] = tmpmax + outprob(t, &(whmm->state[i]), param);
00611 #endif
00612 #ifdef GRAPHOUT
00613 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00614 #ifdef MULTIPATH_VERSION
00615         if (j == wordhmmnum-1) {
00616           wend_token_frame[tn][i] = wordend_frame_src[t];
00617           wend_token_gscore[tn][i] = wordend_gscore_src[t];
00618         } else {
00619           wend_token_frame[tn][i] = wend_token_frame[tl][j];
00620           wend_token_gscore[tn][i] = wend_token_gscore[tl][j];
00621         }
00622 #else
00623         wend_token_frame[tn][i] = wend_token_frame[tl][j];
00624         wend_token_gscore[tn][i] = wend_token_gscore[tl][j];
00625 #endif
00626 #endif
00627 #endif
00628       }
00629     } /* end of node loop */
00630 
00631     /* 時間 t のViterbi計算終了.新たな前向きスコア g_new[t] をセット */
00632     /* Viterbi end for frame [t].  set the new forward score g_new[t] */
00633     g_new[t] = wordtrellis[tn][0];
00634 #ifdef GRAPHOUT
00635 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00636     /* new wordend */
00637     wordend_frame_dst[t] = wend_token_frame[tn][0];
00638     wordend_gscore_dst[t] = wend_token_gscore[tn][0];
00639 #endif
00640 #endif
00641     /* 指定された least_frame より先まで t が進んでおり,かつこの t において
00642        スコアエンベロープによって生き残ったノードが一つも無かった場合,
00643        このフレームで計算を打ち切りそれ以上先([0..t-1])は計算しない */
00644     /* if frame 't' already reached the 'least_frame' and no node was
00645        survived in this frame (all nodes pruned by score envelope),
00646        terminate computation at this frame and do not computer further
00647        frame ([0..t-1]). */
00648     if (t < least_frame && (!node_exist_p)) {
00649       /* crear the rest scores */
00650       for (i=t-1;i>=0;i--) {
00651         g_new[i] = LOG_ZERO;
00652 #ifdef GRAPHOUT
00653 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00654         wordend_frame_dst[i] = -1;
00655         wordend_gscore_dst[i] = LOG_ZERO;
00656 #endif
00657 #endif
00658       }
00659       /* terminate loop */
00660       break;
00661     }
00662     
00663   } /* end of time loop */
00664 
00665 #ifdef MULTIPATH_VERSION
00666   /* 前向きスコアの最終値を計算 (状態 0 から時間 0 への遷移) */
00667   /* compute the total forward score (transition from state 0 to frame 0 */
00668   if (t < 0) {                  /* computed till the end */
00669     tmpmax = LOG_ZERO;
00670     for(ac=whmm->state[0].ac;ac;ac=ac->next) {
00671       tmpscore = wordtrellis[tn][ac->arc] + ac->a;
00672       if (tmpmax < tmpscore) tmpmax = tmpscore;
00673     }
00674     *final_g = tmpmax;
00675   } else {
00676     *final_g = LOG_ZERO;
00677   }
00678 #endif
00679 
00680   /* free work area */
00681   free_hmm(whmm);
00682 }
00683 
00703 static void
00704 do_viterbi_next_word(NODE *now, NODE *new, HMM_Logical *lastphone
00705 #ifdef MULTIPATH_VERSION
00706                      , boolean sp
00707 #endif
00708                      , HTK_Param *param)
00709 {
00710   int t, n;
00711 #ifndef MULTIPATH_VERSION
00712   LOGPROB a_value;
00713 
00714   /* もし展開元仮説の最後の単語の音素長が 1 であれば,その音素は
00715      直前の scan_word で計算されていない.この場合, now->g[] に以前の
00716      初期値が格納されている.
00717      もし音素長が1以上であれば,now->g[] はその手前まで計算した状態
00718      のスコアが入っているので,now->g[t] から初期値を設定する必要がある */
00719   /* If the length of last word is 1, it means the last phone was not
00720      scanned in the last call of scan_word().  In this case, now->g[]
00721      keeps the previous initial value, so start viterbi with the old scores.
00722      If the length is more than 1, the now->g[] keeps the values of the
00723      scan result till the previous phone, so make initial value
00724      considering last transition probability. */
00725   if (winfo->wlen[now->seq[now->seqnum-1]] > 1) {
00726     n = hmm_logical_state_num(lastphone);
00727     a_value = (hmm_logical_trans(lastphone))->a[n-2][n-1];
00728     for(t=0; t<peseqlen-1; t++) g[t] = now->g[t+1] + a_value;
00729     g[peseqlen-1] = LOG_ZERO;
00730   } else {
00731     for(t=0; t<peseqlen; t++) g[t] = now->g[t];
00732   }
00733   
00734 # else /* MULTIPATH_VERSION */
00735   
00736   for(t=0; t<peseqlen; t++) g[t] = now->g[t];
00737   phmmseq[0] = lastphone;
00738   has_sp[0] = sp;
00739   
00740 #endif /* MULTIPATH_VERSION */
00741   
00742   do_viterbi(g, new->g
00743 #ifdef MULTIPATH_VERSION
00744              , phmmseq, has_sp, 1, param
00745 #else
00746              , &lastphone, 1, param
00747 #endif
00748              , peseqlen, now->estimated_next_t
00749 #ifdef MULTIPATH_VERSION
00750              , &(new->final_g)
00751 #endif
00752 #ifdef GRAPHOUT
00753 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00754              , now->wordend_frame, new->wordend_frame
00755              , now->wordend_gscore, new->wordend_gscore
00756 #endif
00757 #endif
00758              );
00759 
00760 #ifndef MULTIPATH_VERSION
00761 #ifdef GRAPHOUT
00762 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00763   /* 次回の next_word 用に境界情報を調整 */
00764   /* proceed word boundary for one step for next_word */
00765   new->wordend_frame[peseqlen-1] = new->wordend_frame[0];
00766   new->wordend_gscore[peseqlen-1] = new->wordend_gscore[0];
00767   for (t=0;t<peseqlen-1;t++) {
00768     new->wordend_frame[t] = new->wordend_frame[t+1];
00769     new->wordend_gscore[t] = new->wordend_gscore[t+1];
00770   }
00771 #endif
00772 #endif
00773 #endif
00774 }
00775 
00791 void
00792 scan_word(NODE *now, HTK_Param *param)
00793 {
00794   int   i,t;
00795   WORD_ID word;
00796   int phmmlen;
00797 #ifdef MULTIPATH_VERSION
00798   boolean tail_ph_sp_attached;
00799 #endif
00800   
00801 #ifdef GRAPHOUT
00802 #ifndef GRAPHOUT_PRECISE_BOUNDARY
00803   if (ccd_flag) {
00804     now->tail_g_score = now->g[now->bestt];
00805   }
00806 #endif
00807 #endif
00808 
00809   /* ----------------------- prepare phoneme sequence ------------------ */
00810   /* triphoneなら先頭の1音素はここでは対象外(あとでnext_wordでやる) */
00811   /*             末尾の1音素はコンテキストにしたがって置換 */
00812   /* with triphone, modify the tail phone of the last word according to the
00813      previous word, and do not compute the head phone here (that will be
00814      computed later in next_word() */
00815   word = now->seq[now->seqnum-1];
00816   
00817 #ifdef TCD
00818     j_printf("w=");
00819     for(i=0;i<winfo->wlen[word];i++) {
00820       j_printf(" %s",(winfo->wseq[word][i])->name);
00821     }
00822     if (ccd_flag) {
00823       if (now->last_ph != NULL) {
00824         j_printf(" | %s", (now->last_ph)->name);
00825       }
00826     }
00827     j_printf("\n");
00828 #endif /* TCD */
00829     
00830   if (ccd_flag) {
00831     
00832     /* the tail triphone of the last word varies by context */
00833     if (now->last_ph != NULL) {
00834       tailph = get_right_context_HMM(winfo->wseq[word][winfo->wlen[word]-1], now->last_ph->name, hmminfo);
00835       if (tailph == NULL) {
00836         /* fallback to the original bi/mono-phone */
00837         /* error if the original is pseudo phone (not explicitly defined
00838            in hmmdefs/hmmlist) */
00839         /* exception: word with 1 phone (triphone may exist in the next expansion */
00840         if (winfo->wlen[word] > 1 && winfo->wseq[word][winfo->wlen[word]-1]->is_pseudo){
00841           error_missing_right_triphone(winfo->wseq[word][winfo->wlen[word]-1], now->last_ph->name);
00842         }
00843 
00844         tailph = winfo->wseq[word][winfo->wlen[word]-1];
00845       }
00846     } else {
00847       tailph = winfo->wseq[word][winfo->wlen[word]-1];
00848     }
00849     /* 長さ1の単語は次のnextwordでさらに変化するのでここではscanしない */
00850     /* do not scan word if the length is 1, as it further varies in the
00851        following next_word() */
00852     if (winfo->wlen[word] == 1) {
00853       now->last_ph = tailph;
00854 #ifdef MULTIPATH_VERSION
00855       now->last_ph_sp_attached = TRUE;
00856 #endif
00857 #ifdef GRAPHOUT
00858 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00859       /* 単語境界伝搬情報を初期化 */
00860       /* initialize word boundary propagation info */
00861       for (t=0;t<peseqlen;t++) {
00862         now->wordend_frame[t] = t;
00863         now->wordend_gscore[t] = now->g[t];
00864       }
00865 #endif
00866 #endif
00867 #ifdef TCD
00868       j_printf("suspended as %s\n", (now->last_ph)->name);
00869 #endif
00870       return;
00871     }
00872 
00873     /* scan範囲の音素列を準備 */
00874     /* prepare HMM of the scan range */
00875     phmmlen = winfo->wlen[word] - 1;
00876     if (phmmlen > phmmlen_max) {
00877       j_error("short of phmmlen\n");
00878     }
00879     for (i=0;i<phmmlen-1;i++) {
00880       phmmseq[i] = winfo->wseq[word][i+1];
00881 #ifdef MULTIPATH_VERSION
00882       has_sp[i] = FALSE;
00883 #endif
00884     }
00885     phmmseq[phmmlen-1] = tailph;
00886 #ifdef MULTIPATH_VERSION
00887     has_sp[phmmlen-1] = (enable_iwsp) ? TRUE : FALSE;
00888 #endif
00889   } else {
00890     phmmlen = winfo->wlen[word];
00891 #ifdef MULTIPATH_VERSION
00892     for (i=0;i<phmmlen;i++) {
00893       phmmseq[i] = winfo->wseq[word][i];
00894       has_sp[i] = FALSE;
00895     }
00896     if (enable_iwsp) has_sp[phmmlen-1] = TRUE;
00897 #else
00898     for (i=0;i<phmmlen;i++) phmmseq[i] = winfo->wseq[word][i];
00899 #endif
00900   }
00901 
00902   /* 元のg[]をいったん待避しておく */
00903   /* temporally keeps the original g[] */
00904   for (t=0;t<peseqlen;t++) g[t] = now->g[t];
00905 
00906 #ifdef GRAPHOUT
00907 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00908   /* 単語境界伝搬情報を初期化 */
00909   /* initialize word boundary propagation info */
00910   for (t=0;t<peseqlen;t++) {
00911     wef[t] = t;
00912     wes[t] = now->g[t];
00913   }
00914 #endif
00915 #endif
00916 
00917   /* viterbiを実行して g[] から now->g[] を更新する */
00918   /* do viterbi computation for phmmseq from g[] to now->g[] */
00919   do_viterbi(g, now->g, phmmseq
00920 #ifdef MULTIPATH_VERSION
00921              , has_sp
00922 #endif
00923              , phmmlen, param, peseqlen, now->estimated_next_t
00924 #ifdef MULTIPATH_VERSION
00925              , &(now->final_g)
00926 #endif
00927 #ifdef GRAPHOUT
00928 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00929              /* 単語境界情報 we[] から now->wordend_frame[] を更新する */
00930              /* propagate word boundary info from we[] to now->wordend_frame[] */
00931              , wef, now->wordend_frame
00932              , wes, now->wordend_gscore
00933 #endif
00934 #endif
00935              );
00936 #ifndef MULTIPATH_VERSION
00937 #ifdef GRAPHOUT
00938 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00939   /* 次回の next_word 用に境界情報を調整 */
00940   /* proceed word boundary for one step for next_word */
00941   now->wordend_frame[peseqlen-1] = now->wordend_frame[0];
00942   now->wordend_gscore[peseqlen-1] = now->wordend_gscore[0];
00943   for (t=0;t<peseqlen-1;t++) {
00944     now->wordend_frame[t] = now->wordend_frame[t+1];
00945     now->wordend_gscore[t] = now->wordend_gscore[t+1];
00946   }
00947 #endif
00948 #endif
00949 #endif
00950 
00951   if (ccd_flag) {
00952     /* 次回のために now->last_ph を更新 */
00953     /* update 'now->last_ph' for future scan_word() */
00954     now->last_ph = winfo->wseq[word][0];
00955 #ifdef MULTIPATH_VERSION
00956     now->last_ph_sp_attached = FALSE; /* wlen > 1 here */
00957 #endif
00958 #ifdef TCD
00959     j_printf("last_ph = %s\n", (now->last_ph)->name);
00960 #endif
00961   }
00962 }
00963 
00964 
00965 /**************************************************************************/
00966 /*** 新仮説の展開とヒューリスティックを繋いだ全体スコアを計算           ***/
00967 /*** Expand new hypothesis and compute the total score (with heuristic) ***/
00968 /**************************************************************************/
00969 
00970 static HMM_Logical *lastphone, *newphone;
00971 static LOGPROB *g_src;
00972 
00996 void
00997 next_word(NODE *now, NODE *new, NEXTWORD *nword, HTK_Param *param, BACKTRELLIS *backtrellis)
00998 {
00999   int   t;
01000   int lastword;
01001   int   i;
01002   LOGPROB a_value;
01003   LOGPROB tmpp;
01004   int   startt;
01005   int word;
01006   TRELLIS_ATOM *tre;
01007   LOGPROB totalscore;
01008 #ifdef GRAPHOUT
01009 #ifdef GRAPHOUT_PRECISE_BOUNDARY
01010   short *wendf;
01011   LOGPROB *wends;
01012 #endif
01013 #endif
01014 
01015 
01016   word = nword->id;
01017   lastword = now->seq[now->seqnum-1];
01018 
01019   /* lastphone (直前単語の先頭音素) を準備 */
01020   /* prepare lastphone (head phone of previous word) */
01021   if (ccd_flag) {
01022     /* 最終音素 triphone を接続単語に会わせて変化 */
01023     /* modify triphone of last phone according to the next word */
01024     lastphone = get_left_context_HMM(now->last_ph, winfo->wseq[word][winfo->wlen[word]-1]->name, hmminfo);
01025     if (lastphone == NULL) {
01026       /* fallback to the original bi/mono-phone */
01027       /* error if the original is pseudo phone (not explicitly defined
01028          in hmmdefs/hmmlist) */
01029       /* exception: word with 1 phone (triphone may exist in the next expansion */
01030       if (now->last_ph->is_pseudo){
01031         error_missing_left_triphone(now->last_ph, winfo->wseq[word][winfo->wlen[word]-1]->name);
01032       }
01033       lastphone = now->last_ph;
01034     }
01035   }
01036 
01037   /* newphone (接続単語の末尾音素) を準備 */
01038   /* prepare newphone (tail phone of next word) */
01039   if (ccd_flag) {
01040     newphone = get_right_context_HMM(winfo->wseq[word][winfo->wlen[word]-1], now->last_ph->name, hmminfo);
01041     if (newphone == NULL) {
01042       /* fallback to the original bi/mono-phone */
01043       /* error if the original is pseudo phone (not explicitly defined
01044          in hmmdefs/hmmlist) */
01045       /* exception: word with 1 phone (triphone may exist in the next expansion */
01046       if (winfo->wlen[word] > 1 && winfo->wseq[word][winfo->wlen[word]-1]->is_pseudo){
01047         error_missing_right_triphone(winfo->wseq[word][winfo->wlen[word]-1], now->last_ph->name);
01048       }
01049       newphone = winfo->wseq[word][winfo->wlen[word]-1];
01050     }
01051   } else {
01052     newphone = winfo->wseq[word][winfo->wlen[word]-1];
01053   }
01054   
01055   /* 単語並び、DFA状態番号、言語スコアを new へ継承・更新 */
01056   /* inherit and update word sequence, DFA state and total LM score to 'new' */
01057   new->score = LOG_ZERO;
01058   for (i=0;i< now->seqnum;i++){
01059     new->seq[i] = now->seq[i];
01060 #ifdef CM_SEARCH
01061 #ifdef CM_MULTIPLE_ALPHA
01062     memcpy(new->cmscore[i], now->cmscore[i], sizeof(LOGPROB) * cm_alpha_num);
01063 #else
01064     new->cmscore[i] = now->cmscore[i];
01065 #endif
01066 #endif /* CM_SEARCH */
01067   }
01068   new->seq[i] = word;
01069   new->seqnum = now->seqnum+1;
01070 #ifdef USE_DFA
01071   new->state = nword->next_state;
01072 #endif
01073 #ifdef USE_NGRAM
01074   new->totallscore = now->totallscore + nword->lscore;
01075 #endif  
01076   if (ccd_flag) {
01077     /* 次仮説の履歴情報として保存 */
01078     /* keep the lastphone for next scan_word() */
01079     new->last_ph = lastphone;
01080 #ifdef MULTIPATH_VERSION
01081     new->last_ph_sp_attached = now->last_ph_sp_attached;
01082 #endif
01083   }
01084 
01085   if (ccd_flag) {
01086     /* 最後の1音素(lastphone)分をscanし,更新したスコアを new に保存 */
01087     /* scan the lastphone and set the updated score to new->g[] */
01088     do_viterbi_next_word(now, new, lastphone
01089 #ifdef MULTIPATH_VERSION
01090                          , now->last_ph_sp_attached
01091 #endif
01092                          , param);
01093     g_src = new->g;
01094   } else {
01095     g_src = now->g;
01096 #ifdef GRAPHOUT
01097 #ifdef GRAPHOUT_PRECISE_BOUNDARY
01098     memcpy(new->wordend_frame, now->wordend_frame, sizeof(short)*peseqlen);
01099     memcpy(new->wordend_gscore, now->wordend_gscore, sizeof(LOGPROB)*peseqlen);
01100 #endif
01101 #endif
01102   }
01103       
01104   /* 次回の scan_word に備えて new->g[] を変更しておく */
01105   /* prepare new->g[] for next scan_word() */
01106 #ifdef MULTIPATH_VERSION
01107   startt = peseqlen-1;
01108 #else
01109   startt = peseqlen-2;
01110 #endif
01111   i = hmm_logical_state_num(newphone);
01112   a_value = (hmm_logical_trans(newphone))->a[i-2][i-1];
01113   for(t=0; t <= startt; t++) {
01114     new->g[t] =
01115 #ifdef MULTIPATH_VERSION
01116       g_src[t]
01117 #else
01118       g_src[t+1] + a_value
01119 #endif
01120 #ifdef USE_NGRAM
01121       + nword->lscore
01122 #else
01123       + penalty2
01124 #endif
01125       ;
01126   }
01127 
01128   /***************************************************************************/
01129   /* 前向き(第2パス),後ろ向き(第1パス)トレリスを接続し最尤接続点を見つける */
01130   /* connect forward/backward trellis to look for the best connection time   */
01131   /***************************************************************************/
01132 #ifdef WORD_GRAPH
01133   /*-----------------------------------------------------------------*/
01134   /* 単語グラフモードでは同じフレームの同じ単語でも直前単語毎にスコ
01135      アが違う.bestt は 固定 */
01136   /* there are several trellis word with the same word ID in the same
01137      frame, with different word context in WORD_GRAPH mode.  And the
01138      best t is fixed (no re-esimation) */
01139   /*-----------------------------------------------------------------*/
01140   /* 最尤接続点は, 最後に参照したTRELLIS_ATOMの終端に固定 */
01141   /* the best connection point is fixed to the end time of last trellis word (no re-alignment */
01142   new->bestt = (nword->tre)->endtime;
01143   /* 次回の展開単語決定のための推定始端時間は,上記の始端 */
01144   /* the estimated next beginning frame for the next word expansion
01145      corresponds to the endtime above (this is also fixed) */
01146   new->estimated_next_t = (nword->tre)->begintime - 1;
01147   
01148   /* 仮説全体のスコアを計算 */
01149 #ifdef MULTIPATH_VERSION
01150   new->score = new->g[new->bestt] + (nword->tre)->backscore;
01151 #else
01152   /* 接続部の状態の出力確率を加算 */
01153   /* add output prob of connection state */
01154   if (newphone->is_pseudo) {
01155     tmpp = outprob_cd(new->bestt, &(newphone->body.pseudo->stateset[newphone->body.pseudo->state_num-2]), param);
01156   } else {
01157     tmpp = outprob_state(new->bestt, newphone->body.defined->s[newphone->body.defined->state_num-2], param);
01158   }
01159   new->score = new->g[new->bestt] + (nword->tre)->backscore + tmpp;
01160 #endif
01161   
01162   /* 展開単語のトレリス上の情報を伝搬 */
01163   new->tre  =  nword->tre;
01164   
01165 #else  /* not WORD_GRAPH */
01166   
01167   /*-----------------------------------------------------------------*/
01168   /* 単語トレリスを探して, 次単語の最尤接続点を発見する */
01169   /* determine the best connection time of the new word, seeking the word
01170      trellis */
01171   /*-----------------------------------------------------------------*/
01172 
01173 #ifdef USE_DFA
01174   if (!looktrellis_flag) {
01175     /* すべてのフレームにわたって最尤を探す */
01176     /* search for best trellis word throughout all frame */
01177     for(t = startt; t >= 0; t--) {
01178       tre = bt_binsearch_atom(backtrellis, t, (WORD_ID) word);
01179       if (tre == NULL) continue;
01180 #ifdef MULTIPATH_VERSION
01181       totalscore = new->g[t] + tre->backscore;
01182 #else
01183       if (newphone->is_pseudo) {
01184         tmpp = outprob_cd(t, &(newphone->body.pseudo->stateset[newphone->body.pseudo->state_num-2]), param);
01185       } else {
01186         tmpp = outprob_state(t, newphone->body.defined->s[newphone->body.defined->state_num-2], param);
01187       }
01188       totalscore = new->g[t] + tre->backscore + tmpp;
01189 #endif
01190       if (new->score < totalscore) {
01191         new->score = totalscore;
01192         new->bestt = t;
01193         new->estimated_next_t = tre->begintime - 1;
01194         new->tre = tre;
01195       }
01196     }
01197   } else {
01198 #endif /* USE_DFA */
01199     
01200   /* 最後に参照したTRELLIS_ATOMの終端時間の前後 */
01201   /* newの推定時間は,上記で採用したTRELLIS_ATOMの始端時間 */
01202 
01203   /* この展開単語のトレリス上の終端時間の前後のみスキャンする
01204      前後に連続して存在するフレームについてのみ計算 */
01205   /* search for best trellis word only around the estimated time */
01206   /* 1. search forward */
01207   for(t = (nword->tre)->endtime; t >= 0; t--) {
01208     tre = bt_binsearch_atom(backtrellis, t, (WORD_ID) word);
01209     if (tre == NULL) break;     /* go to 2 if the trellis word disappear */
01210 #ifdef MULTIPATH_VERSION
01211     totalscore = new->g[t] + tre->backscore;
01212 #else
01213     if (newphone->is_pseudo) {
01214       tmpp = outprob_cd(t, &(newphone->body.pseudo->stateset[newphone->body.pseudo->state_num-2]), param);
01215     } else {
01216       tmpp = outprob_state(t, newphone->body.defined->s[newphone->body.defined->state_num-2], param);
01217     }
01218     totalscore = new->g[t] + tre->backscore + tmpp;
01219 #endif
01220     if (new->score < totalscore) {
01221       new->score = totalscore;
01222       new->bestt = t;
01223       new->estimated_next_t = tre->begintime - 1;
01224       new->tre = tre;
01225     }
01226   }
01227   /* 2. search bckward */
01228   for(t = (nword->tre)->endtime + 1; t <= startt; t++) {
01229     tre = bt_binsearch_atom(backtrellis, t, (WORD_ID) word);
01230     if (tre == NULL) break;     /* end if the trellis word disapper */
01231 #ifdef MULTIPATH_VERSION
01232     totalscore = new->g[t] + tre->backscore;
01233 #else
01234     if (newphone->is_pseudo) {
01235       tmpp = outprob_cd(t, &(newphone->body.pseudo->stateset[newphone->body.pseudo->state_num-2]), param);
01236     } else {
01237       tmpp = outprob_state(t, newphone->body.defined->s[newphone->body.defined->state_num-2], param);
01238     }
01239     totalscore = new->g[t] + tre->backscore + tmpp;
01240 #endif
01241     if (new->score < totalscore) {
01242       new->score = totalscore;
01243       new->bestt = t;
01244       new->estimated_next_t = tre->begintime - 1;
01245       new->tre = tre;
01246     }
01247   }
01248 
01249 #ifdef USE_DFA
01250   }
01251 #endif
01252 
01253 #endif /* WORD_GRAPH */
01254 
01255 #ifdef USE_NGRAM
01256   /* set current LM score */
01257   new->lscore = nword->lscore;
01258 #endif
01259   
01260 }
01261 
01262 
01263 /**********************************************************************/
01264 /********** 初期仮説の生成                 ****************************/
01265 /********** Generate an initial hypothesis ****************************/
01266 /**********************************************************************/
01267 
01287 void
01288 start_word(NODE *new, NEXTWORD *nword, HTK_Param *param, BACKTRELLIS *backtrellis)
01289 {
01290   HMM_Logical *newphone;
01291   WORD_ID word;
01292   TRELLIS_ATOM *tre = NULL;
01293   LOGPROB tmpp;
01294   int t;
01295 
01296   /* initialize data */
01297   word = nword->id;
01298   new->score = LOG_ZERO;
01299   new->seqnum = 1;
01300   new->seq[0] = word;
01301 
01302 #ifdef USE_DFA
01303   new->state = nword->next_state;
01304 #endif
01305 #ifdef USE_NGRAM
01306   new->totallscore = nword->lscore;
01307 #endif  
01308 
01309 #ifdef USE_NGRAM
01310   /* set current LM score */
01311   new->lscore = nword->lscore;
01312 #endif
01313 
01314   /* cross-word triphone need not be handled on startup */
01315   newphone = winfo->wseq[word][winfo->wlen[word]-1];
01316   if (ccd_flag) {
01317     new->last_ph = NULL;
01318   }
01319   
01320 #ifdef USE_NGRAM
01321   new->g[peseqlen-1] = nword->lscore;
01322 #else  /* USE_DFA */
01323   new->g[peseqlen-1] = 0;
01324 #endif
01325   
01326 #ifdef WORD_GRAPH
01327   new->score = new->g[peseqlen-1] + (nword->tre)->backscore;
01328   new->tre  =  nword->tre;
01329   new->bestt = peseqlen-1;
01330   new->estimated_next_t = (nword->tre)->begintime - 1;
01331   
01332 #else
01333   
01334   for (t=peseqlen-1; t>=0; t--) {
01335     tre = bt_binsearch_atom(backtrellis, t, word);
01336     if (tre != NULL) {
01337 #ifdef GRAPHOUT
01338       new->bestt = peseqlen-1;
01339 #else
01340       new->bestt = t;
01341 #endif
01342 #ifdef MULTIPATH_VERSION
01343       new->score = new->g[peseqlen-1] + tre->backscore;
01344 #else
01345       if (newphone->is_pseudo) {
01346         tmpp = outprob_cd(peseqlen-1, &(newphone->body.pseudo->stateset[newphone->body.pseudo->state_num-2]), param);
01347       } else {
01348         tmpp = outprob_state(peseqlen-1, newphone->body.defined->s[newphone->body.defined->state_num-2], param);
01349       }
01350       new->score = new->g[peseqlen-1] + tre->backscore + tmpp;
01351 #endif
01352       new->estimated_next_t = tre->begintime - 1;
01353       new->tre = tre;
01354       break;
01355     }
01356   }
01357   if (tre == NULL) {            /* no word in backtrellis */
01358     new->score = LOG_ZERO;
01359   }
01360 #endif /* WORD_GRAPH */
01361 }
01362 
01380 void
01381 last_next_word(NODE *now, NODE *new, HTK_Param *param)
01382 {
01383   cpy_node(new, now);
01384   if (ccd_flag) {
01385     /* 最終音素分を viterbi して最終スコアを設定 */
01386     /* scan the last phone and update the final score */
01387     do_viterbi_next_word(now, new, now->last_ph
01388 #ifdef MULTIPATH_VERSION
01389                          , now->last_ph_sp_attached
01390 #endif
01391                          , param);
01392 #ifdef MULTIPATH_VERSION
01393     new->score = new->final_g;
01394 #else
01395     new->score = new->g[0];
01396 #endif
01397   } else {
01398 #ifdef MULTIPATH_VERSION
01399     new->score = now->final_g;
01400 #else
01401     new->score = now->g[0];
01402 #endif
01403 #ifdef GRAPHOUT
01404 #ifdef GRAPHOUT_PRECISE_BOUNDARY
01405     /* last boundary has moved to [peseqlen-1] in last scan_word() */
01406     memcpy(new->wordend_frame, now->wordend_frame, sizeof(short)*peseqlen);
01407     memcpy(new->wordend_gscore, now->wordend_gscore, sizeof(LOGPROB)*peseqlen);
01408 #endif
01409 #endif
01410   }
01411 }
01412 
01413 #endif /* PASS2_STRICT_IWCD */

Juliusに対してTue Mar 28 16:20:49 2006に生成されました。  doxygen 1.4.2