annotate hmm/hmm.c @ 73:dcb555b90924

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