2 * principal component analysis (PCA)
3 * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 * @file libavutil/pca.c
24 * principal component analysis (PCA)
37 PCA
*ff_pca_init(int n
){
42 pca
= av_mallocz(sizeof(PCA
));
45 pca
->covariance
= av_mallocz(sizeof(double)*n
*n
);
46 pca
->mean
= av_mallocz(sizeof(double)*n
);
51 void ff_pca_free(PCA
*pca
){
52 av_freep(&pca
->covariance
);
57 void ff_pca_add(PCA
*pca
, double *v
){
64 pca
->covariance
[j
+ i
*n
] += v
[i
]*v
[j
];
69 int ff_pca(PCA
*pca
, double *eigenvector
, double *eigenvalue
){
75 memset(eigenvector
, 0, sizeof(double)*n
*n
);
78 pca
->mean
[j
] /= pca
->count
;
79 eigenvector
[j
+ j
*n
] = 1.0;
81 pca
->covariance
[j
+ i
*n
] /= pca
->count
;
82 pca
->covariance
[j
+ i
*n
] -= pca
->mean
[i
] * pca
->mean
[j
];
83 pca
->covariance
[i
+ j
*n
] = pca
->covariance
[j
+ i
*n
];
85 eigenvalue
[j
]= pca
->covariance
[j
+ j
*n
];
89 for(pass
=0; pass
< 50; pass
++){
94 sum
+= fabs(pca
->covariance
[j
+ i
*n
]);
100 if(eigenvalue
[j
] > maxvalue
){
101 maxvalue
= eigenvalue
[j
];
105 eigenvalue
[k
]= eigenvalue
[i
];
106 eigenvalue
[i
]= maxvalue
;
108 double tmp
= eigenvector
[k
+ j
*n
];
109 eigenvector
[k
+ j
*n
]= eigenvector
[i
+ j
*n
];
110 eigenvector
[i
+ j
*n
]= tmp
;
117 for(j
=i
+1; j
<n
; j
++){
118 double covar
= pca
->covariance
[j
+ i
*n
];
119 double t
,c
,s
,tau
,theta
, h
;
121 if(pass
< 3 && fabs(covar
) < sum
/ (5*n
*n
)) //FIXME why pass < 3
123 if(fabs(covar
) == 0.0) //FIXME should not be needed
125 if(pass
>=3 && fabs((eigenvalue
[j
]+z
[j
])/covar
) > (1LL<<32) && fabs((eigenvalue
[i
]+z
[i
])/covar
) > (1LL<<32)){
126 pca
->covariance
[j
+ i
*n
]=0.0;
130 h
= (eigenvalue
[j
]+z
[j
]) - (eigenvalue
[i
]+z
[i
]);
132 t
=1.0/(fabs(theta
)+sqrt(1.0+theta
*theta
));
133 if(theta
< 0.0) t
= -t
;
141 #define ROTATE(a,i,j,k,l) {\
142 double g=a[j + i*n];\
143 double h=a[l + k*n];\
144 a[j + i*n]=g-s*(h+g*tau);\
145 a[l + k*n]=h+s*(g-h*tau); }
148 ROTATE(pca
->covariance
,FFMIN(k
,i
),FFMAX(k
,i
),FFMIN(k
,j
),FFMAX(k
,j
))
150 ROTATE(eigenvector
,k
,i
,k
,j
)
152 pca
->covariance
[j
+ i
*n
]=0.0;
155 for (i
=0; i
<n
; i
++) {
156 eigenvalue
[i
] += z
[i
];
175 double eigenvector
[LEN
*LEN
];
176 double eigenvalue
[LEN
];
178 pca
= ff_pca_init(LEN
);
180 for(i
=0; i
<9000000; i
++){
183 int pos
= random()%LEN
;
184 int v2
= (random()%101) - 50;
185 v
[0]= (random()%101) - 50;
187 if(j
<=pos
) v
[j
]= v
[0];
191 /* for(j=0; j<LEN; j++){
194 // sum += random()%10;
195 /* for(j=0; j<LEN; j++){
198 // lbt1(v+100,v+100,LEN);
203 ff_pca(pca
, eigenvector
, eigenvalue
);
204 for(i
=0; i
<LEN
; i
++){
208 // (0.5^|x|)^2 = 0.5^2|x| = 0.25^|x|
211 // pca.covariance[i + i*LEN]= pow(0.5, fabs
212 for(j
=i
; j
<LEN
; j
++){
213 printf("%f ", pca
->covariance
[i
+ j
*LEN
]);
219 for(i
=0; i
<LEN
; i
++){
222 memset(v
, 0, sizeof(v
));
223 for(j
=0; j
<LEN
; j
++){
224 for(k
=0; k
<LEN
; k
++){
225 v
[j
] += pca
->covariance
[FFMIN(k
,j
) + FFMAX(k
,j
)*LEN
] * eigenvector
[i
+ k
*LEN
];
227 v
[j
] /= eigenvalue
[i
];
228 error
+= fabs(v
[j
] - eigenvector
[i
+ j
*LEN
]);
230 printf("%f ", error
);
234 for(i
=0; i
<LEN
; i
++){
235 for(j
=0; j
<LEN
; j
++){
236 printf("%9.6f ", eigenvector
[i
+ j
*LEN
]);
238 printf(" %9.1f %f\n", eigenvalue
[i
], eigenvalue
[i
]/eigenvalue
[0]);