cannam@19
|
1 /*
|
cannam@19
|
2 * hmm.c
|
cannam@19
|
3 *
|
cannam@19
|
4 * Created by Mark Levy on 12/02/2006.
|
cannam@19
|
5 * Copyright 2006 Centre for Digital Music, Queen Mary, University of London. All rights reserved.
|
cannam@19
|
6 *
|
cannam@19
|
7 */
|
cannam@19
|
8
|
cannam@19
|
9 #include <stdio.h>
|
cannam@19
|
10 #include <math.h>
|
cannam@19
|
11 #include <stdlib.h>
|
cannam@19
|
12 #include <float.h>
|
cannam@19
|
13 #include <time.h> /* to seed random number generator */
|
cannam@44
|
14
|
cannam@19
|
15 #include <clapack.h> /* LAPACK for matrix inversion */
|
cannam@44
|
16
|
cannam@79
|
17 #include "maths/nan-inf.h"
|
cannam@79
|
18
|
cannam@44
|
19 #ifdef ATLAS_ORDER
|
cannam@44
|
20 #define HAVE_ATLAS 1
|
cannam@44
|
21 #endif
|
cannam@44
|
22
|
cannam@44
|
23 #ifdef HAVE_ATLAS
|
cannam@44
|
24 // Using ATLAS C interface to LAPACK
|
cannam@44
|
25 #define dgetrf_(m, n, a, lda, ipiv, info) \
|
cannam@44
|
26 clapack_dgetrf(CblasColMajor, *m, *n, a, *lda, ipiv)
|
cannam@44
|
27 #define dgetri_(n, a, lda, ipiv, work, lwork, info) \
|
cannam@44
|
28 clapack_dgetri(CblasColMajor, *n, a, *lda, ipiv)
|
cannam@44
|
29 #endif
|
cannam@44
|
30
|
cannam@19
|
31 #ifdef _MAC_OS_X
|
cannam@19
|
32 #include <vecLib/cblas.h>
|
cannam@19
|
33 #else
|
cannam@19
|
34 #include <cblas.h> /* BLAS for matrix multiplication */
|
cannam@19
|
35 #endif
|
cannam@19
|
36
|
cannam@19
|
37 #include "hmm.h"
|
cannam@19
|
38
|
cannam@19
|
39 model_t* hmm_init(double** x, int T, int L, int N)
|
cannam@19
|
40 {
|
cannam@19
|
41 int i, j, d, e, t;
|
cannam@19
|
42 double s, ss;
|
cannam@19
|
43
|
cannam@19
|
44 model_t* model;
|
cannam@19
|
45 model = (model_t*) malloc(sizeof(model_t));
|
cannam@19
|
46 model->N = N;
|
cannam@19
|
47 model->L = L;
|
cannam@19
|
48 model->p0 = (double*) malloc(N*sizeof(double));
|
cannam@19
|
49 model->a = (double**) malloc(N*sizeof(double*));
|
cannam@19
|
50 model->mu = (double**) malloc(N*sizeof(double*));
|
cannam@19
|
51 for (i = 0; i < N; i++)
|
cannam@19
|
52 {
|
cannam@19
|
53 model->a[i] = (double*) malloc(N*sizeof(double));
|
cannam@19
|
54 model->mu[i] = (double*) malloc(L*sizeof(double));
|
cannam@19
|
55 }
|
cannam@19
|
56 model->cov = (double**) malloc(L*sizeof(double*));
|
cannam@19
|
57 for (i = 0; i < L; i++)
|
cannam@19
|
58 model->cov[i] = (double*) malloc(L*sizeof(double));
|
cannam@19
|
59
|
cannam@19
|
60 srand(time(0));
|
cannam@19
|
61 double* global_mean = (double*) malloc(L*sizeof(double));
|
cannam@19
|
62
|
cannam@19
|
63 /* find global mean */
|
cannam@19
|
64 for (d = 0; d < L; d++)
|
cannam@19
|
65 {
|
cannam@19
|
66 global_mean[d] = 0;
|
cannam@19
|
67 for (t = 0; t < T; t++)
|
cannam@19
|
68 global_mean[d] += x[t][d];
|
cannam@19
|
69 global_mean[d] /= T;
|
cannam@19
|
70 }
|
cannam@19
|
71
|
cannam@19
|
72 /* calculate global diagonal covariance */
|
cannam@19
|
73 for (d = 0; d < L; d++)
|
cannam@19
|
74 {
|
cannam@19
|
75 for (e = 0; e < L; e++)
|
cannam@19
|
76 model->cov[d][e] = 0;
|
cannam@19
|
77 for (t = 0; t < T; t++)
|
cannam@19
|
78 model->cov[d][d] += (x[t][d] - global_mean[d]) * (x[t][d] - global_mean[d]);
|
cannam@19
|
79 model->cov[d][d] /= T-1;
|
cannam@19
|
80 }
|
cannam@19
|
81
|
cannam@19
|
82 /* set all means close to global mean */
|
cannam@19
|
83 for (i = 0; i < N; i++)
|
cannam@19
|
84 {
|
cannam@19
|
85 for (d = 0; d < L; d++)
|
cannam@19
|
86 {
|
cannam@19
|
87 /* add some random noise related to covariance */
|
cannam@19
|
88 /* ideally the random number would be Gaussian(0,1), as a hack we make it uniform on [-0.25,0.25] */
|
cannam@19
|
89 model->mu[i][d] = global_mean[d] + (0.5 * rand() / (double) RAND_MAX - 0.25) * sqrt(model->cov[d][d]);
|
cannam@19
|
90 }
|
cannam@19
|
91 }
|
cannam@19
|
92
|
cannam@19
|
93 /* random intial and transition probs */
|
cannam@19
|
94 s = 0;
|
cannam@19
|
95 for (i = 0; i < N; i++)
|
cannam@19
|
96 {
|
cannam@19
|
97 model->p0[i] = 1 + rand() / (double) RAND_MAX;
|
cannam@19
|
98 s += model->p0[i];
|
cannam@19
|
99 ss = 0;
|
cannam@19
|
100 for (j = 0; j < N; j++)
|
cannam@19
|
101 {
|
cannam@19
|
102 model->a[i][j] = 1 + rand() / (double) RAND_MAX;
|
cannam@19
|
103 ss += model->a[i][j];
|
cannam@19
|
104 }
|
cannam@19
|
105 for (j = 0; j < N; j++)
|
cannam@19
|
106 {
|
cannam@19
|
107 model->a[i][j] /= ss;
|
cannam@19
|
108 }
|
cannam@19
|
109 }
|
cannam@19
|
110 for (i = 0; i < N; i++)
|
cannam@19
|
111 model->p0[i] /= s;
|
cannam@19
|
112
|
cannam@19
|
113 free(global_mean);
|
cannam@19
|
114
|
cannam@19
|
115 return model;
|
cannam@19
|
116 }
|
cannam@19
|
117
|
cannam@19
|
118 void hmm_close(model_t* model)
|
cannam@19
|
119 {
|
cannam@19
|
120 int i;
|
cannam@19
|
121
|
cannam@19
|
122 for (i = 0; i < model->N; i++)
|
cannam@19
|
123 {
|
cannam@19
|
124 free(model->a[i]);
|
cannam@19
|
125 free(model->mu[i]);
|
cannam@19
|
126 }
|
cannam@19
|
127 free(model->a);
|
cannam@19
|
128 free(model->mu);
|
cannam@19
|
129 for (i = 0; i < model->L; i++)
|
cannam@19
|
130 free(model->cov[i]);
|
cannam@19
|
131 free(model->cov);
|
cannam@19
|
132 free(model);
|
cannam@19
|
133 }
|
cannam@19
|
134
|
cannam@19
|
135 void hmm_train(double** x, int T, model_t* model)
|
cannam@19
|
136 {
|
cannam@19
|
137 int i, t;
|
cannam@19
|
138 double loglik; /* overall log-likelihood at each iteration */
|
cannam@19
|
139
|
cannam@19
|
140 int N = model->N;
|
cannam@19
|
141 int L = model->L;
|
cannam@19
|
142 double* p0 = model->p0;
|
cannam@19
|
143 double** a = model->a;
|
cannam@19
|
144 double** mu = model->mu;
|
cannam@19
|
145 double** cov = model->cov;
|
cannam@19
|
146
|
cannam@19
|
147 /* allocate memory */
|
cannam@19
|
148 double** gamma = (double**) malloc(T*sizeof(double*));
|
cannam@19
|
149 double*** xi = (double***) malloc(T*sizeof(double**));
|
cannam@19
|
150 for (t = 0; t < T; t++)
|
cannam@19
|
151 {
|
cannam@19
|
152 gamma[t] = (double*) malloc(N*sizeof(double));
|
cannam@19
|
153 xi[t] = (double**) malloc(N*sizeof(double*));
|
cannam@19
|
154 for (i = 0; i < N; i++)
|
cannam@19
|
155 xi[t][i] = (double*) malloc(N*sizeof(double));
|
cannam@19
|
156 }
|
cannam@19
|
157
|
cannam@19
|
158 /* temporary memory */
|
cannam@19
|
159 double* gauss_y = (double*) malloc(L*sizeof(double));
|
cannam@19
|
160 double* gauss_z = (double*) malloc(L*sizeof(double));
|
cannam@19
|
161
|
cannam@19
|
162 /* obs probs P(j|{x}) */
|
cannam@19
|
163 double** b = (double**) malloc(T*sizeof(double*));
|
cannam@19
|
164 for (t = 0; t < T; t++)
|
cannam@19
|
165 b[t] = (double*) malloc(N*sizeof(double));
|
cannam@19
|
166
|
cannam@19
|
167 /* inverse covariance and its determinant */
|
cannam@19
|
168 double** icov = (double**) malloc(L*sizeof(double*));
|
cannam@19
|
169 for (i = 0; i < L; i++)
|
cannam@19
|
170 icov[i] = (double*) malloc(L*sizeof(double));
|
cannam@19
|
171 double detcov;
|
cannam@19
|
172
|
cannam@19
|
173 double thresh = 0.0001;
|
cannam@19
|
174 int niter = 50;
|
cannam@19
|
175 int iter = 0;
|
cannam@19
|
176 double loglik1, loglik2;
|
cannam@30
|
177 int foundnan = 0;
|
cannam@30
|
178
|
cannam@30
|
179 while (iter < niter && !foundnan && !(iter > 1 && (loglik - loglik1) < thresh * (loglik1 - loglik2)))
|
cannam@19
|
180 {
|
cannam@19
|
181 ++iter;
|
cannam@58
|
182 /*
|
cannam@19
|
183 fprintf(stderr, "calculating obsprobs...\n");
|
cannam@19
|
184 fflush(stderr);
|
cannam@58
|
185 */
|
cannam@19
|
186 /* precalculate obs probs */
|
cannam@19
|
187 invert(cov, L, icov, &detcov);
|
cannam@19
|
188
|
cannam@19
|
189 for (t = 0; t < T; t++)
|
cannam@19
|
190 {
|
cannam@19
|
191 //int allzero = 1;
|
cannam@19
|
192 for (i = 0; i < N; i++)
|
cannam@19
|
193 {
|
cannam@19
|
194 b[t][i] = exp(loggauss(x[t], L, mu[i], icov, detcov, gauss_y, gauss_z));
|
cannam@19
|
195
|
cannam@19
|
196 //if (b[t][i] != 0)
|
cannam@19
|
197 // allzero = 0;
|
cannam@19
|
198 }
|
cannam@19
|
199 /*
|
cannam@19
|
200 if (allzero)
|
cannam@19
|
201 {
|
cannam@19
|
202 printf("all the b[t][i] were zero for t = %d, correcting...\n", t);
|
cannam@19
|
203 for (i = 0; i < N; i++)
|
cannam@19
|
204 {
|
cannam@19
|
205 b[t][i] = 0.00001;
|
cannam@19
|
206 }
|
cannam@19
|
207 }
|
cannam@19
|
208 */
|
cannam@19
|
209 }
|
cannam@58
|
210 /*
|
cannam@19
|
211 fprintf(stderr, "forwards-backwards...\n");
|
cannam@19
|
212 fflush(stderr);
|
cannam@58
|
213 */
|
cannam@19
|
214 forward_backwards(xi, gamma, &loglik, &loglik1, &loglik2, iter, N, T, p0, a, b);
|
cannam@58
|
215 /*
|
cannam@19
|
216 fprintf(stderr, "iteration %d: loglik = %f\n", iter, loglik);
|
cannam@19
|
217 fprintf(stderr, "re-estimation...\n");
|
cannam@19
|
218 fflush(stderr);
|
cannam@58
|
219 */
|
cannam@79
|
220 if (ISNAN(loglik)) {
|
cannam@30
|
221 foundnan = 1;
|
cannam@30
|
222 continue;
|
cannam@30
|
223 }
|
cannam@19
|
224
|
cannam@19
|
225 baum_welch(p0, a, mu, cov, N, T, L, x, xi, gamma);
|
cannam@19
|
226
|
cannam@19
|
227 /*
|
cannam@19
|
228 printf("a:\n");
|
cannam@19
|
229 for (i = 0; i < model->N; i++)
|
cannam@19
|
230 {
|
cannam@19
|
231 for (j = 0; j < model->N; j++)
|
cannam@19
|
232 printf("%f ", model->a[i][j]);
|
cannam@19
|
233 printf("\n");
|
cannam@19
|
234 }
|
cannam@19
|
235 printf("\n\n");
|
cannam@19
|
236 */
|
cannam@19
|
237 //hmm_print(model);
|
cannam@19
|
238 }
|
cannam@19
|
239
|
cannam@19
|
240 /* deallocate memory */
|
cannam@19
|
241 for (t = 0; t < T; t++)
|
cannam@19
|
242 {
|
cannam@19
|
243 free(gamma[t]);
|
cannam@19
|
244 free(b[t]);
|
cannam@19
|
245 for (i = 0; i < N; i++)
|
cannam@19
|
246 free(xi[t][i]);
|
cannam@19
|
247 free(xi[t]);
|
cannam@19
|
248 }
|
cannam@19
|
249 free(gamma);
|
cannam@19
|
250 free(xi);
|
cannam@19
|
251 free(b);
|
cannam@19
|
252
|
cannam@19
|
253 for (i = 0; i < L; i++)
|
cannam@19
|
254 free(icov[i]);
|
cannam@19
|
255 free(icov);
|
cannam@19
|
256
|
cannam@19
|
257 free(gauss_y);
|
cannam@19
|
258 free(gauss_z);
|
cannam@19
|
259 }
|
cannam@19
|
260
|
cannam@19
|
261 void mlss_reestimate(double* p0, double** a, double** mu, double** cov, int N, int T, int L, int* q, double** x)
|
cannam@19
|
262 {
|
cannam@19
|
263 /* fit a single Gaussian to observations in each state */
|
cannam@19
|
264
|
cannam@19
|
265 /* calculate the mean observation in each state */
|
cannam@19
|
266
|
cannam@19
|
267 /* calculate the overall covariance */
|
cannam@19
|
268
|
cannam@19
|
269 /* count transitions */
|
cannam@19
|
270
|
cannam@19
|
271 /* estimate initial probs from transitions (???) */
|
cannam@19
|
272 }
|
cannam@19
|
273
|
cannam@19
|
274 void baum_welch(double* p0, double** a, double** mu, double** cov, int N, int T, int L, double** x, double*** xi, double** gamma)
|
cannam@19
|
275 {
|
cannam@19
|
276 int i, j, t;
|
cannam@19
|
277
|
cannam@19
|
278 double* sum_gamma = (double*) malloc(N*sizeof(double));
|
cannam@19
|
279
|
cannam@19
|
280 /* temporary memory */
|
cannam@19
|
281 double* u = (double*) malloc(L*L*sizeof(double));
|
cannam@19
|
282 double* yy = (double*) malloc(T*L*sizeof(double));
|
cannam@19
|
283 double* yy2 = (double*) malloc(T*L*sizeof(double));
|
cannam@19
|
284
|
cannam@19
|
285 /* re-estimate transition probs */
|
cannam@19
|
286 for (i = 0; i < N; i++)
|
cannam@19
|
287 {
|
cannam@19
|
288 sum_gamma[i] = 0;
|
cannam@19
|
289 for (t = 0; t < T-1; t++)
|
cannam@19
|
290 sum_gamma[i] += gamma[t][i];
|
cannam@19
|
291 }
|
cannam@19
|
292
|
cannam@19
|
293 for (i = 0; i < N; i++)
|
cannam@19
|
294 {
|
cannam@19
|
295 if (sum_gamma[i] == 0)
|
cannam@19
|
296 {
|
cannam@58
|
297 /* fprintf(stderr, "sum_gamma[%d] was zero...\n", i); */
|
cannam@19
|
298 }
|
cannam@19
|
299 //double s = 0;
|
cannam@19
|
300 for (j = 0; j < N; j++)
|
cannam@19
|
301 {
|
cannam@19
|
302 a[i][j] = 0;
|
cannam@30
|
303 if (sum_gamma[i] == 0.) continue;
|
cannam@19
|
304 for (t = 0; t < T-1; t++)
|
cannam@19
|
305 a[i][j] += xi[t][i][j];
|
cannam@19
|
306 //s += a[i][j];
|
cannam@19
|
307 a[i][j] /= sum_gamma[i];
|
cannam@19
|
308 }
|
cannam@19
|
309 /*
|
cannam@19
|
310 for (j = 0; j < N; j++)
|
cannam@19
|
311 {
|
cannam@19
|
312 a[i][j] /= s;
|
cannam@19
|
313 }
|
cannam@19
|
314 */
|
cannam@19
|
315 }
|
cannam@19
|
316
|
cannam@19
|
317 /* NB: now we need to sum gamma over all t */
|
cannam@19
|
318 for (i = 0; i < N; i++)
|
cannam@19
|
319 sum_gamma[i] += gamma[T-1][i];
|
cannam@19
|
320
|
cannam@19
|
321 /* re-estimate initial probs */
|
cannam@19
|
322 for (i = 0; i < N; i++)
|
cannam@19
|
323 p0[i] = gamma[0][i];
|
cannam@19
|
324
|
cannam@19
|
325 /* re-estimate covariance */
|
cannam@19
|
326 int d, e;
|
cannam@19
|
327 double sum_sum_gamma = 0;
|
cannam@19
|
328 for (i = 0; i < N; i++)
|
cannam@19
|
329 sum_sum_gamma += sum_gamma[i];
|
cannam@19
|
330
|
cannam@19
|
331 /*
|
cannam@19
|
332 for (d = 0; d < L; d++)
|
cannam@19
|
333 {
|
cannam@19
|
334 for (e = d; e < L; e++)
|
cannam@19
|
335 {
|
cannam@19
|
336 cov[d][e] = 0;
|
cannam@19
|
337 for (t = 0; t < T; t++)
|
cannam@19
|
338 for (j = 0; j < N; j++)
|
cannam@19
|
339 cov[d][e] += gamma[t][j] * (x[t][d] - mu[j][d]) * (x[t][e] - mu[j][e]);
|
cannam@19
|
340
|
cannam@19
|
341 cov[d][e] /= sum_sum_gamma;
|
cannam@19
|
342
|
cannam@79
|
343 if (ISNAN(cov[d][e]))
|
cannam@19
|
344 {
|
cannam@19
|
345 printf("cov[%d][%d] was nan\n", d, e);
|
cannam@19
|
346 for (j = 0; j < N; j++)
|
cannam@19
|
347 for (i = 0; i < L; i++)
|
cannam@79
|
348 if (ISNAN(mu[j][i]))
|
cannam@19
|
349 printf("mu[%d][%d] was nan\n", j, i);
|
cannam@19
|
350 for (t = 0; t < T; t++)
|
cannam@19
|
351 for (j = 0; j < N; j++)
|
cannam@79
|
352 if (ISNAN(gamma[t][j]))
|
cannam@19
|
353 printf("gamma[%d][%d] was nan\n", t, j);
|
cannam@19
|
354 exit(-1);
|
cannam@19
|
355 }
|
cannam@19
|
356 }
|
cannam@19
|
357 }
|
cannam@19
|
358 for (d = 0; d < L; d++)
|
cannam@19
|
359 for (e = 0; e < d; e++)
|
cannam@19
|
360 cov[d][e] = cov[e][d];
|
cannam@19
|
361 */
|
cannam@19
|
362
|
cannam@19
|
363 /* using BLAS */
|
cannam@19
|
364 for (d = 0; d < L; d++)
|
cannam@19
|
365 for (e = 0; e < L; e++)
|
cannam@19
|
366 cov[d][e] = 0;
|
cannam@19
|
367
|
cannam@19
|
368 for (j = 0; j < N; j++)
|
cannam@19
|
369 {
|
cannam@19
|
370 for (d = 0; d < L; d++)
|
cannam@19
|
371 for (t = 0; t < T; t++)
|
cannam@19
|
372 {
|
cannam@19
|
373 yy[d*T+t] = x[t][d] - mu[j][d];
|
cannam@19
|
374 yy2[d*T+t] = gamma[t][j] * (x[t][d] - mu[j][d]);
|
cannam@19
|
375 }
|
cannam@19
|
376
|
cannam@19
|
377 cblas_dgemm(CblasColMajor, CblasTrans, CblasNoTrans, L, L, T, 1.0, yy, T, yy2, T, 0, u, L);
|
cannam@19
|
378
|
cannam@19
|
379 for (e = 0; e < L; e++)
|
cannam@19
|
380 for (d = 0; d < L; d++)
|
cannam@19
|
381 cov[d][e] += u[e*L+d];
|
cannam@19
|
382 }
|
cannam@19
|
383
|
cannam@19
|
384 for (d = 0; d < L; d++)
|
cannam@19
|
385 for (e = 0; e < L; e++)
|
cannam@19
|
386 cov[d][e] /= T; /* sum_sum_gamma; */
|
cannam@19
|
387
|
cannam@19
|
388 //printf("sum_sum_gamma = %f\n", sum_sum_gamma); /* fine, = T IS THIS ALWAYS TRUE with pooled cov?? */
|
cannam@19
|
389
|
cannam@19
|
390 /* re-estimate means */
|
cannam@19
|
391 for (j = 0; j < N; j++)
|
cannam@19
|
392 {
|
cannam@19
|
393 for (d = 0; d < L; d++)
|
cannam@19
|
394 {
|
cannam@19
|
395 mu[j][d] = 0;
|
cannam@19
|
396 for (t = 0; t < T; t++)
|
cannam@19
|
397 mu[j][d] += gamma[t][j] * x[t][d];
|
cannam@19
|
398 mu[j][d] /= sum_gamma[j];
|
cannam@19
|
399 }
|
cannam@19
|
400 }
|
cannam@19
|
401
|
cannam@19
|
402 /* deallocate memory */
|
cannam@19
|
403 free(sum_gamma);
|
cannam@19
|
404 free(yy);
|
cannam@19
|
405 free(yy2);
|
cannam@19
|
406 free(u);
|
cannam@19
|
407 }
|
cannam@19
|
408
|
cannam@19
|
409 void forward_backwards(double*** xi, double** gamma, double* loglik, double* loglik1, double* loglik2, int iter, int N, int T, double* p0, double** a, double** b)
|
cannam@19
|
410 {
|
cannam@19
|
411 /* forwards-backwards with scaling */
|
cannam@19
|
412 int i, j, t;
|
cannam@19
|
413
|
cannam@19
|
414 double** alpha = (double**) malloc(T*sizeof(double*));
|
cannam@19
|
415 double** beta = (double**) malloc(T*sizeof(double*));
|
cannam@19
|
416 for (t = 0; t < T; t++)
|
cannam@19
|
417 {
|
cannam@19
|
418 alpha[t] = (double*) malloc(N*sizeof(double));
|
cannam@19
|
419 beta[t] = (double*) malloc(N*sizeof(double));
|
cannam@19
|
420 }
|
cannam@19
|
421
|
cannam@19
|
422 /* scaling coefficients */
|
cannam@19
|
423 double* c = (double*) malloc(T*sizeof(double));
|
cannam@19
|
424
|
cannam@19
|
425 /* calculate forward probs and scale coefficients */
|
cannam@19
|
426 c[0] = 0;
|
cannam@19
|
427 for (i = 0; i < N; i++)
|
cannam@19
|
428 {
|
cannam@19
|
429 alpha[0][i] = p0[i] * b[0][i];
|
cannam@19
|
430 c[0] += alpha[0][i];
|
cannam@19
|
431
|
cannam@19
|
432 //printf("p0[%d] = %f, b[0][%d] = %f\n", i, p0[i], i, b[0][i]);
|
cannam@19
|
433 }
|
cannam@19
|
434 c[0] = 1 / c[0];
|
cannam@19
|
435 for (i = 0; i < N; i++)
|
cannam@19
|
436 {
|
cannam@19
|
437 alpha[0][i] *= c[0];
|
cannam@19
|
438
|
cannam@19
|
439 //printf("alpha[0][%d] = %f\n", i, alpha[0][i]); /* OK agrees with Matlab */
|
cannam@19
|
440 }
|
cannam@19
|
441
|
cannam@19
|
442 *loglik1 = *loglik;
|
cannam@19
|
443 *loglik = -log(c[0]);
|
cannam@19
|
444 if (iter == 2)
|
cannam@19
|
445 *loglik2 = *loglik;
|
cannam@19
|
446
|
cannam@19
|
447 for (t = 1; t < T; t++)
|
cannam@19
|
448 {
|
cannam@19
|
449 c[t] = 0;
|
cannam@19
|
450 for (j = 0; j < N; j++)
|
cannam@19
|
451 {
|
cannam@19
|
452 alpha[t][j] = 0;
|
cannam@19
|
453 for (i = 0; i < N; i++)
|
cannam@19
|
454 alpha[t][j] += alpha[t-1][i] * a[i][j];
|
cannam@19
|
455 alpha[t][j] *= b[t][j];
|
cannam@19
|
456
|
cannam@19
|
457 c[t] += alpha[t][j];
|
cannam@19
|
458 }
|
cannam@19
|
459
|
cannam@19
|
460 /*
|
cannam@19
|
461 if (c[t] == 0)
|
cannam@19
|
462 {
|
cannam@19
|
463 printf("c[%d] = 0, going to blow up so exiting\n", t);
|
cannam@19
|
464 for (i = 0; i < N; i++)
|
cannam@19
|
465 if (b[t][i] == 0)
|
cannam@19
|
466 fprintf(stderr, "b[%d][%d] was zero\n", t, i);
|
cannam@19
|
467 fprintf(stderr, "x[t] was \n");
|
cannam@19
|
468 for (i = 0; i < L; i++)
|
cannam@19
|
469 fprintf(stderr, "%f ", x[t][i]);
|
cannam@19
|
470 fprintf(stderr, "\n\n");
|
cannam@19
|
471 exit(-1);
|
cannam@19
|
472 }
|
cannam@19
|
473 */
|
cannam@19
|
474
|
cannam@19
|
475 c[t] = 1 / c[t];
|
cannam@19
|
476 for (j = 0; j < N; j++)
|
cannam@19
|
477 alpha[t][j] *= c[t];
|
cannam@19
|
478
|
cannam@19
|
479 //printf("c[%d] = %e\n", t, c[t]);
|
cannam@19
|
480
|
cannam@19
|
481 *loglik -= log(c[t]);
|
cannam@19
|
482 }
|
cannam@19
|
483
|
cannam@19
|
484 /* calculate backwards probs using same coefficients */
|
cannam@19
|
485 for (i = 0; i < N; i++)
|
cannam@19
|
486 beta[T-1][i] = 1;
|
cannam@19
|
487 t = T - 1;
|
cannam@19
|
488 while (1)
|
cannam@19
|
489 {
|
cannam@19
|
490 for (i = 0; i < N; i++)
|
cannam@19
|
491 beta[t][i] *= c[t];
|
cannam@19
|
492
|
cannam@19
|
493 if (t == 0)
|
cannam@19
|
494 break;
|
cannam@19
|
495
|
cannam@19
|
496 for (i = 0; i < N; i++)
|
cannam@19
|
497 {
|
cannam@19
|
498 beta[t-1][i] = 0;
|
cannam@19
|
499 for (j = 0; j < N; j++)
|
cannam@19
|
500 beta[t-1][i] += a[i][j] * b[t][j] * beta[t][j];
|
cannam@19
|
501 }
|
cannam@19
|
502
|
cannam@19
|
503 t--;
|
cannam@19
|
504 }
|
cannam@19
|
505
|
cannam@19
|
506 /*
|
cannam@19
|
507 printf("alpha:\n");
|
cannam@19
|
508 for (t = 0; t < T; t++)
|
cannam@19
|
509 {
|
cannam@19
|
510 for (i = 0; i < N; i++)
|
cannam@19
|
511 printf("%4.4e\t\t", alpha[t][i]);
|
cannam@19
|
512 printf("\n");
|
cannam@19
|
513 }
|
cannam@19
|
514 printf("\n\n");printf("beta:\n");
|
cannam@19
|
515 for (t = 0; t < T; t++)
|
cannam@19
|
516 {
|
cannam@19
|
517 for (i = 0; i < N; i++)
|
cannam@19
|
518 printf("%4.4e\t\t", beta[t][i]);
|
cannam@19
|
519 printf("\n");
|
cannam@19
|
520 }
|
cannam@19
|
521 printf("\n\n");
|
cannam@19
|
522 */
|
cannam@19
|
523
|
cannam@19
|
524 /* calculate posterior probs */
|
cannam@19
|
525 double tot;
|
cannam@19
|
526 for (t = 0; t < T; t++)
|
cannam@19
|
527 {
|
cannam@19
|
528 tot = 0;
|
cannam@19
|
529 for (i = 0; i < N; i++)
|
cannam@19
|
530 {
|
cannam@19
|
531 gamma[t][i] = alpha[t][i] * beta[t][i];
|
cannam@19
|
532 tot += gamma[t][i];
|
cannam@19
|
533 }
|
cannam@19
|
534 for (i = 0; i < N; i++)
|
cannam@19
|
535 {
|
cannam@19
|
536 gamma[t][i] /= tot;
|
cannam@19
|
537
|
cannam@19
|
538 //printf("gamma[%d][%d] = %f\n", t, i, gamma[t][i]);
|
cannam@19
|
539 }
|
cannam@19
|
540 }
|
cannam@19
|
541
|
cannam@19
|
542 for (t = 0; t < T-1; t++)
|
cannam@19
|
543 {
|
cannam@19
|
544 tot = 0;
|
cannam@19
|
545 for (i = 0; i < N; i++)
|
cannam@19
|
546 {
|
cannam@19
|
547 for (j = 0; j < N; j++)
|
cannam@19
|
548 {
|
cannam@19
|
549 xi[t][i][j] = alpha[t][i] * a[i][j] * b[t+1][j] * beta[t+1][j];
|
cannam@19
|
550 tot += xi[t][i][j];
|
cannam@19
|
551 }
|
cannam@19
|
552 }
|
cannam@19
|
553 for (i = 0; i < N; i++)
|
cannam@19
|
554 for (j = 0; j < N; j++)
|
cannam@19
|
555 xi[t][i][j] /= tot;
|
cannam@19
|
556 }
|
cannam@19
|
557
|
cannam@19
|
558 /*
|
cannam@19
|
559 // CHECK - fine
|
cannam@19
|
560 // gamma[t][i] = \sum_j{xi[t][i][j]}
|
cannam@19
|
561 tot = 0;
|
cannam@19
|
562 for (j = 0; j < N; j++)
|
cannam@19
|
563 tot += xi[3][1][j];
|
cannam@19
|
564 printf("gamma[3][1] = %f, sum_j(xi[3][1][j]) = %f\n", gamma[3][1], tot);
|
cannam@19
|
565 */
|
cannam@19
|
566
|
cannam@19
|
567 for (t = 0; t < T; t++)
|
cannam@19
|
568 {
|
cannam@19
|
569 free(alpha[t]);
|
cannam@19
|
570 free(beta[t]);
|
cannam@19
|
571 }
|
cannam@19
|
572 free(alpha);
|
cannam@19
|
573 free(beta);
|
cannam@19
|
574 free(c);
|
cannam@19
|
575 }
|
cannam@19
|
576
|
cannam@19
|
577 void viterbi_decode(double** x, int T, model_t* model, int* q)
|
cannam@19
|
578 {
|
cannam@19
|
579 int i, j, t;
|
cannam@19
|
580 double max;
|
cannam@48
|
581 int havemax;
|
cannam@19
|
582
|
cannam@19
|
583 int N = model->N;
|
cannam@19
|
584 int L = model->L;
|
cannam@19
|
585 double* p0 = model->p0;
|
cannam@19
|
586 double** a = model->a;
|
cannam@19
|
587 double** mu = model->mu;
|
cannam@19
|
588 double** cov = model->cov;
|
cannam@19
|
589
|
cannam@19
|
590 /* inverse covariance and its determinant */
|
cannam@19
|
591 double** icov = (double**) malloc(L*sizeof(double*));
|
cannam@19
|
592 for (i = 0; i < L; i++)
|
cannam@19
|
593 icov[i] = (double*) malloc(L*sizeof(double));
|
cannam@19
|
594 double detcov;
|
cannam@19
|
595
|
cannam@19
|
596 double** logb = (double**) malloc(T*sizeof(double*));
|
cannam@19
|
597 double** phi = (double**) malloc(T*sizeof(double*));
|
cannam@19
|
598 int** psi = (int**) malloc(T*sizeof(int*));
|
cannam@19
|
599 for (t = 0; t < T; t++)
|
cannam@19
|
600 {
|
cannam@19
|
601 logb[t] = (double*) malloc(N*sizeof(double));
|
cannam@19
|
602 phi[t] = (double*) malloc(N*sizeof(double));
|
cannam@19
|
603 psi[t] = (int*) malloc(N*sizeof(int));
|
cannam@19
|
604 }
|
cannam@19
|
605
|
cannam@19
|
606 /* temporary memory */
|
cannam@19
|
607 double* gauss_y = (double*) malloc(L*sizeof(double));
|
cannam@19
|
608 double* gauss_z = (double*) malloc(L*sizeof(double));
|
cannam@19
|
609
|
cannam@19
|
610 /* calculate observation logprobs */
|
cannam@19
|
611 invert(cov, L, icov, &detcov);
|
cannam@19
|
612 for (t = 0; t < T; t++)
|
cannam@19
|
613 for (i = 0; i < N; i++)
|
cannam@19
|
614 logb[t][i] = loggauss(x[t], L, mu[i], icov, detcov, gauss_y, gauss_z);
|
cannam@19
|
615
|
cannam@19
|
616 /* initialise */
|
cannam@19
|
617 for (i = 0; i < N; i++)
|
cannam@19
|
618 {
|
cannam@19
|
619 phi[0][i] = log(p0[i]) + logb[0][i];
|
cannam@19
|
620 psi[0][i] = 0;
|
cannam@19
|
621 }
|
cannam@19
|
622
|
cannam@19
|
623 for (t = 1; t < T; t++)
|
cannam@19
|
624 {
|
cannam@19
|
625 for (j = 0; j < N; j++)
|
cannam@19
|
626 {
|
cannam@48
|
627 max = -1000000;
|
cannam@48
|
628 havemax = 0;
|
cannam@48
|
629
|
cannam@19
|
630 psi[t][j] = 0;
|
cannam@19
|
631 for (i = 0; i < N; i++)
|
cannam@19
|
632 {
|
cannam@48
|
633 if (phi[t-1][i] + log(a[i][j]) > max || !havemax)
|
cannam@19
|
634 {
|
cannam@19
|
635 max = phi[t-1][i] + log(a[i][j]);
|
cannam@19
|
636 phi[t][j] = max + logb[t][j];
|
cannam@19
|
637 psi[t][j] = i;
|
cannam@48
|
638 havemax = 1;
|
cannam@19
|
639 }
|
cannam@19
|
640 }
|
cannam@19
|
641 }
|
cannam@19
|
642 }
|
cannam@19
|
643
|
cannam@19
|
644 /* find maximising state at time T-1 */
|
cannam@19
|
645 max = phi[T-1][0];
|
cannam@19
|
646 q[T-1] = 0;
|
cannam@19
|
647 for (i = 1; i < N; i++)
|
cannam@19
|
648 {
|
cannam@19
|
649 if (phi[T-1][i] > max)
|
cannam@19
|
650 {
|
cannam@19
|
651 max = phi[T-1][i];
|
cannam@19
|
652 q[T-1] = i;
|
cannam@19
|
653 }
|
cannam@19
|
654 }
|
cannam@19
|
655
|
cannam@19
|
656
|
cannam@19
|
657 /* track back */
|
cannam@19
|
658 t = T - 2;
|
cannam@19
|
659 while (t >= 0)
|
cannam@19
|
660 {
|
cannam@19
|
661 q[t] = psi[t+1][q[t+1]];
|
cannam@19
|
662 t--;
|
cannam@19
|
663 }
|
cannam@19
|
664
|
cannam@19
|
665 /* de-allocate memory */
|
cannam@19
|
666 for (i = 0; i < L; i++)
|
cannam@19
|
667 free(icov[i]);
|
cannam@19
|
668 free(icov);
|
cannam@19
|
669 for (t = 0; t < T; t++)
|
cannam@19
|
670 {
|
cannam@19
|
671 free(logb[t]);
|
cannam@19
|
672 free(phi[t]);
|
cannam@19
|
673 free(psi[t]);
|
cannam@19
|
674 }
|
cannam@19
|
675 free(logb);
|
cannam@19
|
676 free(phi);
|
cannam@19
|
677 free(psi);
|
cannam@19
|
678
|
cannam@19
|
679 free(gauss_y);
|
cannam@19
|
680 free(gauss_z);
|
cannam@19
|
681 }
|
cannam@19
|
682
|
cannam@19
|
683 /* invert matrix and calculate determinant using LAPACK */
|
cannam@19
|
684 void invert(double** cov, int L, double** icov, double* detcov)
|
cannam@19
|
685 {
|
cannam@19
|
686 /* copy square matrix into a vector in column-major order */
|
cannam@19
|
687 double* a = (double*) malloc(L*L*sizeof(double));
|
cannam@19
|
688 int i, j;
|
cannam@19
|
689 for(j=0; j < L; j++)
|
cannam@19
|
690 for (i=0; i < L; i++)
|
cannam@19
|
691 a[j*L+i] = cov[i][j];
|
cannam@19
|
692
|
cannam@44
|
693 int M = (int) L;
|
cannam@44
|
694 int* ipiv = (int *) malloc(L*L*sizeof(int));
|
cannam@44
|
695 int ret;
|
cannam@19
|
696
|
cannam@19
|
697 /* LU decomposition */
|
cannam@19
|
698 ret = dgetrf_(&M, &M, a, &M, ipiv, &ret); /* ret should be zero, negative if cov is singular */
|
cannam@19
|
699 if (ret < 0)
|
cannam@19
|
700 {
|
cannam@19
|
701 fprintf(stderr, "Covariance matrix was singular, couldn't invert\n");
|
cannam@19
|
702 exit(-1);
|
cannam@19
|
703 }
|
cannam@19
|
704
|
cannam@19
|
705 /* find determinant */
|
cannam@19
|
706 double det = 1;
|
cannam@19
|
707 for(i = 0; i < L; i++)
|
cannam@19
|
708 det *= a[i*L+i];
|
cannam@19
|
709 // TODO: get this to work!!! If detcov < 0 then cov is bad anyway...
|
cannam@19
|
710 /*
|
cannam@19
|
711 int sign = 1;
|
cannam@19
|
712 for (i = 0; i < L; i++)
|
cannam@19
|
713 if (ipiv[i] != i)
|
cannam@19
|
714 sign = -sign;
|
cannam@19
|
715 det *= sign;
|
cannam@19
|
716 */
|
cannam@19
|
717 if (det < 0)
|
cannam@19
|
718 det = -det;
|
cannam@19
|
719 *detcov = det;
|
cannam@19
|
720
|
cannam@19
|
721 /* allocate required working storage */
|
cannam@44
|
722 #ifndef HAVE_ATLAS
|
cannam@44
|
723 int lwork = -1;
|
cannam@44
|
724 double lwbest = 0.0;
|
cannam@19
|
725 dgetri_(&M, a, &M, ipiv, &lwbest, &lwork, &ret);
|
cannam@44
|
726 lwork = (int) lwbest;
|
cannam@19
|
727 double* work = (double*) malloc(lwork*sizeof(double));
|
cannam@44
|
728 #endif
|
cannam@19
|
729
|
cannam@19
|
730 /* find inverse */
|
cannam@19
|
731 dgetri_(&M, a, &M, ipiv, work, &lwork, &ret);
|
cannam@44
|
732
|
cannam@19
|
733 for(j=0; j < L; j++)
|
cannam@19
|
734 for (i=0; i < L; i++)
|
cannam@19
|
735 icov[i][j] = a[j*L+i];
|
cannam@19
|
736
|
cannam@44
|
737 #ifndef HAVE_ATLAS
|
cannam@19
|
738 free(work);
|
cannam@44
|
739 #endif
|
cannam@19
|
740 free(a);
|
cannam@19
|
741 }
|
cannam@19
|
742
|
cannam@19
|
743 /* probability of multivariate Gaussian given mean, inverse and determinant of covariance */
|
cannam@19
|
744 double gauss(double* x, int L, double* mu, double** icov, double detcov, double* y, double* z)
|
cannam@19
|
745 {
|
cannam@19
|
746 int i, j;
|
cannam@19
|
747 double s = 0;
|
cannam@19
|
748 for (i = 0; i < L; i++)
|
cannam@19
|
749 y[i] = x[i] - mu[i];
|
cannam@19
|
750 for (i = 0; i < L; i++)
|
cannam@19
|
751 {
|
cannam@19
|
752 //z[i] = 0;
|
cannam@19
|
753 //for (j = 0; j < L; j++)
|
cannam@19
|
754 // z[i] += icov[i][j] * y[j];
|
cannam@19
|
755 z[i] = cblas_ddot(L, &icov[i][0], 1, y, 1);
|
cannam@19
|
756 }
|
cannam@19
|
757 s = cblas_ddot(L, z, 1, y, 1);
|
cannam@19
|
758 //for (i = 0; i < L; i++)
|
cannam@19
|
759 // s += z[i] * y[i];
|
cannam@19
|
760
|
cannam@19
|
761 return exp(-s/2.0) / (pow(2*PI, L/2.0) * sqrt(detcov));
|
cannam@19
|
762 }
|
cannam@19
|
763
|
cannam@19
|
764 /* log probability of multivariate Gaussian given mean, inverse and determinant of covariance */
|
cannam@19
|
765 double loggauss(double* x, int L, double* mu, double** icov, double detcov, double* y, double* z)
|
cannam@19
|
766 {
|
cannam@19
|
767 int i, j;
|
cannam@19
|
768 double s = 0;
|
cannam@19
|
769 double ret;
|
cannam@19
|
770 for (i = 0; i < L; i++)
|
cannam@19
|
771 y[i] = x[i] - mu[i];
|
cannam@19
|
772 for (i = 0; i < L; i++)
|
cannam@19
|
773 {
|
cannam@19
|
774 //z[i] = 0;
|
cannam@19
|
775 //for (j = 0; j < L; j++)
|
cannam@19
|
776 // z[i] += icov[i][j] * y[j];
|
cannam@19
|
777 z[i] = cblas_ddot(L, &icov[i][0], 1, y, 1);
|
cannam@19
|
778 }
|
cannam@19
|
779 s = cblas_ddot(L, z, 1, y, 1);
|
cannam@19
|
780 //for (i = 0; i < L; i++)
|
cannam@19
|
781 // s += z[i] * y[i];
|
cannam@19
|
782
|
cannam@19
|
783 ret = -0.5 * (s + L * log(2*PI) + log(detcov));
|
cannam@19
|
784
|
cannam@19
|
785 /*
|
cannam@19
|
786 // TEST
|
cannam@79
|
787 if (ISINF(ret) > 0)
|
cannam@19
|
788 printf("loggauss returning infinity\n");
|
cannam@79
|
789 if (ISINF(ret) < 0)
|
cannam@19
|
790 printf("loggauss returning -infinity\n");
|
cannam@79
|
791 if (ISNAN(ret))
|
cannam@19
|
792 printf("loggauss returning nan\n");
|
cannam@19
|
793 */
|
cannam@19
|
794
|
cannam@19
|
795 return ret;
|
cannam@19
|
796 }
|
cannam@19
|
797
|
cannam@19
|
798 void hmm_print(model_t* model)
|
cannam@19
|
799 {
|
cannam@19
|
800 int i, j;
|
cannam@19
|
801 printf("p0:\n");
|
cannam@19
|
802 for (i = 0; i < model->N; i++)
|
cannam@19
|
803 printf("%f ", model->p0[i]);
|
cannam@19
|
804 printf("\n\n");
|
cannam@19
|
805 printf("a:\n");
|
cannam@19
|
806 for (i = 0; i < model->N; i++)
|
cannam@19
|
807 {
|
cannam@19
|
808 for (j = 0; j < model->N; j++)
|
cannam@19
|
809 printf("%f ", model->a[i][j]);
|
cannam@19
|
810 printf("\n");
|
cannam@19
|
811 }
|
cannam@19
|
812 printf("\n\n");
|
cannam@19
|
813 printf("mu:\n");
|
cannam@19
|
814 for (i = 0; i < model->N; i++)
|
cannam@19
|
815 {
|
cannam@19
|
816 for (j = 0; j < model->L; j++)
|
cannam@19
|
817 printf("%f ", model->mu[i][j]);
|
cannam@19
|
818 printf("\n");
|
cannam@19
|
819 }
|
cannam@19
|
820 printf("\n\n");
|
cannam@19
|
821 printf("cov:\n");
|
cannam@19
|
822 for (i = 0; i < model->L; i++)
|
cannam@19
|
823 {
|
cannam@19
|
824 for (j = 0; j < model->L; j++)
|
cannam@19
|
825 printf("%f ", model->cov[i][j]);
|
cannam@19
|
826 printf("\n");
|
cannam@19
|
827 }
|
cannam@19
|
828 printf("\n\n");
|
cannam@19
|
829 }
|
cannam@19
|
830
|
cannam@19
|
831
|