svd_eigen_HH.cpp

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 #include "svd_eigen_HH.hpp"
00023 
00024 namespace KDL{
00025     
00026     int svd_eigen_HH(const MatrixXd& A,MatrixXd& U,VectorXd& S,MatrixXd& V,VectorXd& tmp,int maxiter,double epsilon)
00027     {
00028         //get the rows/columns of the matrix
00029         const int rows = A.rows();
00030         const int cols = A.cols();
00031     
00032         U.setZero();
00033         U.corner(Eigen::TopLeft,rows,cols)=A;
00034 
00035         int i(-1),its(-1),j(-1),jj(-1),k(-1),nm=0;
00036         int ppi(0);
00037         bool flag,maxarg1,maxarg2;
00038         double anorm(0),c(0),f(0),h(0),s(0),scale(0),x(0),y(0),z(0),g(0);
00039 
00040         /* Householder reduction to bidiagonal form. */
00041         for (i=0;i<cols;i++) {
00042             ppi=i+1;
00043             tmp(i)=scale*g;
00044             g=s=scale=0.0; 
00045             if (i<rows) {
00046                 // compute the sum of the i-th column, starting from the i-th row
00047                 for (k=i;k<rows;k++) scale += fabs(U(k,i));
00048                 if (fabs(scale)>epsilon) {
00049                     // multiply the i-th column by 1.0/scale, start from the i-th element
00050                     // sum of squares of column i, start from the i-th element
00051                     for (k=i;k<rows;k++) {
00052                         U(k,i) /= scale;
00053                         s += U(k,i)*U(k,i);
00054                     }
00055                     f=U(i,i);  // f is the diag elem
00056                     assert(s>=0);
00057                     g = -SIGN(sqrt(s),f);
00058                     h=f*g-s;
00059                     U(i,i)=f-g;
00060                     for (j=ppi;j<cols;j++) {
00061                         // dot product of columns i and j, starting from the i-th row
00062                         for (s=0.0,k=i;k<rows;k++) s += U(k,i)*U(k,j);
00063                         assert(h!=0);
00064                         f=s/h;
00065                         // copy the scaled i-th column into the j-th column
00066                         for (k=i;k<rows;k++) U(k,j) += f*U(k,i);
00067                     }
00068                     for (k=i;k<rows;k++) U(k,i) *= scale;
00069                 }
00070             }
00071             // save singular value
00072             S(i)=scale*g;
00073             g=s=scale=0.0;
00074             if ((i <rows) && (i+1 != cols)) {
00075                 // sum of row i, start from columns i+1
00076                 for (k=ppi;k<cols;k++) scale += fabs(U(i,k));
00077                 if (fabs(scale)>epsilon) {
00078                     for (k=ppi;k<cols;k++) {
00079                         U(i,k) /= scale;
00080                         s += U(i,k)*U(i,k);
00081                     }
00082                     f=U(i,ppi);
00083                     assert(s>=0);
00084                     g = -SIGN(sqrt(s),f);
00085                     h=f*g-s;
00086                     U(i,ppi)=f-g;
00087                     assert(h!=0);
00088                     for (k=ppi;k<cols;k++) tmp(k)=U(i,k)/h;
00089                     for (j=ppi;j<rows;j++) {
00090                         for (s=0.0,k=ppi;k<cols;k++) s += U(j,k)*U(i,k);
00091                         for (k=ppi;k<cols;k++) U(j,k) += s*tmp(k);
00092                     }
00093                     for (k=ppi;k<cols;k++) U(i,k) *= scale;
00094                 }
00095             }
00096             maxarg1=anorm;
00097             maxarg2=(fabs(S(i))+fabs(tmp(i)));
00098             anorm = maxarg1 > maxarg2 ? maxarg1 : maxarg2;              
00099         }
00100         /* Accumulation of right-hand transformations. */
00101         for (i=cols-1;i>=0;i--) {
00102             if (i<cols-1) {
00103                 if (fabs(g)>epsilon) {
00104                     assert(U(i,ppi)!=0);
00105                     for (j=ppi;j<cols;j++) V(j,i)=(U(i,j)/U(i,ppi))/g;
00106                     for (j=ppi;j<cols;j++) {
00107                         for (s=0.0,k=ppi;k<cols;k++) s += U(i,k)*V(k,j);
00108                         for (k=ppi;k<cols;k++) V(k,j) += s*V(k,i);
00109                     }
00110                 }
00111                 for (j=ppi;j<cols;j++) V(i,j)=V(j,i)=0.0;
00112             }
00113             V(i,i)=1.0;
00114             g=tmp(i);
00115             ppi=i;
00116         }
00117         /* Accumulation of left-hand transformations. */
00118         for (i=cols-1<rows-1 ? cols-1:rows-1;i>=0;i--) {
00119             ppi=i+1;
00120             g=S(i);
00121             for (j=ppi;j<cols;j++) U(i,j)=0.0;
00122             if (fabs(g)>epsilon) {
00123                 g=1.0/g;
00124                 for (j=ppi;j<cols;j++) {
00125                     for (s=0.0,k=ppi;k<rows;k++) s += U(k,i)*U(k,j);
00126                     assert(U(i,i)!=0);
00127                     f=(s/U(i,i))*g;
00128                     for (k=i;k<rows;k++) U(k,j) += f*U(k,i);
00129                 }
00130                 for (j=i;j<rows;j++) U(j,i) *= g;
00131             } else {
00132                 for (j=i;j<rows;j++) U(j,i)=0.0;
00133             }
00134             ++U(i,i);
00135         }
00136         
00137         /* Diagonalization of the bidiagonal form. */
00138         for (k=cols-1;k>=0;k--) { /* Loop over singular values. */
00139             for (its=1;its<=maxiter;its++) {  /* Loop over allowed iterations. */
00140                 flag=true;
00141                 for (ppi=k;ppi>=0;ppi--) {  /* Test for splitting. */
00142                     nm=ppi-1;             /* Note that tmp[1] is always zero. */
00143                     if ((fabs(tmp(ppi))+anorm) == anorm) {
00144                         flag=false;
00145                         break;
00146                     }
00147                     if ((fabs(S(nm)+anorm) == anorm)) break;
00148                 }
00149                 if (flag) {
00150                     c=0.0;           /* Cancellation of tmp[l], if l>1: */
00151                     s=1.0;
00152                     for (i=ppi;i<=k;i++) {
00153                         f=s*tmp(i);
00154                         tmp(i)=c*tmp(i);
00155                         if ((fabs(f)+anorm) == anorm) break;
00156                         g=S(i);
00157                         h=PYTHAG(f,g);
00158                         S(i)=h;
00159                         assert(h!=0);
00160                         h=1.0/h;
00161                         c=g*h;
00162                         s=(-f*h);
00163                         for (j=0;j<rows;j++) {
00164                             y=U(j,nm);
00165                             z=U(j,i);
00166                             U(j,nm)=y*c+z*s;
00167                             U(j,i)=z*c-y*s;
00168                         }
00169                     }
00170                 }
00171                 z=S(k);
00172                 
00173                 if (ppi == k) {       /* Convergence. */
00174                     if (z < 0.0) {   /* Singular value is made nonnegative. */
00175                         S(k) = -z;
00176                         for (j=0;j<cols;j++) V(j,k)=-V(j,k);
00177                     }
00178                     break;
00179                 }
00180                 
00181                 x=S(ppi);            /* Shift from bottom 2-by-2 minor: */
00182                 nm=k-1;
00183                 y=S(nm);
00184                 g=tmp(nm);
00185                 h=tmp(k);
00186                 assert(h!=0&&y!=0);
00187                 f=((y-z)*(y+z)+(g-h)*(g+h))/(2.0*h*y);
00188                 
00189                 g=PYTHAG(f,1.0);
00190                 assert(x!=0);
00191                 assert((f+SIGN(g,f))!=0);
00192                 f=((x-z)*(x+z)+h*((y/(f+SIGN(g,f)))-h))/x;
00193                 
00194                 /* Next QR transformation: */
00195                 c=s=1.0;
00196                 for (j=ppi;j<=nm;j++) {
00197                     i=j+1;
00198                     g=tmp(i);
00199                     y=S(i);
00200                     h=s*g;
00201                     g=c*g;
00202                     z=PYTHAG(f,h);
00203                     tmp(j)=z;
00204                     assert(z!=0);
00205                     c=f/z;
00206                     s=h/z;
00207                     f=x*c+g*s;
00208                     g=g*c-x*s;
00209                     h=y*s;
00210                     y=y*c;
00211                     for (jj=0;jj<cols;jj++) {
00212                         x=V(jj,j);
00213                         z=V(jj,i);
00214                         V(jj,j)=x*c+z*s;
00215                         V(jj,i)=z*c-x*s;
00216                     }
00217                     z=PYTHAG(f,h);
00218                     S(j)=z;
00219                     assert(z!=0);
00220                     if (fabs(z)>epsilon) {
00221                         z=1.0/z;
00222                         c=f*z;
00223                         s=h*z;
00224                     }
00225                     f=(c*g)+(s*y);
00226                     x=(c*y)-(s*g);
00227                     for (jj=0;jj<rows;jj++) {
00228                         y=U(jj,j);
00229                         z=U(jj,i);
00230                         U(jj,j)=y*c+z*s;
00231                         U(jj,i)=z*c-y*s;
00232                     }
00233                 }
00234                 tmp(ppi)=0.0;
00235                 tmp(k)=f;
00236                 S(k)=x;
00237             }
00238         }
00239 
00240         //Sort eigen values:
00241         for (i=0; i<cols; i++){
00242             
00243             double S_max = S(i);
00244             int i_max = i;
00245             for (j=i+1; j<cols; j++){
00246                 double Sj = S(j);
00247                 if (Sj > S_max){
00248                     S_max = Sj;
00249                     i_max = j;
00250                 }
00251             }
00252             if (i_max != i){
00253                 /* swap eigenvalues */
00254                 double tmp = S(i);
00255                 S(i)=S(i_max);
00256                 S(i_max)=tmp;
00257                 
00258                 /* swap eigenvectors */
00259                 U.col(i).swap(U.col(i_max));
00260                 V.col(i).swap(V.col(i_max));
00261             }
00262         }
00263         
00264         if (its == maxiter) 
00265             return (-2);
00266         else 
00267             return (0);
00268     }
00269 }

Generated on Wed Nov 23 19:00:42 2011 for FreeCAD by  doxygen 1.6.1