1 /**
2  * @file   mkwhmm.c
3  *
4  * <JA>
5  * @brief  ��������׻��Ѥη��%HMM����������
6  * </JA>
7  *
8  * <EN>
9  * @brief  Generate compound %HMM instance for recognition from phoneme sequence.
10  * </EN>
11  *
12  * @author Akinobu LEE
13  * @date   Fri Feb 18 18:31:40 2005
14  *
15  * $Revision: 1.3 $
16  *
17  */
18 /*
19  * Copyright (c) 1991-2007 Kawahara Lab., Kyoto University
20  * Copyright (c) 2000-2005 Shikano Lab., Nara Institute of Science and Technology
21  * Copyright (c) 2005-2007 Julius project team, Nagoya Institute of Technology
22  * All rights reserved
23  */
24 
25 /* When not a multi-path mode, initial & accept arc will be stripped and
26    trans prob to accept state will be stored in accept_ac_a. */
27 
28 #include <sent/stddefs.h>
29 #include <sent/hmm.h>
30 
31 /**
32  * Calculate total number of states in a phoneme sequence.
33  *
34  * @param hdseq [in] phoneme sequence as given by pointer list of logical %HMM
35  * @param hdseqlen [in] length of above
36  * @param has_sp [in] indicates where short-pause insertion is possible
37  * @param hmminfo [in] HMM definition
38  *
39  * @return the total number of states in the sequence.
40  */
41 static int
totalstatelen(HMM_Logical ** hdseq,int hdseqlen,boolean * has_sp,HTK_HMM_INFO * hmminfo)42 totalstatelen(HMM_Logical **hdseq, int hdseqlen, boolean *has_sp, HTK_HMM_INFO *hmminfo)
43 {
44   int i, len;
45 
46   len = 0;
47   for (i=0;i<hdseqlen;i++) {
48     len += hmm_logical_state_num(hdseq[i]) - 2;
49     if (has_sp) {
50       if (has_sp[i]) {
51 	len += hmm_logical_state_num(hmminfo->sp) - 2;
52       }
53     }
54   }
55   if (hmminfo->multipath) {
56     /* add count for the initial and final state */
57     len += 2;
58   }
59   return(len);
60 }
61 
62 /**
63  * Add a transition arc on the HMM state.
64  *
65  * @param state [out] HMM state to add the arc
66  * @param arc [in] state id of destination
67  * @param a [in] transition log probability
68  */
69 static void
add_arc(HMM_STATE * state,int arc,LOGPROB a)70 add_arc(HMM_STATE *state, int arc, LOGPROB a)
71 {
72   A_CELL *atmp;
73 
74   atmp = (A_CELL *)mymalloc(sizeof(A_CELL));
75   atmp->a = a;
76   atmp->arc = arc;
77   atmp->next = state->ac;
78   state->ac = atmp;
79 }
80 
81 /* make word(phrase) HMM from HTK_HMM_INFO */
82 /* LM prob will be assigned for cross-word arcs */
83 /* new HMM is malloced and returned */
84 
85 /**
86  * Make a HMM instance for recognition from phoneme sequence, with connection
87  * probabiliry given for each phoneme.
88  *
89  * @param hmminfo [in] HTK %HMM definitions data
90  * @param hdseq [in] phoneme sequence as given by pointer list of logical %HMM
91  * @param hdseqlen [in] length of above
92  * @param has_sp [in] indicates where short-pause insertion is possible
93  * @param lscore [in] list of log probability to be added at the emitting
94  * transition of each phoneme, or NULL if not needed.
95  *
96  * @return newly allocated HMM instance generated from the given data.
97  */
98 HMM *
new_make_word_hmm_with_lm(HTK_HMM_INFO * hmminfo,HMM_Logical ** hdseq,int hdseqlen,boolean * has_sp,LOGPROB * lscore)99 new_make_word_hmm_with_lm(HTK_HMM_INFO *hmminfo, HMM_Logical **hdseq, int hdseqlen, boolean *has_sp, LOGPROB *lscore)
100 {
101   HMM *new;
102   int i,j,n;
103   int afrom, ato;
104   LOGPROB logprob;
105   HTK_HMM_Trans *tr;
106   int state_num;
107 
108   if (has_sp) {
109     if (hmminfo->sp == NULL) {
110       jlog("Error: mkwhmm: no short-pause model in hmminfo\n");
111       return NULL;
112     }
113   }
114 
115   /* allocate needed states */
116   new = (HMM *)mymalloc(sizeof(HMM));
117   new->len = totalstatelen(hdseq, hdseqlen, has_sp, hmminfo);
118   new->state = (HMM_STATE *)mymalloc(sizeof(HMM_STATE) * new->len);
119   for (i=0;i<new->len;i++) {
120     new->state[i].ac = NULL;
121     new->state[i].is_pseudo_state = FALSE;
122     new->state[i].out.state = NULL;
123     new->state[i].out.cdset = NULL;
124   }
125 
126   /* assign outprob informations into the states  */
127   n = 0;
128   if (hmminfo->multipath) n++;	/* skip first state */
129   for (i = 0; i < hdseqlen; i++) {
130     if (hdseq[i]->is_pseudo) {
131       for (j = 1; j < hdseq[i]->body.pseudo->state_num - 1; j++) {
132 	new->state[n].is_pseudo_state = TRUE;
133 	new->state[n].out.cdset = &(hdseq[i]->body.pseudo->stateset[j]);
134 	n++;
135       }
136     } else {
137       for (j = 1; j < hdseq[i]->body.defined->state_num - 1; j++) {
138 	new->state[n].is_pseudo_state = FALSE;
139 	new->state[n].out.state = hdseq[i]->body.defined->s[j];
140 	n++;
141       }
142     }
143     if (has_sp) {
144       if (has_sp[i]) {
145 	/* append sp at the end of the phone */
146 	if (hmminfo->sp->is_pseudo) {
147 	  for (j = 1; j < hmm_logical_state_num(hmminfo->sp) - 1; j++) {
148 	    new->state[n].is_pseudo_state = TRUE;
149 	    new->state[n].out.cdset = &(hmminfo->sp->body.pseudo->stateset[j]);
150 	    n++;
151 	  }
152 	} else {
153 	  for (j = 1; j < hmm_logical_state_num(hmminfo->sp) - 1; j++) {
154 	    new->state[n].is_pseudo_state = FALSE;
155 	    new->state[n].out.state = hmminfo->sp->body.defined->s[j];
156 	    n++;
157 	  }
158 	}
159       }
160     }
161   }
162 
163   /* make transition arcs between each state*/
164 /*
165  *   for (i=0;i<hdseq[0]->def->state_num;i++) {
166  *     if (i != 1 && (hdseq[0]->def->tr->a[0][i]) != LOG_ZERO) {
167  *	 jlog("initial state contains more than 1 arc.\n");
168  *     }
169  *   }
170  */
171 
172   if (hmminfo->multipath) {
173 
174     int *out_from, *out_from_next;
175     LOGPROB *out_a, *out_a_next;
176     int out_num_prev, out_num_next;
177     out_from = (int *)mymalloc(sizeof(int) * new->len);
178     out_from_next = (int *)mymalloc(sizeof(int) * new->len);
179     out_a = (LOGPROB *)mymalloc(sizeof(LOGPROB) * new->len);
180     out_a_next = (LOGPROB *)mymalloc(sizeof(LOGPROB) * new->len);
181 
182     n = 0;			/* n points to previous state */
183 
184     out_from[0] = 0;
185     out_a[0] = 0.0;
186     out_num_prev = 1;
187     for (i = 0; i < hdseqlen; i++) {
188       state_num = hmm_logical_state_num(hdseq[i]);
189       tr = hmm_logical_trans(hdseq[i]);
190       out_num_next = 0;
191       /* arc from initial state */
192       for (ato = 1; ato < state_num; ato++) {
193 	logprob = tr->a[0][ato];
194 	if (logprob != LOG_ZERO) {
195 	  /* expand arc */
196 	  if (ato == state_num-1) {
197 	    /* from initial to final ... register all previously registered arcs for next expansion */
198 	    if (lscore != NULL) logprob += lscore[i];
199 	    for(j=0;j<out_num_prev;j++) {
200 	      out_from_next[out_num_next] = out_from[j];
201 	      out_a_next[out_num_next] = out_a[j] + logprob;
202 	      out_num_next++;
203 	    }
204 	  } else {
205 	    for(j=0;j<out_num_prev;j++) {
206 	      add_arc(&(new->state[out_from[j]]), n + ato,
207 		      out_a[j] + logprob);
208 	    }
209 	  }
210 	}
211       }
212       /* arc from output state */
213       for(afrom = 1; afrom < state_num - 1; afrom++) {
214 	for (ato = 1; ato < state_num; ato++) {
215 	  logprob = tr->a[afrom][ato];
216 	  if (logprob != LOG_ZERO) {
217 	    if (ato == state_num - 1) {
218 	      /* from output state to final ... register the arc for next expansion */
219 	      if (lscore != NULL) logprob += lscore[i];
220 	      out_from_next[out_num_next] = n+afrom;
221 	      out_a_next[out_num_next++] = logprob;
222 	    } else {
223 	      add_arc(&(new->state[n+afrom]), n + ato, logprob);
224 	    }
225 	  }
226 	}
227       }
228       n += state_num - 2;
229       for(j=0;j<out_num_next;j++) {
230 	out_from[j] = out_from_next[j];
231 	out_a[j] = out_a_next[j];
232       }
233       out_num_prev = out_num_next;
234 
235       /* inter-word short pause handling */
236       if (has_sp && has_sp[i]) {
237 
238 	out_num_next = 0;
239 
240 	/* arc from initial state */
241 	for (ato = 1; ato < hmm_logical_state_num(hmminfo->sp); ato++) {
242 	  logprob = hmm_logical_trans(hmminfo->sp)->a[0][ato];
243 	  if (logprob != LOG_ZERO) {
244 	    /* to control short pause insertion, transition probability toward
245 	       the word-end short pause will be given a penalty */
246 	    logprob += hmminfo->iwsp_penalty;
247 	    /* expand arc */
248 	    if (ato == hmm_logical_state_num(hmminfo->sp)-1) {
249 	      /* from initial to final ... register all previously registered arcs for next expansion */
250 	      for(j=0;j<out_num_prev;j++) {
251 		out_from_next[out_num_next] = out_from[j];
252 		out_a_next[out_num_next] = out_a[j] + logprob;
253 		out_num_next++;
254 	      }
255 	    } else {
256 	      for(j=0;j<out_num_prev;j++) {
257 		add_arc(&(new->state[out_from[j]]), n + ato,
258 			out_a[j] + logprob);
259 	      }
260 	    }
261 	  }
262 	}
263 	/* if short pause model doesn't have a model skip transition, also add it */
264 	if (hmm_logical_trans(hmminfo->sp)->a[0][hmm_logical_state_num(hmminfo->sp)-1] == LOG_ZERO) {
265 	  /* to make insertion sp model to have no effect on the original path,
266 	     the skip transition probability should be 0.0 (=100%) */
267 	  logprob = 0.0;
268 	  for(j=0; j<out_num_prev; j++) {
269 	    out_from_next[out_num_next] = out_from[j];
270 	    out_a_next[out_num_next] = out_a[j] + logprob;
271 	    out_num_next++;
272 	  }
273 	}
274 	/* arc from output state */
275 	for(afrom = 1; afrom < hmm_logical_state_num(hmminfo->sp) - 1; afrom++) {
276 	  for (ato = 1; ato < hmm_logical_state_num(hmminfo->sp); ato++) {
277 	    logprob = hmm_logical_trans(hmminfo->sp)->a[afrom][ato];
278 	    if (logprob != LOG_ZERO) {
279 	      if (ato == hmm_logical_state_num(hmminfo->sp) - 1) {
280 		/* from output state to final ... register the arc for next expansion */
281 		out_from_next[out_num_next] = n+afrom;
282 		out_a_next[out_num_next++] = logprob;
283 	      } else {
284 		add_arc(&(new->state[n+afrom]), n + ato, logprob);
285 	      }
286 	    }
287 	  }
288 	}
289 	n += hmm_logical_state_num(hmminfo->sp) - 2;
290 	for(j=0;j<out_num_next;j++) {
291 	  out_from[j] = out_from_next[j];
292 	  out_a[j] = out_a_next[j];
293 	}
294 	out_num_prev = out_num_next;
295       }
296     }
297 
298 
299     for(j=0;j<out_num_prev;j++) {
300       add_arc(&(new->state[out_from[j]]), new->len-1, out_a[j]);
301     }
302     free(out_from);
303     free(out_from_next);
304     free(out_a);
305     free(out_a_next);
306 
307   } else {
308     /* non-multipath version */
309 
310     new->accept_ac_a = LOG_ZERO;
311     n = 0;
312     for (i = 0; i < hdseqlen; i++) {
313       state_num = hmm_logical_state_num(hdseq[i]);
314       tr = hmm_logical_trans(hdseq[i]);
315       /* for each phoneme, consult the transition matrix to form HMM instance */
316       for (afrom = 1; afrom < state_num - 1; afrom++) {
317 	for (ato = 1; ato < state_num; ato++) {
318 	  logprob = tr->a[afrom][ato];
319 	  if (logprob != LOG_ZERO) {
320 	    /* if emitting transition, add connection probability to the arc */
321 	    if (ato == state_num - 1 && lscore != NULL){
322 	      logprob += lscore[i];
323 	    }
324 	    if (n + (ato - afrom) >= new->len) { /* arc to accept node */
325 	      if (new->accept_ac_a != LOG_ZERO) {
326 		jlog("Error: mkwhmm: more than 1 arc to accept node found\n");
327 		return NULL;
328 
329 	      } else {
330 		new->accept_ac_a = logprob;
331 	      }
332 	    } else {
333 	      add_arc(&(new->state[n]), n + (ato - afrom), logprob);
334 	    }
335 	  }
336 	}
337 	n++;
338       }
339     }
340   }
341 
342   return (new);
343 }
344 
345 /**
346  * Make a HMM instance for recognition from phoneme sequence.
347  *
348  * @param hmminfo [in] HTK %HMM definitions data
349  * @param hdseq [in] phoneme sequence as given by pointer list of logical %HMM
350  * @param hdseqlen [in] length of above
351  * @param has_sp [in] indicates where short-pause insertion is possible
352  *
353  * @return newly allocated HMM instance generated from the given data.
354  */
355 HMM *
new_make_word_hmm(HTK_HMM_INFO * hmminfo,HMM_Logical ** hdseq,int hdseqlen,boolean * has_sp)356 new_make_word_hmm(HTK_HMM_INFO *hmminfo, HMM_Logical **hdseq, int hdseqlen, boolean *has_sp)
357 {
358   return(new_make_word_hmm_with_lm(hmminfo, hdseq, hdseqlen, has_sp, NULL));
359 }
360 
361 /**
362  * Free an HMM instance.
363  *
364  * @param d [in] HMM instance to free
365  */
366 void
free_hmm(HMM * d)367 free_hmm(HMM *d)
368 {
369   A_CELL *ac, *atmp;
370   int i;
371 
372   for (i=0;i<d->len;i++) {
373     ac = d->state[i].ac;
374     while (ac) {
375       atmp = ac->next;
376       free(ac);
377       ac = atmp;
378     }
379   }
380   free(d->state);
381   free(d);
382 }
383