00001 
00098 
00099 
00100 
00101 
00102 
00103 
00104 
00105 #include <julius/julius.h>
00106 
00107 #ifndef PASS2_STRICT_IWCD
00108 
00109 #undef TCD                      
00110 
00111 
00112 
00113 
00114 
00115 
00116 #undef STOCKER_DEBUG
00117 
00118 #ifdef STOCKER_DEBUG
00119 static int stocked_num = 0;
00120 static int reused_num = 0;
00121 static int new_num = 0;
00122 static int request_num = 0;
00123 #endif
00124 
00137 static void
00138 free_node_exec(NODE *node)
00139 {
00140   if (node == NULL) return;
00141 
00142   free(node->g);
00143   if (node->g_prev != NULL) free(node->g_prev);
00144 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00145   if (node->region->graphout) {
00146     free(node->wordend_frame);
00147     free(node->wordend_gscore);
00148   }
00149 #endif
00150 
00151   free(node);
00152 }
00153 
00169 void
00170 free_node(NODE *node)
00171 {
00172   if (node == NULL) return;
00173 
00174   if (node->region->graphout) {
00175     if (node->prevgraph != NULL && node->prevgraph->saved == FALSE) {
00176       wordgraph_free(node->prevgraph);
00177     }
00178   }
00179 
00180   
00181   node->next = node->region->pass2.stocker_root;
00182   node->region->pass2.stocker_root = node;
00183 
00184 #ifdef STOCKER_DEBUG
00185   stocked_num++;
00186 #endif
00187 }
00188 
00205 void
00206 clear_stocker(StackDecode *s)
00207 {
00208   NODE *node, *tmp;
00209   node = s->stocker_root;
00210   while(node) {
00211     tmp = node->next;
00212     free_node_exec(node);
00213     node = tmp;
00214   }
00215   s->stocker_root = NULL;
00216 
00217 #ifdef STOCKER_DEBUG
00218   jlog("DEBUG: %d times requested, %d times newly allocated, %d times reused\n", request_num, new_num, reused_num);
00219   stocked_num = 0;
00220   reused_num = 0;
00221   new_num = 0;
00222   request_num = 0;
00223 #endif
00224 }
00225 
00246 NODE *
00247 cpy_node(NODE *dst, NODE *src)
00248 {
00249   int peseqlen;
00250 
00251   peseqlen = src->region->peseqlen;
00252   
00253   dst->next = src->next;
00254   dst->prev = src->prev;
00255   memcpy(dst->g, src->g, sizeof(LOGPROB) * peseqlen);
00256   memcpy(dst->seq, src->seq, sizeof(WORD_ID) * MAXSEQNUM);
00257 #ifdef CM_SEARCH
00258 #ifdef CM_MULTIPLE_ALPHA
00259   {
00260     int w;
00261     for(w=0;w<src->seqnum;w++) {
00262       memcpy(dst->cmscore[w], src->cmscore[w], sizeof(LOGPROB) * src->region->config->annotate.cm_alpha_num);
00263     }
00264   }     
00265 #else
00266   memcpy(dst->cmscore, src->cmscore, sizeof(LOGPROB) * MAXSEQNUM);
00267 #endif
00268 #endif 
00269   dst->seqnum = src->seqnum;
00270   dst->score = src->score;
00271   dst->bestt = src->bestt;
00272   dst->estimated_next_t = src->estimated_next_t;
00273   dst->endflag = src->endflag;
00274   dst->state = src->state;
00275   dst->tre = src->tre;
00276   if (src->g_prev != NULL) { 
00277     memcpy(dst->g_prev, src->g_prev, sizeof(LOGPROB) * peseqlen);
00278     dst->last_ph = src->last_ph;
00279     dst->last_ph_sp_attached = src->last_ph_sp_attached;
00280     dst->lscore = src->lscore;
00281   }
00282   dst->totallscore = src->totallscore;
00283   dst->final_g = src->final_g;
00284 #ifdef VISUALIZE
00285   dst->popnode = src->popnode;
00286 #endif
00287 
00288   if (src->region->graphout) {
00289 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00290     memcpy(dst->wordend_frame, src->wordend_frame, sizeof(short) * peseqlen);
00291     memcpy(dst->wordend_gscore, src->wordend_gscore, sizeof(LOGPROB) * peseqlen);
00292 #endif
00293     dst->prevgraph = src->prevgraph;
00294     dst->lastcontext = src->lastcontext;
00295 #ifndef GRAPHOUT_PRECISE_BOUNDARY
00296     dst->tail_g_score = src->tail_g_score;
00297 #endif
00298   }
00299 
00300   return(dst);
00301 }
00302 
00323 NODE *
00324 newnode(RecogProcess *r)
00325 {
00326   NODE *tmp;
00327   int i;
00328   int peseqlen;
00329 
00330   peseqlen = r->peseqlen;
00331 
00332 #ifdef STOCKER_DEBUG
00333   request_num++;
00334 #endif
00335   if ((tmp = r->pass2.stocker_root) != NULL) {
00336     
00337     r->pass2.stocker_root = tmp->next;
00338 #ifdef STOCKER_DEBUG
00339     stocked_num--;
00340     reused_num++;
00341 #endif
00342   } else {
00343     
00344     tmp =(NODE *)mymalloc(sizeof(NODE));
00345     tmp->g = (LOGPROB *)mymalloc(sizeof(LOGPROB) * peseqlen);
00346     if (r->ccd_flag) {
00347       tmp->g_prev = (LOGPROB *)mymalloc(sizeof(LOGPROB) * peseqlen);
00348     } else {
00349       tmp->g_prev = NULL;
00350     }
00351 
00352 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00353     if (r->graphout) {
00354       tmp->wordend_frame = (short *)mymalloc(sizeof(short) * peseqlen);
00355       tmp->wordend_gscore = (LOGPROB *)mymalloc(sizeof(LOGPROB) * peseqlen);
00356     }
00357 #endif
00358 #ifdef STOCKER_DEBUG
00359     new_num++;
00360 #endif
00361   }
00362 
00363   
00364   
00365   tmp->next=NULL;
00366   tmp->prev=NULL;
00367   tmp->last_ph = NULL;
00368   tmp->last_ph_sp_attached = FALSE;
00369   if (r->ccd_flag) {
00370     if (r->lmtype == LM_PROB) {
00371       tmp->lscore = LOG_ZERO;
00372       tmp->totallscore = LOG_ZERO;
00373     } else if (r->lmtype == LM_DFA) {
00374       tmp->lscore = 0.0;
00375       tmp->totallscore = 0.0;
00376     }
00377   }
00378   tmp->endflag = FALSE;
00379   tmp->seqnum = 0;
00380   for(i=0;i<peseqlen;i++) {
00381     tmp->g[i] = LOG_ZERO;
00382   }
00383   if (r->ccd_flag) {
00384     for(i=0;i<peseqlen;i++) {
00385       tmp->g_prev[i] = LOG_ZERO;
00386     }
00387   }
00388   tmp->final_g = LOG_ZERO;
00389 #ifdef VISUALIZE
00390   tmp->popnode = NULL;
00391 #endif
00392   tmp->tre = NULL;
00393 
00394   if (r->graphout) {
00395     tmp->prevgraph = NULL;
00396     tmp->lastcontext = NULL;
00397   }
00398 
00399   tmp->region = r;
00400 
00401   return(tmp);
00402 }
00403 
00404 
00405 
00406 
00407 
00408 
00409 
00426 void
00427 malloc_wordtrellis(RecogProcess *r)
00428 {
00429   int maxwn;
00430   StackDecode *dwrk;
00431 
00432   maxwn = r->lm->winfo->maxwn + 10;
00433   dwrk = &(r->pass2);
00434 
00435   dwrk->wordtrellis[0] = (LOGPROB *)mymalloc(sizeof(LOGPROB) * maxwn);
00436   dwrk->wordtrellis[1] = (LOGPROB *)mymalloc(sizeof(LOGPROB) * maxwn);
00437 
00438   dwrk->g = (LOGPROB *)mymalloc(sizeof(LOGPROB) * r->peseqlen);
00439 
00440   dwrk->phmmlen_max = r->lm->winfo->maxwlen + 2;
00441   dwrk->phmmseq = (HMM_Logical **)mymalloc(sizeof(HMM_Logical *) * dwrk->phmmlen_max);
00442   if (r->lm->config->enable_iwsp && r->am->hmminfo->multipath) {
00443     dwrk->has_sp = (boolean *)mymalloc(sizeof(boolean) * dwrk->phmmlen_max);
00444   } else {
00445     dwrk->has_sp = NULL;
00446   }
00447 
00448   dwrk->wend_token_frame[0] = NULL;
00449   dwrk->wend_token_frame[1] = NULL;
00450   dwrk->wend_token_gscore[0] = NULL;
00451   dwrk->wend_token_gscore[1] = NULL;
00452 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00453   if (r->graphout) {
00454     dwrk->wend_token_frame[0] = (short *)mymalloc(sizeof(short) * maxwn);
00455     dwrk->wend_token_frame[1] = (short *)mymalloc(sizeof(short) * maxwn);
00456     dwrk->wend_token_gscore[0] = (LOGPROB *)mymalloc(sizeof(LOGPROB) * maxwn);
00457     dwrk->wend_token_gscore[1] = (LOGPROB *)mymalloc(sizeof(LOGPROB) * maxwn);
00458   }
00459 #endif
00460   
00461 }
00462 
00475 void
00476 free_wordtrellis(StackDecode *dwrk)
00477 {
00478   int i;
00479 
00480   free(dwrk->wordtrellis[0]);
00481   free(dwrk->wordtrellis[1]);
00482   free(dwrk->g);
00483   free(dwrk->phmmseq);
00484   if (dwrk->has_sp) {
00485     free(dwrk->has_sp);
00486     dwrk->has_sp = NULL;
00487   }
00488 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00489   for(i=0;i<2;i++) {
00490     if (dwrk->wend_token_frame[i]) {
00491       free(dwrk->wend_token_frame[i]);
00492       dwrk->wend_token_frame[i] = NULL;
00493     }
00494     if (dwrk->wend_token_gscore[i]) {
00495       free(dwrk->wend_token_gscore[i]);
00496       dwrk->wend_token_gscore[i] = NULL;
00497     }
00498   }
00499 #endif
00500 }
00501 
00502 
00503 
00504 
00505 
00506 
00507 
00526 static LOGPROB
00527 get_max_out_arc(HTK_HMM_Trans *tr, int state_num)
00528 {
00529   LOGPROB max_a;
00530   int afrom;
00531   LOGPROB a;
00532   
00533   max_a = LOG_ZERO;
00534   for (afrom = 0; afrom < state_num - 1; afrom++) {
00535     a = tr->a[afrom][state_num-1];
00536     if (max_a < a) max_a = a;
00537   }
00538   return(max_a);
00539 }
00540 
00557 static LOGPROB
00558 max_out_arc(HMM_Logical *l)
00559 {
00560   return(get_max_out_arc(hmm_logical_trans(l), hmm_logical_state_num(l)));
00561 }
00562 
00584 void
00585 scan_word(NODE *now, HTK_Param *param, RecogProcess *r)
00586 {
00587   int   i,t, j;
00588   HMM *whmm;
00589   A_CELL *ac;
00590   WORD_ID word;
00591   LOGPROB tmpmax, tmptmp, score1;
00592   int startt = 0, endt;
00593   int wordhmmnum;
00594   LOGPROB tmpmax_store, store_point_maxarc; 
00595   LOGPROB tmpmax2 = LOG_ZERO;
00596   int phmmlen;
00597   HMM_Logical *ret, *wend;
00598   int store_point;
00599   int crossword_point = 0;
00600   boolean back_rescan = FALSE;
00601   boolean node_exist_p;
00602   int tn;                      
00603   int tl;                      
00604 
00605   
00606   WORD_INFO *winfo;
00607   HTK_HMM_INFO *hmminfo;
00608   LOGPROB *framemaxscore;
00609   int peseqlen;
00610   boolean ccd_flag;
00611   boolean enable_iwsp;
00612 #ifdef SCAN_BEAM
00613   LOGPROB scan_beam_thres;
00614 #endif
00615   StackDecode *dwrk;
00616 
00617   winfo = r->lm->winfo;
00618   hmminfo = r->am->hmminfo;
00619   dwrk = &(r->pass2);
00620   peseqlen = r->peseqlen;
00621   framemaxscore = r->pass2.framemaxscore;
00622   ccd_flag = r->ccd_flag;
00623   enable_iwsp = r->lm->config->enable_iwsp; 
00624 #ifdef SCAN_BEAM
00625   scan_beam_thres = r->config->pass2.scan_beam_thres;
00626 #endif
00627 
00628   if (hmminfo->multipath) {
00629     store_point = -1;
00630   } else {
00631     store_point = 0;
00632   }
00633   
00634   
00635 
00636   if (ccd_flag) {
00637     
00638     
00639     if (now->last_ph == NULL) {
00640       
00641       
00642       back_rescan = FALSE;
00643     } else {
00644       
00645       
00646       back_rescan = TRUE;
00647     }
00648   }
00649 #ifdef TCD
00650   if (now->last_ph != NULL) {
00651     jlog("DEBUG: inherited last_ph: %s\n", (now->last_ph)->name);
00652     if (now->last_ph_sp_attached) jlog("DEBUG: (sp attached)\n"); 
00653   } else {
00654     jlog("DEBUG: no last_ph inherited\n");
00655   }
00656 #endif
00657 
00658   
00659   
00660   word = now->seq[now->seqnum-1];
00661 
00662   if (ccd_flag) {
00663 
00664     if (back_rescan) {
00665       
00666       
00667       
00668       phmmlen = winfo->wlen[word] + 1;
00669       if (phmmlen > dwrk->phmmlen_max) {
00670         j_internal_error("scan_word: num of phonemes in a word exceed phmmlenmax (%d) ?\n", dwrk->phmmlen_max);
00671       }
00672       for (i=0;i<phmmlen - 2;i++) dwrk->phmmseq[i] = winfo->wseq[word][i];
00673       if (enable_iwsp && hmminfo->multipath) {
00674         for (i=0;i<phmmlen - 2;i++) dwrk->has_sp[i] = FALSE;
00675       }
00676 
00677       
00678       
00679       wend = winfo->wseq[word][winfo->wlen[word]-1];
00680       ret = get_right_context_HMM(wend, now->last_ph->name, hmminfo);
00681       if (ret == NULL) {        
00682         
00683         
00684 
00685         
00686         if (winfo->wlen[word] > 1 && wend->is_pseudo) {
00687           error_missing_right_triphone(wend, now->last_ph->name);
00688         }
00689         dwrk->phmmseq[phmmlen-2] = wend;
00690       } else {
00691         dwrk->phmmseq[phmmlen-2] = ret;
00692       }
00693       ret = get_left_context_HMM(now->last_ph, wend->name, hmminfo);
00694       if (ret == NULL) {
00695         
00696         
00697 
00698         if (now->last_ph->is_pseudo) {
00699           error_missing_left_triphone(now->last_ph, wend->name);
00700         }
00701         dwrk->phmmseq[phmmlen-1] = now->last_ph;
00702       } else {
00703         dwrk->phmmseq[phmmlen-1] = ret;
00704       }
00705 
00706       if (enable_iwsp && hmminfo->multipath) {
00707         dwrk->has_sp[phmmlen-2] = TRUE;
00708         dwrk->has_sp[phmmlen-1] = now->last_ph_sp_attached;
00709       }
00710  
00711 #ifdef TCD
00712       jlog("DEBUG: w=");
00713       for(i=0;i<winfo->wlen[word];i++) {
00714         jlog(" %s",(winfo->wseq[word][i])->name);
00715         if (enable_iwsp && hmminfo->multipath && dwrk->has_sp[i]) jlog("(sp)");
00716       }
00717       jlog(" | %s\n", (now->last_ph)->name);
00718       if (hmminfo->multipath && now->last_ph_sp_attached) jlog("DEBUG:   (sp)\n");
00719       jlog("DEBUG: scan for:");
00720       
00721       for (i=0;i<phmmlen;i++) {
00722         jlog(" %s", dwrk->phmmseq[i]->name);
00723         if (enable_iwsp && hmminfo->multipath && dwrk->has_sp[i]) jlog("(sp)");
00724       }
00725       jlog("\n");
00726 #endif
00727 
00728       
00729       
00730       whmm = new_make_word_hmm(hmminfo, dwrk->phmmseq, phmmlen, (enable_iwsp && hmminfo->multipath) ? dwrk->has_sp : NULL);
00731       if (whmm == NULL) {
00732         j_internal_error("Error: failed to make word hmm for word #%d \"%s [%s]\"\n", word, winfo->wname[word], winfo->woutput[word]);
00733       }
00734       
00735       
00736       
00737 
00738       for (t=0;t<peseqlen;t++) {
00739         dwrk->g[t]=now->g_prev[t];
00740 
00741       }
00742       
00743       
00744       
00745 
00746       if (hmminfo->multipath) {
00747         store_point = hmm_logical_state_num(dwrk->phmmseq[0]) - 2;
00748         store_point_maxarc = max_out_arc(dwrk->phmmseq[0]);
00749         if (enable_iwsp && dwrk->has_sp[0]) {
00750           store_point += hmm_logical_state_num(hmminfo->sp) - 2;
00751           if (store_point_maxarc < max_out_arc(hmminfo->sp)) {
00752             store_point_maxarc = max_out_arc(hmminfo->sp);
00753           }
00754         }
00755       } else {
00756         store_point = hmm_logical_state_num(dwrk->phmmseq[0]) - 2 - 1;
00757       }
00758       
00759       
00760       if (hmminfo->multipath) {
00761         crossword_point = whmm->len - hmm_logical_state_num(dwrk->phmmseq[phmmlen-1]);
00762         if (enable_iwsp && dwrk->has_sp[phmmlen-1]) {
00763           crossword_point -= hmm_logical_state_num(hmminfo->sp) - 2;
00764         }
00765       } else {
00766         crossword_point = whmm->len - (hmm_logical_state_num(dwrk->phmmseq[phmmlen-1]) - 2) - 1;
00767       }
00768       
00769     } else {                    
00770       
00771       
00772       
00773 #ifdef TCD
00774       jlog("DEBUG: scan(org):");
00775       for (i=0;i<winfo->wlen[word];i++) {
00776         jlog(" %s", (winfo->wseq[word][i])->name);
00777       }
00778       jlog("\n");
00779 #endif
00780 
00781       if (enable_iwsp && hmminfo->multipath) {
00782         
00783         for(i=0;i<winfo->wlen[word];i++) {
00784           dwrk->has_sp[i] = FALSE;
00785         }
00786         dwrk->has_sp[winfo->wlen[word]-1] = TRUE;
00787       }
00788       
00789       
00790       
00791       whmm = new_make_word_hmm(hmminfo, winfo->wseq[word], winfo->wlen[word], (enable_iwsp && hmminfo->multipath) ? dwrk->has_sp : NULL);
00792       if (whmm == NULL) {
00793         j_internal_error("Error: failed to make word hmm for word #%d \"%s [%s]\"\n", word, winfo->wname[word], winfo->woutput[word]);
00794       }
00795       
00796       
00797       
00798       for (t=0;t<peseqlen;t++) {
00799         dwrk->g[t]=now->g[t];
00800       }
00801       
00802       
00803       
00804 
00805       if (hmminfo->multipath) {
00806         store_point = hmm_logical_state_num(winfo->wseq[word][0]) - 2;
00807         store_point_maxarc = max_out_arc(winfo->wseq[word][0]);
00808         if (enable_iwsp && dwrk->has_sp[0]) {
00809           store_point += hmm_logical_state_num(hmminfo->sp) - 2;
00810           if (store_point_maxarc < max_out_arc(hmminfo->sp)) {
00811             store_point_maxarc = max_out_arc(hmminfo->sp);
00812           }
00813         }
00814       } else {
00815         store_point = hmm_logical_state_num(winfo->wseq[word][0]) - 2 - 1;
00816       }
00817 
00818       
00819       
00820       crossword_point = -1;
00821     }
00822     
00823   } else {                      
00824 
00825     if (enable_iwsp && hmminfo->multipath) {
00826       
00827       for(i=0;i<winfo->wlen[word];i++) {
00828         dwrk->has_sp[i] = FALSE;
00829       }
00830       dwrk->has_sp[winfo->wlen[word]-1] = TRUE;
00831     }
00832 
00833     
00834     
00835     whmm = new_make_word_hmm(hmminfo, winfo->wseq[word], winfo->wlen[word], (enable_iwsp && hmminfo->multipath) ? dwrk->has_sp : NULL);
00836     if (whmm == NULL) {
00837       j_internal_error("Error: failed to make word hmm for word #%d \"%s [%s]\"\n", word, winfo->wname[word], winfo->woutput[word]);
00838     }
00839 
00840     
00841     
00842     for (t=0;t<peseqlen;t++) {
00843       dwrk->g[t]=now->g[t];
00844     }
00845     
00846   }
00847 
00848 #ifdef TCD
00849   jlog("DEBUG: whmm len   = %d\n",whmm->len);
00850   jlog("DEBUG: crossword_point = %d\n", crossword_point);
00851   jlog("DEBUG: g[] store point = %d\n", store_point);
00852 #endif
00853 
00854   wordhmmnum = whmm->len;
00855   if (wordhmmnum >= winfo->maxwn + 10) {
00856     j_internal_error("scan_word: word too long (>%d)\n", winfo->maxwn + 10);
00857   }
00858 
00859 #ifndef GRAPHOUT_PRECISE_BOUNDARY
00860   if (r->graphout) {
00861     if (ccd_flag) {
00862       now->tail_g_score = now->g[now->bestt];
00863     }
00864   }
00865 #endif
00866 
00867   
00868   
00869   
00870   
00871   for(t = peseqlen-1; t >=0 ; t--) {
00872     if (
00873 #ifdef SCAN_BEAM
00874         dwrk->g[t] > framemaxscore[t] - scan_beam_thres &&
00875 #endif
00876         dwrk->g[t] > LOG_ZERO) {
00877       break;
00878     }
00879   }
00880   if (t < 0) {                  
00881     for(t=0;t<peseqlen;t++) {
00882       if (ccd_flag) now->g_prev[t] = LOG_ZERO;
00883       now->g[t] = LOG_ZERO;
00884     }
00885 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00886     if (r->graphout) {
00887       for(t=0;t<peseqlen;t++) {
00888         now->wordend_frame[t] = -1;
00889         now->wordend_gscore[t] = LOG_ZERO;
00890       }
00891     }
00892 #endif
00893     goto end_of_scan;
00894   }
00895   startt = t;
00896   
00897   
00898   for(t=peseqlen-1;t>startt;t--) {
00899     if (ccd_flag) now->g_prev[t] = LOG_ZERO;
00900     now->g[t] = LOG_ZERO;
00901 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00902     if (r->graphout) {
00903       now->wordend_frame[t] = -1;
00904       now->wordend_gscore[t] = LOG_ZERO;
00905     }
00906 #endif
00907   }
00908 
00909   
00910   tn = 0; tl = 1;
00911 
00912 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00913   if (r->graphout) {
00914     for(i=0;i<wordhmmnum;i++) {
00915       dwrk->wend_token_frame[tn][i] = -1;
00916       dwrk->wend_token_gscore[tn][i] = LOG_ZERO;
00917     }
00918   }
00919 #endif
00920   
00921   if (! hmminfo->multipath) {
00922     
00923 
00924     
00925     
00926     
00927     for(i=0;i<wordhmmnum-1;i++) dwrk->wordtrellis[tn][i] = LOG_ZERO;
00928     dwrk->wordtrellis[tn][wordhmmnum-1] = dwrk->g[startt] + outprob(&(r->am->hmmwrk), startt, &(whmm->state[wordhmmnum-1]), param);
00929     if (ccd_flag) {
00930       now->g_prev[startt] = dwrk->wordtrellis[tn][store_point];
00931     }
00932     now->g[startt] = dwrk->wordtrellis[tn][0];
00933     
00934 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00935     if (r->graphout) {
00936       if (ccd_flag) {
00937         if (back_rescan) {
00938           if (wordhmmnum-1 == crossword_point) {
00939             dwrk->wend_token_frame[tn][wordhmmnum-1] = startt;
00940             dwrk->wend_token_gscore[tn][wordhmmnum-1] = dwrk->g[startt];
00941           } else {
00942             dwrk->wend_token_frame[tn][wordhmmnum-1] = -1;
00943             dwrk->wend_token_gscore[tn][wordhmmnum-1] = LOG_ZERO;
00944           }
00945         } else {
00946           dwrk->wend_token_frame[tn][wordhmmnum-1] = startt;
00947           dwrk->wend_token_gscore[tn][wordhmmnum-1] = dwrk->g[startt];
00948         }
00949       } else {
00950         dwrk->wend_token_frame[tn][wordhmmnum-1] = startt;
00951         dwrk->wend_token_gscore[tn][wordhmmnum-1] = dwrk->g[startt];
00952       }
00953       now->wordend_frame[startt] = dwrk->wend_token_frame[tn][0];
00954       now->wordend_gscore[startt] = dwrk->wend_token_gscore[tn][0];
00955     }
00956 #endif
00957   } 
00958   
00959   endt = startt;
00960 
00961   
00962   
00963   for(t = hmminfo->multipath ? startt : startt - 1; t >= 0; t--) {
00964     
00965     
00966     i = tn; tn = tl; tl = i;
00967     
00968     node_exist_p = FALSE;       
00969 
00970     if (hmminfo->multipath) {
00971 
00972       
00973       
00974 
00975       
00976       
00977       tmpmax_store = LOG_ZERO;
00978 
00979     } else {
00980     
00981       
00982       
00983       tmptmp = LOG_ZERO;
00984       for (ac=whmm->state[wordhmmnum-1].ac;ac;ac=ac->next) {
00985         score1 = dwrk->wordtrellis[tl][ac->arc] + ac->a;
00986         if (tmptmp < score1) {
00987           j = ac->arc;
00988           tmptmp = score1;
00989         }
00990       }
00991       if (dwrk->g[t] > tmptmp) {
00992         tmpmax = dwrk->g[t];
00993 #ifdef GRAPHOUT_PRECISE_BOUNDARY
00994         if (r->graphout) {
00995           if (!back_rescan || wordhmmnum-1 == crossword_point) {
00996             dwrk->wend_token_frame[tn][wordhmmnum-1] = t;
00997             dwrk->wend_token_gscore[tn][wordhmmnum-1] = dwrk->g[t];
00998           } else {
00999             dwrk->wend_token_frame[tn][wordhmmnum-1] = dwrk->wend_token_frame[tl][j];
01000             dwrk->wend_token_gscore[tn][wordhmmnum-1] = dwrk->wend_token_gscore[tl][j];
01001           }
01002         }
01003 #endif
01004       } else {
01005         tmpmax = tmptmp;
01006 #ifdef GRAPHOUT_PRECISE_BOUNDARY
01007         if (r->graphout) {
01008           dwrk->wend_token_frame[tn][wordhmmnum-1] = dwrk->wend_token_frame[tl][j];
01009           dwrk->wend_token_gscore[tn][wordhmmnum-1] = dwrk->wend_token_gscore[tl][j];
01010         }
01011 #endif
01012       }
01013 
01014       
01015       
01016       if (
01017 #ifdef SCAN_BEAM
01018           tmpmax <= framemaxscore[t] - scan_beam_thres ||
01019 #endif
01020           tmpmax <= LOG_ZERO
01021           ) {
01022         dwrk->wordtrellis[tn][wordhmmnum-1] = LOG_ZERO;
01023 #ifdef GRAPHOUT_PRECISE_BOUNDARY
01024         if (r->graphout) {
01025           dwrk->wend_token_frame[tn][wordhmmnum-1] = -1;
01026           dwrk->wend_token_gscore[tn][wordhmmnum-1] = LOG_ZERO;
01027         }
01028 #endif
01029       } else {
01030         node_exist_p = TRUE;
01031         dwrk->wordtrellis[tn][wordhmmnum-1] = tmpmax + outprob(&(r->am->hmmwrk), t, &(whmm->state[wordhmmnum-1]), param);
01032       }
01033 
01034     } 
01035 
01036     
01037     
01038     for(i=wordhmmnum-2;i>=0;i--) {
01039 
01040       if (ccd_flag) {
01041 
01042         
01043         
01044         
01045         
01046         if (! hmminfo->multipath) {
01047           if (i == store_point) {
01048             tmpmax2 = LOG_ZERO;
01049           }
01050         }
01051         tmpmax = LOG_ZERO;
01052         for (ac=whmm->state[i].ac;ac;ac=ac->next) {
01053           if (hmminfo->multipath) {
01054             if (ac->arc == wordhmmnum-1) score1 = dwrk->g[t];
01055             else if (t + 1 > startt) score1 = LOG_ZERO;
01056             else score1 = dwrk->wordtrellis[tl][ac->arc];
01057             score1 += ac->a;
01058           } else {
01059             score1 = dwrk->wordtrellis[tl][ac->arc] + ac->a;
01060           }
01061           if (i <= crossword_point && ac->arc > crossword_point) {
01062             
01063             
01064             score1 += now->lscore; 
01065           }
01066 
01067           if (hmminfo->multipath) {
01068             if (i <= store_point && ac->arc > store_point) {
01069               if (tmpmax_store < score1) tmpmax_store = score1;
01070             }
01071           } else {
01072             if (i == store_point && i != ac->arc) {
01073               if (tmpmax2 < score1) tmpmax2 = score1;
01074             }
01075           }
01076 
01077           if (tmpmax < score1) {
01078             tmpmax = score1;
01079             j = ac->arc;
01080           }
01081         }
01082 
01083         
01084         
01085         if (
01086 #ifdef SCAN_BEAM
01087             tmpmax <= framemaxscore[t] - scan_beam_thres ||
01088 #endif
01089             tmpmax <= LOG_ZERO
01090             ) {  
01091           dwrk->wordtrellis[tn][i] = LOG_ZERO;
01092 #ifdef GRAPHOUT_PRECISE_BOUNDARY
01093           if (r->graphout) {
01094             dwrk->wend_token_frame[tn][i] = -1;
01095             dwrk->wend_token_gscore[tn][i] = LOG_ZERO;
01096           }
01097 #endif
01098           if (! hmminfo->multipath) {
01099             if (i == store_point) now->g_prev[t] = LOG_ZERO;
01100           }
01101         } else { 
01102           if (! hmminfo->multipath) {
01103             if (i == store_point) now->g_prev[t] = tmpmax2;
01104           }
01105 #ifdef GRAPHOUT_PRECISE_BOUNDARY
01106           if (r->graphout) {
01107 
01108             if (hmminfo->multipath) {
01109               if ((back_rescan && i <= crossword_point && j > crossword_point)
01110                   || j == wordhmmnum-1) {
01111                 dwrk->wend_token_frame[tn][i] = t;
01112                 dwrk->wend_token_gscore[tn][i] = tmpmax;
01113               } else {
01114                 dwrk->wend_token_frame[tn][i] = dwrk->wend_token_frame[tl][j];
01115                 dwrk->wend_token_gscore[tn][i] = dwrk->wend_token_gscore[tl][j];
01116               }
01117             } else {
01118               if (i <= crossword_point && j > crossword_point) {
01119                 dwrk->wend_token_frame[tn][i] = t;
01120                 dwrk->wend_token_gscore[tn][i] = tmpmax;
01121               } else {
01122                 dwrk->wend_token_frame[tn][i] = dwrk->wend_token_frame[tl][j];
01123                 dwrk->wend_token_gscore[tn][i] = dwrk->wend_token_gscore[tl][j];
01124               }
01125             }
01126           }
01127 #endif
01128           node_exist_p = TRUE;  
01129 
01130           dwrk->wordtrellis[tn][i] = tmpmax;
01131           if (! hmminfo->multipath || i > 0) {
01132             
01133             dwrk->wordtrellis[tn][i] += outprob(&(r->am->hmmwrk), t, &(whmm->state[i]), param);
01134           }
01135         }
01136         
01137       } else {                  
01138 
01139         
01140         
01141         tmpmax = LOG_ZERO;
01142         if (hmminfo->multipath) {
01143           for (ac=whmm->state[i].ac;ac;ac=ac->next) {
01144             if (ac->arc == wordhmmnum-1) score1 = dwrk->g[t];
01145             else if (t + 1 > startt) score1 = LOG_ZERO;
01146             else score1 = dwrk->wordtrellis[tl][ac->arc];
01147             score1 += ac->a;
01148             if (tmpmax < score1) {
01149               tmpmax = score1;
01150               j = ac->arc;
01151             }
01152           }
01153         } else {
01154           for (ac=whmm->state[i].ac;ac;ac=ac->next) {
01155             score1 = dwrk->wordtrellis[tl][ac->arc] + ac->a;
01156             if (tmpmax < score1) {
01157               tmpmax = score1;
01158               j = ac->arc;
01159             }
01160           }
01161         }
01162 
01163         
01164         
01165         if (
01166 #ifdef SCAN_BEAM
01167             tmpmax <= framemaxscore[t] - scan_beam_thres ||
01168 #endif
01169             tmpmax <= LOG_ZERO
01170             ) {
01171           
01172           dwrk->wordtrellis[tn][i] = LOG_ZERO;
01173 #ifdef GRAPHOUT_PRECISE_BOUNDARY
01174           if (r->graphout) {
01175             dwrk->wend_token_frame[tn][i] = -1;
01176             dwrk->wend_token_gscore[tn][i] = LOG_ZERO;
01177           }
01178 #endif
01179         } else {
01180           
01181           node_exist_p = TRUE;
01182 #ifdef GRAPHOUT_PRECISE_BOUNDARY
01183           if (r->graphout) {
01184             if (hmminfo->multipath) {
01185               if (j == wordhmmnum-1) {
01186                 dwrk->wend_token_frame[tn][i] = t;
01187                 dwrk->wend_token_gscore[tn][i] = tmpmax;
01188               } else {
01189                 dwrk->wend_token_frame[tn][i] = dwrk->wend_token_frame[tl][j];
01190                 dwrk->wend_token_gscore[tn][i] = dwrk->wend_token_gscore[tl][j];
01191               }
01192             } else {
01193               dwrk->wend_token_frame[tn][i] = dwrk->wend_token_frame[tl][j];
01194               dwrk->wend_token_gscore[tn][i] = dwrk->wend_token_gscore[tl][j];
01195             }
01196           }
01197 #endif
01198           
01199           dwrk->wordtrellis[tn][i] = tmpmax;
01200           if (! hmminfo->multipath || i > 0) {
01201             dwrk->wordtrellis[tn][i] += outprob(&(r->am->hmmwrk), t, &(whmm->state[i]), param);
01202           }
01203         }
01204         
01205       }
01206     } 
01207 
01208     
01209     
01210 
01211     now->g[t] = dwrk->wordtrellis[tn][0];
01212 #ifdef GRAPHOUT_PRECISE_BOUNDARY
01213     if (r->graphout) {
01214       now->wordend_frame[t] = dwrk->wend_token_frame[tn][0];
01215       now->wordend_gscore[t] = dwrk->wend_token_gscore[tn][0];
01216     }
01217 #endif
01218 
01219     if (hmminfo->multipath) {
01220       
01221       
01222       if (ccd_flag) {
01223          
01224         tmpmax_store -= store_point_maxarc;
01225         if (tmpmax_store < LOG_ZERO) tmpmax_store = LOG_ZERO;
01226         now->g_prev[t] = tmpmax_store;
01227       }
01228     }
01229 
01230     
01231     if (node_exist_p) endt = t;
01232     
01233     
01234 
01235 
01236 
01237     
01238 
01239 
01240 
01241     if (t < now->estimated_next_t && (!node_exist_p)) {
01242       
01243       for (i=t-1;i>=0;i--) {
01244         now->g[i] = LOG_ZERO;
01245 #ifdef GRAPHOUT_PRECISE_BOUNDARY
01246         if (r->graphout) {
01247           now->wordend_frame[i] = -1;
01248           now->wordend_gscore[i] = LOG_ZERO;
01249         }
01250 #endif
01251         if (ccd_flag) now->g_prev[i] = LOG_ZERO;
01252       }
01253       
01254       break;
01255     }
01256     
01257   } 
01258   
01259   if (debug2_flag) jlog("DEBUG: scanned: [%3d-%3d]\n", endt, startt);
01260 
01261  end_of_scan:
01262 
01263   if (hmminfo->multipath) {
01264     
01265     
01266     if (endt == 0) {
01267       tmpmax = LOG_ZERO;
01268       for(ac=whmm->state[0].ac;ac;ac=ac->next) {
01269         score1 = dwrk->wordtrellis[tn][ac->arc] + ac->a;
01270         if (tmpmax < score1) tmpmax = score1;
01271       }
01272       now->final_g = score1;
01273     } else {
01274       now->final_g = LOG_ZERO;
01275     }
01276   }
01277   
01278   
01279   
01280   if (ccd_flag) {
01281     if (store_point == (hmminfo->multipath ? wordhmmnum - 2 : wordhmmnum - 1)) {
01282       
01283 
01284 
01285       
01286 
01287 
01288 
01289       for (t = startt; t>=0; t--) {
01290         now->g_prev[t] = dwrk->g[t];
01291       }
01292     }
01293 #ifndef GRAPHOUT_PRECISE_BOUNDARY
01294     if (r->graphout) {
01295       if (now->tail_g_score != LOG_ZERO) {
01296         if (now->prevgraph != NULL) {
01297           (now->prevgraph)->leftscore = now->tail_g_score;
01298         }
01299       }
01300     }
01301 #endif
01302     
01303     
01304     if (back_rescan) {
01305       now->last_ph = dwrk->phmmseq[0];
01306     } else {
01307       now->last_ph = winfo->wseq[word][0];
01308     }
01309     if (enable_iwsp && hmminfo->multipath) {
01310       now->last_ph_sp_attached = dwrk->has_sp[0];
01311     }
01312   }
01313 
01314 #ifdef GRAPHOUT_PRECISE_BOUNDARY
01315   if (! hmminfo->multipath) {
01316     if (r->graphout) {
01317       
01318       
01319       now->wordend_frame[peseqlen-1] = now->wordend_frame[0];
01320       now->wordend_gscore[peseqlen-1] = now->wordend_gscore[0];
01321       for (t=0;t<peseqlen-1;t++) {
01322         now->wordend_frame[t] = now->wordend_frame[t+1];
01323         now->wordend_gscore[t] = now->wordend_gscore[t+1];
01324       }
01325     }
01326   }
01327 #endif
01328 
01329   
01330   free_hmm(whmm);
01331 #ifdef TCD
01332   if (hmminfo->multipath) {
01333     if (ccd_flag) {
01334       jlog("DEBUG: last_ph = %s", (now->last_ph)->name);
01335       if (now->last_ph_sp_attached) jlog(" (sp attached)");
01336       jlog("\n");
01337     }
01338   } else {
01339     jlog("DEBUG: last_ph = %s\n", (now->last_ph)->name);
01340   }
01341 #endif
01342 }
01343 
01344 
01345 
01346 
01347 
01348 
01349 
01377 void
01378 next_word(NODE *now, NODE *new, NEXTWORD *nword, HTK_Param *param, RecogProcess *r)
01379 {
01380   int   t;
01381   HMM_Logical *newphone;
01382   int lastword;
01383   int   i;
01384   LOGPROB tmpp;
01385   LOGPROB a_value;
01386   int   startt;
01387   int word;
01388   LOGPROB totalscore;
01389   TRELLIS_ATOM *tre;
01390 
01391   BACKTRELLIS *backtrellis;
01392   WORD_INFO *winfo;
01393   HTK_HMM_INFO *hmminfo;
01394   int peseqlen;
01395   boolean ccd_flag;
01396 
01397   backtrellis = r->backtrellis;
01398   winfo = r->lm->winfo;
01399   hmminfo = r->am->hmminfo;
01400   peseqlen = r->peseqlen;
01401   ccd_flag = r->ccd_flag;
01402 
01403   new->score = LOG_ZERO;
01404 
01405   word = nword->id;
01406   lastword=now->seq[now->seqnum-1];
01407 
01408   
01409   
01410   for (i=0;i< now->seqnum;i++){ 
01411     new->seq[i] = now->seq[i];
01412 #ifdef CM_SEARCH
01413 #ifdef CM_MULTIPLE_ALPHA
01414     memcpy(new->cmscore[i], now->cmscore[i], sizeof(LOGPROB) * r->config->annotate.cm_alpha_num);
01415 #else
01416     new->cmscore[i] = now->cmscore[i];
01417 #endif
01418 #endif 
01419   }
01420   new->seq[i] = word;
01421   new->seqnum = now->seqnum+1;
01422   new->state = nword->next_state;
01423   new->totallscore = now->totallscore + nword->lscore;
01424   if (hmminfo->multipath) new->final_g = now->final_g;
01425   
01426   if (ccd_flag) {
01427     
01428     
01429 
01430     
01431 
01432     newphone = get_right_context_HMM(winfo->wseq[word][winfo->wlen[word]-1], now->last_ph->name, hmminfo);
01433     if (newphone == NULL) {     
01434       
01435       
01436 
01437       
01438       if (winfo->wlen[word] > 1 && winfo->wseq[word][winfo->wlen[word]-1]->is_pseudo){
01439         error_missing_right_triphone(winfo->wseq[word][winfo->wlen[word]-1], now->last_ph->name);
01440       }
01441       newphone = winfo->wseq[word][winfo->wlen[word]-1];
01442     }
01443     
01444     
01445     
01446     new->last_ph = now->last_ph;
01447     if (hmminfo->multipath) {
01448       new->last_ph_sp_attached = now->last_ph_sp_attached;
01449     }
01450     
01451     
01452     
01453     for (t=0;t<peseqlen;t++) {
01454       new->g_prev[t] = now->g_prev[t];
01455     }
01456     
01457   } else {                      
01458     
01459     
01460     
01461     newphone = winfo->wseq[word][winfo->wlen[word]-1];
01462   }
01463 
01464 
01465   if (r->lmtype == LM_PROB) {
01466     new->lscore = nword->lscore;
01467   } else if (r->lmtype == LM_DFA) {
01468     new->lscore = 0.0;
01469   }
01470 
01471   if (! hmminfo->multipath) {
01472     
01473     
01474     i = hmm_logical_state_num(newphone);
01475     a_value = (hmm_logical_trans(newphone))->a[i-2][i-1];
01476   }
01477 
01478   
01479   
01480   
01481   
01482 
01483   if (hmminfo->multipath) {
01484     startt = peseqlen-1;
01485   } else {
01486     startt = peseqlen-2;
01487     new->g[startt+1] = LOG_ZERO;
01488   }
01489 
01490   
01491   
01492   
01493 
01494   
01495 
01496   
01497   if (hmminfo->multipath) {
01498     for(t=startt;t>=0;t--) {
01499       new->g[t] = now->g[t] + nword->lscore;
01500     }
01501   } else {
01502     for(t=startt;t>=0;t--) {
01503       new->g[t] = now->g[t+1] + a_value + nword->lscore;
01504     }
01505   }
01506 
01507   new->tre = NULL;
01508 
01509   if (r->lmtype == LM_DFA && !r->config->pass2.looktrellis_flag) {
01510     
01511     
01512     for(t = startt; t >= 0; t--) {
01513       tre = bt_binsearch_atom(backtrellis, t, (WORD_ID) word);
01514       if (tre == NULL) continue;
01515       totalscore = new->g[t] + tre->backscore;
01516       if (! hmminfo->multipath) {
01517         if (newphone->is_pseudo) {
01518           tmpp = outprob_cd(&(r->am->hmmwrk), t, &(newphone->body.pseudo->stateset[newphone->body.pseudo->state_num-2]), param);
01519         } else {
01520           tmpp = outprob_state(&(r->am->hmmwrk), t, newphone->body.defined->s[newphone->body.defined->state_num-2], param);
01521         }
01522         totalscore += tmpp;
01523       }
01524       if (new->score < totalscore) {
01525         new->score = totalscore;
01526         new->bestt = t;
01527         new->estimated_next_t = tre->begintime - 1;
01528         new->tre  =  tre;
01529       }
01530     }
01531 
01532     return;
01533 
01534   }
01535       
01536   
01537 
01538   
01539   
01540   for(t = (nword->tre)->endtime; t >= 0; t--) {
01541     tre = bt_binsearch_atom(backtrellis, t, (WORD_ID) word);
01542     if (tre == NULL) break;     
01543     totalscore = new->g[t] + tre->backscore;
01544     if (! hmminfo->multipath) {
01545       if (newphone->is_pseudo) {
01546         tmpp = outprob_cd(&(r->am->hmmwrk), t, &(newphone->body.pseudo->stateset[newphone->body.pseudo->state_num-2]), param);
01547       } else {
01548         tmpp = outprob_state(&(r->am->hmmwrk), t, newphone->body.defined->s[newphone->body.defined->state_num-2], param);
01549       }
01550       totalscore += tmpp;
01551     }
01552     if (new->score < totalscore) {
01553       new->score = totalscore;
01554       new->bestt = t;
01555       new->estimated_next_t = tre->begintime - 1;
01556       new->tre = tre;
01557     }
01558   }
01559   
01560   for(t = (nword->tre)->endtime + 1; t <= startt; t++) {
01561     tre = bt_binsearch_atom(backtrellis, t, (WORD_ID) word);
01562     if (tre == NULL) break;     
01563     totalscore = new->g[t] + tre->backscore;
01564     if (! hmminfo->multipath) {
01565       if (newphone->is_pseudo) {
01566         tmpp = outprob_cd(&(r->am->hmmwrk), t, &(newphone->body.pseudo->stateset[newphone->body.pseudo->state_num-2]), param);
01567       } else {
01568         tmpp = outprob_state(&(r->am->hmmwrk), t, newphone->body.defined->s[newphone->body.defined->state_num-2], param);
01569       }
01570       totalscore += tmpp;
01571     }
01572     if (new->score < totalscore) {
01573       new->score = totalscore;
01574       new->bestt = t;
01575       new->estimated_next_t = tre->begintime - 1;
01576       new->tre = tre;
01577     }
01578   }
01579 
01580 }
01581 
01582 
01583 
01584 
01585 
01586 
01609 void
01610 start_word(NODE *new, NEXTWORD *nword, HTK_Param *param, RecogProcess *r)
01611 {
01612   HMM_Logical *newphone;
01613   WORD_ID word;
01614   LOGPROB tmpp;
01615   int t;
01616   TRELLIS_ATOM *tre = NULL;
01617 
01618   BACKTRELLIS *backtrellis;
01619   WORD_INFO *winfo;
01620   int peseqlen;
01621   boolean ccd_flag;
01622 
01623   backtrellis = r->backtrellis;
01624   winfo = r->lm->winfo;
01625   peseqlen = r->peseqlen;
01626   ccd_flag = r->ccd_flag;
01627 
01628   
01629   word = nword->id;
01630   new->score = LOG_ZERO;
01631   new->seqnum = 1;
01632   new->seq[0] = word;
01633 
01634   new->state = nword->next_state;
01635   new->totallscore = nword->lscore;
01636 
01637   
01638   newphone = winfo->wseq[word][winfo->wlen[word]-1];
01639   if (ccd_flag) {
01640     new->last_ph = NULL;
01641     new->last_ph_sp_attached = FALSE;
01642   }
01643   new->lscore = nword->lscore;
01644 
01645   if (r->lmtype == LM_PROB) {
01646     new->g[peseqlen-1] = nword->lscore;
01647   } else if (r->lmtype == LM_DFA) {
01648     new->g[peseqlen-1] = 0;
01649   }
01650   
01651   for (t=peseqlen-1; t>=0; t--) {
01652     tre = bt_binsearch_atom(backtrellis, t, word);
01653     if (tre != NULL) {
01654       if (r->graphout) {
01655         new->bestt = peseqlen-1;
01656       } else {
01657         new->bestt = t;
01658       }
01659       new->score = new->g[peseqlen-1] + tre->backscore;
01660       if (! r->am->hmminfo->multipath) {
01661         if (newphone->is_pseudo) {
01662           tmpp = outprob_cd(&(r->am->hmmwrk), peseqlen-1, &(newphone->body.pseudo->stateset[newphone->body.pseudo->state_num-2]), param);
01663         } else {
01664           tmpp = outprob_state(&(r->am->hmmwrk), peseqlen-1, newphone->body.defined->s[newphone->body.defined->state_num-2], param);
01665         }
01666         new->score += tmpp;
01667       }
01668       new->estimated_next_t = tre->begintime - 1;
01669       new->tre = tre;
01670       break;
01671     }
01672   }
01673   if (tre == NULL) {            
01674     new->score = LOG_ZERO;
01675   }
01676 
01677 }
01678 
01679 
01703 void
01704 last_next_word(NODE *now, NODE *new, HTK_Param *param, RecogProcess *r)
01705 {
01706   cpy_node(new, now);
01707   
01708   
01709   if (r->am->hmminfo->multipath) {
01710     new->score = now->final_g;
01711   } else {
01712     new->score = now->g[0];
01713   }
01714 }
01715 
01716 
01717 #endif 
01718 
01719