123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- #ifdef HAVE_CONFIG_H
- #include "config.h"
- #endif
- #include <float.h>
- #include <math.h>
- #include <string.h>
- #include "svd.h"
- #include "pythag.h"
- int svd(double **_w,double *_s,int _nrows,int _ncols){
- double e2;
- double tol;
- int i;
- int j;
- int col_rank;
- int slimit;
- int sweepi;
- int nrots;
- e2=8*_nrows*DBL_EPSILON*DBL_EPSILON;
- tol=0.125*DBL_EPSILON;
- for(i=0;i<_ncols;i++)for(j=0;j<_ncols;j++)_w[i+_nrows][j]=i==j;
- col_rank=_ncols;
- slimit=_ncols>24?_ncols>>2:6;
- sweepi=0;
- do{
- int k;
- nrots=0;
- for(j=0;j<col_rank-1;j++)for(k=j+1;k<col_rank;k++){
- double vt;
- double ee;
- double ff;
- double gg;
- double c;
- double s;
- double x;
- double y;
- ff=ee=gg=0;
- for(i=0;i<_nrows;i++){
- ee+=_w[i][j]*_w[i][j];
- ff+=_w[i][j]*_w[i][k];
- gg+=_w[i][k]*_w[i][k];
- }
- _s[j]=ee;
- _s[k]=gg;
- if(ee>=gg){
- if(ee<=e2*_s[0]||fabs(ff)<=tol*ee)continue;
- ff/=ee;
- gg=1-gg/ee;
- vt=pythag(2*ff,gg);
- c=sqrt(fabs(0.5*(1+gg/vt)));
- s=ff/(vt*c);
- }
- else{
- ff/=gg;
- ee=ee/gg-1;
- vt=pythag(2*ff,ee);
- s=sqrt(fabs(0.5*(1-ee/vt)));
- if(ff<0)s=-s;
- c=ff/(vt*s);
- }
- for(i=0;i<_nrows+_ncols;i++){
- x=_w[i][j];
- y=_w[i][k];
- _w[i][j]=x*c+y*s;
- _w[i][k]=y*c-x*s;
- }
- nrots++;
- }
- while(col_rank>1&&_s[col_rank-1]<=_s[0]*tol+tol*tol)col_rank--;
- }
- while(nrots>0&&++sweepi<=slimit);
- return col_rank-(col_rank>0&&_s[0]<=0);
- }
- int svd_pseudoinverse(double **_w,double *_s,int _nrows,int _ncols){
- int rank;
- int i;
- int j;
- int k;
- rank=svd(_w,_s,_nrows,_ncols);
-
- for(j=0;j<_ncols;j++)for(i=0;i<rank;i++)_w[_nrows+j][i]/=_s[i];
-
- for(i=0;i<_nrows;i++){
- memset(_s,0,_ncols*sizeof(*_s));
- for(j=0;j<_ncols;j++)for(k=0;k<rank;k++)_s[j]+=_w[i][k]*_w[_nrows+j][k];
- memcpy(_w[i],_s,_ncols*sizeof(*_s));
- }
- return rank;
- }
|