Mercurial > hg > qm-dsp
diff hmm/hmm.c @ 483:fdaa63607c15
Untabify, indent, tidy
author | Chris Cannam <cannam@all-day-breakfast.com> |
---|---|
date | Fri, 31 May 2019 11:54:32 +0100 |
parents | 7e8d1f26b098 |
children | d48276a3ae24 |
line wrap: on
line diff
--- a/hmm/hmm.c Fri May 31 11:02:28 2019 +0100 +++ b/hmm/hmm.c Fri May 31 11:54:32 2019 +0100 @@ -16,9 +16,9 @@ #include <math.h> #include <stdlib.h> #include <float.h> -#include <time.h> /* to seed random number generator */ +#include <time.h> /* to seed random number generator */ -#include <clapack.h> /* LAPACK for matrix inversion */ +#include <clapack.h> /* LAPACK for matrix inversion */ #include "maths/nan-inf.h" @@ -37,788 +37,652 @@ #ifdef _MAC_OS_X #include <vecLib/cblas.h> #else -#include <cblas.h> /* BLAS for matrix multiplication */ +#include <cblas.h> /* BLAS for matrix multiplication */ #endif #include "hmm.h" model_t* hmm_init(double** x, int T, int L, int N) { - int i, j, d, e, t; - double s, ss; - - model_t* model; - model = (model_t*) malloc(sizeof(model_t)); - model->N = N; - model->L = L; - model->p0 = (double*) malloc(N*sizeof(double)); - model->a = (double**) malloc(N*sizeof(double*)); - model->mu = (double**) malloc(N*sizeof(double*)); - for (i = 0; i < N; i++) - { - model->a[i] = (double*) malloc(N*sizeof(double)); - model->mu[i] = (double*) malloc(L*sizeof(double)); - } - model->cov = (double**) malloc(L*sizeof(double*)); - for (i = 0; i < L; i++) - model->cov[i] = (double*) malloc(L*sizeof(double)); - - srand(time(0)); - double* global_mean = (double*) malloc(L*sizeof(double)); - - /* find global mean */ - for (d = 0; d < L; d++) - { - global_mean[d] = 0; - for (t = 0; t < T; t++) - global_mean[d] += x[t][d]; - global_mean[d] /= T; - } - - /* calculate global diagonal covariance */ - for (d = 0; d < L; d++) - { - for (e = 0; e < L; e++) - model->cov[d][e] = 0; - for (t = 0; t < T; t++) - model->cov[d][d] += (x[t][d] - global_mean[d]) * (x[t][d] - global_mean[d]); - model->cov[d][d] /= T-1; - } - - /* set all means close to global mean */ - for (i = 0; i < N; i++) - { - for (d = 0; d < L; d++) - { - /* add some random noise related to covariance */ - /* ideally the random number would be Gaussian(0,1), as a hack we make it uniform on [-0.25,0.25] */ - model->mu[i][d] = global_mean[d] + (0.5 * rand() / (double) RAND_MAX - 0.25) * sqrt(model->cov[d][d]); - } - } - - /* random intial and transition probs */ - s = 0; - for (i = 0; i < N; i++) - { - model->p0[i] = 1 + rand() / (double) RAND_MAX; - s += model->p0[i]; - ss = 0; - for (j = 0; j < N; j++) - { - model->a[i][j] = 1 + rand() / (double) RAND_MAX; - ss += model->a[i][j]; - } - for (j = 0; j < N; j++) - { - model->a[i][j] /= ss; - } - } - for (i = 0; i < N; i++) - model->p0[i] /= s; - - free(global_mean); - - return model; + int i, j, d, e, t; + double s, ss; + + model_t* model; + model = (model_t*) malloc(sizeof(model_t)); + model->N = N; + model->L = L; + model->p0 = (double*) malloc(N*sizeof(double)); + model->a = (double**) malloc(N*sizeof(double*)); + model->mu = (double**) malloc(N*sizeof(double*)); + for (i = 0; i < N; i++) { + model->a[i] = (double*) malloc(N*sizeof(double)); + model->mu[i] = (double*) malloc(L*sizeof(double)); + } + model->cov = (double**) malloc(L*sizeof(double*)); + for (i = 0; i < L; i++) { + model->cov[i] = (double*) malloc(L*sizeof(double)); + } + + srand(time(0)); + double* global_mean = (double*) malloc(L*sizeof(double)); + + /* find global mean */ + for (d = 0; d < L; d++) { + global_mean[d] = 0; + for (t = 0; t < T; t++) { + global_mean[d] += x[t][d]; + } + global_mean[d] /= T; + } + + /* calculate global diagonal covariance */ + for (d = 0; d < L; d++) { + for (e = 0; e < L; e++) { + model->cov[d][e] = 0; + } + for (t = 0; t < T; t++) { + model->cov[d][d] += + (x[t][d] - global_mean[d]) * (x[t][d] - global_mean[d]); + } + model->cov[d][d] /= T-1; + } + + /* set all means close to global mean */ + for (i = 0; i < N; i++) { + for (d = 0; d < L; d++) { + /* add some random noise related to covariance */ + /* ideally the random number would be Gaussian(0,1), + as a hack we make it uniform on [-0.25,0.25] */ + model->mu[i][d] = global_mean[d] + + (0.5 * rand() / (double) RAND_MAX - 0.25) + * sqrt(model->cov[d][d]); + } + } + + /* random initial and transition probs */ + s = 0; + for (i = 0; i < N; i++) { + model->p0[i] = 1 + rand() / (double) RAND_MAX; + s += model->p0[i]; + ss = 0; + for (j = 0; j < N; j++) { + model->a[i][j] = 1 + rand() / (double) RAND_MAX; + ss += model->a[i][j]; + } + for (j = 0; j < N; j++) { + model->a[i][j] /= ss; + } + } + for (i = 0; i < N; i++) { + model->p0[i] /= s; + } + + free(global_mean); + + return model; } void hmm_close(model_t* model) { - int i; - - for (i = 0; i < model->N; i++) - { - free(model->a[i]); - free(model->mu[i]); - } - free(model->a); - free(model->mu); - for (i = 0; i < model->L; i++) - free(model->cov[i]); - free(model->cov); - free(model); + int i; + + for (i = 0; i < model->N; i++) { + free(model->a[i]); + free(model->mu[i]); + } + free(model->a); + free(model->mu); + for (i = 0; i < model->L; i++) { + free(model->cov[i]); + } + free(model->cov); + free(model); } void hmm_train(double** x, int T, model_t* model) { - int i, t; - double loglik; /* overall log-likelihood at each iteration */ - - int N = model->N; - int L = model->L; - double* p0 = model->p0; - double** a = model->a; - double** mu = model->mu; - double** cov = model->cov; - - /* allocate memory */ - double** gamma = (double**) malloc(T*sizeof(double*)); - double*** xi = (double***) malloc(T*sizeof(double**)); - for (t = 0; t < T; t++) - { - gamma[t] = (double*) malloc(N*sizeof(double)); - xi[t] = (double**) malloc(N*sizeof(double*)); - for (i = 0; i < N; i++) - xi[t][i] = (double*) malloc(N*sizeof(double)); - } - - /* temporary memory */ - double* gauss_y = (double*) malloc(L*sizeof(double)); - double* gauss_z = (double*) malloc(L*sizeof(double)); - - /* obs probs P(j|{x}) */ - double** b = (double**) malloc(T*sizeof(double*)); - for (t = 0; t < T; t++) - b[t] = (double*) malloc(N*sizeof(double)); - - /* inverse covariance and its determinant */ - double** icov = (double**) malloc(L*sizeof(double*)); - for (i = 0; i < L; i++) - icov[i] = (double*) malloc(L*sizeof(double)); - double detcov; - - double thresh = 0.0001; - int niter = 50; - int iter = 0; - double loglik1, loglik2; - int foundnan = 0; + int i, t; + double loglik; /* overall log-likelihood at each iteration */ + + int N = model->N; + int L = model->L; + double* p0 = model->p0; + double** a = model->a; + double** mu = model->mu; + double** cov = model->cov; + + /* allocate memory */ + double** gamma = (double**) malloc(T*sizeof(double*)); + double*** xi = (double***) malloc(T*sizeof(double**)); + for (t = 0; t < T; t++) { + gamma[t] = (double*) malloc(N*sizeof(double)); + xi[t] = (double**) malloc(N*sizeof(double*)); + for (i = 0; i < N; i++) { + xi[t][i] = (double*) malloc(N*sizeof(double)); + } + } + + /* temporary memory */ + double* gauss_y = (double*) malloc(L*sizeof(double)); + double* gauss_z = (double*) malloc(L*sizeof(double)); + + /* obs probs P(j|{x}) */ + double** b = (double**) malloc(T*sizeof(double*)); + for (t = 0; t < T; t++) { + b[t] = (double*) malloc(N*sizeof(double)); + } + + /* inverse covariance and its determinant */ + double** icov = (double**) malloc(L*sizeof(double*)); + for (i = 0; i < L; i++) { + icov[i] = (double*) malloc(L*sizeof(double)); + } + double detcov; + + double thresh = 0.0001; + int niter = 50; + int iter = 0; + double loglik1, loglik2; + int foundnan = 0; - while (iter < niter && !foundnan && !(iter > 1 && (loglik - loglik1) < thresh * (loglik1 - loglik2))) - { - ++iter; -/* - fprintf(stderr, "calculating obsprobs...\n"); - fflush(stderr); -*/ - /* precalculate obs probs */ - invert(cov, L, icov, &detcov); - - for (t = 0; t < T; t++) - { - //int allzero = 1; - for (i = 0; i < N; i++) - { - b[t][i] = exp(loggauss(x[t], L, mu[i], icov, detcov, gauss_y, gauss_z)); - - //if (b[t][i] != 0) - // allzero = 0; - } - /* - if (allzero) - { - printf("all the b[t][i] were zero for t = %d, correcting...\n", t); - for (i = 0; i < N; i++) - { - b[t][i] = 0.00001; - } - } - */ - } -/* - fprintf(stderr, "forwards-backwards...\n"); - fflush(stderr); -*/ - forward_backwards(xi, gamma, &loglik, &loglik1, &loglik2, iter, N, T, p0, a, b); -/* - fprintf(stderr, "iteration %d: loglik = %f\n", iter, loglik); - fprintf(stderr, "re-estimation...\n"); - fflush(stderr); -*/ - if (ISNAN(loglik)) { - foundnan = 1; - continue; - } - - baum_welch(p0, a, mu, cov, N, T, L, x, xi, gamma); - - /* - printf("a:\n"); - for (i = 0; i < model->N; i++) - { - for (j = 0; j < model->N; j++) - printf("%f ", model->a[i][j]); - printf("\n"); - } - printf("\n\n"); - */ - //hmm_print(model); - } - - /* deallocate memory */ - for (t = 0; t < T; t++) - { - free(gamma[t]); - free(b[t]); - for (i = 0; i < N; i++) - free(xi[t][i]); - free(xi[t]); - } - free(gamma); - free(xi); - free(b); - - for (i = 0; i < L; i++) - free(icov[i]); - free(icov); - - free(gauss_y); - free(gauss_z); + while (iter < niter && !foundnan && + !(iter > 1 && (loglik - loglik1) < thresh * (loglik1 - loglik2))) { + + ++iter; + + /* precalculate obs probs */ + invert(cov, L, icov, &detcov); + + for (t = 0; t < T; t++) { + for (i = 0; i < N; i++) { + b[t][i] = exp(loggauss(x[t], L, mu[i], icov, detcov, gauss_y, gauss_z)); + } + } + forward_backwards(xi, gamma, &loglik, &loglik1, &loglik2, + iter, N, T, p0, a, b); + if (ISNAN(loglik)) { + foundnan = 1; + continue; + } + + baum_welch(p0, a, mu, cov, N, T, L, x, xi, gamma); + } + + /* deallocate memory */ + for (t = 0; t < T; t++) { + free(gamma[t]); + free(b[t]); + for (i = 0; i < N; i++) { + free(xi[t][i]); + } + free(xi[t]); + } + free(gamma); + free(xi); + free(b); + + for (i = 0; i < L; i++) { + free(icov[i]); + } + free(icov); + + free(gauss_y); + free(gauss_z); } -void baum_welch(double* p0, double** a, double** mu, double** cov, int N, int T, int L, double** x, double*** xi, double** gamma) +void baum_welch(double* p0, double** a, double** mu, double** cov, + int N, int T, int L, double** x, double*** xi, double** gamma) { - int i, j, t; - - double* sum_gamma = (double*) malloc(N*sizeof(double)); - - /* temporary memory */ - double* u = (double*) malloc(L*L*sizeof(double)); - double* yy = (double*) malloc(T*L*sizeof(double)); - double* yy2 = (double*) malloc(T*L*sizeof(double)); - - /* re-estimate transition probs */ - for (i = 0; i < N; i++) - { - sum_gamma[i] = 0; - for (t = 0; t < T-1; t++) - sum_gamma[i] += gamma[t][i]; - } - - for (i = 0; i < N; i++) - { - if (sum_gamma[i] == 0) - { -/* fprintf(stderr, "sum_gamma[%d] was zero...\n", i); */ - } - //double s = 0; - for (j = 0; j < N; j++) - { - a[i][j] = 0; - if (sum_gamma[i] == 0.) continue; - for (t = 0; t < T-1; t++) - a[i][j] += xi[t][i][j]; - //s += a[i][j]; - a[i][j] /= sum_gamma[i]; - } - /* - for (j = 0; j < N; j++) - { - a[i][j] /= s; - } - */ - } - - /* NB: now we need to sum gamma over all t */ - for (i = 0; i < N; i++) - sum_gamma[i] += gamma[T-1][i]; - - /* re-estimate initial probs */ - for (i = 0; i < N; i++) - p0[i] = gamma[0][i]; - - /* re-estimate covariance */ - int d, e; - double sum_sum_gamma = 0; - for (i = 0; i < N; i++) - sum_sum_gamma += sum_gamma[i]; - - /* - for (d = 0; d < L; d++) - { - for (e = d; e < L; e++) - { - cov[d][e] = 0; - for (t = 0; t < T; t++) - for (j = 0; j < N; j++) - cov[d][e] += gamma[t][j] * (x[t][d] - mu[j][d]) * (x[t][e] - mu[j][e]); - - cov[d][e] /= sum_sum_gamma; - - if (ISNAN(cov[d][e])) - { - printf("cov[%d][%d] was nan\n", d, e); - for (j = 0; j < N; j++) - for (i = 0; i < L; i++) - if (ISNAN(mu[j][i])) - printf("mu[%d][%d] was nan\n", j, i); - for (t = 0; t < T; t++) - for (j = 0; j < N; j++) - if (ISNAN(gamma[t][j])) - printf("gamma[%d][%d] was nan\n", t, j); - exit(-1); - } - } - } - for (d = 0; d < L; d++) - for (e = 0; e < d; e++) - cov[d][e] = cov[e][d]; - */ - - /* using BLAS */ - for (d = 0; d < L; d++) - for (e = 0; e < L; e++) - cov[d][e] = 0; - - for (j = 0; j < N; j++) - { - for (d = 0; d < L; d++) - for (t = 0; t < T; t++) - { - yy[d*T+t] = x[t][d] - mu[j][d]; - yy2[d*T+t] = gamma[t][j] * (x[t][d] - mu[j][d]); - } - - cblas_dgemm(CblasColMajor, CblasTrans, CblasNoTrans, L, L, T, 1.0, yy, T, yy2, T, 0, u, L); - - for (e = 0; e < L; e++) - for (d = 0; d < L; d++) - cov[d][e] += u[e*L+d]; - } - - for (d = 0; d < L; d++) - for (e = 0; e < L; e++) - cov[d][e] /= T; /* sum_sum_gamma; */ - - //printf("sum_sum_gamma = %f\n", sum_sum_gamma); /* fine, = T IS THIS ALWAYS TRUE with pooled cov?? */ - - /* re-estimate means */ - for (j = 0; j < N; j++) - { - for (d = 0; d < L; d++) - { - mu[j][d] = 0; - for (t = 0; t < T; t++) - mu[j][d] += gamma[t][j] * x[t][d]; - mu[j][d] /= sum_gamma[j]; - } - } - - /* deallocate memory */ - free(sum_gamma); - free(yy); - free(yy2); - free(u); + int i, j, t; + + double* sum_gamma = (double*) malloc(N*sizeof(double)); + + /* temporary memory */ + double* u = (double*) malloc(L*L*sizeof(double)); + double* yy = (double*) malloc(T*L*sizeof(double)); + double* yy2 = (double*) malloc(T*L*sizeof(double)); + + /* re-estimate transition probs */ + for (i = 0; i < N; i++) { + sum_gamma[i] = 0; + for (t = 0; t < T-1; t++) { + sum_gamma[i] += gamma[t][i]; + } + } + + for (i = 0; i < N; i++) { + for (j = 0; j < N; j++) { + a[i][j] = 0; + if (sum_gamma[i] == 0.) { + continue; + } + for (t = 0; t < T-1; t++) { + a[i][j] += xi[t][i][j]; + } + a[i][j] /= sum_gamma[i]; + } + } + + /* NB: now we need to sum gamma over all t */ + for (i = 0; i < N; i++) { + sum_gamma[i] += gamma[T-1][i]; + } + + /* re-estimate initial probs */ + for (i = 0; i < N; i++) { + p0[i] = gamma[0][i]; + } + + /* re-estimate covariance */ + int d, e; + double sum_sum_gamma = 0; + for (i = 0; i < N; i++) { + sum_sum_gamma += sum_gamma[i]; + } + + /* using BLAS */ + for (d = 0; d < L; d++) { + for (e = 0; e < L; e++) { + cov[d][e] = 0; + } + } + + for (j = 0; j < N; j++) { + + for (d = 0; d < L; d++) { + for (t = 0; t < T; t++) { + yy[d*T+t] = x[t][d] - mu[j][d]; + yy2[d*T+t] = gamma[t][j] * (x[t][d] - mu[j][d]); + } + } + + cblas_dgemm(CblasColMajor, CblasTrans, CblasNoTrans, + L, L, T, 1.0, yy, T, yy2, T, 0, u, L); + + for (e = 0; e < L; e++) { + for (d = 0; d < L; d++) { + cov[d][e] += u[e*L+d]; + } + } + } + + for (d = 0; d < L; d++) { + for (e = 0; e < L; e++) { + cov[d][e] /= T; /* sum_sum_gamma; */ + } + } + + //printf("sum_sum_gamma = %f\n", sum_sum_gamma); /* fine, = T IS THIS ALWAYS TRUE with pooled cov?? */ + + /* re-estimate means */ + for (j = 0; j < N; j++) { + for (d = 0; d < L; d++) { + mu[j][d] = 0; + for (t = 0; t < T; t++) + mu[j][d] += gamma[t][j] * x[t][d]; + mu[j][d] /= sum_gamma[j]; + } + } + + /* deallocate memory */ + free(sum_gamma); + free(yy); + free(yy2); + free(u); } -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) +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) { - /* forwards-backwards with scaling */ - int i, j, t; + /* forwards-backwards with scaling */ + int i, j, t; + + double** alpha = (double**) malloc(T*sizeof(double*)); + double** beta = (double**) malloc(T*sizeof(double*)); + for (t = 0; t < T; t++) { + alpha[t] = (double*) malloc(N*sizeof(double)); + beta[t] = (double*) malloc(N*sizeof(double)); + } + + /* scaling coefficients */ + double* c = (double*) malloc(T*sizeof(double)); + + /* calculate forward probs and scale coefficients */ + c[0] = 0; + for (i = 0; i < N; i++) { + alpha[0][i] = p0[i] * b[0][i]; + c[0] += alpha[0][i]; + } + c[0] = 1 / c[0]; + for (i = 0; i < N; i++) { + alpha[0][i] *= c[0]; + } + + *loglik1 = *loglik; + *loglik = -log(c[0]); + if (iter == 2) { + *loglik2 = *loglik; + } + + for (t = 1; t < T; t++) { + + c[t] = 0; + + for (j = 0; j < N; j++) { + alpha[t][j] = 0; + for (i = 0; i < N; i++) { + alpha[t][j] += alpha[t-1][i] * a[i][j]; + } + alpha[t][j] *= b[t][j]; + + c[t] += alpha[t][j]; + } + + c[t] = 1 / c[t]; + for (j = 0; j < N; j++) { + alpha[t][j] *= c[t]; + } + + *loglik -= log(c[t]); + } + + /* calculate backwards probs using same coefficients */ + for (i = 0; i < N; i++) { + beta[T-1][i] = 1; + } + t = T - 1; + + while (1) { + for (i = 0; i < N; i++) { + beta[t][i] *= c[t]; + } + + if (t == 0) { + break; + } + + for (i = 0; i < N; i++) { + beta[t-1][i] = 0; + for (j = 0; j < N; j++) { + beta[t-1][i] += a[i][j] * b[t][j] * beta[t][j]; + } + } + + t--; + } - double** alpha = (double**) malloc(T*sizeof(double*)); - double** beta = (double**) malloc(T*sizeof(double*)); - for (t = 0; t < T; t++) - { - alpha[t] = (double*) malloc(N*sizeof(double)); - beta[t] = (double*) malloc(N*sizeof(double)); - } + /* calculate posterior probs */ + double tot; + for (t = 0; t < T; t++) { + tot = 0; + for (i = 0; i < N; i++) { + gamma[t][i] = alpha[t][i] * beta[t][i]; + tot += gamma[t][i]; + } + for (i = 0; i < N; i++) { + gamma[t][i] /= tot; + } + } - /* scaling coefficients */ - double* c = (double*) malloc(T*sizeof(double)); + for (t = 0; t < T-1; t++) { + tot = 0; + for (i = 0; i < N; i++) { + for (j = 0; j < N; j++) { + xi[t][i][j] = alpha[t][i] * a[i][j] * b[t+1][j] * beta[t+1][j]; + tot += xi[t][i][j]; + } + } + for (i = 0; i < N; i++) { + for (j = 0; j < N; j++) { + xi[t][i][j] /= tot; + } + } + } - /* calculate forward probs and scale coefficients */ - c[0] = 0; - for (i = 0; i < N; i++) - { - alpha[0][i] = p0[i] * b[0][i]; - c[0] += alpha[0][i]; - - //printf("p0[%d] = %f, b[0][%d] = %f\n", i, p0[i], i, b[0][i]); - } - c[0] = 1 / c[0]; - for (i = 0; i < N; i++) - { - alpha[0][i] *= c[0]; - - //printf("alpha[0][%d] = %f\n", i, alpha[0][i]); /* OK agrees with Matlab */ - } - - *loglik1 = *loglik; - *loglik = -log(c[0]); - if (iter == 2) - *loglik2 = *loglik; - - for (t = 1; t < T; t++) - { - c[t] = 0; - for (j = 0; j < N; j++) - { - alpha[t][j] = 0; - for (i = 0; i < N; i++) - alpha[t][j] += alpha[t-1][i] * a[i][j]; - alpha[t][j] *= b[t][j]; - - c[t] += alpha[t][j]; - } - - /* - if (c[t] == 0) - { - printf("c[%d] = 0, going to blow up so exiting\n", t); - for (i = 0; i < N; i++) - if (b[t][i] == 0) - fprintf(stderr, "b[%d][%d] was zero\n", t, i); - fprintf(stderr, "x[t] was \n"); - for (i = 0; i < L; i++) - fprintf(stderr, "%f ", x[t][i]); - fprintf(stderr, "\n\n"); - exit(-1); - } - */ - - c[t] = 1 / c[t]; - for (j = 0; j < N; j++) - alpha[t][j] *= c[t]; - - //printf("c[%d] = %e\n", t, c[t]); - - *loglik -= log(c[t]); - } - - /* calculate backwards probs using same coefficients */ - for (i = 0; i < N; i++) - beta[T-1][i] = 1; - t = T - 1; - while (1) - { - for (i = 0; i < N; i++) - beta[t][i] *= c[t]; - - if (t == 0) - break; - - for (i = 0; i < N; i++) - { - beta[t-1][i] = 0; - for (j = 0; j < N; j++) - beta[t-1][i] += a[i][j] * b[t][j] * beta[t][j]; - } - - t--; - } - - /* - printf("alpha:\n"); - for (t = 0; t < T; t++) - { - for (i = 0; i < N; i++) - printf("%4.4e\t\t", alpha[t][i]); - printf("\n"); - } - printf("\n\n");printf("beta:\n"); - for (t = 0; t < T; t++) - { - for (i = 0; i < N; i++) - printf("%4.4e\t\t", beta[t][i]); - printf("\n"); - } - printf("\n\n"); - */ - - /* calculate posterior probs */ - double tot; - for (t = 0; t < T; t++) - { - tot = 0; - for (i = 0; i < N; i++) - { - gamma[t][i] = alpha[t][i] * beta[t][i]; - tot += gamma[t][i]; - } - for (i = 0; i < N; i++) - { - gamma[t][i] /= tot; - - //printf("gamma[%d][%d] = %f\n", t, i, gamma[t][i]); - } - } - - for (t = 0; t < T-1; t++) - { - tot = 0; - for (i = 0; i < N; i++) - { - for (j = 0; j < N; j++) - { - xi[t][i][j] = alpha[t][i] * a[i][j] * b[t+1][j] * beta[t+1][j]; - tot += xi[t][i][j]; - } - } - for (i = 0; i < N; i++) - for (j = 0; j < N; j++) - xi[t][i][j] /= tot; - } - - /* - // CHECK - fine - // gamma[t][i] = \sum_j{xi[t][i][j]} - tot = 0; - for (j = 0; j < N; j++) - tot += xi[3][1][j]; - printf("gamma[3][1] = %f, sum_j(xi[3][1][j]) = %f\n", gamma[3][1], tot); - */ - - for (t = 0; t < T; t++) - { - free(alpha[t]); - free(beta[t]); - } - free(alpha); - free(beta); - free(c); + for (t = 0; t < T; t++) { + free(alpha[t]); + free(beta[t]); + } + free(alpha); + free(beta); + free(c); } void viterbi_decode(double** x, int T, model_t* model, int* q) { - int i, j, t; - double max; - int havemax; + int i, j, t; + double max; + int havemax; - int N = model->N; - int L = model->L; - double* p0 = model->p0; - double** a = model->a; - double** mu = model->mu; - double** cov = model->cov; + int N = model->N; + int L = model->L; + double* p0 = model->p0; + double** a = model->a; + double** mu = model->mu; + double** cov = model->cov; - /* inverse covariance and its determinant */ - double** icov = (double**) malloc(L*sizeof(double*)); - for (i = 0; i < L; i++) - icov[i] = (double*) malloc(L*sizeof(double)); - double detcov; + /* inverse covariance and its determinant */ + double** icov = (double**) malloc(L*sizeof(double*)); + for (i = 0; i < L; i++) { + icov[i] = (double*) malloc(L*sizeof(double)); + } + double detcov; - double** logb = (double**) malloc(T*sizeof(double*)); - double** phi = (double**) malloc(T*sizeof(double*)); - int** psi = (int**) malloc(T*sizeof(int*)); - for (t = 0; t < T; t++) - { - logb[t] = (double*) malloc(N*sizeof(double)); - phi[t] = (double*) malloc(N*sizeof(double)); - psi[t] = (int*) malloc(N*sizeof(int)); - } + double** logb = (double**) malloc(T*sizeof(double*)); + double** phi = (double**) malloc(T*sizeof(double*)); + int** psi = (int**) malloc(T*sizeof(int*)); + + for (t = 0; t < T; t++) { + logb[t] = (double*) malloc(N*sizeof(double)); + phi[t] = (double*) malloc(N*sizeof(double)); + psi[t] = (int*) malloc(N*sizeof(int)); + } - /* temporary memory */ - double* gauss_y = (double*) malloc(L*sizeof(double)); - double* gauss_z = (double*) malloc(L*sizeof(double)); + /* temporary memory */ + double* gauss_y = (double*) malloc(L*sizeof(double)); + double* gauss_z = (double*) malloc(L*sizeof(double)); - /* calculate observation logprobs */ - invert(cov, L, icov, &detcov); - for (t = 0; t < T; t++) - for (i = 0; i < N; i++) - logb[t][i] = loggauss(x[t], L, mu[i], icov, detcov, gauss_y, gauss_z); + /* calculate observation logprobs */ + invert(cov, L, icov, &detcov); + for (t = 0; t < T; t++) { + for (i = 0; i < N; i++) { + logb[t][i] = loggauss + (x[t], L, mu[i], icov, detcov, gauss_y, gauss_z); + } + } - /* initialise */ - for (i = 0; i < N; i++) - { - phi[0][i] = log(p0[i]) + logb[0][i]; - psi[0][i] = 0; - } + /* initialise */ + for (i = 0; i < N; i++) { + phi[0][i] = log(p0[i]) + logb[0][i]; + psi[0][i] = 0; + } - for (t = 1; t < T; t++) - { - for (j = 0; j < N; j++) - { - max = -1000000; - havemax = 0; + for (t = 1; t < T; t++) { + for (j = 0; j < N; j++) { + max = -1000000; + havemax = 0; - psi[t][j] = 0; - for (i = 0; i < N; i++) - { - if (phi[t-1][i] + log(a[i][j]) > max || !havemax) - { - max = phi[t-1][i] + log(a[i][j]); - phi[t][j] = max + logb[t][j]; - psi[t][j] = i; - havemax = 1; - } - } - } - } + psi[t][j] = 0; + for (i = 0; i < N; i++) { + if (phi[t-1][i] + log(a[i][j]) > max || !havemax) { + max = phi[t-1][i] + log(a[i][j]); + phi[t][j] = max + logb[t][j]; + psi[t][j] = i; + havemax = 1; + } + } + } + } - /* find maximising state at time T-1 */ - max = phi[T-1][0]; - q[T-1] = 0; - for (i = 1; i < N; i++) - { - if (phi[T-1][i] > max) - { - max = phi[T-1][i]; - q[T-1] = i; - } - } - + /* find maximising state at time T-1 */ + max = phi[T-1][0]; + q[T-1] = 0; + for (i = 1; i < N; i++) { + if (phi[T-1][i] > max) { + max = phi[T-1][i]; + q[T-1] = i; + } + } - /* track back */ - t = T - 2; - while (t >= 0) - { - q[t] = psi[t+1][q[t+1]]; - t--; - } + /* track back */ + t = T - 2; + while (t >= 0) { + q[t] = psi[t+1][q[t+1]]; + t--; + } - /* de-allocate memory */ - for (i = 0; i < L; i++) - free(icov[i]); - free(icov); - for (t = 0; t < T; t++) - { - free(logb[t]); - free(phi[t]); - free(psi[t]); - } - free(logb); - free(phi); - free(psi); + /* de-allocate memory */ + for (i = 0; i < L; i++) { + free(icov[i]); + } + free(icov); + for (t = 0; t < T; t++) { + free(logb[t]); + free(phi[t]); + free(psi[t]); + } + free(logb); + free(phi); + free(psi); - free(gauss_y); - free(gauss_z); + free(gauss_y); + free(gauss_z); } /* invert matrix and calculate determinant using LAPACK */ void invert(double** cov, int L, double** icov, double* detcov) { - /* copy square matrix into a vector in column-major order */ - double* a = (double*) malloc(L*L*sizeof(double)); - int i, j; - for(j=0; j < L; j++) - for (i=0; i < L; i++) - a[j*L+i] = cov[i][j]; + /* copy square matrix into a vector in column-major order */ + double* a = (double*) malloc(L*L*sizeof(double)); + int i, j; + for (j=0; j < L; j++) { + for (i=0; i < L; i++) { + a[j*L+i] = cov[i][j]; + } + } - int M = (int) L; - int* ipiv = (int *) malloc(L*L*sizeof(int)); - int ret; + int M = (int) L; + int* ipiv = (int *) malloc(L*L*sizeof(int)); + int ret; - /* LU decomposition */ - ret = dgetrf_(&M, &M, a, &M, ipiv, &ret); /* ret should be zero, negative if cov is singular */ - if (ret < 0) - { - fprintf(stderr, "Covariance matrix was singular, couldn't invert\n"); - exit(-1); - } + /* LU decomposition */ + ret = dgetrf_(&M, &M, a, &M, ipiv, &ret); /* ret should be zero, negative if cov is singular */ + if (ret < 0) { + fprintf(stderr, "Covariance matrix was singular, couldn't invert\n"); + exit(-1); + } - /* find determinant */ - double det = 1; - for(i = 0; i < L; i++) - det *= a[i*L+i]; - // TODO: get this to work!!! If detcov < 0 then cov is bad anyway... - /* - int sign = 1; - for (i = 0; i < L; i++) - if (ipiv[i] != i) - sign = -sign; - det *= sign; - */ - if (det < 0) - det = -det; - *detcov = det; + /* find determinant */ + double det = 1; + for (i = 0; i < L; i++) { + det *= a[i*L+i]; + } + + // TODO: get this to work!!! If detcov < 0 then cov is bad anyway... + if (det < 0) { + det = -det; + } + *detcov = det; - /* allocate required working storage */ + /* allocate required working storage */ #ifndef HAVE_ATLAS - int lwork = -1; - double lwbest = 0.0; - dgetri_(&M, a, &M, ipiv, &lwbest, &lwork, &ret); - lwork = (int) lwbest; - double* work = (double*) malloc(lwork*sizeof(double)); + int lwork = -1; + double lwbest = 0.0; + dgetri_(&M, a, &M, ipiv, &lwbest, &lwork, &ret); + lwork = (int) lwbest; + double* work = (double*) malloc(lwork*sizeof(double)); #endif - /* find inverse */ - dgetri_(&M, a, &M, ipiv, work, &lwork, &ret); + /* find inverse */ + dgetri_(&M, a, &M, ipiv, work, &lwork, &ret); - for(j=0; j < L; j++) - for (i=0; i < L; i++) - icov[i][j] = a[j*L+i]; + for (j=0; j < L; j++) { + for (i=0; i < L; i++) { + icov[i][j] = a[j*L+i]; + } + } #ifndef HAVE_ATLAS - free(work); + free(work); #endif - free(a); + free(a); } /* probability of multivariate Gaussian given mean, inverse and determinant of covariance */ double gauss(double* x, int L, double* mu, double** icov, double detcov, double* y, double* z) { - int i; - double s = 0; - for (i = 0; i < L; i++) - y[i] = x[i] - mu[i]; - for (i = 0; i < L; i++) - { - //z[i] = 0; - //for (j = 0; j < L; j++) - // z[i] += icov[i][j] * y[j]; - z[i] = cblas_ddot(L, &icov[i][0], 1, y, 1); - } - s = cblas_ddot(L, z, 1, y, 1); - //for (i = 0; i < L; i++) - // s += z[i] * y[i]; + int i; + double s = 0; + + for (i = 0; i < L; i++) { + y[i] = x[i] - mu[i]; + } + + for (i = 0; i < L; i++) { + z[i] = cblas_ddot(L, &icov[i][0], 1, y, 1); + } + + s = cblas_ddot(L, z, 1, y, 1); - return exp(-s/2.0) / (pow(2*PI, L/2.0) * sqrt(detcov)); + return exp(-s/2.0) / (pow(2*PI, L/2.0) * sqrt(detcov)); } /* log probability of multivariate Gaussian given mean, inverse and determinant of covariance */ double loggauss(double* x, int L, double* mu, double** icov, double detcov, double* y, double* z) { - int i; - double s = 0; - double ret; - for (i = 0; i < L; i++) - y[i] = x[i] - mu[i]; - for (i = 0; i < L; i++) - { - //z[i] = 0; - //for (j = 0; j < L; j++) - // z[i] += icov[i][j] * y[j]; - z[i] = cblas_ddot(L, &icov[i][0], 1, y, 1); - } - s = cblas_ddot(L, z, 1, y, 1); - //for (i = 0; i < L; i++) - // s += z[i] * y[i]; + int i; + double s = 0; + double ret; + + for (i = 0; i < L; i++) { + y[i] = x[i] - mu[i]; + } + + for (i = 0; i < L; i++) { + z[i] = cblas_ddot(L, &icov[i][0], 1, y, 1); + } + + s = cblas_ddot(L, z, 1, y, 1); - ret = -0.5 * (s + L * log(2*PI) + log(detcov)); + ret = -0.5 * (s + L * log(2*PI) + log(detcov)); - /* - // TEST - if (ISINF(ret) > 0) - printf("loggauss returning infinity\n"); - if (ISINF(ret) < 0) - printf("loggauss returning -infinity\n"); - if (ISNAN(ret)) - printf("loggauss returning nan\n"); - */ - - return ret; + return ret; } void hmm_print(model_t* model) { - int i, j; - printf("p0:\n"); - for (i = 0; i < model->N; i++) - printf("%f ", model->p0[i]); - printf("\n\n"); - printf("a:\n"); - for (i = 0; i < model->N; i++) - { - for (j = 0; j < model->N; j++) - printf("%f ", model->a[i][j]); - printf("\n"); - } - printf("\n\n"); - printf("mu:\n"); - for (i = 0; i < model->N; i++) - { - for (j = 0; j < model->L; j++) - printf("%f ", model->mu[i][j]); - printf("\n"); - } - printf("\n\n"); - printf("cov:\n"); - for (i = 0; i < model->L; i++) - { - for (j = 0; j < model->L; j++) - printf("%f ", model->cov[i][j]); - printf("\n"); - } - printf("\n\n"); + int i, j; + printf("p0:\n"); + for (i = 0; i < model->N; i++) { + printf("%f ", model->p0[i]); + } + printf("\n\n"); + printf("a:\n"); + for (i = 0; i < model->N; i++) { + for (j = 0; j < model->N; j++) { + printf("%f ", model->a[i][j]); + } + printf("\n"); + } + printf("\n\n"); + printf("mu:\n"); + for (i = 0; i < model->N; i++) { + for (j = 0; j < model->L; j++) { + printf("%f ", model->mu[i][j]); + } + printf("\n"); + } + printf("\n\n"); + printf("cov:\n"); + for (i = 0; i < model->L; i++) { + for (j = 0; j < model->L; j++) { + printf("%f ", model->cov[i][j]); + } + printf("\n"); + } + printf("\n\n"); }