1 /*---------------------------------------------------------------------------* 2 * srec_results.c * 3 * * 4 * Copyright 2007, 2008 Nuance Communciations, Inc. * 5 * * 6 * Licensed under the Apache License, Version 2.0 (the 'License'); * 7 * you may not use this file except in compliance with the License. * 8 * * 9 * You may obtain a copy of the License at * 10 * http://www.apache.org/licenses/LICENSE-2.0 * 11 * * 12 * Unless required by applicable law or agreed to in writing, software * 13 * distributed under the License is distributed on an 'AS IS' BASIS, * 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 15 * See the License for the specific language governing permissions and * 16 * limitations under the License. * 17 * * 18 *---------------------------------------------------------------------------*/ 19 20 #include"passert.h" 21 22 #include"portable.h" 23 #include"srec.h" 24 #include"search_network.h" 25 #include"srec_stats.h" 26 #if USE_COMP_STATS 27 #include"comp_stats.h" 28 #endif 29 #include"srec_results.h" 30 31 static srec* WHICH_RECOG(multi_srec* recm) 32 { 33 srec* return_rec = NULL; 34 costdata current_best_cost = MAXcostdata; 35 int i = 0; 36 #if DO_ALLOW_MULTIPLE_MODELS 37 for (i = 0; i < recm->num_activated_recs; i++) 38 { 39 #endif 40 if (current_best_cost > recm->rec[i].current_best_cost) 41 { 42 current_best_cost = recm->rec[i].current_best_cost; 43 return_rec = &recm->rec[i]; 44 } 45 #if DO_ALLOW_MULTIPLE_MODELS 46 } 47 #endif 48 return return_rec; 49 } 50 51 int srec_get_bestcost_recog_id(multi_srec* recm, int* id) 52 { 53 srec* rec = WHICH_RECOG(recm); 54 if (!rec) *id = -1; 55 else *id = rec->id; 56 return 0; 57 } 58 59 void srec_result_strip_slot_markers(char* result) 60 { 61 if (!result) return; 62 else 63 { 64 char *p = result, *q = p; 65 for (; (*q = *p); q++, p++) 66 { 67 if (p[0] == IMPORTED_RULES_DELIM && (p[2] == ' ' || p[2] == '\0')) 68 { 69 p += 2; 70 *q = *p; 71 } 72 } 73 } 74 } 75 76 int srec_has_results(multi_srec* recm) 77 { 78 srec* rec = WHICH_RECOG(recm); 79 frameID end_frame; 80 if (!rec) 81 return 0; 82 end_frame = rec->current_search_frame; 83 if (!rec->srec_ended) 84 return 0; 85 if (rec->word_lattice->words_for_frame[end_frame] != MAXwtokenID) 86 return 1; 87 if (rec->astar_stack->num_complete_paths) 88 return 1; 89 return 0; 90 } 91 92 int srec_clear_results(multi_srec* recm) 93 { 94 srec* rec = WHICH_RECOG(recm); 95 frameID ifr; 96 SREC_STATS_SHOW(); 97 SREC_STATS_CLEAR(); 98 99 if (!rec) 100 return 1; 101 astar_stack_clear(rec->astar_stack); 102 for (ifr = 0; ifr <= rec->current_search_frame; ifr++) 103 rec->word_lattice->words_for_frame[ifr] = MAXwtokenID; 104 105 return 0; 106 } 107 108 void* srec_nbest_prepare_list(multi_srec* recm, int n, asr_int32_t* bestcost) 109 { 110 int rc; 111 srec* rec = WHICH_RECOG(recm); 112 AstarStack* stack = rec ? rec->astar_stack : 0; 113 114 if (!stack) 115 return NULL; 116 #if USE_COMP_STATS 117 start_cs_clock1(&comp_stats->astar); 118 #endif 119 rc = astar_stack_prepare(stack, n, rec); 120 if (rc) 121 { 122 *bestcost = MAXbcostdata; 123 return (void*)rec; 124 } 125 astar_stack_do_backwards_search(rec, n); 126 #if USE_COMP_STATS 127 end_cs_clock1(&comp_stats->astar, 1); 128 #endif 129 if (stack->num_complete_paths) 130 { 131 *bestcost = stack->complete_paths[0]->costsofar; 132 } 133 else 134 { 135 *bestcost = MAXbcostdata; 136 } 137 138 return (void*)(rec); 139 } 140 141 void srec_nbest_destroy_list(void* rec_void) 142 { 143 srec* rec = (srec*)rec_void; 144 AstarStack* stack = rec ? rec->astar_stack : 0; 145 astar_stack_clear(stack); 146 } 147 148 int srec_nbest_get_num_choices(void* rec_void) 149 { 150 srec* rec = (srec*)rec_void; 151 AstarStack* stack = rec ? rec->astar_stack : 0; 152 return stack ? stack->num_complete_paths : 0; 153 } 154 155 int srec_nbest_put_confidence_value(void* rec_void, int choice, int confidence_value) 156 { 157 srec* rec = (srec*)rec_void; 158 AstarStack* stack = rec ? rec->astar_stack : 0; 159 if (!stack) 160 { 161 return 1; 162 } 163 else 164 { 165 stack->complete_path_confidences[choice] = confidence_value; 166 return 0; 167 } 168 } 169 170 int srec_nbest_get_confidence_value(void* rec_void, int choice) 171 { 172 srec* rec = (srec*)rec_void; 173 AstarStack* stack = rec ? rec->astar_stack : 0; 174 return stack->complete_path_confidences[choice]; 175 } 176 177 int srec_nbest_fix_homonym_confidence_values(void* rec_void) 178 { 179 int i, num_fixed = 0; 180 srec* rec = (srec*)rec_void; 181 AstarStack* stack = rec ? rec->astar_stack : 0; 182 if (!stack) 183 return num_fixed; 184 for(i=1; i<stack->num_complete_paths; i++) { 185 partial_path* parp = stack->complete_paths[i]; 186 for (; parp; parp = parp->next) { 187 word_token* wtoken = &rec->word_token_array[ parp->token_index]; 188 if(WORD_TOKEN_GET_HOMONYM( wtoken)) { 189 stack->complete_path_confidences[i] = stack->complete_path_confidences[i-1]; 190 num_fixed++; 191 break; 192 } 193 } 194 } 195 return num_fixed; 196 } 197 198 LCHAR* srec_nbest_get_word(void* nbest, size_t choice) 199 { 200 srec* rec = (srec*)nbest; 201 return rec->context->olabels->words[choice]; 202 } 203 204 int srec_nbest_remove_result(void* rec_void, int n) 205 { 206 int i; 207 srec* rec = (srec*)rec_void; 208 AstarStack* stack = rec ? rec->astar_stack : 0; 209 210 211 if (!stack || n < 0 || n >= stack->num_complete_paths) 212 { 213 return 0; /* out of range error */ 214 } 215 216 /* free the partial_path which represents the entry */ 217 free_partial_path(stack, stack->complete_paths[n]); 218 219 /* now I need to move everybody up one so I do not have a hole 220 in the middle of my nbest list */ 221 for (i = n + 1 ; i < stack->num_complete_paths; i++) 222 stack->complete_paths[i-1] = stack->complete_paths[i]; 223 stack->complete_paths[i-1] = 0; /* empty the last one */ 224 225 /* finally change the size of my nbest list */ 226 stack->num_complete_paths--; 227 228 return 1; 229 } 230 231 ESR_ReturnCode srec_nbest_get_resultWordIDs(void* rec_void, size_t index, wordID* wordIDs, size_t* len, asr_int32_t* cost) 232 { 233 const srec* rec = (srec*) rec_void; 234 AstarStack* stack = rec ? rec->astar_stack : 0; 235 partial_path* parp; 236 wordID id; 237 size_t currentLen = 0; 238 239 if (!stack || index >= (size_t) stack->num_complete_paths) 240 { 241 if (wordIDs) *wordIDs = MAXwordID; 242 if (len) *len = 0; 243 *cost = MAXbcostdata; 244 return ESR_ARGUMENT_OUT_OF_BOUNDS; /* out of range error */ 245 } 246 247 parp = stack->complete_paths[index]; 248 *cost = stack->complete_paths[index]->costsofar; 249 if (len == NULL || wordIDs == NULL) 250 return ESR_SUCCESS; 251 if (parp && parp->word == rec->context->beg_silence_word) 252 parp = parp->next; 253 while (parp) 254 { 255 id = parp->word; 256 if (id == rec->context->end_silence_word) 257 break; 258 259 if (currentLen >= *len) 260 { 261 *wordIDs = MAXwordID; 262 *len = currentLen + 1; 263 return ESR_BUFFER_OVERFLOW; /* too little space error */ 264 } 265 *wordIDs = id; 266 ++wordIDs; 267 ++currentLen; 268 parp = parp->next; 269 } 270 --currentLen; 271 272 if (currentLen >= *len) 273 { 274 *wordIDs = MAXwordID; 275 *len = currentLen + 1; 276 return ESR_BUFFER_OVERFLOW; /* too little space error */ 277 } 278 *wordIDs = MAXwordID; 279 *len = currentLen + 1; 280 return ESR_SUCCESS; 281 } 282 283 int srec_nbest_get_result(void* rec_void, int n, char* label, int label_len, asr_int32_t* cost, int whether_strip_slot_markers) 284 { 285 const srec* rec = (srec*)rec_void; 286 AstarStack* stack = rec ? rec->astar_stack : 0; 287 partial_path* parp; 288 word_token* wtoken; 289 int return_len; 290 291 if (!stack || n < 0 || n >= stack->num_complete_paths) 292 { 293 *label = 0; 294 *cost = MAXbcostdata; 295 return 1; /* out of range error */ 296 } 297 298 return_len = 0; 299 parp = stack->complete_paths[n]; 300 *cost = stack->complete_paths[n]->costsofar; 301 for (; parp; parp = parp->next) 302 { 303 const char *p; 304 int lenp; 305 wtoken = &rec->word_token_array[ parp->token_index]; 306 p = "NULL"; 307 if (rec->context->olabels->words[wtoken->word]) 308 p = rec->context->olabels->words[wtoken->word]; 309 if (!strcmp(p, "-pau2-")) 310 break; 311 312 lenp = (char)strlen(p); 313 if (return_len + lenp >= label_len) 314 { 315 *label = 0; 316 return 1; /* too little space error */ 317 } 318 strcpy(label + return_len, p); 319 return_len += lenp; 320 if (whether_strip_slot_markers) 321 { 322 if (label[return_len-2] == IMPORTED_RULES_DELIM) 323 { 324 label[return_len-2] = 0; 325 return_len -= 2; 326 } 327 } 328 329 #define SHOW_END_TIMES 1 330 #if SHOW_END_TIMES 331 { 332 char et[16]; 333 lenp = sprintf(et, "@%d", wtoken->end_time); 334 if (return_len + lenp >= label_len) 335 return 0; 336 strcpy(label + return_len, et); 337 return_len += lenp; 338 } 339 #endif 340 lenp = 1; 341 if (return_len + lenp >= label_len) 342 return 0; /* too little space error */ 343 strcpy(label + return_len, " "); 344 return_len += lenp; 345 } 346 *(label + return_len) = 0; 347 return 0; 348 } 349 350 int srec_nbest_get_choice_info(void* rec_void, int ibest, asr_int32_t* infoval, char* infoname) 351 { 352 srec* rec = (srec*)rec_void; 353 AstarStack* stack = rec ? rec->astar_stack : 0; 354 355 if (!stack) 356 return 1; 357 358 if (ibest < 0 || ibest >= stack->num_complete_paths) 359 return 1; 360 361 /*!strcmp(infoname,"num_speech_frames")|| 362 !strcmp(infoname,"speech_frames_cost"))*/ 363 if (1) 364 { 365 partial_path* parp = stack->complete_paths[ibest]; 366 frameID start_frame = MAXframeID; 367 frameID i, end_frame = MAXframeID; 368 frameID num_speech_frames; 369 bigcostdata speech_frames_cost, start_cost = 0, end_cost = 0; 370 word_token* wtoken; 371 frameID num_words; 372 373 for (num_words = 0 ; parp; parp = parp->next) 374 { 375 if (parp->token_index == MAXwtokenID) break; 376 wtoken = &rec->word_token_array[ parp->token_index]; 377 if (wtoken->word == rec->context->beg_silence_word) 378 { 379 start_frame = wtoken->end_time; 380 start_cost = wtoken->cost + rec->accumulated_cost_offset[ start_frame]; 381 num_words--; 382 } 383 else if (parp->next && 384 parp->next->token_index != MAXwtokenID && 385 rec->word_token_array[ parp->next->token_index].word == rec->context->end_silence_word) 386 { 387 end_frame = wtoken->end_time; 388 end_cost = wtoken->cost + rec->accumulated_cost_offset[ end_frame]; 389 num_words--; 390 } 391 num_words++; 392 } 393 394 if (start_frame != MAXframeID && end_frame != MAXframeID) 395 { 396 num_speech_frames = (frameID)(end_frame - start_frame); 397 speech_frames_cost = end_cost - start_cost; 398 #define WTW_AT_NNREJ_TRAINING 40 399 speech_frames_cost = speech_frames_cost - (num_words + 1) * (rec->context->wtw_average - WTW_AT_NNREJ_TRAINING); 400 if (!strcmp(infoname, "num_speech_frames")) 401 *infoval = num_speech_frames; 402 else if (!strcmp(infoname, "speech_frames_cost")) 403 *infoval = speech_frames_cost; 404 else if (!strcmp(infoname, "gsm_states_score_diff")) 405 { 406 /* this is the best cost, unconstrained by state sequence */ 407 bigcostdata gsm_states_cost = 0; 408 for (i = start_frame + 1; i <= end_frame; i++) 409 { 410 gsm_states_cost += rec->cost_offset_for_frame[i]; 411 *infoval = (asr_int32_t)speech_frames_cost - (asr_int32_t)gsm_states_cost; 412 } 413 } 414 else if (!strcmp(infoname, "gsm_words_score_diff")) 415 { 416 /* this is the best cost, unconstrained by word sequence */ 417 /* we can do this with astar.c ... with some work */ 418 *infoval = 0; 419 } 420 else if (!strcmp(infoname, "num_words")) 421 { 422 *infoval = num_words; 423 } 424 else if (!strcmp(infoname, "gsm_cost")) 425 { 426 bigcostdata gsm_states_cost = 0; 427 for (i = start_frame + 1; i <= end_frame; i++) 428 gsm_states_cost += rec->best_model_cost_for_frame[i]; 429 *infoval = gsm_states_cost; 430 } 431 else if (!strcmp(infoname, "num_total_frames")) 432 { 433 *infoval = rec->current_search_frame; 434 } 435 else if (!strcmp(infoname, "gsm_cost_all_frames")) 436 { 437 bigcostdata gsm_states_cost = 0; 438 for (i = 0; i < rec->current_search_frame; i++) 439 gsm_states_cost += rec->best_model_cost_for_frame[i]; 440 *infoval = gsm_states_cost; 441 } 442 else if (!strcmp(infoname, "acoustic_model_index")) 443 { 444 *infoval = rec->id; 445 } 446 else 447 { 448 log_report("Error: srec_nbest_get_choice_info does not know re %s\n", infoname); 449 return 1; 450 } 451 } 452 } 453 return 0; 454 } 455 456 457 int srec_nbest_sort(void* rec_void) 458 { 459 srec* rec = (srec*)rec_void; 460 AstarStack* stack = rec ? rec->astar_stack : 0; 461 size_t i, j, n; 462 partial_path* parp; 463 464 if (!stack || stack->num_complete_paths < 1) 465 return 0; /* out of range error */ 466 467 n = stack->num_complete_paths; 468 469 /* bubble sort is fine */ 470 /* PLogError("** srec_nbest_sort **\n"); */ 471 for (i = 0;i < n;i++) 472 for (j = i + 1;j < n;j++) 473 if (stack->complete_paths[j]->costsofar < stack->complete_paths[i]->costsofar) 474 { 475 /* PLogMessage(" %d %d", stack->complete_paths[j]->costsofar, stack->complete_paths[j]->costsofar); */ 476 parp = stack->complete_paths[i]; 477 stack->complete_paths[i] = stack->complete_paths[j]; 478 stack->complete_paths[j] = parp; 479 } 480 return 1; 481 482 } 483