libjulius/src/search_bestfirst_main.c

Go to the documentation of this file.
00001 
00041 /*
00042  * Copyright (c) 1991-2007 Kawahara Lab., Kyoto University
00043  * Copyright (c) 2000-2005 Shikano Lab., Nara Institute of Science and Technology
00044  * Copyright (c) 2005-2007 Julius project team, Nagoya Institute of Technology
00045  * All rights reserved
00046  */
00047 
00048 #include <julius/julius.h>
00049 
00050 /* declaration of local functions */
00051 static NODE *get_best_from_stack(NODE **start, int *stacknum);
00052 static int put_to_stack(NODE *new, NODE **start, NODE **bottom, int *stacknum, int stacksize);
00053 static void put_all_in_stack(NODE **start, int *stacknum, WORD_INFO *winfo);
00054 static void free_all_nodes(NODE *node);
00055 static void put_hypo_woutput(NODE *hypo, WORD_INFO *winfo);
00056 static void put_hypo_wname(NODE *hypo, WORD_INFO *winfo);
00057 
00058 /**********************************************************************/
00059 /********** 次単語格納領域の割り当て          *************************/
00060 /********** allocate memory for nextword data *************************/
00061 /**********************************************************************/
00062 
00085 static NEXTWORD **
00086 nw_malloc(int *maxlen, NEXTWORD **root, int max)
00087 {
00088   NEXTWORD *nwtmp;
00089   NEXTWORD **nw;
00090   int i;
00091 
00092   nw = (NEXTWORD **)mymalloc(max * sizeof(NEXTWORD *));
00093   nwtmp = (NEXTWORD *)mymalloc(max * sizeof(NEXTWORD));
00094   for (i=0;i<max; i++) {
00095     nw[i] = &(nwtmp[i]);
00096   }
00097   *maxlen = max;
00098   *root = nwtmp;
00099   return nw;
00100 }
00101 
00117 static void
00118 nw_free(NEXTWORD **nw, NEXTWORD *root)
00119 {
00120   free(root);
00121   free(nw);
00122 }
00123 
00162 static NEXTWORD **
00163 nw_expand(NEXTWORD **nwold, int *maxlen, NEXTWORD **root, int num)
00164 {
00165   NEXTWORD *nwtmp;
00166   NEXTWORD **nw;
00167   int i;
00168   int nwmaxlen;
00169 
00170   nwmaxlen = *maxlen + num;
00171 
00172   nwtmp = (NEXTWORD *)myrealloc(*root, nwmaxlen * sizeof(NEXTWORD));
00173   nw = (NEXTWORD **)myrealloc(nwold, nwmaxlen * sizeof(NEXTWORD *));
00174   nw[0] = nwtmp;
00175   for (i=1;i<nwmaxlen; i++) {
00176     nw[i] = &(nwtmp[i]);
00177   }
00178   *maxlen = nwmaxlen;
00179   *root = nwtmp;
00180   return nw;
00181 }
00182 
00183 
00184 /**********************************************************************/
00185 /********** 仮説スタックの操作         ********************************/
00186 /********** Hypothesis stack operation ********************************/
00187 /**********************************************************************/
00188 
00208 static NODE *
00209 get_best_from_stack(NODE **start, int *stacknum)
00210 {
00211   NODE *tmp;
00212 
00213   /* return top */
00214   tmp=(*start);
00215   if ((*start)!=NULL) {         /* delete it from stack */
00216     (*start)=(*start)->next;
00217     if ((*start)!=NULL) (*start)->prev=NULL;
00218     (*stacknum)--;
00219     return(tmp);
00220   }
00221   else {
00222     return(NULL);
00223   }
00224 }
00225 
00252 static int
00253 can_put_to_stack(NODE *new, NODE **bottom, int *stacknum, int stacksize)
00254 {
00255   /* stack size check */
00256   if ((*stacknum + 1) > stacksize && (*bottom)->score >= new->score) {
00257     /* new node is below the bottom: discard it */
00258     return(-1);
00259   }
00260   return(0);
00261 }
00262 
00291 static int
00292 put_to_stack(NODE *new, NODE **start, NODE **bottom, int *stacknum, int stacksize)
00293 {
00294   NODE *tmp;
00295 
00296   /* stack size is going to increase... */
00297   (*stacknum)++;
00298 
00299   /* stack size check */
00300   if ((*stacknum)>stacksize) {
00301     /* stack size overflow */
00302     (*stacknum)--;
00303     if ((*bottom)->score < new->score) {
00304       /* new node will be inserted in the stack: free the bottom */
00305       tmp=(*bottom);
00306       (*bottom)->prev->next=NULL;
00307       (*bottom)=(*bottom)->prev;
00308       free_node(tmp);
00309     } else {
00310       /* new node is below the bottom: discard it */
00311       free_node(new);
00312       return(-1);
00313     }
00314   }
00315 
00316   /* insert new node on edge */
00317   if ((*start)==NULL) {         /* no node in stack */
00318     /* new node is the only node */
00319     (*start)=new;
00320     (*bottom)=new;
00321     new->next=NULL;
00322     new->prev=NULL;
00323     return(0);
00324   }
00325   if ((*start)->score <= new->score) {
00326     /* insert on the top */
00327     new->next = (*start);
00328     new->next->prev = new;
00329     (*start)=new;
00330     new->prev=NULL;
00331     return(0);
00332   }
00333   if ((*bottom)->score >= new->score) {
00334     /* insert on the bottom */
00335     new->prev = (*bottom);
00336     new->prev->next = new;
00337     (*bottom)=new;
00338     new->next=NULL;
00339     return(0);
00340   }
00341     
00342   /* now the new node is between (*start) and (*bottom) */
00343   if (((*start)->score + (*bottom)->score) / 2 > new->score) {
00344     /* search from bottom */
00345     tmp=(*bottom);
00346     while(tmp->score < new->score) tmp=tmp->prev;
00347     new->prev=tmp;
00348     new->next=tmp->next;
00349     tmp->next->prev=new;
00350     tmp->next=new;
00351   } else {
00352     /* search from start */
00353     tmp=(*start);
00354     while(tmp->score > new->score) tmp=tmp->next;
00355     new->next=tmp;
00356     new->prev=tmp->prev;
00357     tmp->prev->next=new;
00358     tmp->prev=new;
00359   }
00360   return(0);
00361 }
00362 
00379 static void
00380 put_all_in_stack(NODE **start, int *stacknum, WORD_INFO *winfo)
00381 {
00382   NODE *ntmp;
00383   
00384   jlog("DEBUG: hypotheses remained in global stack\n");
00385   while ((ntmp = get_best_from_stack(start, stacknum)) != NULL) {
00386     jlog("DEBUG: %3d: s=%f",*stacknum, ntmp->score);
00387     put_hypo_woutput(ntmp, winfo);
00388     free_node(ntmp);
00389   }
00390 }
00391 
00404 static void
00405 free_all_nodes(NODE *start)
00406 {
00407   NODE *tmp;
00408   NODE *next;
00409 
00410   tmp=start;
00411   while(tmp) {
00412     next=tmp->next;
00413     free_node(tmp);
00414     tmp=next;
00415   }
00416 }
00417 
00418 
00419 #ifdef CONFIDENCE_MEASURE
00420 
00421 /**********************************************************************/
00422 /********** 単語信頼度の計算 ******************************************/
00423 /********** Confidence scoring ****************************************/
00424 /**********************************************************************/
00425 
00426 #ifdef CM_SEARCH
00427 /**************************************************************/
00428 /**** CM computation method 1(default):                  ******/
00429 /****   - Use local posterior probabilities while search ******/
00430 /****   - Obtain CM at hypothesis expansion time         ******/
00431 /**************************************************************/
00432 
00451 static void
00452 cm_init(StackDecode *sd, int wnum, LOGPROB cm_alpha
00453 #ifdef CM_MULTIPLE_ALPHA
00454         , cm_alpha_num
00455 #endif
00456         )
00457 {
00458   sd->l_stacksize = wnum;
00459   sd->l_start = sd->l_bottom = NULL;
00460   sd->l_stacknum = 0;
00461   sd->cm_alpha = cm_alpha;
00462 #ifdef CM_MULTIPLE_ALPHA
00463   if (sd->cmsumlist) {
00464     if (sd->cmsumlistlen < cm_alpha_num) {
00465       free(sd->cmsumlist);
00466       sd->cmsumlist = NULL;
00467     }
00468   }
00469   if (sd->cmsumlist == NULL) {
00470     sd->cmsumlist = (LOGPROB *)mymalloc(sizeof(LOGPROB) * cm_alpha_num);
00471     sd->cmsumlistlen = cm_alpha_num;
00472   }
00473 #endif    
00474 }
00475 
00490 static void
00491 cm_store(StackDecode *sd, NODE *new)
00492 {
00493   /* store the generated hypo into local stack */
00494   put_to_stack(new, &(sd->l_start), &(sd->l_bottom), &(sd->l_stacknum), sd->l_stacksize);
00495 }
00496 
00512 static void
00513 cm_sum_score(StackDecode *sd
00514 #ifdef CM_MULTIPLE_ALPHA
00515              , bgn, end, step
00516 #endif
00517 )
00518 {
00519   NODE *node;
00520   LOGPROB sum;
00521 #ifdef CM_MULTIPLE_ALPHA
00522   LOGPROB a;
00523   int j;
00524 #endif
00525 
00526   if (sd->l_start == NULL) return;      /* no hypo */
00527   sd->cm_tmpbestscore = sd->l_start->score; /* best hypo is at the top of the stack */
00528 
00529 #ifdef CM_MULTIPLE_ALPHA
00530   for (j = 0, a = bgn; a <= end; a += step) {
00531     sum = 0.0;
00532     for(node = sd->l_start; node; node = node->next) {
00533       sum += pow(10, a * (node->score - sd->cm_tmpbestscore));
00534     }
00535     sd->cmsumlist[j++] = sum;   /* store sums for each alpha coef. */
00536   }
00537 #else
00538   sum = 0.0;
00539   for(node = sd->l_start; node; node = node->next) {
00540     sum += pow(10, sd->cm_alpha * (node->score - sd->cm_tmpbestscore));
00541   }
00542   sd->cm_tmpsum = sum;          /* store sum */
00543 #endif
00544 
00545 }
00546 
00563 static void
00564 cm_set_score(StackDecode *sd, NODE *node
00565 #ifdef CM_MULTIPLE_ALPHA
00566              , bgn, end, step
00567 #endif
00568              )
00569 {
00570 #ifdef CM_MULTIPLE_ALPHA
00571   int j;
00572   LOGPROB a;
00573 #endif
00574 
00575 #ifdef CM_MULTIPLE_ALPHA
00576   for (j = 0, a = bgn; a <= end; a += step) {
00577     node->cmscore[node->seqnum-1][j] = pow(10, a * (node->score - sd->cm_tmpbestscore)) / sd->cmsumlist[j];
00578     j++;
00579   }
00580 #else
00581   node->cmscore[node->seqnum-1] = pow(10, sd->cm_alpha * (node->score - sd->cm_tmpbestscore)) / sd->cm_tmpsum;
00582 #endif
00583 }
00584 
00601 static NODE *
00602 cm_get_node(StackDecode *sd)
00603 {
00604   return(get_best_from_stack(&(sd->l_start), &(sd->l_stacknum)));
00605 }
00606 
00607 #endif /* CM_SEARCH */
00608 
00609 #ifdef CM_NBEST
00610 /*****************************************************************/
00611 /**** CM computation method 2: conventional N-best scoring *******/
00612 /**** NOTE: enough N-best should be computed (-n 10 ~ -n 100) ****/
00613 /*****************************************************************/
00614 
00634 static void
00635 cm_compute_from_nbest(StackDecode *sd, NODE *start, int stacknum, JCONF_SEARCH *jconf)
00636 {
00637   NODE *node;
00638   LOGPROB bestscore, sum, s;
00639   WORD_ID w;
00640   int i;
00641   LOGPROB cm_alpha;
00642   int j;
00643 
00644   /* prepare buffer */
00645 #ifdef CM_MULTIPLE_ALPHA
00646   if (sd->cmsumlist) {
00647     if (sd->cmsumlistlen < jconf->annotate.cm_alpha_num) {
00648       free(sd->cmsumlist);
00649       sd->cmsumlist = NULL;
00650     }
00651   }
00652   if (sd->cmsumlist == NULL) {
00653     sd->cmsumlist = (LOGPROB *)mymalloc(sizeof(LOGPROB) * jconf->annotate.cm_alpha_num);
00654     sd->cmsumlistlen = cm_alpha_num;
00655   }
00656 #endif    
00657   if (sd->sentcm == NULL) {             /* not allocated yet */
00658     sd->sentcm = (LOGPROB *)mymalloc(sizeof(LOGPROB)*stacknum);
00659     sd->sentnum = stacknum;
00660   } else if (sd->sentnum < stacknum) { /* need expanded */
00661     sd->sentcm = (LOGPROB *)myrealloc(sentcm, sizeof(LOGPROB)*stacknum);
00662     sd->sentnum = stacknum;
00663   }
00664   if (sd->wordcm == NULL) {
00665     sd->wordcm = (LOGPROB *)mymalloc(sizeof(LOGPROB) * winfo->num);
00666   }
00667   
00668   cm_alpha = jconf->annotate.cm_alpha;
00669 #ifdef CM_MULTIPLE_ALPHA
00670   for (j = 0, cm_alpha = jconf->annotate.cm_alpha_bgn; cm_alpha <= jconf->annotate.cm_alpha_end; cm_alpha += jconf->annotate.cm_alpha_step) {
00671 #endif
00672     /* clear whole word cm buffer */
00673     for(w=0;w<winfo->num;w++) {
00674       sd->wordcm[w] = 0.0;
00675     }
00676     /* get best score */
00677     bestscore = start->score;
00678     /* compute sum score of all hypothesis */
00679     sum = 0.0;
00680     for (node = start; node != NULL; node = node->next) {
00681       sum += pow(10, cm_alpha * (node->score - bestscore));
00682     }
00683     /* compute sentence posteriori probabilities */
00684     i = 0;
00685     for (node = start; node != NULL; node = node->next) {
00686       sd->sentcm[i] = pow(10, cm_alpha * (node->score - bestscore)) / sum;
00687       i++;
00688     }
00689     /* compute word posteriori probabilities */
00690     i = 0;
00691     for (node = start; node != NULL; node = node->next) {
00692       for (w=0;w<node->seqnum;w++) {
00693         sd->wordcm[node->seq[w]] += sd->sentcm[i];
00694       }
00695       i++;
00696     }
00697     /* store the probabilities to node */
00698     for (node = start; node != NULL; node = node->next) {
00699       for (w=0;w<node->seqnum;w++) {
00700 #ifdef CM_MULTIPLE_ALPHA
00701         node->cmscore[w][j] = sd->wordcm[node->seq[w]];
00702 #else   
00703         node->cmscore[w] = sd->wordcm[node->seq[w]];
00704 #endif
00705       }
00706     }
00707 #ifdef CM_MULTIPLE_ALPHA
00708     j++;
00709   }
00710 #endif
00711 }
00712 
00713 #endif /* CM_NBEST */
00714 
00715 #endif /* CONFIDENCE_MEASURE */
00716 
00717 
00718 /**********************************************************************/
00719 /********** Enveloped best-first search *******************************/
00720 /**********************************************************************/
00721 
00722 /*
00723  * 1. Word envelope
00724  *
00725  * 一種の仮説ビーム幅を設定: 展開元となった仮説の数をその仮説長(単語数)
00726  * ごとにカウントする. 一定数を越えたらそれより短い仮説は以後展開しない. 
00727  * 
00728  * Introduce a kind of beam width to search tree: count the number of
00729  * popped hypotheses per the depth of the hypotheses, and when a count
00730  * in a certain depth reaches the threshold, all hypotheses shorter than
00731  * the depth will be dropped from candidates.
00732  *
00733  */
00734 
00748 static void
00749 wb_init(StackDecode *s)
00750 {
00751   int i;
00752   for(i=0;i<=MAXSEQNUM;i++) s->hypo_len_count[i] = 0;
00753   s->maximum_filled_length = -1;
00754 }
00755 
00782 static boolean
00783 wb_ok(StackDecode *s, NODE *now, int width)
00784 {
00785   if (now->seqnum <= s->maximum_filled_length) {
00786     /* word expansion is not allowed because a word expansion count
00787        at deeper level has already reached the limit */
00788     return FALSE;
00789   } else {
00790     /* word expansion is possible.  Increment the word expansion count
00791        of the given depth */
00792     s->hypo_len_count[now->seqnum]++;
00793     if (s->hypo_len_count[now->seqnum] > width) {
00794       /* the word expansion count of this level has reached the limit, so
00795          set the beam-filled depth to this level to inhibit further
00796          expansion of shorter hypotheses. */
00797       if (s->maximum_filled_length < now->seqnum) s->maximum_filled_length = now->seqnum;
00798     }
00799     return TRUE;
00800   }
00801 }
00802 
00803 #ifdef SCAN_BEAM
00804 /*
00805  * 2. Score envelope
00806  *
00807  * Viterbi計算量の削減: 入力フレームごとの最大尤度 (score envelope) を
00808  * 全仮説にわたって記録しておく. 仮説の前向き尤度計算時に,その envelope
00809  * から一定幅以上スコアが下回るとき,Viterbi パスの演算を中断する. 
00810  *
00811  * ここでは,取り出した仮説からフレームごとの score envelope を更新する
00812  * 部分が記述されている. Envelope を考慮した Viterbi 計算の実際は
00813  * scan_word() を参照のこと. 
00814  *
00815  * Reduce computation cost of hypothesis Viterbi processing by setting a
00816  * "score envelope" that holds the maximum scores at every frames
00817  * throughout the expanded hypotheses.  When calculating Viterbi path
00818  * on HMM trellis for updating score of popped hypothesis, Viterbi paths
00819  * that goes below a certain range from the score envelope are dropped.
00820  *
00821  * These functions are for updating the score envelope according to the
00822  * popped hypothesis.  For actual Viterbi process with score envelope, 
00823  * see scan_word().
00824  *
00825  */
00826 
00842 static void
00843 envl_init(StackDecode *s, int framenum)
00844 {
00845   int i;
00846   for(i=0;i<framenum;i++) s->framemaxscore[i] = LOG_ZERO;
00847 }
00848 
00865 static void
00866 envl_update(StackDecode *s, NODE *n, int framenum)
00867 {
00868   int t;
00869   for(t=framenum-1;t>=0;t--) {
00870     if (s->framemaxscore[t] < n->g[t]) s->framemaxscore[t] = n->g[t];
00871   }
00872 }
00873 #endif /* SCAN_BEAM */
00874 
00875 
00876 /**********************************************************************/
00877 /********** Short pause segmentation **********************************/
00878 /**********************************************************************/
00879 
00903 void
00904 segment_set_last_nword(NODE *hypo, RecogProcess *r)
00905 {
00906   int i;
00907   WORD_ID w;
00908 
00909   if (r->sp_break_last_nword_allow_override) {
00910     for(i=0;i<hypo->seqnum;i++) {
00911       w = hypo->seq[i];
00912       if (w != r->sp_break_last_word
00913           && !is_sil(w, r)
00914           && !r->lm->winfo->is_transparent[w]
00915           ) {
00916         r->sp_break_last_nword = w;
00917         break;
00918       }
00919     }
00920 #ifdef SP_BREAK_DEBUG
00921     printf("sp_break_last_nword=%d[%s]\n", r->sp_break_last_nword, r->lm->winfo->woutput[r->sp_break_last_nword]);
00922 #endif
00923   } else {
00924     r->sp_break_last_nword = WORD_INVALID;
00925   }
00926 }
00927 
00928 
00929 /**********************************************************************/
00930 /********* Debug output of hypothesis while search ********************/
00931 /**********************************************************************/
00932 
00947 static void
00948 put_hypo_woutput(NODE *hypo, WORD_INFO *winfo)
00949 {
00950   int i,w;
00951 
00952   if (hypo != NULL) {
00953     for (i=hypo->seqnum-1;i>=0;i--) {
00954       w = hypo->seq[i];
00955       jlog(" %s", winfo->woutput[w]);
00956     }
00957   }
00958   jlog("\n");  
00959 }
00960 
00975 static void
00976 put_hypo_wname(NODE *hypo, WORD_INFO *winfo)
00977 {
00978   int i,w;
00979 
00980   if (hypo != NULL) {
00981     for (i=hypo->seqnum-1;i>=0;i--) {
00982       w = hypo->seq[i];
00983       jlog(" %s", winfo->wname[w]);
00984     }
00985   }
00986   jlog("\n");  
00987 }
00988 
01001 static void
01002 store_result_pass2(NODE *hypo, RecogProcess *r)
01003 {
01004   int i;
01005   Sentence *s;
01006 
01007   s = &(r->result.sent[r->result.sentnum]);
01008 
01009   s->word_num = hypo->seqnum;
01010   for (i = 0; i < hypo->seqnum; i++) {
01011     s->word[i] = hypo->seq[hypo->seqnum - 1 - i];
01012   }
01013 #ifdef CONFIDENCE_MEASURE
01014   for (i = 0; i < hypo->seqnum; i++) {
01015     s->confidence[i] = hypo->cmscore[hypo->seqnum - 1 - i];
01016   }
01017 #endif
01018 
01019   s->score = hypo->score;
01020   s->score_lm = hypo->totallscore;
01021   s->score_am = hypo->score - hypo->totallscore;
01022   if (r->lmtype == LM_DFA) {
01023     /* output which grammar the hypothesis belongs to on multiple grammar */
01024     /* determine only by the last word */
01025     if (multigram_get_all_num(r->lm) > 1) {
01026       s->gram_id = multigram_get_gram_from_category(r->lm->winfo->wton[hypo->seq[0]], r->lm);
01027     } else {
01028       s->gram_id = 0;
01029     }
01030   }
01031 
01032   r->result.sentnum++;
01033   /* add to tail */
01034 }
01035 
01036 
01037 /**********************************************************************/
01038 /******** Output top 'ncan' hypotheses in a stack and free all ********/
01039 /**********************************************************************/
01040 
01083 static void
01084 result_reorder_and_output(NODE **r_start, NODE **r_bottom, int *r_stacknum, int ncan, RecogProcess *r, HTK_Param *param)
01085 {
01086   NODE *now;
01087   int num;
01088 
01089 #ifdef CM_NBEST 
01090   /* compute CM from the N-best sentence candidates */
01091   cm_compute_from_nbest(&(r->pass2), *r_start, *r_stacknum, r->config);
01092 #endif
01093   num = 0;
01094   while ((now = get_best_from_stack(r_start,r_stacknum)) != NULL && num < ncan) {
01095     num++;
01096     /* output result */
01097     store_result_pass2(now, r);
01098 
01099     /* if in sp segmentation mode, */
01100     /* set the last context-aware word for next recognition */
01101     if (r->lmtype == LM_PROB && r->config->successive.enabled && num == 1) segment_set_last_nword(now, r);
01102     /* do forced alignment if needed */
01103     if (r->config->annotate.align_result_word_flag) word_rev_align(now->seq, now->seqnum, param, &(r->result.sent[r->result.sentnum-1]), r);
01104     if (r->config->annotate.align_result_phoneme_flag) phoneme_rev_align(now->seq, now->seqnum, param, &(r->result.sent[r->result.sentnum-1]), r);
01105     if (r->config->annotate.align_result_state_flag) state_rev_align(now->seq, now->seqnum, param, &(r->result.sent[r->result.sentnum-1]), r);
01106 
01107     free_node(now);
01108   }
01109   r->result.status = J_RESULT_STATUS_SUCCESS;
01110   /* free the rest */
01111   if (now != NULL) free_node(now);
01112   free_all_nodes(*r_start);
01113 }  
01114 
01115 
01116 /**********************************************************************/
01117 /********* Main stack decoding function *******************************/
01118 /**********************************************************************/
01119 
01147 void
01148 wchmm_fbs(HTK_Param *param, RecogProcess *r, int cate_bgn, int cate_num)
01149 {
01150   /* 文仮説スタック */
01151   /* hypothesis stack (double-linked list) */
01152   int stacknum;                 /* current stack size */
01153   NODE *start = NULL;           /* top node */
01154   NODE *bottom = NULL;          /* bottom node */
01155 
01156   /* 認識結果格納スタック(結果はここへいったん集められる) */
01157   /* result sentence stack (found results will be stored here and then re-ordered) */
01158   static int r_stacksize;
01159   static int r_stacknum;
01160   static NODE *r_start = NULL;
01161   static NODE *r_bottom = NULL;
01162 
01163   /* ワークエリア */
01164   /* work area */
01165   static NEXTWORD fornoise; /* Dummy NEXTWORD data for short-pause insertion handling */
01166 
01167   NEXTWORD **nextword, *nwroot; /* buffer to store predicted words */
01168   int maxnwnum;                 /* current allocated number of words in nextword */
01169   int nwnum;                    /* current number of words in nextword */
01170   NODE *now, *new;              /* popped current hypo., expanded new hypo. */
01171   NODE *now_noise;             /* for inserting/deleting noise word */
01172   boolean now_noise_calced;
01173   boolean acc;
01174   int t;
01175   int w,i,j;
01176   LOGPROB last_score = LOG_ZERO;
01177   /* for graph generation */
01178   LOGPROB prev_score;
01179   WordGraph *wordgraph_root = NULL;
01180   boolean merged_p;
01181 #ifdef GRAPHOUT_DYNAMIC
01182   int dynamic_merged_num = 0;
01183   WordGraph *wtmp;
01184   LOGPROB lscore_prev;
01185 #endif
01186 #ifdef GRAPHOUT_SEARCH
01187   int terminate_search_num = 0;
01188 #endif
01189 
01190   /* local temporal parameter */
01191   int stacksize, ncan, maxhypo, peseqlen;
01192   static JCONF_SEARCH *jconf;
01193   static WORD_INFO *winfo;
01194   static NGRAM_INFO *ngram;
01195   static DFA_INFO *gdfa;
01196   static BACKTRELLIS *backtrellis;
01197   static StackDecode *dwrk;
01198 
01199   if (r->lmtype == LM_DFA) {
01200     if (debug2_flag) jlog("DEBUG: only words in these categories will be expanded: %d-%d\n", cate_bgn, cate_bgn + cate_num-1);
01201   }
01202 
01203   /*
01204    * 初期化
01205    * Initialize
01206    */
01207 
01208   /* just for quick access */
01209   jconf = r->config;
01210   winfo = r->lm->winfo;
01211   if (r->lmtype == LM_PROB) {
01212     ngram = r->lm->ngram;
01213   } else if (r->lmtype == LM_DFA) {
01214     gdfa = r->lm->dfa;
01215   }
01216   backtrellis = r->backtrellis;
01217   dwrk = &(r->pass2);
01218 
01219   stacksize = jconf->pass2.stack_size;
01220   ncan = jconf->pass2.nbest;
01221   maxhypo = jconf->pass2.hypo_overflow;
01222   peseqlen = backtrellis->framelen;
01223 
01224   /* store data for sub routines */
01225   r->peseqlen = backtrellis->framelen;
01226   //recog->ccd_flag = recog->jconf->am.ccd_flag;
01227   /* 予測単語格納領域を確保 */
01228   /* malloc area for word prediction */
01229   /* the initial maximum number of nextwords is the size of vocabulary */
01230   nextword = nw_malloc(&maxnwnum, &nwroot, winfo->num);
01231   /* 前向きスコア計算用の領域を確保 */
01232   /* malloc are for forward viterbi (scan_word()) */
01233   malloc_wordtrellis(r);                /* scan_word用領域 */
01234   /* 仮説スタック初期化 */
01235   /* initialize hypothesis stack */
01236   start = bottom = NULL;
01237   stacknum = 0;
01238   /* 結果格納スタック初期化 */
01239   /* initialize result stack */
01240   r_stacksize = ncan;
01241   r_start = r_bottom = NULL;
01242   r_stacknum = 0;
01243 
01244   /* カウンタ初期化 */
01245   /* initialize counter */
01246   dwrk->popctr = 0;
01247   dwrk->genectr = 0;
01248   dwrk->pushctr = 0;
01249   dwrk->finishnum = 0;
01250   
01251 #ifdef CM_SEARCH
01252   /* initialize local stack */
01253   cm_init(dwrk, winfo->num, jconf->annotate.cm_alpha
01254 #ifdef CM_MULTIPLE_ALPHA
01255           , jconf->annotate.cm_alpha_num
01256 #endif
01257           );
01258 #endif
01259 #ifdef SCAN_BEAM
01260   /* prepare and initialize score envelope */
01261   dwrk->framemaxscore = (LOGPROB *)mymalloc(sizeof(LOGPROB)*peseqlen);
01262   envl_init(dwrk, peseqlen);
01263 #endif /* SCAN_BEAM */
01264 
01265   /* prepare result storage */
01266   result_sentence_malloc(r, jconf->output.output_hypo_maxnum);
01267 
01268   /* エンベロープ探索用の単語長別展開数カウンタを初期化 */
01269   /* initialize counters for envelope search */
01270   if (jconf->pass2.enveloped_bestfirst_width >= 0) wb_init(dwrk);
01271 
01272   if (jconf->graph.enabled) {
01273     wordgraph_init(r->wchmm);
01274   }
01275 
01276   /* 
01277    * 初期仮説(1単語からなる)を得, 文仮説スタックにいれる
01278    * get a set of initial words from LM function and push them as initial
01279    * hypotheses
01280    */
01281   /* the first words will be stored in nextword[] */
01282   if (r->lmtype == LM_PROB) {
01283     nwnum = ngram_firstwords(nextword, peseqlen, maxnwnum, r);
01284   } else if (r->lmtype == LM_DFA) {
01285     nwnum = dfa_firstwords(nextword, peseqlen, maxnwnum, r);
01286     /* 溢れたら、バッファを増やして再チャレンジ */
01287     /* If the number of nextwords can exceed the buffer size, expand the
01288        nextword data area */
01289     while (nwnum < 0) {
01290       nextword = nw_expand(nextword, &maxnwnum, &nwroot, winfo->num);
01291       nwnum = dfa_firstwords(nextword, peseqlen, maxnwnum, r);
01292     }
01293   }
01294 
01295   if (debug2_flag) {
01296     jlog("DEBUG: %d words in wordtrellis as first hypothesis\n", nwnum);
01297   }
01298   
01299   /* store them to stack */
01300   for (w = 0; w < nwnum; w++) {
01301     if (r->lmtype == LM_DFA) {
01302       /* limit word hypothesis */
01303       if (! (winfo->wton[nextword[w]->id] >= cate_bgn && winfo->wton[nextword[w]->id] < cate_bgn + cate_num)) {
01304         continue;
01305       }
01306     }
01307     /* generate new hypothesis */
01308     new = newnode(r);
01309     start_word(new, nextword[w], param, r);
01310     if (r->lmtype == LM_DFA) {
01311       if (new->score <= LOG_ZERO) { /* not on trellis */
01312         free_node(new);
01313         continue;
01314       }
01315     }
01316     dwrk->genectr++;
01317 #ifdef CM_SEARCH
01318     /* store the local hypothesis to temporal stack */
01319     cm_store(dwrk, new);
01320 #else 
01321     /* put to stack */
01322     if (put_to_stack(new, &start, &bottom, &stacknum, stacksize) != -1) {
01323       dwrk->current = new;
01324       //callback_exec(CALLBACK_DEBUG_PASS2_PUSH, r);
01325       if (jconf->graph.enabled) {
01326         new->prevgraph = NULL;
01327         new->lastcontext = NULL;
01328       }
01329       dwrk->pushctr++;
01330     }
01331 #endif
01332   }
01333 #ifdef CM_SEARCH
01334   /* compute score sum */
01335   cm_sum_score(dwrk
01336 #ifdef CM_MULTIPLE_ALPHA
01337                , jconf->annotate.cm_alpha_bgn
01338                , jconf->annotate.cm_alpha_end
01339                , jconf->annotate.cm_alpha_step
01340 #endif
01341                );
01342 
01343   /* compute CM and put the generated hypotheses to global stack */
01344   while ((new = cm_get_node(dwrk)) != NULL) {
01345     cm_set_score(dwrk, new
01346 #ifdef CM_MULTIPLE_ALPHA
01347                  , jconf->annotate.cm_alpha_bgn
01348                  , jconf->annotate.cm_alpha_end
01349                  , jconf->annotate.cm_alpha_step
01350 #endif
01351                  );
01352 #ifdef CM_SEARCH_LIMIT
01353     if (new->cmscore[new->seqnum-1] < jconf->annotate.cm_cut_thres
01354 #ifdef CM_SEARCH_LIMIT_AFTER
01355         && dwrk->finishnum > 0
01356 #endif
01357         ) {
01358       free_node(new);
01359       continue;
01360     }
01361 #endif /* CM_SEARCH_LIMIT */
01362     
01363     if (put_to_stack(new, &start, &bottom, &stacknum, stacksize) != -1) {
01364       dwrk->current = new;
01365       //callback_exec(CALLBACK_DEBUG_PASS2_PUSH, r);
01366       if (r->graphout) {
01367         new->prevgraph = NULL;
01368         new->lastcontext = NULL;
01369       }
01370       dwrk->pushctr++;
01371     }
01372   }
01373 #endif
01374 
01375   if (debug2_flag) {
01376     jlog("DEBUG: %d pushed\n", dwrk->pushctr);
01377   }
01378   
01379   /********************/
01380   /* main search loop */
01381   /********************/
01382 
01383   for (;;) {
01384 
01385     /* if terminate signal has been received, cancel this input */
01386     /* 
01387      * if (recog->process_want_terminate) {
01388      *   jlog("DEBUG: process terminated by request\n");
01389      *   break;
01390      * }
01391      */
01392     
01393     /* 
01394      * 仮説スタックから最もスコアの高い仮説を取り出す
01395      * pop the top hypothesis from stack
01396      */
01397 #ifdef DEBUG
01398     jlog("DEBUG: get one hypothesis\n");
01399 #endif
01400     now = get_best_from_stack(&start,&stacknum);
01401     if (now == NULL) {  /* stack empty ---> 探索終了*/
01402       jlog("WARNING: %02d %s: hypothesis stack exhausted, terminate search now\n", r->config->id, r->config->name);
01403       jlog("STAT: %02d %s: %d sentences have been found\n", r->config->id, r->config->name, dwrk->finishnum);
01404       break;
01405     }
01406     /* (bogus score check) */
01407     if (now->score <= LOG_ZERO) {
01408       free_node(now);
01409       continue;
01410     }
01411 
01412 
01413     /* 単語グラフ用に pop 仮説の f スコアを一時保存 */
01414     if (r->graphout) {
01415       prev_score = now->score;
01416     }
01417 
01418     /* word envelope チェック */
01419     /* consult word envelope */
01420     if (jconf->pass2.enveloped_bestfirst_width >= 0) {
01421       if (!wb_ok(dwrk, now, jconf->pass2.enveloped_bestfirst_width)) {
01422         /* この仮説長における展開元仮説数の累計数は既に閾値を越えている. 
01423            そのため,この仮説は捨てる. */
01424         /* the number of popped hypotheses at the length already
01425            reaches its limit, so the current popped hypothesis should
01426            be discarded here with no expansion */
01427         if (debug2_flag) {
01428           jlog("DEBUG: popped but pruned by word envelope:");
01429           put_hypo_woutput(now, r->lm->winfo);
01430         }
01431         free_node(now);
01432         continue;
01433       }
01434     }
01435     
01436 #ifdef CM_SEARCH_LIMIT_POP
01437     if (now->cmscore[now->seqnum-1] < jconf->annotate.cm_cut_thres_pop) {
01438       free_node(now);
01439       continue;
01440     }
01441 #endif /* CM_SEARCH_LIMIT_POP */
01442 
01443     dwrk->popctr++;
01444 
01445     /* (for debug) 取り出した仮説とそのスコアを出力 */
01446     /*             output information of the popped hypothesis to stdout */
01447     if (debug2_flag) {
01448       jlog("DEBUG: --- pop %d:\n", dwrk->popctr);
01449       jlog("DEBUG:  "); put_hypo_woutput(now, r->lm->winfo);
01450       jlog("DEBUG:  "); put_hypo_wname(now, r->lm->winfo);
01451       jlog("DEBUG:  %d words, f=%f, g=%f\n", now->seqnum, now->score, now->g[now->bestt]);
01452       jlog("DEBUG:  last word on trellis: [%d-%d]\n", now->estimated_next_t + 1, now->bestt);
01453     }
01454 
01455     dwrk->current = now;
01456     //callback_exec(CALLBACK_DEBUG_PASS2_POP, r);
01457 
01458     if (r->graphout) {
01459 
01460 #ifdef GRAPHOUT_DYNAMIC
01461       /* merge last word in popped hypo if possible */
01462       wtmp = wordgraph_check_merge(now->prevgraph, &wordgraph_root, now->seq[now->seqnum-1], &merged_p, jconf);
01463       if (wtmp != NULL) {               /* wtmp holds merged word */
01464         dynamic_merged_num++;
01465 
01466         lscore_prev = (now->prevgraph) ? now->prevgraph->lscore_tmp : 0.0;
01467 
01468         if (now->prevgraph != NULL) {
01469           if (now->prevgraph->saved) {
01470             j_internal_error("wchmm_fbs: already saved??\n");
01471           }
01472           wordgraph_free(now->prevgraph);
01473         }
01474 
01475         if (now->lastcontext != NULL
01476             && now->lastcontext != wtmp /* avoid self loop */
01477             ) {
01478           wordgraph_check_and_add_leftword(now->lastcontext, wtmp, lscore_prev);
01479 #ifdef GRAPHOUT_SEARCH_CONSIDER_RIGHT
01480           if (merged_p) {
01481             if (wordgraph_check_and_add_rightword(wtmp, now->lastcontext, lscore_prev) == FALSE) {
01482               merged_p = TRUE;
01483             } else {
01484               merged_p = FALSE;
01485             }
01486           } else {
01487             wordgraph_check_and_add_rightword(wtmp, now->lastcontext, lscore_prev);
01488           }
01489 #else
01490           wordgraph_check_and_add_rightword(wtmp, now->lastcontext, lscore_prev);
01491 #endif    
01492         }
01493         
01494         now->prevgraph = wtmp;  /* change word to the merged one */
01495 
01496         /*printf("last word merged\n");*/
01497         /* previous still remains at memory here... (will be purged later) */
01498       } else {
01499         wordgraph_save(now->prevgraph, now->lastcontext, &wordgraph_root);
01500       }
01501 #ifdef GRAPHOUT_SEARCH
01502       /* if recent hypotheses are included in the existing graph, terminate */
01503       if (merged_p && now->endflag == FALSE
01504 #ifdef GRAPHOUT_SEARCH_DELAY_TERMINATION
01505           /* Do not apply search termination by graph merging
01506              until the first sentence candidate is found. */
01507           && (jconf->graph.graphout_search_delay == FALSE || dwrk->finishnum > 0)
01508 #endif
01509           ) {
01510         terminate_search_num++;
01511         free_node(now);
01512         continue;
01513       }
01514 #endif
01515 #else  /* ~GRAPHOUT_DYNAMIC */
01516       /* always save */
01517       wordgraph_save(now->prevgraph, now->lastcontext, &wordgraph_root);
01518 #endif /* ~GRAPHOUT_DYNAMIC */
01519     }
01520 
01521     /* 取り出した仮説のスコアを元に score envelope を更新 */
01522     /* update score envelope using the popped hypothesis */
01523     envl_update(dwrk, now, peseqlen);
01524 
01525     /* 
01526      * 取り出した仮説の受理フラグが既に立っていれば,
01527      * その仮説は探索終了とみなし,結果として出力して次のループへ. 
01528      *
01529      * If the popped hypothesis already reached to the end, 
01530      * we can treat it as a recognition result.
01531      */
01532 #ifdef DEBUG
01533     VERMES("endflag check\n");
01534 #endif
01535     
01536     if (now->endflag) {
01537       if (debug2_flag) {
01538         jlog("DEBUG:  This is a full sentence candidate\n");
01539       }
01540       /* quick, dirty hack */
01541       if (now->score == last_score) {
01542         free_node(now);
01543         continue;
01544       } else {
01545         last_score = now->score;
01546       }
01547       
01548       dwrk->finishnum++;
01549       if (debug2_flag) {
01550         jlog("DEBUG:  %d-th sentence found\n", dwrk->finishnum);
01551       }
01552 
01553         /* 一定数の仮説が得られたあとスコアでソートするため,
01554            一時的に別のスタックに格納しておく */
01555         /* store the result to result stack
01556            after search is finished, they will be re-ordered and output */
01557         put_to_stack(now, &r_start, &r_bottom, &r_stacknum, r_stacksize);
01558         /* 指定数の文仮説が得られたなら探索を終了する */
01559         /* finish search if specified number of results are found */
01560         if (dwrk->finishnum >= ncan) {
01561           break;
01562         } else {
01563           continue;
01564         }
01565       
01566     } /* end of now->endflag */
01567 
01568     
01569     /* 
01570      * 探索失敗を検出する. 
01571      * 仮説数が maxhypo 以上展開されたら, もうこれ以上は探索しない
01572      *
01573      * detecting search failure:
01574      * if the number of expanded hypotheses reaches maxhypo, giveup further search
01575      */
01576 #ifdef DEBUG
01577     jlog("DEBUG: loop end check\n");
01578 #endif
01579     if (dwrk->popctr >= maxhypo) {
01580       jlog("WARNING: %02d %s: num of popped hypotheses reached the limit (%d)\n", r->config->id, r->config->name, maxhypo);
01581       /* (for debug) 探索失敗時に、スタックに残った情報を吐き出す */
01582       /* (for debug) output all hypothesis remaining in the stack */
01583       if (debug2_flag) put_all_in_stack(&start, &stacknum, r->lm->winfo);
01584       free_node(now);
01585       break;                    /* end of search */
01586     }
01587     /* 仮説長が一定値を越えたとき,その仮説を破棄する */
01588     /* check hypothesis word length overflow */
01589     if (now->seqnum >= MAXSEQNUM) {
01590       jlog("ERROR: sentence length exceeded system limit ( > %d)\n", MAXSEQNUM);
01591       free_node(now);
01592       continue;
01593     }
01594 
01595 #ifndef GRAPHOUT_PRECISE_BOUNDARY
01596     if (r->graphout) {
01597       /* if monophone (= no backscan), the tail g score should be kept here */
01598       /* else, updated tail g score will be computed in scan_word()  */
01599       if(!jconf->am.ccd_flag) {
01600         now->tail_g_score = now->g[now->bestt];
01601       }
01602     }
01603 #endif
01604 
01605     /*
01606      * 前向きスコアを更新する: 最後の単語の部分の前向きスコアを計算する. 
01607      * update forward score: compute forward trellis for the last word
01608      */
01609 #ifdef DEBUG
01610     jlog("DEBUG: scan_word\n");
01611 #endif
01612     scan_word(now, param, r);
01613     if (now->score < LOG_ZERO) { /* another end-of-search detecter */
01614       jlog("WARNING: too low score, ignore: score=%f",now->score);
01615       put_hypo_woutput(now, r->lm->winfo);
01616       free_node(now);
01617       continue;
01618     }
01619 
01620     /* 
01621      * 取り出した仮説が文として受理可能であれば,
01622      * 受理フラグを立ててをスタックにいれ直しておく. 
01623      * (次に取り出されたら解となる)
01624      *
01625      * if the current popped hypothesis is acceptable, set endflag
01626      * and return it to stack: it will become the recognition result
01627      * when popped again.
01628      */
01629 #ifdef DEBUG
01630     jlog("DEBUG: accept check\n");
01631 #endif
01632 
01633     if (r->lmtype == LM_PROB) {
01634       acc = ngram_acceptable(now, r);
01635     } else if (r->lmtype == LM_DFA) {
01636       acc = dfa_acceptable(now, r);
01637     }
01638     if (acc && now->estimated_next_t <= 5) {
01639       new = newnode(r);
01640       /* new に now の中身をコピーして,最終的なスコアを計算 */
01641       /* copy content of 'now' to 'new', and compute the final score */
01642       last_next_word(now, new, param, r);
01643       if (debug2_flag) {
01644         jlog("DEBUG:  This is acceptable as a sentence candidate\n");
01645       }
01646       /* g[] が入力始端に達していなければ棄却 */
01647       /* reject this sentence candidate if g[] does not reach the end */
01648       if (new->score <= LOG_ZERO) {
01649         if (debug2_flag) {
01650           jlog("DEBUG:  But invalid because Viterbi pass does not reach the 0th frame\n");
01651         }
01652         free_node(new);
01653         free_node(now);
01654         continue;
01655       }
01656       /* 受理フラグを立てて入れ直す */
01657       /* set endflag and push again  */
01658       if (debug2_flag) {
01659         jlog("DEBUG  This hypo itself was pushed with final score=%f\n", new->score);
01660       }
01661       new->endflag = TRUE;
01662       if (put_to_stack(new, &start, &bottom, &stacknum, stacksize) != -1) {
01663         if (r->graphout) {
01664           if (new->score > LOG_ZERO) {
01665             new->lastcontext = now->prevgraph;
01666             new->prevgraph = wordgraph_assign(new->seq[new->seqnum-1],
01667                                               WORD_INVALID,
01668                                               (new->seqnum >= 2) ? new->seq[new->seqnum-2] : WORD_INVALID,
01669                                               0,
01670 #ifdef GRAPHOUT_PRECISE_BOUNDARY
01671                                               /* wordend are shifted to the last */
01672 #ifdef PASS2_STRICT_IWCD
01673                                               new->wordend_frame[0],
01674 #else
01675                                               now->wordend_frame[0],
01676 #endif
01677 #else
01678                                               now->bestt,
01679 #endif
01680                                               new->score,
01681                                               prev_score,
01682                                               now->g[0],
01683 #ifdef GRAPHOUT_PRECISE_BOUNDARY
01684 #ifdef PASS2_STRICT_IWCD
01685                                               new->wordend_gscore[0],
01686 #else
01687                                               now->wordend_gscore[0],
01688 #endif
01689 #else
01690                                               now->tail_g_score,
01691 #endif
01692                                               now->lscore,
01693 #ifdef CM_SEARCH
01694                                               new->cmscore[new->seqnum-1],
01695 #else
01696                                               LOG_ZERO,
01697 #endif
01698                                               r
01699                                               );
01700           } else {
01701             new->lastcontext = now->lastcontext;
01702             new->prevgraph = now->prevgraph;
01703           }
01704         } /* put_to_stack() != -1 */
01705       } /* recog->graphout */
01706       /* この仮説はここで終わらずに, ここからさらに単語展開する */
01707       /* continue with the 'now' hypothesis, not terminate here */
01708     }
01709     
01710     /*
01711      * この仮説から,次単語集合を決定する. 
01712      * 次単語集合は, この仮説の推定始端フレーム周辺に存在した
01713      * 第1パスのトレリス単語集合. 
01714      *
01715      * N-gramの場合は各単語の n-gram 接続確率が含まれる. 
01716      * DFA の場合は, その中でさらに DFA 上で接続可能なもののみが返ってくる
01717      */
01718     /*
01719      * Determine next word set that can connect to this hypothesis.
01720      * They come from the trellis word that has been survived at near the
01721      * beginning of the last word.
01722      *
01723      * In N-gram mode, they also contain N-gram probabilities toward the
01724      * source hypothesis.  In DFA mode, the word set is further reduced
01725      * by the grammatical constraint
01726      */
01727 #ifdef DEBUG
01728     jlog("DEBUG: get next words\n");
01729 #endif
01730     if (r->lmtype == LM_PROB) {
01731       nwnum = ngram_nextwords(now, nextword, maxnwnum, r);
01732     } else if (r->lmtype == LM_DFA) {
01733       nwnum = dfa_nextwords(now, nextword, maxnwnum, r);
01734       /* nextword が溢れたら、バッファを増やして再チャレンジ */
01735       /* If the number of nextwords can exceed the buffer size, expand the
01736          nextword data area */
01737       while (nwnum < 0) {
01738         nextword = nw_expand(nextword, &maxnwnum, &nwroot, winfo->num);
01739         nwnum = dfa_nextwords(now, nextword, maxnwnum, r);
01740       }
01741     }
01742     if (debug2_flag) {
01743       jlog("DEBUG:  %d words extracted from wordtrellis\n", nwnum);
01744     }
01745 
01746     /* 
01747      * 仮説と次単語集合から新たな文仮説を生成し,スタックにいれる. 
01748      */
01749     /*
01750      * generate new hypotheses from 'now' and 'nextword', 
01751      * and push them to stack
01752      */
01753 #ifdef DEBUG
01754     jlog("DEBUG: generate hypo\n");
01755 #endif
01756 
01757     if (r->lmtype == LM_DFA) {
01758       now_noise_calced = FALSE; /* TRUE is noise-inserted score has been calculated */
01759     }
01760     i = dwrk->pushctr;          /* store old value */
01761 
01762 #ifdef CM_SEARCH
01763     /* initialize local stack */
01764     cm_init(dwrk, winfo->num, jconf->annotate.cm_alpha
01765 #ifdef CM_MULTIPLE_ALPHA
01766             , jconf->annotate.cm_alpha_num
01767 #endif
01768             );
01769 #endif
01770 
01771     /* for each nextword, generate a new hypothesis */
01772     for (w = 0; w < nwnum; w++) {
01773       if (r->lmtype == LM_DFA) {
01774         /* limit word hypothesis */
01775         if (! (winfo->wton[nextword[w]->id] >= cate_bgn && winfo->wton[nextword[w]->id] < cate_bgn + cate_num)) {
01776           continue;
01777         }
01778       }
01779       new = newnode(r);
01780 
01781       if (r->lmtype == LM_DFA) {
01782 
01783         if (nextword[w]->can_insert_sp == TRUE) {
01784           /* ノイズを挟んだトレリススコアを計算し,挟まない場合との最大値を取る */
01785           /* compute hypothesis score with noise inserted */
01786           
01787           if (now_noise_calced == FALSE) {
01788             /* now に sp をつけた仮説 now_noise を作り,そのスコアを計算 */
01789             /* generate temporal hypothesis 'now_noise' which has short-pause
01790                word after the original 'now' */
01791             fornoise.id = gdfa->sp_id;
01792             now_noise = newnode(r);
01793             cpy_node(now_noise, now);
01794 #if 0
01795             now_noise_tmp = newnode(r);
01796             next_word(now, now_noise_tmp, &fornoise, param, r);
01797             scan_word(now_noise_tmp, param, r);
01798             for(t=0;t<peseqlen;t++) {
01799               now_noise->g[t] = max(now_noise_tmp->g[t], now->g[t]);
01800             }
01801             free_node(now_noise_tmp);
01802 #else
01803             /* expand NOISE only if it exists in backward trellis */
01804             /* begin patch by kashima */
01805             if (jconf->pass2.looktrellis_flag) {
01806               if(!dfa_look_around(&fornoise, now, r)){
01807                 free_node(now_noise);
01808                 free_node(new);
01809                 continue;
01810               }
01811             }
01812             /* end patch by kashima */
01813             
01814             /* now_nosie の スコア g[] を計算し,元の now の g[] と比較して
01815                高い方を採用 */
01816             /* compute trellis score g[], and adopt the maximum score
01817                for each frame compared with now->g[] */
01818             next_word(now, now_noise, &fornoise, param, r);
01819             scan_word(now_noise, param, r);
01820             for(t=0;t<peseqlen;t++) {
01821               now_noise->g[t] = max(now_noise->g[t], now->g[t]);
01822             }
01823             /* ノイズを挟んだ際を考慮したスコアを計算したので,
01824                ここで最後のノイズ単語を now_noise から消す */
01825             /* now that score has been computed considering pause insertion,
01826                we can delete the last noise word from now_noise here */
01827             now_noise->seqnum--;
01828 #endif
01829             now_noise_calced = TRUE;
01830           }
01831           
01832           /* expand word only if it exists in backward trellis */
01833           /* begin patch by kashima */
01834           if (jconf->pass2.looktrellis_flag) {
01835             if(!dfa_look_around(nextword[w], now_noise, r)){
01836               free_node(new);
01837               continue;
01838             }
01839           }
01840           /* end patch by kashima */
01841           
01842           /* 新しい仮説' new' を 'now_noise' から生成 */
01843           /* generate a new hypothesis 'new' from 'now_noise' */
01844           next_word(now_noise, new, nextword[w], param, r);
01845           
01846         } else {
01847           
01848           /* expand word only if it exists in backward trellis */
01849           /* begin patch by kashima */
01850           if (jconf->pass2.looktrellis_flag) {
01851             if(!dfa_look_around(nextword[w], now, r)){
01852               free_node(new);
01853               continue;
01854             }
01855           }
01856           /* end patch by kashima */
01857           
01858           /* 新しい仮説' new' を 'now_noise' から生成 */
01859           /* generate a new hypothesis 'new' from 'now_noise' */
01860           next_word(now, new, nextword[w], param, r);
01861           
01862         }
01863       }
01864 
01865       if (r->lmtype == LM_PROB) {
01866 
01867         /* 新しい仮説' new' を 'now_noise' から生成
01868            N-gram の場合はノイズを特別扱いしない */
01869         /* generate a new hypothesis 'new' from 'now'.
01870            pause insertion is treated as same as normal words in N-gram mode. */
01871         next_word(now, new, nextword[w], param, r);
01872 
01873       }
01874 
01875       if (new->score <= LOG_ZERO) { /* not on trellis */
01876         free_node(new);
01877         continue;
01878       }
01879         
01880       dwrk->genectr++;
01881 
01882 #ifdef CM_SEARCH
01883       /* store the local hypothesis to temporal stack */
01884       cm_store(dwrk, new);
01885 #else 
01886       /* 生成した仮説 'new' をスタックに入れる */
01887       /* push the generated hypothesis 'new' to stack */
01888 
01889       /* stack overflow */
01890       if (can_put_to_stack(new, &bottom, &stacknum, stacksize) == -1) {
01891         free_node(new);
01892         continue;
01893       }
01894       
01895       if (r->graphout) {
01896         /* assign a word arc to the last fixed word */
01897         new->lastcontext = now->prevgraph;
01898         new->prevgraph = wordgraph_assign(new->seq[new->seqnum-2],
01899                                           new->seq[new->seqnum-1],
01900                                           (new->seqnum >= 3) ? new->seq[new->seqnum-3] : WORD_INVALID,
01901                                           new->bestt + 1,
01902 #ifdef GRAPHOUT_PRECISE_BOUNDARY
01903 #ifdef PASS2_STRICT_IWCD
01904                                           /* most up-to-date wordend_gscore is on new, because the last phone of 'now' will be computed at next_word() */
01905                                           new->wordend_frame[new->bestt],
01906 #else
01907                                           now->wordend_frame[new->bestt],
01908 #endif
01909 #else
01910                                           now->bestt,
01911 #endif
01912                                           new->score, prev_score,
01913 #ifdef PASS2_STRICT_IWCD
01914                                           new->g[new->bestt] - new->lscore,
01915 #else
01916                                           now->g[new->bestt+1],
01917 #endif
01918 #ifdef GRAPHOUT_PRECISE_BOUNDARY
01919 #ifdef PASS2_STRICT_IWCD
01920                                           /* most up-to-date wordend_gscore is on new, because the last phone of 'now' will be computed at next_word() */
01921                                           new->wordend_gscore[new->bestt],
01922 #else
01923                                           now->wordend_gscore[new->bestt],
01924 #endif
01925 #else
01926                                           now->tail_g_score,
01927 #endif
01928                                           now->lscore,
01929 #ifdef CM_SEARCH
01930                                           new->cmscore[new->seqnum-2],
01931 #else
01932                                           LOG_ZERO,
01933 #endif
01934                                           r
01935                                           );
01936       } /* recog->graphout */
01937       put_to_stack(new, &start, &bottom, &stacknum, stacksize);
01938       if (debug2_flag) {
01939         j = new->seq[new->seqnum-1];
01940         jlog("DEBUG:  %15s [%15s](id=%5d)(%f) [%d-%d] pushed\n",winfo->wname[j], winfo->woutput[j], j, new->score, new->estimated_next_t + 1, new->bestt);
01941       }
01942       dwrk->current = new;
01943       //callback_exec(CALLBACK_DEBUG_PASS2_PUSH, r);
01944       dwrk->pushctr++;
01945 #endif
01946     } /* end of nextword loop */
01947 
01948 #ifdef CM_SEARCH
01949     /* compute score sum */
01950     cm_sum_score(dwrk
01951 #ifdef CM_MULTIPLE_ALPHA
01952                  , jconf->annotate.cm_alpha_bgn 
01953                  , jconf->annotate.cm_alpha_end
01954                  , jconf->annotate.cm_alpha_step
01955 #endif
01956                  );
01957     /* compute CM and put the generated hypotheses to global stack */
01958     while ((new = cm_get_node(dwrk)) != NULL) {
01959       cm_set_score(dwrk, new
01960 #ifdef CM_MULTIPLE_ALPHA
01961                    , jconf->annotate.cm_alpha_bgn
01962                    , jconf->annotate.cm_alpha_end
01963                    , jconf->annotate.cm_alpha_step
01964 #endif
01965                    );
01966 #ifdef CM_SEARCH_LIMIT
01967       if (new->cmscore[new->seqnum-1] < jconf->annotate.cm_cut_thres
01968 #ifdef CM_SEARCH_LIMIT_AFTER
01969           && dwrk->finishnum > 0
01970 #endif
01971           ) {
01972         free_node(new);
01973         continue;
01974       }
01975 #endif /* CM_SEARCH_LIMIT */
01976       /*      j = new->seq[new->seqnum-1];
01977               printf("  %15s [%15s](id=%5d)(%f) [%d-%d] cm=%f\n",winfo->wname[j], winfo->woutput[j], j, new->score, new->estimated_next_t + 1, new->bestt, new->cmscore[new->seqnum-1]);*/
01978 
01979       /* stack overflow */
01980       if (can_put_to_stack(new, &bottom, &stacknum, stacksize) == -1) {
01981         free_node(new);
01982         continue;
01983       }
01984 
01985       if (r->graphout) {
01986 
01987         /* assign a word arc to the last fixed word */
01988         new->lastcontext = now->prevgraph;
01989         new->prevgraph = wordgraph_assign(new->seq[new->seqnum-2],
01990                                           new->seq[new->seqnum-1],
01991                                           (new->seqnum >= 3) ? new->seq[new->seqnum-3] : WORD_INVALID,
01992                                           new->bestt + 1,
01993 #ifdef GRAPHOUT_PRECISE_BOUNDARY
01994 #ifdef PASS2_STRICT_IWCD
01995                                           new->wordend_frame[new->bestt],
01996 #else
01997                                           now->wordend_frame[new->bestt],
01998 #endif
01999 #else
02000                                           now->bestt,
02001 #endif
02002                                           new->score, prev_score,
02003 #ifdef PASS2_STRICT_IWCD
02004                                           new->g[new->bestt] - new->lscore,
02005 #else
02006                                           now->g[new->bestt+1],
02007 #endif
02008 #ifdef GRAPHOUT_PRECISE_BOUNDARY
02009 #ifdef PASS2_STRICT_IWCD
02010                                           new->wordend_gscore[new->bestt],
02011 #else
02012                                           now->wordend_gscore[new->bestt],
02013 #endif
02014 #else
02015                                           now->tail_g_score,
02016 #endif
02017                                           now->lscore,
02018 #ifdef CM_SEARCH
02019                                           new->cmscore[new->seqnum-2],
02020 #else
02021                                           LOG_ZERO,
02022 #endif
02023                                           r
02024                                           );
02025       } /* recog->graphout */
02026       
02027       put_to_stack(new, &start, &bottom, &stacknum, stacksize);
02028       if (debug2_flag) {
02029         j = new->seq[new->seqnum-1];
02030         jlog("DEBUG:  %15s [%15s](id=%5d)(%f) [%d-%d] pushed\n",winfo->wname[j], winfo->woutput[j], j, new->score, new->estimated_next_t + 1, new->bestt);
02031       }
02032       dwrk->current = new;
02033       //callback_exec(CALLBACK_DEBUG_PASS2_PUSH, r);
02034       dwrk->pushctr++;
02035     }
02036 #endif
02037 
02038     if (debug2_flag) {
02039       jlog("DEBUG: %d pushed\n",dwrk->pushctr-i);
02040     }
02041     if (r->lmtype == LM_DFA) {
02042       if (now_noise_calced == TRUE) free_node(now_noise);
02043     }
02044     
02045     /* 
02046      * 取り出した仮説を捨てる
02047      * free the source hypothesis
02048      */
02049     free_node(now);
02050 
02051   }
02052   /***************/
02053   /* End of Loop */
02054   /***************/
02055 
02056   /* output */
02057   /* 探索失敗で一つも候補が得られなければ,第1パスの結果をそのまま出力する */
02058   /* If search failed and no candidate obtained in this pass, output
02059      the result of the previous 1st pass as a final result. */
02060   if (dwrk->finishnum == 0) {           /* if search failed */
02061     if (verbose_flag) {
02062       jlog("WARNING: %02d %s: got no candidates, output 1st pass result as a final result\n", r->config->id, r->config->name);
02063     }
02064     /* make hypothesis data from the result of previous 1st pass */
02065     now = newnode(r);
02066     for (i=0;i<r->pass1_wnum;i++) {
02067       now->seq[i] = r->pass1_wseq[r->pass1_wnum-1-i];
02068     }
02069     now->seqnum = r->pass1_wnum;
02070     now->score = r->pass1_score;
02071 #ifdef CONFIDENCE_MEASURE
02072     /* fill in null values */
02073 #ifdef CM_MULTIPLE_ALPHA
02074     for(j=0;j<jconf->annotate.cm_alpha_num;j++) {
02075       for(i=0;i<now->seqnum;i++) now->cmscore[i][j] = 0.0;
02076     }
02077 #else
02078     for(i=0;i<now->seqnum;i++) now->cmscore[i] = 0.0;
02079 #endif
02080 #endif /* CONFIDENCE_MEASURE */
02081 
02082     if (r->lmtype == LM_PROB && r->config->successive.enabled) {
02083       /* if in sp segment mode, */
02084       /* find segment restart words from 1st pass result */
02085       segment_set_last_nword(now, r);
02086     }
02087     /* do forced alignment if needed */
02088     if (jconf->annotate.align_result_word_flag) word_rev_align(now->seq, now->seqnum, param, &(r->result.pass1), r);
02089     if (jconf->annotate.align_result_phoneme_flag) phoneme_rev_align(now->seq, now->seqnum, param, &(r->result.pass1), r);
02090     if (jconf->annotate.align_result_state_flag) state_rev_align(now->seq, now->seqnum, param, &(r->result.pass1), r);
02091 
02092     /* output it */
02093     r->result.status = J_RESULT_STATUS_FAIL;
02094     //callback_exec(CALLBACK_RESULT, r);
02095 
02096     free_node(now);
02097 
02098   } else {                      /* if at least 1 candidate found */
02099     if (debug2_flag) {
02100       jlog("STAT: %02d %s: got %d candidates\n", r->config->id, r->config->name, dwrk->finishnum);
02101     }
02102       /* 結果はまだ出力されていないので,文候補用スタック内をソートして
02103          ここで出力する */
02104       /* As all of the found candidate are in result stack, we sort them
02105          and output them here  */
02106       if (debug2_flag) jlog("DEBUG: done\n");
02107       result_reorder_and_output(&r_start, &r_bottom, &r_stacknum, jconf->output.output_hypo_maxnum, r, param);
02108       //callback_exec(CALLBACK_RESULT, r);
02109       //callback_exec(CALLBACK_EVENT_PASS2_END, r);
02110   }
02111   
02112   /* 各種カウンタを出力 */
02113   /* output counters */
02114   if (verbose_flag) {
02115     jlog("STAT: %02d %s: %d generated, %d pushed, %d nodes popped in %d\n",
02116          r->config->id, r->config->name,
02117          dwrk->genectr, dwrk->pushctr, dwrk->popctr, backtrellis->framelen);
02118     jlog_flush();
02119 #ifdef GRAPHOUT_DYNAMIC
02120     if (r->graphout) {
02121       jlog("STAT: %02d %s: graph: %d merged", r->config->id, r->config->name, dynamic_merged_num);
02122 #ifdef GRAPHOUT_SEARCH
02123       jlog("S, %d terminated", terminate_search_num);
02124 #endif
02125       jlog(" in %d\n", dwrk->popctr);
02126     }
02127 #endif
02128   }
02129     
02130   if (dwrk->finishnum > 0 && r->graphout) {
02131     if (verbose_flag) jlog("STAT: ------ wordgraph post-processing begin ------\n");
02132     /* garbage collection and word merging */
02133     /* words with no following word (except end of sentence) will be erased */
02134     wordgraph_purge_leaf_nodes(&wordgraph_root, r);
02135 #ifdef GRAPHOUT_DEPTHCUT
02136     /* perform word graph depth cutting here */
02137     wordgraph_depth_cut(&wordgraph_root, r);
02138 #endif
02139 
02140     /* if GRAPHOUT_PRECISE_BOUNDARY defined,
02141        propagate exact time boundary to the right context.
02142        words of different boundary will be duplicated here.
02143     */
02144     wordgraph_adjust_boundary(&wordgraph_root, r);
02145 
02146     if (jconf->graph.confnet) {
02147       /* CONFUSION NETWORK GENERATION */
02148 
02149       /* old merging functions should be skipped */
02150 
02151       /* finalize: sort and annotate ID */
02152       r->graph_totalwordnum = wordgraph_sort_and_annotate_id(&wordgraph_root, r);
02153       /* check coherence */
02154       wordgraph_check_coherence(wordgraph_root, r);
02155       /* compute graph CM by forward-backward processing */
02156       graph_forward_backward(wordgraph_root, r);
02157       if (verbose_flag) jlog("STAT: ------ wordgraph post-processing end ------\n");
02158 
02159       r->result.wg = wordgraph_root;
02160 
02161       /* 
02162        * if (jconf->graph.lattice) {
02163        *   callback_exec(CALLBACK_RESULT_GRAPH, r);
02164        * }
02165        */
02166       
02167       /* parse the graph to extract order relationship */
02168       graph_make_order(wordgraph_root, r);
02169       /* create confusion network */
02170       r->result.confnet = confnet_create(wordgraph_root, r);
02171       /* output confusion network */
02172       //callback_exec(CALLBACK_RESULT_CONFNET, r);
02173       /* free area for order relationship */
02174       graph_free_order();
02175       /* free confusion network clusters */
02176       //cn_free_all(&(r->result.confnet));
02177 
02178     } else if (jconf->graph.lattice) {
02179       /* WORD LATTICE POSTPROCESSING */
02180 
02181       /* merge words with the same time and same score */
02182       wordgraph_compaction_thesame(&wordgraph_root);
02183       /* merge words with the same time (skip if "-graphrange -1") */
02184       wordgraph_compaction_exacttime(&wordgraph_root, r);
02185       /* merge words of near time (skip if "-graphrange" value <= 0 */
02186       wordgraph_compaction_neighbor(&wordgraph_root, r);
02187       /* finalize: sort and annotate ID */
02188       r->graph_totalwordnum = wordgraph_sort_and_annotate_id(&wordgraph_root, r);
02189       /* check coherence */
02190       wordgraph_check_coherence(wordgraph_root, r);
02191       /* compute graph CM by forward-backward processing */
02192       graph_forward_backward(wordgraph_root, r);
02193       if (verbose_flag) jlog("STAT: ------ wordgraph post-processing end ------\n");
02194       /* output graph */
02195       r->result.wg = wordgraph_root;
02196       //callback_exec(CALLBACK_RESULT_GRAPH, r);
02197 
02198     } else {
02199       j_internal_error("InternalError: graph generation specified but no output format specified?\n");
02200     }
02201 
02202     /* clear all wordgraph */
02203     //wordgraph_clean(&(r->result.wg));
02204   } /* r->graphout */
02205 
02206   
02207   /* 終了処理 */
02208   /* finalize */
02209   nw_free(nextword, nwroot);
02210   free_all_nodes(start);
02211   free_wordtrellis();
02212 #ifdef SCAN_BEAM
02213   free(dwrk->framemaxscore);
02214 #endif
02215   //result_sentence_free(r);
02216   clear_stocker(dwrk);
02217 }
02218 
02219 /* end of file */

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