Blender V2.61 - r43446

svd_eigen_HH.hpp

Go to the documentation of this file.
00001 // Copyright  (C)  2007  Ruben Smits <ruben dot smits at mech dot kuleuven dot be>
00002 
00003 // Version: 1.0
00004 // Author: Ruben Smits <ruben dot smits at mech dot kuleuven dot be>
00005 // Maintainer: Ruben Smits <ruben dot smits at mech dot kuleuven dot be>
00006 // URL: http://www.orocos.org/kdl
00007 
00008 // This library is free software; you can redistribute it and/or
00009 // modify it under the terms of the GNU Lesser General Public
00010 // License as published by the Free Software Foundation; either
00011 // version 2.1 of the License, or (at your option) any later version.
00012 
00013 // This library is distributed in the hope that it will be useful,
00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016 // Lesser General Public License for more details.
00017 
00018 // You should have received a copy of the GNU Lesser General Public
00019 // License along with this library; if not, write to the Free Software
00020 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00021 
00022 
00023 //Based on the svd of the KDL-0.2 library by Erwin Aertbelien
00024 #ifndef SVD_EIGEN_HH_HPP
00025 #define SVD_EIGEN_HH_HPP
00026 
00027 
00028 #include <Eigen/Core>
00029 #include <algorithm>
00030 
00031 namespace KDL
00032 {
00033     template<typename Scalar> inline Scalar PYTHAG(Scalar a,Scalar b) {
00034         double at,bt,ct;
00035         at = fabs(a);
00036         bt = fabs(b);
00037         if (at > bt ) {
00038             ct=bt/at;
00039             return Scalar(at*sqrt(1.0+ct*ct));
00040         } else {
00041             if (bt==0)
00042                 return Scalar(0.0);
00043             else {
00044                 ct=at/bt;
00045                 return Scalar(bt*sqrt(1.0+ct*ct));
00046             }
00047         }
00048     }
00049 
00050 
00051     template<typename Scalar> inline Scalar SIGN(Scalar a,Scalar b) {
00052         return ((b) >= Scalar(0.0) ? fabs(a) : -fabs(a));
00053     }
00054 
00067     template<typename MatrixA, typename MatrixUV, typename VectorS> 
00068     int svd_eigen_HH(
00069         const Eigen::MatrixBase<MatrixA>&       A,
00070         Eigen::MatrixBase<MatrixUV>&            U,
00071         Eigen::MatrixBase<VectorS>&             S,
00072         Eigen::MatrixBase<MatrixUV>&            V,
00073         Eigen::MatrixBase<VectorS>&             tmp,
00074         int maxiter=150)
00075     {
00076         //get the rows/columns of the matrix
00077         const int rows = A.rows();
00078         const int cols = A.cols();
00079         
00080         U = A;
00081         
00082         int i(-1),its(-1),j(-1),jj(-1),k(-1),nm=0;
00083         int ppi(0);
00084         bool flag;
00085         e_scalar maxarg1,maxarg2,anorm(0),c(0),f(0),h(0),s(0),scale(0),x(0),y(0),z(0),g(0);
00086         
00087         g=scale=anorm=e_scalar(0.0);
00088         
00089         /* Householder reduction to bidiagonal form. */
00090         for (i=0;i<cols;i++) {
00091             ppi=i+1;
00092             tmp(i)=scale*g;
00093             g=s=scale=e_scalar(0.0); 
00094             if (i<rows) {
00095                 // compute the sum of the i-th column, starting from the i-th row
00096                 for (k=i;k<rows;k++) scale += fabs(U(k,i));
00097                 if (scale!=0) {
00098                     // multiply the i-th column by 1.0/scale, start from the i-th element
00099                     // sum of squares of column i, start from the i-th element
00100                     for (k=i;k<rows;k++) {
00101                         U(k,i) /= scale;
00102                         s += U(k,i)*U(k,i);
00103                     }
00104                     f=U(i,i);  // f is the diag elem
00105                     g = -SIGN(e_scalar(sqrt(s)),f);
00106                     h=f*g-s;
00107                     U(i,i)=f-g;
00108                     for (j=ppi;j<cols;j++) {
00109                         // dot product of columns i and j, starting from the i-th row
00110                         for (s=0.0,k=i;k<rows;k++) s += U(k,i)*U(k,j);
00111                         f=s/h;
00112                         // copy the scaled i-th column into the j-th column
00113                         for (k=i;k<rows;k++) U(k,j) += f*U(k,i);
00114                     }
00115                     for (k=i;k<rows;k++) U(k,i) *= scale;
00116                 }
00117             }
00118             // save singular value
00119             S(i)=scale*g;
00120             g=s=scale=e_scalar(0.0);
00121             if ((i <rows) && (i+1 != cols)) {
00122                 // sum of row i, start from columns i+1
00123                 for (k=ppi;k<cols;k++) scale += fabs(U(i,k));
00124                 if (scale!=0) {
00125                     for (k=ppi;k<cols;k++) {
00126                         U(i,k) /= scale;
00127                         s += U(i,k)*U(i,k);
00128                     }
00129                     f=U(i,ppi);
00130                     g = -SIGN(e_scalar(sqrt(s)),f);
00131                     h=f*g-s;
00132                     U(i,ppi)=f-g;
00133                     for (k=ppi;k<cols;k++) tmp(k)=U(i,k)/h;
00134                     for (j=ppi;j<rows;j++) {
00135                         for (s=0.0,k=ppi;k<cols;k++) s += U(j,k)*U(i,k);
00136                         for (k=ppi;k<cols;k++) U(j,k) += s*tmp(k);
00137                     }
00138                     for (k=ppi;k<cols;k++) U(i,k) *= scale;
00139                 }
00140             }
00141             maxarg1=anorm;
00142             maxarg2=(fabs(S(i))+fabs(tmp(i)));
00143             anorm = maxarg1 > maxarg2 ? maxarg1 : maxarg2;      
00144         }
00145         /* Accumulation of right-hand transformations. */
00146         for (i=cols-1;i>=0;i--) {
00147             if (i<cols-1) {
00148                 if (g) {
00149                     for (j=ppi;j<cols;j++) V(j,i)=(U(i,j)/U(i,ppi))/g;
00150                     for (j=ppi;j<cols;j++) {
00151                         for (s=0.0,k=ppi;k<cols;k++) s += U(i,k)*V(k,j);
00152                         for (k=ppi;k<cols;k++) V(k,j) += s*V(k,i);
00153                     }
00154                 }
00155                 for (j=ppi;j<cols;j++) V(i,j)=V(j,i)=0.0;
00156             }
00157             V(i,i)=1.0;
00158             g=tmp(i);
00159             ppi=i;
00160         }
00161         /* Accumulation of left-hand transformations. */
00162         for (i=cols-1<rows-1 ? cols-1:rows-1;i>=0;i--) {
00163             ppi=i+1;
00164             g=S(i);
00165             for (j=ppi;j<cols;j++) U(i,j)=0.0;
00166             if (g) {
00167                 g=e_scalar(1.0)/g;
00168                 for (j=ppi;j<cols;j++) {
00169                     for (s=0.0,k=ppi;k<rows;k++) s += U(k,i)*U(k,j);
00170                     f=(s/U(i,i))*g;
00171                     for (k=i;k<rows;k++) U(k,j) += f*U(k,i);
00172                 }
00173                 for (j=i;j<rows;j++) U(j,i) *= g;
00174             } else {
00175                 for (j=i;j<rows;j++) U(j,i)=0.0;
00176             }
00177             ++U(i,i);
00178         }
00179         
00180         /* Diagonalization of the bidiagonal form. */
00181         for (k=cols-1;k>=0;k--) { /* Loop over singular values. */
00182             for (its=1;its<=maxiter;its++) {  /* Loop over allowed iterations. */
00183                 flag=true;
00184                 for (ppi=k;ppi>=0;ppi--) {  /* Test for splitting. */
00185                     nm=ppi-1;             /* Note that tmp(1) is always zero. */
00186                     if ((fabs(tmp(ppi))+anorm) == anorm) {
00187                         flag=false;
00188                         break;
00189                     }
00190                     if ((fabs(S(nm)+anorm) == anorm)) break;
00191                 }
00192                 if (flag) {
00193                     c=e_scalar(0.0);           /* Cancellation of tmp(l), if l>1: */
00194                     s=e_scalar(1.);
00195                     for (i=ppi;i<=k;i++) {
00196                         f=s*tmp(i);
00197                         tmp(i)=c*tmp(i);
00198                         if ((fabs(f)+anorm) == anorm) break;
00199                         g=S(i);
00200                         h=PYTHAG(f,g);
00201                         S(i)=h;
00202                         h=e_scalar(1.0)/h;
00203                         c=g*h;
00204                         s=(-f*h);
00205                         for (j=0;j<rows;j++) {
00206                             y=U(j,nm);
00207                             z=U(j,i);
00208                             U(j,nm)=y*c+z*s;
00209                             U(j,i)=z*c-y*s;
00210                         }
00211                     }
00212                 }
00213                 z=S(k);
00214                 
00215                 if (ppi == k) {       /* Convergence. */
00216                     if (z < e_scalar(0.0)) {   /* Singular value is made nonnegative. */
00217                         S(k) = -z;
00218                         for (j=0;j<cols;j++) V(j,k)=-V(j,k);
00219                     }
00220                     break;
00221                 }
00222                 
00223                 x=S(ppi);            /* Shift from bottom 2-by-2 minor: */
00224                 nm=k-1;
00225                 y=S(nm);
00226                 g=tmp(nm);
00227                 h=tmp(k);
00228                 f=((y-z)*(y+z)+(g-h)*(g+h))/(e_scalar(2.0)*h*y);
00229                 
00230                 g=PYTHAG(f,e_scalar(1.0));
00231                 f=((x-z)*(x+z)+h*((y/(f+SIGN(g,f)))-h))/x;
00232                 
00233                 /* Next QR transformation: */
00234                 c=s=1.0;
00235                 for (j=ppi;j<=nm;j++) {
00236                     i=j+1;
00237                     g=tmp(i);
00238                     y=S(i);
00239                     h=s*g;
00240                     g=c*g;
00241                     z=PYTHAG(f,h);
00242                     tmp(j)=z;
00243                     c=f/z;
00244                     s=h/z;
00245                     f=x*c+g*s;
00246                     g=g*c-x*s;
00247                     h=y*s;
00248                     y=y*c;
00249                     for (jj=0;jj<cols;jj++) {
00250                         x=V(jj,j);
00251                         z=V(jj,i);
00252                         V(jj,j)=x*c+z*s;
00253                         V(jj,i)=z*c-x*s;
00254                     }
00255                     z=PYTHAG(f,h);
00256                     S(j)=z;
00257                     if (z) {
00258                         z=e_scalar(1.0)/z;
00259                         c=f*z;
00260                         s=h*z;
00261                     }
00262                     f=(c*g)+(s*y);
00263                     x=(c*y)-(s*g);
00264                     for (jj=0;jj<rows;jj++) {
00265                         y=U(jj,j);
00266                         z=U(jj,i);
00267                         U(jj,j)=y*c+z*s;
00268                         U(jj,i)=z*c-y*s;
00269                     }
00270                 }
00271                 tmp(ppi)=0.0;
00272                 tmp(k)=f;
00273                 S(k)=x;
00274             }
00275         }
00276 
00277         //Sort eigen values:
00278         for (i=0; i<cols; i++){
00279             
00280             double S_max = S(i);
00281             int i_max = i;
00282             for (j=i+1; j<cols; j++){
00283                 double Sj = S(j);
00284                 if (Sj > S_max){
00285                     S_max = Sj;
00286                     i_max = j;
00287                 }
00288             }
00289             if (i_max != i){
00290                 /* swap eigenvalues */
00291                 e_scalar tmp = S(i);
00292                 S(i)=S(i_max);
00293                 S(i_max)=tmp;
00294                 
00295                 /* swap eigenvectors */
00296                 U.col(i).swap(U.col(i_max));
00297                 V.col(i).swap(V.col(i_max));
00298             }
00299         }
00300         
00301         
00302         if (its == maxiter) 
00303             return (-2);
00304         else 
00305             return (0);
00306     }
00307 
00308 }
00309 #endif