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
WHICH_RECOG(multi_srec * recm)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
srec_get_bestcost_recog_id(multi_srec * recm,int * id)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
srec_result_strip_slot_markers(char * result)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
srec_has_results(multi_srec * recm)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
srec_clear_results(multi_srec * recm)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
srec_nbest_prepare_list(multi_srec * recm,int n,asr_int32_t * bestcost)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
srec_nbest_destroy_list(void * rec_void)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
srec_nbest_get_num_choices(void * rec_void)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
srec_nbest_put_confidence_value(void * rec_void,int choice,int confidence_value)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
srec_nbest_get_confidence_value(void * rec_void,int choice)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
srec_nbest_fix_homonym_confidence_values(void * rec_void)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
srec_nbest_get_word(void * nbest,size_t choice)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
srec_nbest_remove_result(void * rec_void,int n)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
srec_nbest_get_resultWordIDs(void * rec_void,size_t index,wordID * wordIDs,size_t * len,asr_int32_t * cost)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
srec_nbest_get_result(void * rec_void,int n,char * label,int label_len,asr_int32_t * cost,int whether_strip_slot_markers)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
srec_nbest_get_choice_info(void * rec_void,int ibest,asr_int32_t * infoval,char * infoname)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
srec_nbest_sort(void * rec_void)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