annotate ffmpeg/libavutil/pca.c @ 13:844d341cf643 tip

Back up before ISMIR
author Yading Song <yading.song@eecs.qmul.ac.uk>
date Thu, 31 Oct 2013 13:17:06 +0000
parents f445c3017523
children
rev   line source
yading@11 1 /*
yading@11 2 * principal component analysis (PCA)
yading@11 3 * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
yading@11 4 *
yading@11 5 * This file is part of FFmpeg.
yading@11 6 *
yading@11 7 * FFmpeg is free software; you can redistribute it and/or
yading@11 8 * modify it under the terms of the GNU Lesser General Public
yading@11 9 * License as published by the Free Software Foundation; either
yading@11 10 * version 2.1 of the License, or (at your option) any later version.
yading@11 11 *
yading@11 12 * FFmpeg is distributed in the hope that it will be useful,
yading@11 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
yading@11 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
yading@11 15 * Lesser General Public License for more details.
yading@11 16 *
yading@11 17 * You should have received a copy of the GNU Lesser General Public
yading@11 18 * License along with FFmpeg; if not, write to the Free Software
yading@11 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
yading@11 20 */
yading@11 21
yading@11 22 /**
yading@11 23 * @file
yading@11 24 * principal component analysis (PCA)
yading@11 25 */
yading@11 26
yading@11 27 #include "common.h"
yading@11 28 #include "pca.h"
yading@11 29
yading@11 30 typedef struct PCA{
yading@11 31 int count;
yading@11 32 int n;
yading@11 33 double *covariance;
yading@11 34 double *mean;
yading@11 35 double *z;
yading@11 36 }PCA;
yading@11 37
yading@11 38 PCA *ff_pca_init(int n){
yading@11 39 PCA *pca;
yading@11 40 if(n<=0)
yading@11 41 return NULL;
yading@11 42
yading@11 43 pca= av_mallocz(sizeof(*pca));
yading@11 44 pca->n= n;
yading@11 45 pca->z = av_malloc(sizeof(*pca->z) * n);
yading@11 46 pca->count=0;
yading@11 47 pca->covariance= av_calloc(n*n, sizeof(double));
yading@11 48 pca->mean= av_calloc(n, sizeof(double));
yading@11 49
yading@11 50 return pca;
yading@11 51 }
yading@11 52
yading@11 53 void ff_pca_free(PCA *pca){
yading@11 54 av_freep(&pca->covariance);
yading@11 55 av_freep(&pca->mean);
yading@11 56 av_freep(&pca->z);
yading@11 57 av_free(pca);
yading@11 58 }
yading@11 59
yading@11 60 void ff_pca_add(PCA *pca, double *v){
yading@11 61 int i, j;
yading@11 62 const int n= pca->n;
yading@11 63
yading@11 64 for(i=0; i<n; i++){
yading@11 65 pca->mean[i] += v[i];
yading@11 66 for(j=i; j<n; j++)
yading@11 67 pca->covariance[j + i*n] += v[i]*v[j];
yading@11 68 }
yading@11 69 pca->count++;
yading@11 70 }
yading@11 71
yading@11 72 int ff_pca(PCA *pca, double *eigenvector, double *eigenvalue){
yading@11 73 int i, j, pass;
yading@11 74 int k=0;
yading@11 75 const int n= pca->n;
yading@11 76 double *z = pca->z;
yading@11 77
yading@11 78 memset(eigenvector, 0, sizeof(double)*n*n);
yading@11 79
yading@11 80 for(j=0; j<n; j++){
yading@11 81 pca->mean[j] /= pca->count;
yading@11 82 eigenvector[j + j*n] = 1.0;
yading@11 83 for(i=0; i<=j; i++){
yading@11 84 pca->covariance[j + i*n] /= pca->count;
yading@11 85 pca->covariance[j + i*n] -= pca->mean[i] * pca->mean[j];
yading@11 86 pca->covariance[i + j*n] = pca->covariance[j + i*n];
yading@11 87 }
yading@11 88 eigenvalue[j]= pca->covariance[j + j*n];
yading@11 89 z[j]= 0;
yading@11 90 }
yading@11 91
yading@11 92 for(pass=0; pass < 50; pass++){
yading@11 93 double sum=0;
yading@11 94
yading@11 95 for(i=0; i<n; i++)
yading@11 96 for(j=i+1; j<n; j++)
yading@11 97 sum += fabs(pca->covariance[j + i*n]);
yading@11 98
yading@11 99 if(sum == 0){
yading@11 100 for(i=0; i<n; i++){
yading@11 101 double maxvalue= -1;
yading@11 102 for(j=i; j<n; j++){
yading@11 103 if(eigenvalue[j] > maxvalue){
yading@11 104 maxvalue= eigenvalue[j];
yading@11 105 k= j;
yading@11 106 }
yading@11 107 }
yading@11 108 eigenvalue[k]= eigenvalue[i];
yading@11 109 eigenvalue[i]= maxvalue;
yading@11 110 for(j=0; j<n; j++){
yading@11 111 double tmp= eigenvector[k + j*n];
yading@11 112 eigenvector[k + j*n]= eigenvector[i + j*n];
yading@11 113 eigenvector[i + j*n]= tmp;
yading@11 114 }
yading@11 115 }
yading@11 116 return pass;
yading@11 117 }
yading@11 118
yading@11 119 for(i=0; i<n; i++){
yading@11 120 for(j=i+1; j<n; j++){
yading@11 121 double covar= pca->covariance[j + i*n];
yading@11 122 double t,c,s,tau,theta, h;
yading@11 123
yading@11 124 if(pass < 3 && fabs(covar) < sum / (5*n*n)) //FIXME why pass < 3
yading@11 125 continue;
yading@11 126 if(fabs(covar) == 0.0) //FIXME should not be needed
yading@11 127 continue;
yading@11 128 if(pass >=3 && fabs((eigenvalue[j]+z[j])/covar) > (1LL<<32) && fabs((eigenvalue[i]+z[i])/covar) > (1LL<<32)){
yading@11 129 pca->covariance[j + i*n]=0.0;
yading@11 130 continue;
yading@11 131 }
yading@11 132
yading@11 133 h= (eigenvalue[j]+z[j]) - (eigenvalue[i]+z[i]);
yading@11 134 theta=0.5*h/covar;
yading@11 135 t=1.0/(fabs(theta)+sqrt(1.0+theta*theta));
yading@11 136 if(theta < 0.0) t = -t;
yading@11 137
yading@11 138 c=1.0/sqrt(1+t*t);
yading@11 139 s=t*c;
yading@11 140 tau=s/(1.0+c);
yading@11 141 z[i] -= t*covar;
yading@11 142 z[j] += t*covar;
yading@11 143
yading@11 144 #define ROTATE(a,i,j,k,l) {\
yading@11 145 double g=a[j + i*n];\
yading@11 146 double h=a[l + k*n];\
yading@11 147 a[j + i*n]=g-s*(h+g*tau);\
yading@11 148 a[l + k*n]=h+s*(g-h*tau); }
yading@11 149 for(k=0; k<n; k++) {
yading@11 150 if(k!=i && k!=j){
yading@11 151 ROTATE(pca->covariance,FFMIN(k,i),FFMAX(k,i),FFMIN(k,j),FFMAX(k,j))
yading@11 152 }
yading@11 153 ROTATE(eigenvector,k,i,k,j)
yading@11 154 }
yading@11 155 pca->covariance[j + i*n]=0.0;
yading@11 156 }
yading@11 157 }
yading@11 158 for (i=0; i<n; i++) {
yading@11 159 eigenvalue[i] += z[i];
yading@11 160 z[i]=0.0;
yading@11 161 }
yading@11 162 }
yading@11 163
yading@11 164 return -1;
yading@11 165 }
yading@11 166
yading@11 167 #ifdef TEST
yading@11 168
yading@11 169 #undef printf
yading@11 170 #include <stdio.h>
yading@11 171 #include <stdlib.h>
yading@11 172 #include "lfg.h"
yading@11 173
yading@11 174 int main(void){
yading@11 175 PCA *pca;
yading@11 176 int i, j, k;
yading@11 177 #define LEN 8
yading@11 178 double eigenvector[LEN*LEN];
yading@11 179 double eigenvalue[LEN];
yading@11 180 AVLFG prng;
yading@11 181
yading@11 182 av_lfg_init(&prng, 1);
yading@11 183
yading@11 184 pca= ff_pca_init(LEN);
yading@11 185
yading@11 186 for(i=0; i<9000000; i++){
yading@11 187 double v[2*LEN+100];
yading@11 188 double sum=0;
yading@11 189 int pos = av_lfg_get(&prng) % LEN;
yading@11 190 int v2 = av_lfg_get(&prng) % 101 - 50;
yading@11 191 v[0] = av_lfg_get(&prng) % 101 - 50;
yading@11 192 for(j=1; j<8; j++){
yading@11 193 if(j<=pos) v[j]= v[0];
yading@11 194 else v[j]= v2;
yading@11 195 sum += v[j];
yading@11 196 }
yading@11 197 /* for(j=0; j<LEN; j++){
yading@11 198 v[j] -= v[pos];
yading@11 199 }*/
yading@11 200 // sum += av_lfg_get(&prng) % 10;
yading@11 201 /* for(j=0; j<LEN; j++){
yading@11 202 v[j] -= sum/LEN;
yading@11 203 }*/
yading@11 204 // lbt1(v+100,v+100,LEN);
yading@11 205 ff_pca_add(pca, v);
yading@11 206 }
yading@11 207
yading@11 208
yading@11 209 ff_pca(pca, eigenvector, eigenvalue);
yading@11 210 for(i=0; i<LEN; i++){
yading@11 211 pca->count= 1;
yading@11 212 pca->mean[i]= 0;
yading@11 213
yading@11 214 // (0.5^|x|)^2 = 0.5^2|x| = 0.25^|x|
yading@11 215
yading@11 216
yading@11 217 // pca.covariance[i + i*LEN]= pow(0.5, fabs
yading@11 218 for(j=i; j<LEN; j++){
yading@11 219 printf("%f ", pca->covariance[i + j*LEN]);
yading@11 220 }
yading@11 221 printf("\n");
yading@11 222 }
yading@11 223
yading@11 224 for(i=0; i<LEN; i++){
yading@11 225 double v[LEN];
yading@11 226 double error=0;
yading@11 227 memset(v, 0, sizeof(v));
yading@11 228 for(j=0; j<LEN; j++){
yading@11 229 for(k=0; k<LEN; k++){
yading@11 230 v[j] += pca->covariance[FFMIN(k,j) + FFMAX(k,j)*LEN] * eigenvector[i + k*LEN];
yading@11 231 }
yading@11 232 v[j] /= eigenvalue[i];
yading@11 233 error += fabs(v[j] - eigenvector[i + j*LEN]);
yading@11 234 }
yading@11 235 printf("%f ", error);
yading@11 236 }
yading@11 237 printf("\n");
yading@11 238
yading@11 239 for(i=0; i<LEN; i++){
yading@11 240 for(j=0; j<LEN; j++){
yading@11 241 printf("%9.6f ", eigenvector[i + j*LEN]);
yading@11 242 }
yading@11 243 printf(" %9.1f %f\n", eigenvalue[i], eigenvalue[i]/eigenvalue[0]);
yading@11 244 }
yading@11 245
yading@11 246 return 0;
yading@11 247 }
yading@11 248 #endif