Mercurial > hg > qm-dsp
diff maths/pca/pca.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 |
line wrap: on
line diff
--- a/maths/pca/pca.c Fri May 31 11:02:28 2019 +0100 +++ b/maths/pca/pca.c Fri May 31 11:54:32 2019 +0100 @@ -32,58 +32,58 @@ /* Create m * m covariance matrix from given n * m data matrix. */ void covcol(double** data, int n, int m, double** symmat) { -double *mean; -int i, j, j1, j2; + double *mean; + int i, j, j1, j2; /* Allocate storage for mean vector */ -mean = (double*) malloc(m*sizeof(double)); + mean = (double*) malloc(m*sizeof(double)); /* Determine mean of column vectors of input data matrix */ -for (j = 0; j < m; j++) + for (j = 0; j < m; j++) { - mean[j] = 0.0; - for (i = 0; i < n; i++) + mean[j] = 0.0; + for (i = 0; i < n; i++) { - mean[j] += data[i][j]; + mean[j] += data[i][j]; } - mean[j] /= (double)n; + mean[j] /= (double)n; } /* -printf("\nMeans of column vectors:\n"); -for (j = 0; j < m; j++) { - printf("%12.1f",mean[j]); } printf("\n"); - */ + printf("\nMeans of column vectors:\n"); + for (j = 0; j < m; j++) { + printf("%12.1f",mean[j]); } printf("\n"); +*/ /* Center the column vectors. */ -for (i = 0; i < n; i++) + for (i = 0; i < n; i++) { - for (j = 0; j < m; j++) + for (j = 0; j < m; j++) { - data[i][j] -= mean[j]; + data[i][j] -= mean[j]; } } /* Calculate the m * m covariance matrix. */ -for (j1 = 0; j1 < m; j1++) + for (j1 = 0; j1 < m; j1++) { - for (j2 = j1; j2 < m; j2++) + for (j2 = j1; j2 < m; j2++) { - symmat[j1][j2] = 0.0; - for (i = 0; i < n; i++) + symmat[j1][j2] = 0.0; + for (i = 0; i < n; i++) { - symmat[j1][j2] += data[i][j1] * data[i][j2]; + symmat[j1][j2] += data[i][j1] * data[i][j2]; } - symmat[j2][j1] = symmat[j1][j2]; + symmat[j2][j1] = symmat[j1][j2]; } } -free(mean); + free(mean); -return; + return; } @@ -101,84 +101,84 @@ /** Reduce a real, symmetric matrix to a symmetric, tridiag. matrix. */ /* Householder reduction of matrix a to tridiagonal form. -Algorithm: Martin et al., Num. Math. 11, 181-195, 1968. -Ref: Smith et al., Matrix Eigensystem Routines -- EISPACK Guide -Springer-Verlag, 1976, pp. 489-494. -W H Press et al., Numerical Recipes in C, Cambridge U P, -1988, pp. 373-374. */ + Algorithm: Martin et al., Num. Math. 11, 181-195, 1968. + Ref: Smith et al., Matrix Eigensystem Routines -- EISPACK Guide + Springer-Verlag, 1976, pp. 489-494. + W H Press et al., Numerical Recipes in C, Cambridge U P, + 1988, pp. 373-374. */ void tred2(double** a, int n, double* d, double* e) { - int l, k, j, i; - double scale, hh, h, g, f; - - for (i = n-1; i >= 1; i--) + int l, k, j, i; + double scale, hh, h, g, f; + + for (i = n-1; i >= 1; i--) { - l = i - 1; - h = scale = 0.0; - if (l > 0) - { - for (k = 0; k <= l; k++) - scale += fabs(a[i][k]); - if (scale == 0.0) - e[i] = a[i][l]; - else - { - for (k = 0; k <= l; k++) - { - a[i][k] /= scale; - h += a[i][k] * a[i][k]; - } - f = a[i][l]; - g = f>0 ? -sqrt(h) : sqrt(h); - e[i] = scale * g; - h -= f * g; - a[i][l] = f - g; - f = 0.0; - for (j = 0; j <= l; j++) - { - a[j][i] = a[i][j]/h; - g = 0.0; - for (k = 0; k <= j; k++) - g += a[j][k] * a[i][k]; - for (k = j+1; k <= l; k++) - g += a[k][j] * a[i][k]; - e[j] = g / h; - f += e[j] * a[i][j]; - } - hh = f / (h + h); - for (j = 0; j <= l; j++) - { - f = a[i][j]; - e[j] = g = e[j] - hh * f; - for (k = 0; k <= j; k++) - a[j][k] -= (f * e[k] + g * a[i][k]); - } - } - } - else - e[i] = a[i][l]; - d[i] = h; + l = i - 1; + h = scale = 0.0; + if (l > 0) + { + for (k = 0; k <= l; k++) + scale += fabs(a[i][k]); + if (scale == 0.0) + e[i] = a[i][l]; + else + { + for (k = 0; k <= l; k++) + { + a[i][k] /= scale; + h += a[i][k] * a[i][k]; + } + f = a[i][l]; + g = f>0 ? -sqrt(h) : sqrt(h); + e[i] = scale * g; + h -= f * g; + a[i][l] = f - g; + f = 0.0; + for (j = 0; j <= l; j++) + { + a[j][i] = a[i][j]/h; + g = 0.0; + for (k = 0; k <= j; k++) + g += a[j][k] * a[i][k]; + for (k = j+1; k <= l; k++) + g += a[k][j] * a[i][k]; + e[j] = g / h; + f += e[j] * a[i][j]; + } + hh = f / (h + h); + for (j = 0; j <= l; j++) + { + f = a[i][j]; + e[j] = g = e[j] - hh * f; + for (k = 0; k <= j; k++) + a[j][k] -= (f * e[k] + g * a[i][k]); + } + } + } + else + e[i] = a[i][l]; + d[i] = h; } - d[0] = 0.0; - e[0] = 0.0; - for (i = 0; i < n; i++) + d[0] = 0.0; + e[0] = 0.0; + for (i = 0; i < n; i++) { - l = i - 1; - if (d[i]) - { - for (j = 0; j <= l; j++) - { - g = 0.0; - for (k = 0; k <= l; k++) - g += a[i][k] * a[k][j]; - for (k = 0; k <= l; k++) - a[k][j] -= g * a[k][i]; - } - } - d[i] = a[i][i]; - a[i][i] = 1.0; - for (j = 0; j <= l; j++) - a[j][i] = a[i][j] = 0.0; + l = i - 1; + if (d[i]) + { + for (j = 0; j <= l; j++) + { + g = 0.0; + for (k = 0; k <= l; k++) + g += a[i][k] * a[k][j]; + for (k = 0; k <= l; k++) + a[k][j] -= g * a[k][i]; + } + } + d[i] = a[i][i]; + a[i][i] = 1.0; + for (j = 0; j <= l; j++) + a[j][i] = a[i][j] = 0.0; } } @@ -186,171 +186,168 @@ void tqli(double* d, double* e, int n, double** z) { - int m, l, iter, i, k; - double s, r, p, g, f, dd, c, b; - - for (i = 1; i < n; i++) - e[i-1] = e[i]; - e[n-1] = 0.0; - for (l = 0; l < n; l++) + int m, l, iter, i, k; + double s, r, p, g, f, dd, c, b; + + for (i = 1; i < n; i++) + e[i-1] = e[i]; + e[n-1] = 0.0; + for (l = 0; l < n; l++) { - iter = 0; - do - { - for (m = l; m < n-1; m++) - { - dd = fabs(d[m]) + fabs(d[m+1]); - if (fabs(e[m]) + dd == dd) break; - } - if (m != l) - { - if (iter++ == 30) erhand("No convergence in TLQI."); - g = (d[l+1] - d[l]) / (2.0 * e[l]); - r = sqrt((g * g) + 1.0); - g = d[m] - d[l] + e[l] / (g + SIGN(r, g)); - s = c = 1.0; - p = 0.0; - for (i = m-1; i >= l; i--) - { - f = s * e[i]; - b = c * e[i]; - if (fabs(f) >= fabs(g)) + iter = 0; + do + { + for (m = l; m < n-1; m++) + { + dd = fabs(d[m]) + fabs(d[m+1]); + if (fabs(e[m]) + dd == dd) break; + } + if (m != l) + { + if (iter++ == 30) erhand("No convergence in TLQI."); + g = (d[l+1] - d[l]) / (2.0 * e[l]); + r = sqrt((g * g) + 1.0); + g = d[m] - d[l] + e[l] / (g + SIGN(r, g)); + s = c = 1.0; + p = 0.0; + for (i = m-1; i >= l; i--) + { + f = s * e[i]; + b = c * e[i]; + if (fabs(f) >= fabs(g)) { - c = g / f; - r = sqrt((c * c) + 1.0); - e[i+1] = f * r; - c *= (s = 1.0/r); + c = g / f; + r = sqrt((c * c) + 1.0); + e[i+1] = f * r; + c *= (s = 1.0/r); } - else + else { - s = f / g; - r = sqrt((s * s) + 1.0); - e[i+1] = g * r; - s *= (c = 1.0/r); + s = f / g; + r = sqrt((s * s) + 1.0); + e[i+1] = g * r; + s *= (c = 1.0/r); } - g = d[i+1] - p; - r = (d[i] - g) * s + 2.0 * c * b; - p = s * r; - d[i+1] = g + p; - g = c * r - b; - for (k = 0; k < n; k++) - { - f = z[k][i+1]; - z[k][i+1] = s * z[k][i] + c * f; - z[k][i] = c * z[k][i] - s * f; - } - } - d[l] = d[l] - p; - e[l] = g; - e[m] = 0.0; - } - } while (m != l); - } + g = d[i+1] - p; + r = (d[i] - g) * s + 2.0 * c * b; + p = s * r; + d[i+1] = g + p; + g = c * r - b; + for (k = 0; k < n; k++) + { + f = z[k][i+1]; + z[k][i+1] = s * z[k][i] + c * f; + z[k][i] = c * z[k][i] - s * f; + } + } + d[l] = d[l] - p; + e[l] = g; + e[m] = 0.0; + } + } while (m != l); + } } /* In place projection onto basis vectors */ void pca_project(double** data, int n, int m, int ncomponents) { - int i, j, k, k2; - double **symmat, /* **symmat2, */ *evals, *interm; - - //TODO: assert ncomponents < m - - symmat = (double**) malloc(m*sizeof(double*)); - for (i = 0; i < m; i++) - symmat[i] = (double*) malloc(m*sizeof(double)); - - covcol(data, n, m, symmat); - - /********************************************************************* - Eigen-reduction - **********************************************************************/ - + int i, j, k, k2; + double **symmat, /* **symmat2, */ *evals, *interm; + + //TODO: assert ncomponents < m + + symmat = (double**) malloc(m*sizeof(double*)); + for (i = 0; i < m; i++) + symmat[i] = (double*) malloc(m*sizeof(double)); + + covcol(data, n, m, symmat); + + /********************************************************************* + Eigen-reduction + **********************************************************************/ + /* Allocate storage for dummy and new vectors. */ evals = (double*) malloc(m*sizeof(double)); /* Storage alloc. for vector of eigenvalues */ interm = (double*) malloc(m*sizeof(double)); /* Storage alloc. for 'intermediate' vector */ //MALLOC_ARRAY(symmat2,m,m,double); - //for (i = 0; i < m; i++) { - // for (j = 0; j < m; j++) { - // symmat2[i][j] = symmat[i][j]; /* Needed below for col. projections */ - // } - //} + //for (i = 0; i < m; i++) { + // for (j = 0; j < m; j++) { + // symmat2[i][j] = symmat[i][j]; /* Needed below for col. projections */ + // } + //} tred2(symmat, m, evals, interm); /* Triangular decomposition */ -tqli(evals, interm, m, symmat); /* Reduction of sym. trid. matrix */ + tqli(evals, interm, m, symmat); /* Reduction of sym. trid. matrix */ /* evals now contains the eigenvalues, -columns of symmat now contain the associated eigenvectors. */ + columns of symmat now contain the associated eigenvectors. */ /* - printf("\nEigenvalues:\n"); - for (j = m-1; j >= 0; j--) { - printf("%18.5f\n", evals[j]); } - printf("\n(Eigenvalues should be strictly positive; limited\n"); - printf("precision machine arithmetic may affect this.\n"); - printf("Eigenvalues are often expressed as cumulative\n"); - printf("percentages, representing the 'percentage variance\n"); - printf("explained' by the associated axis or principal component.)\n"); - - printf("\nEigenvectors:\n"); - printf("(First three; their definition in terms of original vbes.)\n"); - for (j = 0; j < m; j++) { - for (i = 1; i <= 3; i++) { - printf("%12.4f", symmat[j][m-i]); } - printf("\n"); } - */ + printf("\nEigenvalues:\n"); + for (j = m-1; j >= 0; j--) { + printf("%18.5f\n", evals[j]); } + printf("\n(Eigenvalues should be strictly positive; limited\n"); + printf("precision machine arithmetic may affect this.\n"); + printf("Eigenvalues are often expressed as cumulative\n"); + printf("percentages, representing the 'percentage variance\n"); + printf("explained' by the associated axis or principal component.)\n"); + + printf("\nEigenvectors:\n"); + printf("(First three; their definition in terms of original vbes.)\n"); + for (j = 0; j < m; j++) { + for (i = 1; i <= 3; i++) { + printf("%12.4f", symmat[j][m-i]); } + printf("\n"); } +*/ /* Form projections of row-points on prin. components. */ /* Store in 'data', overwriting original data. */ -for (i = 0; i < n; i++) { - for (j = 0; j < m; j++) { - interm[j] = data[i][j]; } /* data[i][j] will be overwritten */ + for (i = 0; i < n; i++) { + for (j = 0; j < m; j++) { + interm[j] = data[i][j]; } /* data[i][j] will be overwritten */ for (k = 0; k < ncomponents; k++) { - data[i][k] = 0.0; - for (k2 = 0; k2 < m; k2++) { - data[i][k] += interm[k2] * symmat[k2][m-k-1]; } + data[i][k] = 0.0; + for (k2 = 0; k2 < m; k2++) { + data[i][k] += interm[k2] * symmat[k2][m-k-1]; } } -} + } -/* -printf("\nProjections of row-points on first 3 prin. comps.:\n"); - for (i = 0; i < n; i++) { - for (j = 0; j < 3; j++) { - printf("%12.4f", data[i][j]); } - printf("\n"); } - */ +/* + printf("\nProjections of row-points on first 3 prin. comps.:\n"); + for (i = 0; i < n; i++) { + for (j = 0; j < 3; j++) { + printf("%12.4f", data[i][j]); } + printf("\n"); } +*/ /* Form projections of col.-points on first three prin. components. */ /* Store in 'symmat2', overwriting what was stored in this. */ //for (j = 0; j < m; j++) { -// for (k = 0; k < m; k++) { -// interm[k] = symmat2[j][k]; } /*symmat2[j][k] will be overwritten*/ +// for (k = 0; k < m; k++) { +// interm[k] = symmat2[j][k]; } /*symmat2[j][k] will be overwritten*/ // for (i = 0; i < 3; i++) { -// symmat2[j][i] = 0.0; -// for (k2 = 0; k2 < m; k2++) { -// symmat2[j][i] += interm[k2] * symmat[k2][m-i-1]; } -// if (evals[m-i-1] > 0.0005) /* Guard against zero eigenvalue */ -// symmat2[j][i] /= sqrt(evals[m-i-1]); /* Rescale */ -// else -// symmat2[j][i] = 0.0; /* Standard kludge */ +// symmat2[j][i] = 0.0; +// for (k2 = 0; k2 < m; k2++) { +// symmat2[j][i] += interm[k2] * symmat[k2][m-i-1]; } +// if (evals[m-i-1] > 0.0005) /* Guard against zero eigenvalue */ +// symmat2[j][i] /= sqrt(evals[m-i-1]); /* Rescale */ +// else +// symmat2[j][i] = 0.0; /* Standard kludge */ // } // } /* - printf("\nProjections of column-points on first 3 prin. comps.:\n"); - for (j = 0; j < m; j++) { - for (k = 0; k < 3; k++) { - printf("%12.4f", symmat2[j][k]); } - printf("\n"); } - */ + printf("\nProjections of column-points on first 3 prin. comps.:\n"); + for (j = 0; j < m; j++) { + for (k = 0; k < 3; k++) { + printf("%12.4f", symmat2[j][k]); } + printf("\n"); } +*/ -for (i = 0; i < m; i++) - free(symmat[i]); -free(symmat); + for (i = 0; i < m; i++) + free(symmat[i]); + free(symmat); //FREE_ARRAY(symmat2,m); -free(evals); -free(interm); + free(evals); + free(interm); } - - -