annotate hmm/hmm.c @ 172:17a7d6bb9af6

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