1 /**
2  * @file   hmm_lookup.c
3  *
4  * <JA>
5  * @brief  %HMM ��̾��������Τ�������
6  *
7  * "g-u+i" �ʤɤ� %HMM ����̾���顤�б����� %HMM ������������ޤ���
8  *
9  * ������̤�����%HMM HMM_Logical �ؤΥݥ������֤���ޤ���HMM_Logical �ϡ�
10  * �ºݤ��������Ƥ��� %HMM �ؤΥݥ����������뤤�ϥХ��ե�����Υե���
11  * ������%HMM̾�Ǥ��Ĥ���餬%HMM����ե������HMMList���������Ƥ��ʤ���硤
12  * �б����� pseudo %HMM set �ؤΥݥ����Τɤ��餫���ݻ����Ƥ��ޤ���
13  *
14  * �ޤ�������̾�������̾�ؤΥޥåԥ��ؿ��ؤμ�%HMM̾�� pseudo %HMM̾��
15  * �ɲ���Ͽ�⤳���ǹԤʤ��ޤ���
16  * </JA>
17  *
18  * <EN>
19  * @brief  Look up logical %HMM entry from phone name
20  *
21  * These function is for searching %HMM definition from phone name
22  * like "g-u+i".
23  *
24  * The result is pointer to the corresponding logical %HMM (HMM_Logical).
25  * The logical %HMM holds either pointer to an actual %HMM data defined in
26  * HTK %HMM definition, or pointer to a pseudo %HMM set when the query name
27  * is biphone or monophone and they are not defined in either HTK %HMM
28  * definition or HMMList mapping file.
29  *
30  * Adding physical %HMM defined in HTK %HMM definitions and pseudo phones
31  * to the logical %HMM mapping function is also done here.
32  * </EN>
33  *
34  * @author Akinobu LEE
35  * @date   Tue Feb 15 22:34:30 2005
36  *
37  * $Revision: 1.4 $
38  *
39  */
40 /*
41  * Copyright (c) 1991-2007 Kawahara Lab., Kyoto University
42  * Copyright (c) 2000-2005 Shikano Lab., Nara Institute of Science and Technology
43  * Copyright (c) 2005-2007 Julius project team, Nagoya Institute of Technology
44  * All rights reserved
45  */
46 
47 /* physical HMMs ... already indexed when reading in hmmdefs */
48 /* logical HMMs  ... already indexed when reading in HMMList */
49 
50 #include <sent/stddefs.h>
51 #include <sent/htk_hmm.h>
52 #include <sent/ptree.h>
53 
54 /**
55  * Look up physical (defined in HTK %HMM definition file) %HMM by its name.
56  *
57  * @param hmminfo [in] HMM definition data
58  * @param keyname [in] key string of %HMM name
59  *
60  * @return pointer to the found physical %HMM, NULL if not found.
61  */
62 HTK_HMM_Data *
htk_hmmdata_lookup_physical(HTK_HMM_INFO * hmminfo,char * keyname)63 htk_hmmdata_lookup_physical(HTK_HMM_INFO *hmminfo, char *keyname)
64 {
65   HTK_HMM_Data *tmp;
66   tmp = aptree_search_data(keyname, hmminfo->physical_root);
67   if (tmp != NULL && strmatch(tmp->name, keyname)) {
68     return tmp;
69   } else {
70     return NULL;
71   }
72 }
73 
74 /**
75  * Look up logical %HMM by its name.
76  *
77  * @param hmminfo [in] HMM definition data
78  * @param keyname [in] key string of %HMM name
79  *
80  * @return pointer to the found logical %HMM, NULL if not found.
81  */
82 HMM_Logical *
htk_hmmdata_lookup_logical(HTK_HMM_INFO * hmminfo,char * keyname)83 htk_hmmdata_lookup_logical(HTK_HMM_INFO *hmminfo, char *keyname)
84 {
85   HMM_Logical *tmp;
86   tmp = aptree_search_data(keyname, hmminfo->logical_root);
87   if (tmp != NULL && strmatch(tmp->name, keyname)) {
88     return tmp;
89   } else {
90     return NULL;
91   }
92 }
93 
94 /**
95  * Count the number of logical %HMM and store it.
96  *
97  * @param hmminfo [in] %HMM definition data.
98  */
99 static void
hmm_count_logical_num(HTK_HMM_INFO * hmminfo)100 hmm_count_logical_num(HTK_HMM_INFO *hmminfo)
101 {
102   HMM_Logical *lg;
103   int n;
104 
105   n = 0;
106   for (lg = hmminfo->lgstart; lg; lg = lg->next) n++;
107   hmminfo->totallogicalnum = n;
108 }
109 
110 /**
111  * @brief  Add all physical %HMM to logical %HMM.
112  *
113  * This function should be called only if HMMList is not specified.
114  * Julius assumes all the triphones should be explicitly mapped
115  * using HMMList file.
116  *
117  * @param hmminfo [in] %HMM definition data.
118  */
119 void
hmm_add_physical_to_logical(HTK_HMM_INFO * hmminfo)120 hmm_add_physical_to_logical(HTK_HMM_INFO *hmminfo)
121 {
122   HMM_Logical *new, *match = NULL;
123   HTK_HMM_Data *ph;
124 
125   for (ph = hmminfo->start; ph; ph = ph->next) {
126 
127     /* check if same name already exist */
128     if (hmminfo->logical_root != NULL) {
129       match = aptree_search_data(ph->name, hmminfo->logical_root);
130       if (match != NULL && strmatch(match->name, ph->name)) {
131 	/* the physcal name was already mapped to other HMMs in HMMList */
132 	jlog("Warning: hmm_lookup: \"%s\" is defined in hmmdefs, but \"%s\" will be used instead\n", ph->name, (match->body.defined)->name);
133 	continue;
134       }
135     }
136     /* create new HMM_Logical */
137     /* body refers to the physical HMM */
138     new = (HMM_Logical *)mybmalloc2(sizeof(HMM_Logical), &(hmminfo->lroot));
139     new->name = (char *)mybmalloc2(strlen(ph->name) + 1, &(hmminfo->lroot));
140     strcpy(new->name, ph->name);
141     new->is_pseudo = FALSE;
142     new->body.defined = ph;
143     new->next = hmminfo->lgstart;
144     hmminfo->lgstart = new;
145     if (hmminfo->logical_root == NULL) {
146       hmminfo->logical_root = aptree_make_root_node(new, &(hmminfo->lroot));
147     } else {
148       aptree_add_entry(new->name, new, match->name, &(hmminfo->logical_root), &(hmminfo->lroot));
149     }
150   }
151 
152   /* re-count total number */
153   hmm_count_logical_num(hmminfo);
154 }
155 
156 
157 
158 /**
159  * @brief  Add a pseudo monophone and pseudo biphone to logical %HMM.
160  *
161  * Logical %HMM specified in HMMlist precedes
162  * pseudo %HMM: if some monophones or biphones are already
163  * defined in HMMList, pseudo %HMM will not be added.
164  *
165  * @param hmminfo [in] %HMM definition data.
166  * @param name [in] name of the pseudo phone to add.
167  */
168 static boolean
hmm_add_pseudo_phones_sub(HTK_HMM_INFO * hmminfo,char * name)169 hmm_add_pseudo_phones_sub(HTK_HMM_INFO *hmminfo, char *name)
170 {
171   HMM_Logical *new, *match;
172 
173   /* check if already exist */
174   match = aptree_search_data(name, hmminfo->logical_root);
175   if (match != NULL && strmatch(match->name, name)) {
176     /* already exist in list */
177     /*    if (! match->is_pseudo) {*/
178       /* this pseudo-HMM is already defined as real HMM in hmmdefs or in HMMList */
179     /*designated_count++;
180       }*/
181   } else {
182     /* create new HMM_Logical with pseudo body */
183     new = (HMM_Logical *)mybmalloc2(sizeof(HMM_Logical), &(hmminfo->lroot));
184     new->name = (char *)mybmalloc2(strlen(name) + 1, &(hmminfo->lroot));
185     strcpy(new->name, name);
186     new->is_pseudo = TRUE;
187     new->body.pseudo = cdset_lookup(hmminfo, name);
188     if (new->body.pseudo == NULL) {	/* should never happen */
189       jlog("Error: hmm_lookup: tried to add pseudo phone \"%s\" to logical HMM, but no corresponding CD_Set found.  Why??\n");
190       return FALSE;
191     }
192     new->next = hmminfo->lgstart;
193     hmminfo->lgstart = new;
194     if (hmminfo->logical_root == NULL) {
195       hmminfo->logical_root = aptree_make_root_node(new, &(hmminfo->lroot));
196     } else {
197       aptree_add_entry(new->name, new, match->name, &(hmminfo->logical_root), &(hmminfo->lroot));
198     }
199     hmminfo->totalpseudonum++;
200   }
201   return TRUE;
202 }
203 
204 /**
205  * Update logical %HMM list by adding all the possible pseudo monophone
206  * and biphone to the list.
207  *
208  * @param hmminfo [in] %HMM definition data.
209  */
210 void
hmm_add_pseudo_phones(HTK_HMM_INFO * hmminfo)211 hmm_add_pseudo_phones(HTK_HMM_INFO *hmminfo)
212 {
213   HMM_Logical *lg;
214   char buf[MAX_HMMNAME_LEN];
215   boolean ok_p = TRUE;
216 
217   hmminfo->totalpseudonum = 0;
218   /* add pseudo monophone */
219   for (lg = hmminfo->lgstart; lg; lg = lg->next) {
220     if (lg->is_pseudo) continue;
221     if (hmm_add_pseudo_phones_sub(hmminfo, center_name(lg->name, buf)) == FALSE) {
222       jlog("Error: hmm_lookup: failed to add \"%s\" as logical\n", center_name(lg->name, buf));
223       ok_p = FALSE;
224     }
225   }
226   /* add pseudo biphone, i.e. "a-k" etc. */
227   for (lg = hmminfo->lgstart; lg; lg = lg->next) {
228     if (lg->is_pseudo) continue;
229     if (hmm_add_pseudo_phones_sub(hmminfo, leftcenter_name(lg->name, buf)) == FALSE) {
230       jlog("Error: hmm_lookup: failed to add \"%s\" as logical\n", leftcenter_name(lg->name, buf));
231       ok_p = FALSE;
232     }
233   }
234   /* add pseudo biphone, i.e. "k+e" etc. */
235   for (lg = hmminfo->lgstart; lg; lg = lg->next) {
236     if (lg->is_pseudo) continue;
237     if (hmm_add_pseudo_phones_sub(hmminfo, rightcenter_name(lg->name, buf)) == FALSE) {
238       jlog("Error: hmm_lookup: failed to add \"%s\" as logical\n", rightcenter_name(lg->name, buf));
239       ok_p = FALSE;
240     }
241   }
242   jlog("Stat: hmm_lookup: %d pseudo phones are added to logical HMM list\n", hmminfo->totalpseudonum);
243   /* re-count total number */
244   hmm_count_logical_num(hmminfo);
245 }
246 
247 /**
248  * Generic function to get the number of states in a logical %HMM.
249  *
250  * @param lg [in] logical %HMM
251  *
252  * @return the number of states in the logical %HMM.
253  */
254 int
hmm_logical_state_num(HMM_Logical * lg)255 hmm_logical_state_num(HMM_Logical *lg)
256 {
257   int len;
258   if (lg->is_pseudo) len = lg->body.pseudo->state_num;
259   else len = lg->body.defined->state_num;
260   return(len);
261 }
262 
263 /**
264  * Generic function to get transition matrix of a logical %HMM.
265  *
266  * @param lg [in] logical %HMM
267  *
268  * @return pointer to the transition matrix of the logical %HMM.
269  */
270 HTK_HMM_Trans *
hmm_logical_trans(HMM_Logical * lg)271 hmm_logical_trans(HMM_Logical *lg)
272 {
273   HTK_HMM_Trans *tr;
274   if (lg->is_pseudo) tr = lg->body.pseudo->tr;
275   else tr = lg->body.defined->tr;
276   return(tr);
277 }
278