1 /* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* ====================================================================
3  * Copyright (c) 1999-2004 Carnegie Mellon University.  All rights
4  * reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  *
18  * This work was supported in part by funding from the Defense Advanced
19  * Research Projects Agency and the National Science Foundation of the
20  * United States of America, and the CMU Sphinx Speech Consortium.
21  *
22  * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND
23  * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
24  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY
26  * NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  *
34  * ====================================================================
35  *
36  */
37 /*
38  * hmm.h -- HMM data structure.
39  *
40  * **********************************************
41  * CMU ARPA Speech Project
42  *
43  * Copyright (c) 1997 Carnegie Mellon University.
44  * ALL RIGHTS RESERVED.
45  * **********************************************
46  *
47  * HISTORY
48  * $Log$
49  * Revision 1.1  2006/04/05  20:27:30  dhdfu
50  * A Great Reorganzation of header files and executables
51  *
52  * Revision 1.9  2006/02/22 16:46:38  arthchan2003
53  * Merged from SPHINX3_5_2_RCI_IRII_BRANCH: 1, Added function hmm_vit_eval, a wrapper of computing the hmm level scores. 2, Fixed issues in , 3, Fixed issues of dox-doc
54  *
55  * Revision 1.8.4.6  2005/09/25 18:53:36  arthchan2003
56  * Added hmm_vit_eval, in lextree.c, hmm_dump and hmm_vit_eval is now separated.
57  *
58  * Revision 1.8.4.5  2005/07/26 02:17:44  arthchan2003
59  * Fixed  keyword problem.
60  *
61  * Revision 1.8.4.4  2005/07/17 05:15:47  arthchan2003
62  * Totally removed the data members in hmm_t structure
63  *
64  * Revision 1.8.4.3  2005/07/05 05:47:59  arthchan2003
65  * Fixed dox-doc. struct level of documentation are included.
66  *
67  * Revision 1.8.4.2  2005/07/04 07:15:55  arthchan2003
68  * Removed fsg compliant stuff from hmm_t
69  *
70  * Revision 1.8.4.1  2005/06/27 05:38:54  arthchan2003
71  * Added changes to make libsearch/fsg_* family of code to be compiled.
72  *
73  * Revision 1.8  2005/06/21 18:34:41  arthchan2003
74  * Log. 1, Fixed doxygen documentation for all functions. 2, Add $Log$
75  * Revision 1.1  2006/04/05  20:27:30  dhdfu
76  * A Great Reorganzation of header files and executables
77  *
78  * Log. 1, Fixed doxygen documentation for all functions. 2, Add Revision 1.9  2006/02/22 16:46:38  arthchan2003
79  * Log. 1, Fixed doxygen documentation for all functions. 2, Add Merged from SPHINX3_5_2_RCI_IRII_BRANCH: 1, Added function hmm_vit_eval, a wrapper of computing the hmm level scores. 2, Fixed issues in , 3, Fixed issues of dox-doc
80  * Log. 1, Fixed doxygen documentation for all functions. 2, Add
81  *
82  * Revision 1.4  2005/06/13 04:02:55  archan
83  * Fixed most doxygen-style documentation under libs3decoder.
84  *
85  * Revision 1.3  2005/03/30 01:22:46  archan
86  * Fixed mistakes in last updates. Add
87  *
88  *
89  * 29-Feb-2000	M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University
90  * 		Modified hmm_t.state to be a run-time array instead of a compile-time
91  * 		one.  Modified compile-time 3 and 5-state versions of hmm_vit_eval
92  * 		into hmm_vit_eval_3st and hmm_vit_eval_5st, to allow run-time selection.
93  * 		Removed hmm_init().
94  *
95  * 08-Dec-1999	M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University.
96  * 		Added HMM_SKIPARCS compile-time option and hmm_init().
97  *
98  * 10-May-1999	M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University.
99  * 		Started, based on an earlier version.
100  */
101 
102 
103 #ifndef _S3_HMM_H_
104 #define _S3_HMM_H_
105 
106 #include <stdio.h>
107 
108 #include "s3types.h"
109 
110 #ifdef __cplusplus
111 extern "C" {
112 #endif
113 #if 0
114 } /* Fool Emacs into not indenting things. */
115 #endif
116 
117 /** Hardcoded limit on the number of states (temporary) */
118 #define MAX_HMM_NSTATE 5
119 
120 /** \file hmm.h
121  * \brief HMM data structure and operation
122  *
123  * For efficiency, this version is hardwired for two possible HMM
124  * topologies, but will fall back to others:
125  *
126  * 5-state left-to-right HMMs: (0 is the *emitting* entry state and E
127  * is a non-emitting exit state; the x's indicate allowed transitions
128  * between source and destination states):
129  *
130  *               0   1   2   3   4   E (destination-states)
131  *           0   x   x   x
132  *           1       x   x   x
133  *           2           x   x   x
134  *           3               x   x   x
135  *           4                   x   x
136  *    (source-states)
137  * 5-state topologies that contain a subset of the above transitions should work as well.
138  *
139  * 3-state left-to-right HMMs (similar notation as the 5-state topology above):
140  *
141  *               0   1   2   E (destination-states)
142  *           0   x   x   x
143  *           1       x   x   x
144  *           2           x   x
145  *    (source-states)
146  * 3-state topologies that contain a subset of the above transitions should work as well.  */
147 
148 /** \struct hmm_context_t
149  * \brief Shared information between a set of HMMs.
150  *
151  * We assume that the initial state is emitting and that the
152  * transition matrix is n_emit_state x (n_emit_state+1), where the
153  * extra destination dimension correponds to the non-emitting final or
154  * exit state.
155  */
156 typedef struct hmm_context_s {
157     int32 n_emit_state;    /**< Number of emitting states in this set of HMMs. */
158     const int32 ***tp;	   /**< State transition scores tp[id][from][to] (logs3 values). */
159     const int32 *senscore; /**< State emission scores senscore[senid] (logs3 values). */
160     const s3senid_t **sseq;/**< Senone sequence mapping. */
161     int32 *st_sen_scr;     /**< Temporary array of senone scores (for some topologies). */
162     void *udata;           /**< Whatever you feel like, gosh. */
163 } hmm_context_t;
164 
165 /**  \struct hmm_state_t
166  * \brief A single state in the HMM
167  */
168 typedef struct {
169     int32 score;	/**< State score (path log-likelihood) */
170     union {
171         long id;	/**< History index */
172         void *ptr;      /**< History object */
173     } history;
174 } hmm_state_t;
175 
176 /** \struct hmm_t
177  * \brief An individual HMM among the HMM search space.
178  *
179  * An individual HMM among the HMM search space.  An HMM with N
180  * emitting states consists of N+2 internal states including the
181  * non-emitting entry (in) and exit (out) states.
182  */
183 
184 typedef struct hmm_s {
185     hmm_context_t *ctx;                /**< Shared context data for this HMM. */
186     hmm_state_t state[MAX_HMM_NSTATE]; /**< Per-state data for emitting states */
187     hmm_state_t out;                   /**< Non-emitting exit state */
188     union {
189         int32 *mpx_ssid; /**< Senone sequence IDs for each state (for multiplex HMMs). */
190         int32 ssid;      /**< Senone sequence ID. */
191     } s;
192     int32 bestscore;	/**< Best [emitting] state score in current frame (for pruning). */
193     s3tmatid_t tmatid;  /**< Transition matrix ID (see hmm_context_t). */
194     s3frmid_t frame;	/**< Frame in which this HMM was last active; <0 if inactive */
195     uint8 mpx;          /**< Is this HMM multiplex? (hoisted for speed) */
196     uint8 n_emit_state; /**< Number of emitting states (hoisted for speed) */
197 } hmm_t;
198 
199 /** Access macros. */
200 #define hmm_context(h) ((hmm_t *)(h))->ctx
201 #define hmm_is_mpx(h) ((hmm_t *)(h))->mpx
202 #define hmm_state(h,st) ((hmm_t *)(h))->state[st]
203 
204 #define hmm_in_score(h) hmm_state(h,0).score
205 #define hmm_score(h,st) hmm_state(h,st).score
206 #define hmm_out_score(h) ((hmm_t *)(h))->out.score
207 
208 #define hmm_in_history(h) hmm_state(h,0).history.id
209 #define hmm_history(h,st) hmm_state(h,st).history.id
210 #define hmm_out_history(h) ((hmm_t *)(h))->out.history.id
211 
212 #define hmm_in_histobj(h) hmm_state(h,0).history.ptr
213 #define hmm_histobj(h,st) hmm_state(h,st).history.ptr
214 #define hmm_out_histobj(h) ((hmm_t *)(h))->out.history.ptr
215 
216 #define hmm_bestscore(h) ((hmm_t *)(h))->bestscore
217 #define hmm_frame(h) ((hmm_t *)(h))->frame
218 #define hmm_mpx_ssid(h,st) ((hmm_t *)(h))->s.mpx_ssid[st]
219 #define hmm_nonmpx_ssid(h) ((hmm_t *)(h))->s.ssid
220 #define hmm_ssid(h,st) (hmm_is_mpx((hmm_t *)(h))                        \
221                         ? hmm_mpx_ssid(h,st) : ((hmm_t *)(h))->s.ssid)
222 #define hmm_senid(h,st) (hmm_ssid(h,st) == -1                           \
223                          ? -1 : ((hmm_t *)(h))->ctx->sseq[hmm_ssid(h,st)][st])
224 #define hmm_senscr(h,st) (hmm_ssid(h,st) == -1                          \
225                           ? S3_LOGPROB_ZERO                             \
226                           : ((hmm_t *)(h))->ctx->senscore[hmm_senid(h,st)])
227 #define hmm_tmatid(h) ((hmm_t *)(h))->tmatid
228 #define hmm_tprob(h,i,j) ((hmm_t *)(h))->ctx->tp[hmm_tmatid(h)][i][j]
229 #define hmm_n_emit_state(h) (((hmm_t *)(h))->n_emit_state)
230 #define hmm_n_state(h) (((hmm_t *)(h))->n_emit_state + 1)
231 
232 /**
233  * Create an HMM context.
234  **/
235 hmm_context_t *hmm_context_init(int32 n_emit_state,
236                                 int32 ***tp,
237                                 int32 *senscore,
238                                 s3senid_t **sseq);
239 
240 /**
241  * Change the senone score array for a context.
242  **/
243 #define hmm_context_set_senscore(ctx, senscr) ((ctx)->senscore = (senscr))
244 
245 /**
246  * Free an HMM context.
247  *
248  * \note The transition matrices, senone scores, and senone sequence
249  * mapping are all assumed to be allocated externally, and will NOT be
250  * freed by this function.
251  **/
252 void hmm_context_free(hmm_context_t *ctx);
253 
254 /**
255  * Populate a previously-allocated HMM structure, allocating internal data.
256  **/
257 void hmm_init(hmm_context_t *ctx, hmm_t *hmm, int mpx,
258               int32 ssid, s3tmatid_t tmatid);
259 
260 /**
261  * Free an HMM structure, releasing internal data (but not the HMM structure itself).
262  */
263 void hmm_deinit(hmm_t *hmm);
264 
265 /**
266  * Reset the states of the HMM to the invalid condition; i.e., scores
267  * to WORST_SCORE and hist to undefined.
268  */
269 void hmm_clear(hmm_t *h);
270 
271 /**
272  * Reset the scores of the HMM.
273  */
274 void hmm_clear_scores(hmm_t *h);
275 
276 /**
277  * Renormalize the scores in this HMM based on the given best score.
278  */
279 void hmm_normalize(hmm_t *h, int32 bestscr);
280 
281 /**
282  * Enter an HMM with the given path score and history ID.
283  **/
284 void hmm_enter(hmm_t *h, int32 score,
285                int32 histid, int32 frame);
286 
287 /**
288  * Enter an HMM with the given path score and history object.
289  **/
290 void hmm_enter_obj(hmm_t *h, int32 score,
291                    void *histobj, int32 frame);
292 
293 /**
294  * Viterbi evaluation of given HMM.  (NOTE that if this module were being used for tracking
295  * state segmentations, the dummy, non-emitting exit state would have to be updated separately.
296  * In the Viterbi DP diagram, transitions to the exit state occur from the current time; they
297  * are vertical transitions.  Hence they should be made only after the history has been logged
298  * for the emitting states.  But we're not bothered with state segmentations, for now.  So, we
299  * update the exit state as well.)
300 */
301 int32 hmm_vit_eval(hmm_t *hmm);
302 
303 
304 /**
305  * Like hmm_vit_eval, but dump HMM state and relevant senscr to fp first, for debugging;.
306  */
307 int32 hmm_dump_vit_eval(hmm_t *hmm,  /**< In/Out: HMM being updated */
308                         FILE *fp /**< An output file pointer */
309     );
310 
311 /**
312  * For debugging, dump the whole HMM out.
313  */
314 
315 void hmm_dump(hmm_t *h,  /**< In/Out: HMM being updated */
316               FILE *fp /**< An output file pointer */
317     );
318 
319 
320 #if 0
321 { /* Stop indent from complaining */
322 #endif
323 #ifdef __cplusplus
324 }
325 #endif
326 
327 #endif
328