yading@11: /* yading@11: * principal component analysis (PCA) yading@11: * Copyright (c) 2004 Michael Niedermayer yading@11: * yading@11: * This file is part of FFmpeg. yading@11: * yading@11: * FFmpeg is free software; you can redistribute it and/or yading@11: * modify it under the terms of the GNU Lesser General Public yading@11: * License as published by the Free Software Foundation; either yading@11: * version 2.1 of the License, or (at your option) any later version. yading@11: * yading@11: * FFmpeg is distributed in the hope that it will be useful, yading@11: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@11: * Lesser General Public License for more details. yading@11: * yading@11: * You should have received a copy of the GNU Lesser General Public yading@11: * License along with FFmpeg; if not, write to the Free Software yading@11: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA yading@11: */ yading@11: yading@11: /** yading@11: * @file yading@11: * principal component analysis (PCA) yading@11: */ yading@11: yading@11: #include "common.h" yading@11: #include "pca.h" yading@11: yading@11: typedef struct PCA{ yading@11: int count; yading@11: int n; yading@11: double *covariance; yading@11: double *mean; yading@11: double *z; yading@11: }PCA; yading@11: yading@11: PCA *ff_pca_init(int n){ yading@11: PCA *pca; yading@11: if(n<=0) yading@11: return NULL; yading@11: yading@11: pca= av_mallocz(sizeof(*pca)); yading@11: pca->n= n; yading@11: pca->z = av_malloc(sizeof(*pca->z) * n); yading@11: pca->count=0; yading@11: pca->covariance= av_calloc(n*n, sizeof(double)); yading@11: pca->mean= av_calloc(n, sizeof(double)); yading@11: yading@11: return pca; yading@11: } yading@11: yading@11: void ff_pca_free(PCA *pca){ yading@11: av_freep(&pca->covariance); yading@11: av_freep(&pca->mean); yading@11: av_freep(&pca->z); yading@11: av_free(pca); yading@11: } yading@11: yading@11: void ff_pca_add(PCA *pca, double *v){ yading@11: int i, j; yading@11: const int n= pca->n; yading@11: yading@11: for(i=0; imean[i] += v[i]; yading@11: for(j=i; jcovariance[j + i*n] += v[i]*v[j]; yading@11: } yading@11: pca->count++; yading@11: } yading@11: yading@11: int ff_pca(PCA *pca, double *eigenvector, double *eigenvalue){ yading@11: int i, j, pass; yading@11: int k=0; yading@11: const int n= pca->n; yading@11: double *z = pca->z; yading@11: yading@11: memset(eigenvector, 0, sizeof(double)*n*n); yading@11: yading@11: for(j=0; jmean[j] /= pca->count; yading@11: eigenvector[j + j*n] = 1.0; yading@11: for(i=0; i<=j; i++){ yading@11: pca->covariance[j + i*n] /= pca->count; yading@11: pca->covariance[j + i*n] -= pca->mean[i] * pca->mean[j]; yading@11: pca->covariance[i + j*n] = pca->covariance[j + i*n]; yading@11: } yading@11: eigenvalue[j]= pca->covariance[j + j*n]; yading@11: z[j]= 0; yading@11: } yading@11: yading@11: for(pass=0; pass < 50; pass++){ yading@11: double sum=0; yading@11: yading@11: for(i=0; icovariance[j + i*n]); yading@11: yading@11: if(sum == 0){ yading@11: for(i=0; i maxvalue){ yading@11: maxvalue= eigenvalue[j]; yading@11: k= j; yading@11: } yading@11: } yading@11: eigenvalue[k]= eigenvalue[i]; yading@11: eigenvalue[i]= maxvalue; yading@11: for(j=0; jcovariance[j + i*n]; yading@11: double t,c,s,tau,theta, h; yading@11: yading@11: if(pass < 3 && fabs(covar) < sum / (5*n*n)) //FIXME why pass < 3 yading@11: continue; yading@11: if(fabs(covar) == 0.0) //FIXME should not be needed yading@11: continue; yading@11: if(pass >=3 && fabs((eigenvalue[j]+z[j])/covar) > (1LL<<32) && fabs((eigenvalue[i]+z[i])/covar) > (1LL<<32)){ yading@11: pca->covariance[j + i*n]=0.0; yading@11: continue; yading@11: } yading@11: yading@11: h= (eigenvalue[j]+z[j]) - (eigenvalue[i]+z[i]); yading@11: theta=0.5*h/covar; yading@11: t=1.0/(fabs(theta)+sqrt(1.0+theta*theta)); yading@11: if(theta < 0.0) t = -t; yading@11: yading@11: c=1.0/sqrt(1+t*t); yading@11: s=t*c; yading@11: tau=s/(1.0+c); yading@11: z[i] -= t*covar; yading@11: z[j] += t*covar; yading@11: yading@11: #define ROTATE(a,i,j,k,l) {\ yading@11: double g=a[j + i*n];\ yading@11: double h=a[l + k*n];\ yading@11: a[j + i*n]=g-s*(h+g*tau);\ yading@11: a[l + k*n]=h+s*(g-h*tau); } yading@11: for(k=0; kcovariance,FFMIN(k,i),FFMAX(k,i),FFMIN(k,j),FFMAX(k,j)) yading@11: } yading@11: ROTATE(eigenvector,k,i,k,j) yading@11: } yading@11: pca->covariance[j + i*n]=0.0; yading@11: } yading@11: } yading@11: for (i=0; i yading@11: #include yading@11: #include "lfg.h" yading@11: yading@11: int main(void){ yading@11: PCA *pca; yading@11: int i, j, k; yading@11: #define LEN 8 yading@11: double eigenvector[LEN*LEN]; yading@11: double eigenvalue[LEN]; yading@11: AVLFG prng; yading@11: yading@11: av_lfg_init(&prng, 1); yading@11: yading@11: pca= ff_pca_init(LEN); yading@11: yading@11: for(i=0; i<9000000; i++){ yading@11: double v[2*LEN+100]; yading@11: double sum=0; yading@11: int pos = av_lfg_get(&prng) % LEN; yading@11: int v2 = av_lfg_get(&prng) % 101 - 50; yading@11: v[0] = av_lfg_get(&prng) % 101 - 50; yading@11: for(j=1; j<8; j++){ yading@11: if(j<=pos) v[j]= v[0]; yading@11: else v[j]= v2; yading@11: sum += v[j]; yading@11: } yading@11: /* for(j=0; jcount= 1; yading@11: pca->mean[i]= 0; yading@11: yading@11: // (0.5^|x|)^2 = 0.5^2|x| = 0.25^|x| yading@11: yading@11: yading@11: // pca.covariance[i + i*LEN]= pow(0.5, fabs yading@11: for(j=i; jcovariance[i + j*LEN]); yading@11: } yading@11: printf("\n"); yading@11: } yading@11: yading@11: for(i=0; icovariance[FFMIN(k,j) + FFMAX(k,j)*LEN] * eigenvector[i + k*LEN]; yading@11: } yading@11: v[j] /= eigenvalue[i]; yading@11: error += fabs(v[j] - eigenvector[i + j*LEN]); yading@11: } yading@11: printf("%f ", error); yading@11: } yading@11: printf("\n"); yading@11: yading@11: for(i=0; i