Home || Architecture || Video Search || Visual Search || Scripts || Applications || Important Messages || OGL || Src

MatKLM.h

Go to the documentation of this file.
00001 #ifndef Impala_Core_Matrix_MatKLM_h
00002 #define Impala_Core_Matrix_MatKLM_h
00003 
00004 #include "Core/Matrix/MatCovariance.h"
00005 
00006 namespace Impala
00007 {
00008 namespace Core
00009 {
00010 namespace Matrix
00011 {
00012 
00013 
00014 // KLM helping functions
00015 
00016 /*
00017  Householder reduction of a real, symmetric matrix a[0..n-1][0..n-1]
00018  Output: a is replaced by the orthogonal matrix Q effecting the
00019  transformation. d[0..n-1] returns the diagonal elements of the
00020  tridiagonal matrix, and e[0..n-1] the off-diagonal elements, with e[0]=0;
00021  */
00022 template<class MatrixT, class VectorT>
00023 void
00024 Tred2(MatrixT* a, VectorT* d, VectorT* e)
00025 {
00026     int i,j,k,l;
00027     double scale,hh,h,g,f;
00028 
00029     int n = VecNrElem(d);
00030 
00031     for (i=n-1; i>0; i--)
00032     {
00033         l = i-1;
00034         h = scale = 0.0;
00035         if (l>0)
00036         {
00037             for (k=0; k<=l; k++)
00038                 scale += fabs(*MatE(a, i, k));
00039             if (scale == 0.0)
00040                 *VecE(e, i) = *MatE(a, i, l);
00041             else
00042             {
00043                 for (k=0; k<=l; k++)
00044                 {
00045                     *MatE(a, i, k) /= scale; //use scale a's for transformation
00046                     h += *MatE(a, i, k) * *MatE(a, i, k);
00047                 }
00048                 f = *MatE(a, i, l);
00049                 g = (f >=0.0 ? -sqrt(h) : sqrt(h));
00050                 *VecE(e, i) = scale*g;
00051                 h -= f*g;
00052                 *MatE(a, i, l) = f-g;
00053                 f = 0.0;
00054                 for (j=0; j<=l; j++)
00055                 {
00056                     *MatE(a, j, i) = *MatE(a, i, j)/h;
00057                     g = 0.0;
00058                     for (k=0; k<=j; k++)
00059                         g += *MatE(a, j, k) * *MatE(a, i, k);
00060                     for (k=j+1; k<=l; k++)
00061                         g += *MatE(a, k, j) * *MatE(a, i, k);
00062                     *VecE(e, j) = g/h; //form element of p in temporarily unused element of e
00063                     f += *VecE(e, j) * *MatE(a, i, j);
00064                 }
00065                 hh = f/(h+h);
00066                 for (j=0; j<=l; j++)
00067                 {
00068                     f = *MatE(a, i, j);
00069                     *VecE(e, j) = g = *VecE(e, j)-hh*f;
00070                     for (k=0; k<=j; k++)
00071                         *MatE(a, j, k) -= (f * *VecE(e, k) 
00072                                              + g * *MatE(a, i, k));
00073                 }
00074             }
00075         }
00076         else
00077             *VecE(e, i) = *MatE(a, i, l);
00078         *VecE(d, i) = h;
00079     }
00080 
00081     *VecE(d, 0) = 0.0;
00082     *VecE(e, 0) = 0.0;
00083 
00084     for (i=0; i<n; i++)
00085     {
00086         l = i-1;
00087         if (*VecE(d, i))
00088         {
00089             for (j=0; j<=l; j++)
00090             {
00091                 g = 0.0;
00092                 for (k=0; k<=l; k++)
00093                     g += *MatE(a, i, k) * *MatE(a, k, j);
00094                 for (k=0; k<=l; k++)
00095                     *MatE(a, k, j) -= g * *MatE(a, k, i);
00096             }
00097         }
00098         *VecE(d, i) = *MatE(a, i, i);
00099         *MatE(a, i, i) = 1.0;
00100         for (j=0; j<=l; j++)
00101             *MatE(a, j, i) = *MatE(a, i, j) = 0.0;
00102     }
00103 }
00104 
00105 /*
00106  QL algorithm with implicit shifts, to determin the eigenvalues and eigenvectors
00107  of a real, symetric, tridiagonal matrix, of of a real, symmetric matrix previously
00108  reduced by tred2
00109  Input: d[0..n-1] contains the diagonal elements of the tridiagonal matrix
00110  e[0..n-1] inputs the subdiagonal elements of the tridiagonal matrix with e[0]
00111  arbitrary
00112  Output: d returns the eigenvalues, e is destroyed.
00113  If the eigenvectors of a tridiagonal matrix are desired, the matrix
00114  z[0..n-1][0..n-1] is input as the identity matrix. If the eigenvectors of
00115  a matrix that has been reduced by tred2 are required, then z is input as
00116  the matrix output by tred2.
00117  In either case, the kth column of z returns the normalized eigenvector
00118  corresponding to d[k]
00119  */
00120 template<class MatrixT, class VectorT>
00121 void
00122 Tqli(VectorT* d, VectorT* e, MatrixT* z)
00123 {
00124 
00125     int m,l,iter,i,k;
00126     double s,r,p,g,f,dd,c,b;
00127 
00128     int n = VecNrElem(e);
00129 
00130     for (i=1; i<n; i++)
00131         *VecE(e, i-1) = *VecE(e, i); //renumber
00132     *VecE(e, n-1) = 0.0;
00133 
00134 
00135     for (l=0; l<n; l++)
00136     {
00137         iter=0;
00138         do {
00139             for (m=l; m<n-1; m++)
00140             {
00141                 dd = fabs(*VecE(d, m)) + fabs(*VecE(d, m+1));
00142                 if ( (fabs(*VecE(e, m)) + dd) == dd)
00143                     break;
00144             }
00145             if (m != l)
00146             {
00147                 if (iter++ == 30)
00148                     std::cout << "Tqli: Too many iterations" << std::endl;
00149                 g = (*VecE(d, l+1) - *VecE(d, l)) / (2.0 * *VecE(e, l));
00150                 r = sqrt(g*g + 1.0);//=pythag(g,1.0);
00151                 g = *VecE(d, m) - *VecE(d, l) + *VecE(e, l)/(g+SIGN(r,g));
00152                 s = c = 1.0;
00153                 p = 0.0;
00154                 for (i=m-1; i>=l; i--)
00155                 {
00156                     f = s * *VecE(e, i);
00157                     b = c * *VecE(e, i);
00158                     *VecE(e, i+1) = (r=sqrt(f*f+g*g));//=(r=pythag(f,g));
00159                     if (r == 0.0)
00160                     {
00161                         *VecE(d, i+1) -= p;
00162                         *VecE(e, m) = 0.0;
00163                         break;
00164                     }
00165                     s = f/r;
00166                     c = g/r;
00167                     g = *VecE(d, i+1)-p;
00168                     r = (*VecE(d, i)-g)*s + 2.0*c*b;
00169                     *VecE(d, i+1) = g+(p=s*r);
00170                     g = c*r-b;
00171 
00172                     for (k=0; k<n; k++)
00173                     {
00174                         f = *MatE(z, k, i+1);
00175                         *MatE(z, k, i+1) = s * *MatE(z, k, i) + c*f;
00176                         *MatE(z, k, i) = c * *MatE(z, k, i) - s*f;
00177                     }
00178                 }
00179                 if (r==0.0 && i>=l)
00180                     continue;
00181                 *VecE(d, l) -= p;
00182                 *VecE(e, l) = g;
00183                 *VecE(e, m) = 0.0;
00184             }
00185         } while (m != l);
00186     }
00187 
00188     //eigenvalues d[0..n-1], eigenvectors z[0..n-1][0..n-1], sort them now
00189     int j;
00190     for (i=0; i<n-1; i++)
00191     {
00192         p = *VecE(d, k=i);
00193         for (j=i+1; j<n; j++)
00194             if (*VecE(d, j) >= p)
00195                 p = *VecE(d, k=j);
00196         if (k!=i)
00197         { //insert
00198             *VecE(d, k) = *VecE(d, i);
00199             *VecE(d, i) = p;
00200             //exchange corresponding eigenvectors
00201             for (j=0; j<n; j++)
00202             {
00203                 p = *MatE(z, j, i);
00204                 *MatE(z, j, i) = *MatE(z, j, k);
00205                 *MatE(z, j, k) = p;
00206             }
00207         }
00208     }
00209 }
00210 
00211 /*
00212  *  Karhunen Loeve mapping (PCA)
00213  *  Principal Componant Analysis to reduce matrix to newDim dimensions
00214  */
00215 template<class ArrayT>
00216 inline ArrayT*
00217 MatKLM(ArrayT* m, int newDim)
00218 {
00219     typedef ArrayT Mat;
00220     typedef ArrayT Vec;
00221 
00222     int nr = MatNrRow(m);
00223     int nc = MatNrCol(m);
00224 
00225     if (newDim<1 || newDim>nc)
00226     {
00227         std::cout << "MatKLM: new dimensionality invalid, set to 1..." << std::endl;
00228         newDim = 1;
00229     }
00230 
00231     Mat* newfvec = MatCreate<Mat>(nr, newDim);
00232     Mat* a = MatCovariance(m, (Mat*) 0);
00233     Vec* d = VecCreate<Vec>(nc);
00234     Vec* e = VecCreate<Vec>(nc);
00235 
00236     Tred2(a, d, e);
00237     Tqli(d, e, a);
00238 
00239     // d[k] is an eigenvalue and a[][k] is a corresponding eigenvector
00240 
00241     for (int k=0; k<nr; k++)
00242     {
00243         for (int i=0; i<newDim; i++)
00244         {
00245             double vl = 0.0;
00246             for (int j=0; j<nc; j++)
00247                 vl += *MatE(m, k, j) * *MatE(a, j, i);
00248             *MatE(newfvec, k, i) = vl;
00249         }
00250     }
00251     delete a;
00252     delete d;
00253     delete e;
00254     return newfvec;
00255 }
00256 
00257 } // namespace Matrix
00258 } // namespace Core
00259 } // namespace Impala
00260 
00261 #endif

Generated on Fri Mar 19 09:31:15 2010 for ImpalaSrc by  doxygen 1.5.1