svd_eigen_Macie.hpp

Go to the documentation of this file.
00001 // Copyright  (C)  2008  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 //implementation of svd according to (Maciejewski and Klein,1989)
00024 //and (Braun, Ulrey, Maciejewski and Siegel,2002)
00025 #ifndef SVD_BOOST_MACIE
00026 #define SVD_BOOST_MACIE
00027 
00028 #include <Eigen/Core>
00029 USING_PART_OF_NAMESPACE_EIGEN
00030 
00031 namespace KDL
00032 {
00033     int svd_eigen_Macie(const MatrixXd& A,MatrixXd& U,VectorXd& S, MatrixXd& V,
00034                         MatrixXd& B, VectorXd& tempi,
00035                         double treshold,bool toggle)
00036     {
00037         bool rotate = true;
00038         unsigned int sweeps=0;
00039         unsigned int rotations=0;
00040         if(toggle){
00041             //Calculate B from new A and previous V
00042             B=(A*V).lazy();
00043             while(rotate){
00044                 rotate=false;
00045                 rotations=0;
00046                 //Perform rotations between columns of B
00047                 for(unsigned int i=0;i<B.cols();i++){
00048                     for(unsigned int j=i+1;j<B.cols();j++){
00049                         //calculate plane rotation
00050                         double p = B.col(i).dot(B.col(j));
00051                         double qi =B.col(i).dot(B.col(i));
00052                         double qj = B.col(j).dot(B.col(j));
00053                         double q=qi-qj;
00054                         double alpha = pow(p,2.0)/(qi*qj);
00055                         //if columns are orthogonal with precision
00056                         //treshold, don't perform rotation and continue
00057                         if(alpha<treshold)
00058                             continue;
00059                         rotations++;
00060                         double c = sqrt(4*pow(p,2.0)+pow(q,2.0));
00061                         double cos,sin;
00062                         if(q>=0){
00063                             cos=sqrt((c+q)/(2*c));
00064                             sin=p/(c*cos);
00065                         }else{
00066                             if(p<0)
00067                                 sin=-sqrt((c-q)/(2*c));
00068                             else
00069                                 sin=sqrt((c-q)/(2*c));
00070                             cos=p/(c*sin);
00071                         }
00072 
00073                         //Apply plane rotation to columns of B
00074                         tempi = cos*B.col(i) + sin*B.col(j);
00075                         B.col(j) = - sin*B.col(i) + cos*B.col(j);
00076                         B.col(i) = tempi;
00077                         
00078                         //Apply plane rotation to columns of V
00079                         tempi.start(V.rows()) = cos*V.col(i) + sin*V.col(j);
00080                         V.col(j) = - sin*V.col(i) + cos*V.col(j);
00081                         V.col(i) = tempi.start(V.rows());
00082 
00083                         rotate=true;
00084                     }
00085                 }
00086                 //Only calculate new U and S if there were any rotations
00087                 if(rotations!=0){
00088                     for(unsigned int i=0;i<U.rows();i++) {
00089                         if(i<B.cols()){
00090                             double si=sqrt(B.col(i).dot(B.col(i)));
00091                             if(si==0)
00092                                 U.col(i) = B.col(i);
00093                             else
00094                                 U.col(i) = B.col(i)/si;
00095                             S(i)=si;
00096                         }
00097                         else
00098                             U.col(i) = 0*tempi;
00099                     }
00100                     sweeps++;
00101                 }
00102             }
00103             return sweeps;
00104         }else{
00105             //Calculate B from new A and previous U'
00106             B =(U.transpose() * A).lazy();
00107             while(rotate){
00108                 rotate=false;
00109                 rotations=0;
00110                 //Perform rotations between rows of B
00111                 for(unsigned int i=0;i<B.cols();i++){
00112                     for(unsigned int j=i+1;j<B.cols();j++){
00113                         //calculate plane rotation
00114                         double p = B.row(i).dot(B.row(j));
00115                         double qi = B.row(i).dot(B.row(i));
00116                         double qj = B.row(j).dot(B.row(j));
00117 
00118                         double q=qi-qj;
00119                         double alpha = pow(p,2.0)/(qi*qj);
00120                         //if columns are orthogonal with precision
00121                         //treshold, don't perform rotation and
00122                         //continue
00123                         if(alpha<treshold)
00124                             continue;
00125                         rotations++;
00126                         double c = sqrt(4*pow(p,2.0)+pow(q,2.0));
00127                         double cos,sin;
00128                         if(q>=0){
00129                             cos=sqrt((c+q)/(2*c));
00130                             sin=p/(c*cos);
00131                         }else{
00132                             if(p<0)
00133                                 sin=-sqrt((c-q)/(2*c));
00134                             else
00135                                 sin=sqrt((c-q)/(2*c));
00136                             cos=p/(c*sin);
00137                         }
00138 
00139                         //Apply plane rotation to rows of B
00140                         tempi.start(B.cols()) =  cos*B.row(i) + sin*B.row(j);
00141                         B.row(j) =  - sin*B.row(i) + cos*B.row(j);
00142                         B.row(i) =  tempi.start(B.cols());
00143 
00144 
00145                         //Apply plane rotation to rows of U
00146                         tempi.start(U.rows()) = cos*U.col(i) + sin*U.col(j);
00147                         U.col(j) = - sin*U.col(i) + cos*U.col(j);
00148                         U.col(i) = tempi.start(U.rows());
00149 
00150                         rotate=true;
00151                     }
00152                 }
00153 
00154                 //Only calculate new U and S if there were any rotations
00155                 if(rotations!=0){
00156                     for(unsigned int i=0;i<V.rows();i++) {
00157                         double si=sqrt(B.row(i).dot(B.row(i)));
00158                         if(si==0)
00159                             V.col(i) = B.row(i);
00160                         else
00161                             V.col(i) = B.row(i)/si;
00162                         S(i)=si;
00163                     }
00164                     sweeps++;
00165                 }
00166             }
00167             return sweeps;
00168         }
00169     }
00170 
00171 
00172 }
00173 #endif

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