Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

base/SVD.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002   Copyright (C)2002 David Jung <opensim@pobox.com>
00003 
00004   This program/file is free software; you can redistribute it and/or modify
00005   it under the terms of the GNU General Public License as published by
00006   the Free Software Foundation; either version 2 of the License, or
00007   (at your option) any later version.
00008   
00009   This program is distributed in the hope that it will be useful,
00010   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012   GNU General Public License for more details. (http://www.gnu.org)
00013   
00014   You should have received a copy of the GNU General Public License
00015   along with this program; if not, write to the Free Software
00016   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017   
00018   $Id: SVD.cpp 1029 2004-02-11 20:45:54Z jungd $
00019   $Revision: 1.16 $
00020   $Date: 2004-02-11 15:45:54 -0500 (Wed, 11 Feb 2004) $
00021   $Author: jungd $
00022  
00023 ****************************************************************************/
00024 
00025 
00026 /*
00027  *
00028  * Singular Value Decomposition of a Matrix
00029  *
00030  * Currently uses the code from Numerical Recipies in C
00031  */
00032 
00033 
00034  
00035 #include <base/SVD>
00036 
00037 #include <base/Math>
00038 
00039 using base::SVD;
00040 
00041 using base::Math;
00042 using base::Matrix;
00043 using base::Vector;
00044 
00045 
00046 
00047 const Real SVD::maxCondition = 1e100;
00048 const Real SVD::minSingValue = 1e-6;
00049 
00050 inline float FMIN(float a, float b) { return a<b?a:b; }
00051 inline float FMAX(float a, float b) { return a>b?a:b; }
00052 inline int IMIN(int a, int b) { return a<b?a:b; }
00053 inline int IMAX(int a, int b) { return a>b?a:b; }
00054 
00055 inline float SQR(float a) { return (a==0.0)?0.0:a*a; }
00056 
00057 
00058 inline void nrerror(char error_text[])
00059 { throw std::runtime_error(Exception(String(error_text))); }
00060 
00061 
00062 extern "C" {
00063 
00064 #include <stdio.h>  
00065 #include <stdlib.h>
00066 #include <math.h>
00067   
00068   
00069 #define NR_END 1
00070 #define FREE_ARG char*
00071   
00072 
00073 #define SIGN(a,b) ((b) >= 0.0 ? fabs(a) : -fabs(a))
00074 
00075 
00076 
00077 float *vector(long nl, long nh)
00078 /* allocate a float vector with subscript range v[nl..nh] */
00079 {
00080         float *v;
00081 
00082         v=(float *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(float)));
00083         if (!v) nrerror("allocation failure in vector()");
00084         return v-nl+NR_END;
00085 }
00086 
00087 void free_matrix(float **m, long nrl, long nrh, long ncl, long nch)
00088 /* free a float matrix allocated by matrix() */
00089 {
00090         free((FREE_ARG) (m[nrl]+ncl-NR_END));
00091         free((FREE_ARG) (m+nrl-NR_END));
00092 }
00093 
00094 
00095 
00096 void free_vector(float *v, long nl, long nh)
00097 /* free a float vector allocated with vector() */
00098 {
00099         free((FREE_ARG) (v+nl-NR_END));
00100 }
00101 
00102 
00103 
00104 float **matrix(long nrl, long nrh, long ncl, long nch)
00105 /* allocate a float matrix with subscript range m[nrl..nrh][ncl..nch] */
00106 {
00107         long i, nrow=nrh-nrl+1,ncol=nch-ncl+1;
00108         float **m;
00109 
00110         /* allocate pointers to rows */
00111         m=(float **) malloc((size_t)((nrow+NR_END)*sizeof(float*)));
00112         if (!m) nrerror("allocation failure 1 in matrix()");
00113         m += NR_END;
00114         m -= nrl;
00115 
00116         /* allocate rows and set pointers to them */
00117         m[nrl]=(float *) malloc((size_t)((nrow*ncol+NR_END)*sizeof(float)));
00118         if (!m[nrl]) nrerror("allocation failure 2 in matrix()");
00119         m[nrl] += NR_END;
00120         m[nrl] -= ncl;
00121 
00122         for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol;
00123 
00124         /* return pointer to array of pointers to rows */
00125         return m;
00126 }
00127 
00128 
00129 float pythag(float a, float b)
00130 {
00131         float absa, absb;
00132         absa=fabs(a);
00133         absb=fabs(b);
00134         if(absa>absb)
00135                 return(absa*sqrt(1.0+SQR(absb/absa)));
00136         else
00137                 return(absb==0.0 ? 0.0 : absb*sqrt(1.0+SQR(absa/absb)));
00138 }
00139 
00140 
00141 
00142 // the actual SVD routine
00143 
00144 void svdcmp(float **a, int m, int n, float w[], float **v)
00145 {
00146         float pythag(float a, float b);
00147         int flag,i,its,j,jj,k,l,nm, front, back;
00148         float anorm,c,f,g,h,s,scale,x,y,z,*rv1, *rv2, tol;
00149         float **ut, **vt;
00150 
00151         vt=matrix(1,n,1,n);
00152         ut=matrix(1,m,1,n);
00153 
00154         tol=(float)(1e-6);
00155 
00156         rv1=vector(1,n);
00157         rv2=vector(1,n);
00158         g=scale=anorm=0.0;
00159         for (i=1;i<=n;i++) {
00160                 l=i+1;
00161                 rv1[i]=scale*g;
00162                 g=s=scale=0.0;
00163                 if (i <= m) {
00164                         for (k=i;k<=m;k++) 
00165                                 scale += fabs(a[k][i]);
00166                         if (scale) {
00167                                 for (k=i;k<=m;k++) {
00168                                         a[k][i] /= scale;
00169                                         s += a[k][i]*a[k][i];
00170                                 }
00171                                 f=a[i][i];
00172                                 g = -SIGN(sqrt(s),f);
00173                                 h=f*g-s;
00174                                 a[i][i]=f-g;
00175                                 for (j=l;j<=n;j++) {
00176                                         for (s=0.0,k=i;k<=m;k++) s += a[k][i]*a[k][j];
00177                                         f=s/h;
00178                                         for (k=i;k<=m;k++) a[k][j] += f*a[k][i];
00179                                 }
00180                                 for (k=i;k<=m;k++) a[k][i] *= scale;
00181                         }
00182                 }
00183                 w[i]=scale *g;
00184                 g=s=scale=0.0;
00185                 if (i <= m && i != n) {
00186                         for (k=l;k<=n;k++) scale += fabs(a[i][k]);
00187                         if (scale) {
00188                                 for (k=l;k<=n;k++) {
00189                                         a[i][k] /= scale;
00190                                         s += a[i][k]*a[i][k];
00191                                 }
00192                                 f=a[i][l];
00193                                 g = -SIGN(sqrt(s),f);
00194                                 h=f*g-s;
00195                                 a[i][l]=f-g;
00196                                 for (k=l;k<=n;k++) rv1[k]=a[i][k]/h;
00197                                 for (j=l;j<=m;j++) {
00198                                         for (s=0.0,k=l;k<=n;k++) s += a[j][k]*a[i][k];
00199                                         for (k=l;k<=n;k++) a[j][k] += s*rv1[k];
00200                                 }
00201                                 for (k=l;k<=n;k++) a[i][k] *= scale;
00202                         }
00203                 }
00204                 anorm=FMAX(anorm,(fabs(w[i])+fabs(rv1[i])));
00205         }
00206         for (i=n;i>=1;i--) {
00207                 if (i < n) {
00208                         if (g) {
00209                                 for (j=l;j<=n;j++)
00210                                         v[j][i]=(a[i][j]/a[i][l])/g;
00211                                 for (j=l;j<=n;j++) {
00212                                         for (s=0.0,k=l;k<=n;k++) s += a[i][k]*v[k][j];
00213                                         for (k=l;k<=n;k++) v[k][j] += s*v[k][i];
00214                                 }
00215                         }
00216                         for (j=l;j<=n;j++) v[i][j]=v[j][i]=0.0;
00217                 }
00218                 v[i][i]=1.0;
00219                 g=rv1[i];
00220                 l=i;
00221         }
00222         for (i=IMIN(m,n);i>=1;i--) {
00223                 l=i+1;
00224                 g=w[i];
00225                 for (j=l;j<=n;j++) a[i][j]=0.0;
00226                 if (g) {
00227                         g=1.0/g;
00228                         for (j=l;j<=n;j++) {
00229                                 for (s=0.0,k=l;k<=m;k++) s += a[k][i]*a[k][j];
00230                                 f=(s/a[i][i])*g;
00231                                 for (k=i;k<=m;k++) a[k][j] += f*a[k][i];
00232                         }
00233                         for (j=i;j<=m;j++) a[j][i] *= g;
00234                 } else for (j=i;j<=m;j++) a[j][i]=0.0;
00235                 ++a[i][i];
00236         }
00237         for (k=n;k>=1;k--) {
00238                 for (its=1;its<=30;its++) {
00239                         flag=1;
00240                         for (l=k;l>=1;l--) {
00241                                 nm=l-1;
00242                                 if ((float)(fabs(rv1[l])+anorm) == anorm) {
00243                                         flag=0;
00244                                         break;
00245                                 }
00246                                 if ((float)(fabs(w[nm])+anorm) == anorm) break;
00247                         }
00248                         if (flag) {
00249                                 c=0.0;
00250                                 s=1.0;
00251                                 for (i=l;i<=k;i++) {
00252                                         f=s*rv1[i];
00253                                         rv1[i]=c*rv1[i];
00254                                         if ((float)(fabs(f)+anorm) == anorm) break;
00255                                         g=w[i];
00256                                         h=pythag(f,g);
00257                                         w[i]=h;
00258                                         h=1.0/h;
00259                                         c=g*h;
00260                                         s = -f*h;
00261                                         for (j=1;j<=m;j++) {
00262                                                 y=a[j][nm];
00263                                                 z=a[j][i];
00264                                                 a[j][nm]=y*c+z*s;
00265                                                 a[j][i]=z*c-y*s;
00266                                         }
00267                                 }
00268                         }
00269                         z=w[k];
00270                         if (l == k) {
00271                                 if (z < 0.0) {
00272                                         w[k] = -z;
00273                                         for (j=1;j<=n;j++) v[j][k] = -v[j][k];
00274                                 }
00275                                 break;
00276                         }
00277                         if (its == 30) nrerror("no convergence in 30 svdcmp iterations");
00278                         x=w[l];
00279                         nm=k-1;
00280                         y=w[nm];
00281                         g=rv1[nm];
00282                         h=rv1[k];
00283                         f=((y-z)*(y+z)+(g-h)*(g+h))/(2.0*h*y);
00284                         g=pythag(f,1.0);
00285                         f=((x-z)*(x+z)+h*((y/(f+SIGN(g,f)))-h))/x;
00286                         c=s=1.0;
00287                         for (j=l;j<=nm;j++) {
00288                                 i=j+1;
00289                                 g=rv1[i];
00290                                 y=w[i];
00291                                 h=s*g;
00292                                 g=c*g;
00293                                 z=pythag(f,h);
00294                                 rv1[j]=z;
00295                                 c=f/z;
00296                                 s=h/z;
00297                                 f=x*c+g*s;
00298                                 g = g*c-x*s;
00299                                 h=y*s;
00300                                 y *= c;
00301                                 for (jj=1;jj<=n;jj++) {
00302                                         x=v[jj][j];
00303                                         z=v[jj][i];
00304                                         v[jj][j]=x*c+z*s;
00305                                         v[jj][i]=z*c-x*s;
00306                                 }
00307                                 z=pythag(f,h);
00308                                 w[j]=z;
00309                                 if (z) {
00310                                         z=1.0/z;
00311                                         c=f*z;
00312                                         s=h*z;
00313                                 }
00314                                 f=c*g+s*y;
00315                                 x=c*y-s*g;
00316                                 for (jj=1;jj<=m;jj++) {
00317                                         y=a[jj][j];
00318                                         z=a[jj][i];
00319                                         a[jj][j]=y*c+z*s;
00320                                         a[jj][i]=z*c-y*s;
00321                                 }
00322                         }
00323                         rv1[l]=0.0;
00324                         rv1[k]=f;
00325                         w[k]=x;
00326                 }
00327         }
00328 
00329 
00330 
00331         front=1;
00332         back=n;
00333         for(i=1;i<=n;i++)
00334         {
00335                 if(w[i]<tol)
00336                 {
00337                         rv1[back]=i;
00338                         back--;
00339                 }
00340                 else
00341                 {
00342                         rv1[front]=i;
00343                         front++;
00344                 }
00345         }
00346 
00347         for(i=1;i<=n;i++)
00348         {
00349                 rv2[i]=w[(int)(rv1[i])];
00350                 for(j=1;j<=n;j++)
00351                         vt[j][i]=v[j][(int)(rv1[i])];
00352                 for(j=1;j<=m;j++)
00353                         ut[j][i]=a[j][(int)(rv1[i])];
00354         }
00355 
00356         for(i=1;i<=n;i++)
00357         {
00358                 w[i]=rv2[i];
00359                 for(j=1;j<=n;j++)
00360                         v[j][i]=vt[j][i];
00361                 for(j=1;j<=m;j++)
00362                         a[j][i]=ut[j][i];
00363         }
00364 
00365         free_vector(rv1,1,n);
00366         free_vector(rv2,1,n);
00367         free_matrix(vt,1,n,1,m);
00368         free_matrix(ut,1,m,1,n);
00369 
00370 }
00371 
00372 
00373 
00374 
00375 } // extern C
00376 
00377 
00378 
00379 SVD::SVD(const Matrix &A)
00380   : M(A.rows()), N(A.cols())
00381 {
00382   float **v, *w, **u;
00383 
00384   // convert A to an NR matrix (put in u, which will be replaced)
00385   v=::matrix(1,N,1,N);  // v matrix
00386   u=::matrix(1,M,1,N);  // u matrix has extra columns of zeros
00387   w=::vector(1,N);      // vector of singular values
00388   
00389   for(Int r=0; r<M; r++)
00390     for(Int c=0; c<N; c++)
00391       u[r+1][c+1] = float( A(r,c) ); // NB: possible loss of precision (Real != float necesarily)
00392   
00393   // call NR SVD
00394   svdcmp(u, int(M), int(N), w, v);
00395   
00396   // now store results into U, V & s
00397   UMat = zeroMatrix(M,M);
00398   for(Int r=0; r<M; r++)
00399     for(Int c=0; c< Math::minimum(N,M); c++)
00400       UMat(r,c) = Real( u[r+1][c+1] );
00401   
00402   VMat.resize(N,N);
00403   for(Int r=0; r<N; r++)
00404     for(Int c=0; c<N; c++)
00405       VMat(r,c) = Real( v[r+1][c+1] );
00406   
00407   s.resize(N);
00408   for(Int i=0; i<N; i++)
00409     s[i] = Real( w[i+1] );
00410 }
00411 
00412 
00413 
00414 const Matrix& SVD::U() const
00415 {
00416   return UMat;
00417 }
00418 
00419 const Matrix& SVD::V() const
00420 {
00421   return VMat;
00422 }
00423 
00424 const Vector SVD::diag() const
00425 {
00426   Vector d( Math::minimum(M,N) );
00427   d = vectorRange(s, Range(0, d.size()));
00428   return d;
00429 }
00430   
00431 
00432 Matrix SVD::S() const
00433 {
00434   Matrix S( zeroMatrix(M,N) );
00435   for(Int i=0; i< Math::minimum(N,M); i++)
00436     S(i,i) = s[i];
00437   return S;
00438 }
00439 
00440 
00441 Real SVD::condition(Real maxCond) const
00442 {
00443   Vector d(diag());
00444   Int minInd = min_index(d);
00445   Int maxInd = max_index(d);
00446    
00447   Real min = d[minInd];
00448   Real max = d[maxInd];
00449 
00450   if(min / max < 1.0/maxCond)
00451     return maxCond;
00452   else
00453     return max / min;
00454 
00455 }
00456 
00457 
00458 Matrix SVD::inv(Real minSingVal) const
00459 {
00460   // combine the products to form the pseudo inverse solution
00461   const Int M = UMat.size1();
00462   const Int N = VMat.size1();
00463   Matrix tmpMat( zeroMatrix(N, M) ); // VMat * 'D^-1'
00464   matrixRange(tmpMat, Range(0,N), Range(0,N) ) = VMat;
00465    
00466   // invert the diagonal elements and apply to the tmpMat matrix
00467   for(Int i=0; i<s.size(); i++)
00468     {
00469       Real tmp = s[i];
00470       if(fabs(tmp) < minSingVal)
00471         tmp = 0.0;
00472       else
00473         tmp = 1.0 / tmp;
00474        
00475       matrixColumn(tmpMat,i) *= tmp;
00476     }
00477                                                                                                                                                                                                     
00478   // U^-1 == U^T
00479   Matrix invA(N, M);
00480   invA = tmpMat * transpose(UMat);
00481                                                                                                                                                                                                     
00482   return invA;
00483 }
00484  
00485 

Generated on Thu Jul 29 15:56:15 2004 for OpenSim by doxygen 1.3.6