MOAB  4.9.3pre
JacobiSVD.h
Go to the documentation of this file.
00001 // This file is part of Eigen, a lightweight C++ template library
00002 // for linear algebra.
00003 //
00004 // Copyright (C) 2009-2010 Benoit Jacob <[email protected]>
00005 // Copyright (C) 2013-2014 Gael Guennebaud <[email protected]>
00006 //
00007 // This Source Code Form is subject to the terms of the Mozilla
00008 // Public License v. 2.0. If a copy of the MPL was not distributed
00009 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
00010 
00011 #ifndef EIGEN_JACOBISVD_H
00012 #define EIGEN_JACOBISVD_H
00013 
00014 namespace Eigen { 
00015 
00016 namespace internal {
00017 // forward declaration (needed by ICC)
00018 // the empty body is required by MSVC
00019 template<typename MatrixType, int QRPreconditioner,
00020          bool IsComplex = NumTraits<typename MatrixType::Scalar>::IsComplex>
00021 struct svd_precondition_2x2_block_to_be_real {};
00022 
00023 /*** QR preconditioners (R-SVD)
00024  ***
00025  *** Their role is to reduce the problem of computing the SVD to the case of a square matrix.
00026  *** This approach, known as R-SVD, is an optimization for rectangular-enough matrices, and is a requirement for
00027  *** JacobiSVD which by itself is only able to work on square matrices.
00028  ***/
00029 
00030 enum { PreconditionIfMoreColsThanRows, PreconditionIfMoreRowsThanCols };
00031 
00032 template<typename MatrixType, int QRPreconditioner, int Case>
00033 struct qr_preconditioner_should_do_anything
00034 {
00035   enum { a = MatrixType::RowsAtCompileTime != Dynamic &&
00036              MatrixType::ColsAtCompileTime != Dynamic &&
00037              MatrixType::ColsAtCompileTime <= MatrixType::RowsAtCompileTime,
00038          b = MatrixType::RowsAtCompileTime != Dynamic &&
00039              MatrixType::ColsAtCompileTime != Dynamic &&
00040              MatrixType::RowsAtCompileTime <= MatrixType::ColsAtCompileTime,
00041          ret = !( (QRPreconditioner == NoQRPreconditioner) ||
00042                   (Case == PreconditionIfMoreColsThanRows && bool(a)) ||
00043                   (Case == PreconditionIfMoreRowsThanCols && bool(b)) )
00044   };
00045 };
00046 
00047 template<typename MatrixType, int QRPreconditioner, int Case,
00048          bool DoAnything = qr_preconditioner_should_do_anything<MatrixType, QRPreconditioner, Case>::ret
00049 > struct qr_preconditioner_impl {};
00050 
00051 template<typename MatrixType, int QRPreconditioner, int Case>
00052 class qr_preconditioner_impl<MatrixType, QRPreconditioner, Case, false>
00053 {
00054 public:
00055   void allocate(const JacobiSVD<MatrixType, QRPreconditioner>&) {}
00056   bool run(JacobiSVD<MatrixType, QRPreconditioner>&, const MatrixType&)
00057   {
00058     return false;
00059   }
00060 };
00061 
00062 /*** preconditioner using FullPivHouseholderQR ***/
00063 
00064 template<typename MatrixType>
00065 class qr_preconditioner_impl<MatrixType, FullPivHouseholderQRPreconditioner, PreconditionIfMoreRowsThanCols, true>
00066 {
00067 public:
00068   typedef typename MatrixType::Scalar Scalar;
00069   enum
00070   {
00071     RowsAtCompileTime = MatrixType::RowsAtCompileTime,
00072     MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime
00073   };
00074   typedef Matrix<Scalar, 1, RowsAtCompileTime, RowMajor, 1, MaxRowsAtCompileTime> WorkspaceType;
00075 
00076   void allocate(const JacobiSVD<MatrixType, FullPivHouseholderQRPreconditioner>& svd)
00077   {
00078     if (svd.rows() != m_qr.rows() || svd.cols() != m_qr.cols())
00079     {
00080       m_qr.~QRType();
00081       ::new (&m_qr) QRType(svd.rows(), svd.cols());
00082     }
00083     if (svd.m_computeFullU) m_workspace.resize(svd.rows());
00084   }
00085 
00086   bool run(JacobiSVD<MatrixType, FullPivHouseholderQRPreconditioner>& svd, const MatrixType& matrix)
00087   {
00088     if(matrix.rows() > matrix.cols())
00089     {
00090       m_qr.compute(matrix);
00091       svd.m_workMatrix = m_qr.matrixQR().block(0,0,matrix.cols(),matrix.cols()).template triangularView<Upper>();
00092       if(svd.m_computeFullU) m_qr.matrixQ().evalTo(svd.m_matrixU, m_workspace);
00093       if(svd.computeV()) svd.m_matrixV = m_qr.colsPermutation();
00094       return true;
00095     }
00096     return false;
00097   }
00098 private:
00099   typedef FullPivHouseholderQR<MatrixType> QRType;
00100   QRType m_qr;
00101   WorkspaceType m_workspace;
00102 };
00103 
00104 template<typename MatrixType>
00105 class qr_preconditioner_impl<MatrixType, FullPivHouseholderQRPreconditioner, PreconditionIfMoreColsThanRows, true>
00106 {
00107 public:
00108   typedef typename MatrixType::Scalar Scalar;
00109   enum
00110   {
00111     RowsAtCompileTime = MatrixType::RowsAtCompileTime,
00112     ColsAtCompileTime = MatrixType::ColsAtCompileTime,
00113     MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
00114     MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime,
00115     Options = MatrixType::Options
00116   };
00117   typedef Matrix<Scalar, ColsAtCompileTime, RowsAtCompileTime, Options, MaxColsAtCompileTime, MaxRowsAtCompileTime>
00118           TransposeTypeWithSameStorageOrder;
00119 
00120   void allocate(const JacobiSVD<MatrixType, FullPivHouseholderQRPreconditioner>& svd)
00121   {
00122     if (svd.cols() != m_qr.rows() || svd.rows() != m_qr.cols())
00123     {
00124       m_qr.~QRType();
00125       ::new (&m_qr) QRType(svd.cols(), svd.rows());
00126     }
00127     m_adjoint.resize(svd.cols(), svd.rows());
00128     if (svd.m_computeFullV) m_workspace.resize(svd.cols());
00129   }
00130 
00131   bool run(JacobiSVD<MatrixType, FullPivHouseholderQRPreconditioner>& svd, const MatrixType& matrix)
00132   {
00133     if(matrix.cols() > matrix.rows())
00134     {
00135       m_adjoint = matrix.adjoint();
00136       m_qr.compute(m_adjoint);
00137       svd.m_workMatrix = m_qr.matrixQR().block(0,0,matrix.rows(),matrix.rows()).template triangularView<Upper>().adjoint();
00138       if(svd.m_computeFullV) m_qr.matrixQ().evalTo(svd.m_matrixV, m_workspace);
00139       if(svd.computeU()) svd.m_matrixU = m_qr.colsPermutation();
00140       return true;
00141     }
00142     else return false;
00143   }
00144 private:
00145   typedef FullPivHouseholderQR<TransposeTypeWithSameStorageOrder> QRType;
00146   QRType m_qr;
00147   TransposeTypeWithSameStorageOrder m_adjoint;
00148   typename internal::plain_row_type<MatrixType>::type m_workspace;
00149 };
00150 
00151 /*** preconditioner using ColPivHouseholderQR ***/
00152 
00153 template<typename MatrixType>
00154 class qr_preconditioner_impl<MatrixType, ColPivHouseholderQRPreconditioner, PreconditionIfMoreRowsThanCols, true>
00155 {
00156 public:
00157   void allocate(const JacobiSVD<MatrixType, ColPivHouseholderQRPreconditioner>& svd)
00158   {
00159     if (svd.rows() != m_qr.rows() || svd.cols() != m_qr.cols())
00160     {
00161       m_qr.~QRType();
00162       ::new (&m_qr) QRType(svd.rows(), svd.cols());
00163     }
00164     if (svd.m_computeFullU) m_workspace.resize(svd.rows());
00165     else if (svd.m_computeThinU) m_workspace.resize(svd.cols());
00166   }
00167 
00168   bool run(JacobiSVD<MatrixType, ColPivHouseholderQRPreconditioner>& svd, const MatrixType& matrix)
00169   {
00170     if(matrix.rows() > matrix.cols())
00171     {
00172       m_qr.compute(matrix);
00173       svd.m_workMatrix = m_qr.matrixQR().block(0,0,matrix.cols(),matrix.cols()).template triangularView<Upper>();
00174       if(svd.m_computeFullU) m_qr.householderQ().evalTo(svd.m_matrixU, m_workspace);
00175       else if(svd.m_computeThinU)
00176       {
00177         svd.m_matrixU.setIdentity(matrix.rows(), matrix.cols());
00178         m_qr.householderQ().applyThisOnTheLeft(svd.m_matrixU, m_workspace);
00179       }
00180       if(svd.computeV()) svd.m_matrixV = m_qr.colsPermutation();
00181       return true;
00182     }
00183     return false;
00184   }
00185 
00186 private:
00187   typedef ColPivHouseholderQR<MatrixType> QRType;
00188   QRType m_qr;
00189   typename internal::plain_col_type<MatrixType>::type m_workspace;
00190 };
00191 
00192 template<typename MatrixType>
00193 class qr_preconditioner_impl<MatrixType, ColPivHouseholderQRPreconditioner, PreconditionIfMoreColsThanRows, true>
00194 {
00195 public:
00196   typedef typename MatrixType::Scalar Scalar;
00197   enum
00198   {
00199     RowsAtCompileTime = MatrixType::RowsAtCompileTime,
00200     ColsAtCompileTime = MatrixType::ColsAtCompileTime,
00201     MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
00202     MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime,
00203     Options = MatrixType::Options
00204   };
00205 
00206   typedef Matrix<Scalar, ColsAtCompileTime, RowsAtCompileTime, Options, MaxColsAtCompileTime, MaxRowsAtCompileTime>
00207           TransposeTypeWithSameStorageOrder;
00208 
00209   void allocate(const JacobiSVD<MatrixType, ColPivHouseholderQRPreconditioner>& svd)
00210   {
00211     if (svd.cols() != m_qr.rows() || svd.rows() != m_qr.cols())
00212     {
00213       m_qr.~QRType();
00214       ::new (&m_qr) QRType(svd.cols(), svd.rows());
00215     }
00216     if (svd.m_computeFullV) m_workspace.resize(svd.cols());
00217     else if (svd.m_computeThinV) m_workspace.resize(svd.rows());
00218     m_adjoint.resize(svd.cols(), svd.rows());
00219   }
00220 
00221   bool run(JacobiSVD<MatrixType, ColPivHouseholderQRPreconditioner>& svd, const MatrixType& matrix)
00222   {
00223     if(matrix.cols() > matrix.rows())
00224     {
00225       m_adjoint = matrix.adjoint();
00226       m_qr.compute(m_adjoint);
00227 
00228       svd.m_workMatrix = m_qr.matrixQR().block(0,0,matrix.rows(),matrix.rows()).template triangularView<Upper>().adjoint();
00229       if(svd.m_computeFullV) m_qr.householderQ().evalTo(svd.m_matrixV, m_workspace);
00230       else if(svd.m_computeThinV)
00231       {
00232         svd.m_matrixV.setIdentity(matrix.cols(), matrix.rows());
00233         m_qr.householderQ().applyThisOnTheLeft(svd.m_matrixV, m_workspace);
00234       }
00235       if(svd.computeU()) svd.m_matrixU = m_qr.colsPermutation();
00236       return true;
00237     }
00238     else return false;
00239   }
00240 
00241 private:
00242   typedef ColPivHouseholderQR<TransposeTypeWithSameStorageOrder> QRType;
00243   QRType m_qr;
00244   TransposeTypeWithSameStorageOrder m_adjoint;
00245   typename internal::plain_row_type<MatrixType>::type m_workspace;
00246 };
00247 
00248 /*** preconditioner using HouseholderQR ***/
00249 
00250 template<typename MatrixType>
00251 class qr_preconditioner_impl<MatrixType, HouseholderQRPreconditioner, PreconditionIfMoreRowsThanCols, true>
00252 {
00253 public:
00254   void allocate(const JacobiSVD<MatrixType, HouseholderQRPreconditioner>& svd)
00255   {
00256     if (svd.rows() != m_qr.rows() || svd.cols() != m_qr.cols())
00257     {
00258       m_qr.~QRType();
00259       ::new (&m_qr) QRType(svd.rows(), svd.cols());
00260     }
00261     if (svd.m_computeFullU) m_workspace.resize(svd.rows());
00262     else if (svd.m_computeThinU) m_workspace.resize(svd.cols());
00263   }
00264 
00265   bool run(JacobiSVD<MatrixType, HouseholderQRPreconditioner>& svd, const MatrixType& matrix)
00266   {
00267     if(matrix.rows() > matrix.cols())
00268     {
00269       m_qr.compute(matrix);
00270       svd.m_workMatrix = m_qr.matrixQR().block(0,0,matrix.cols(),matrix.cols()).template triangularView<Upper>();
00271       if(svd.m_computeFullU) m_qr.householderQ().evalTo(svd.m_matrixU, m_workspace);
00272       else if(svd.m_computeThinU)
00273       {
00274         svd.m_matrixU.setIdentity(matrix.rows(), matrix.cols());
00275         m_qr.householderQ().applyThisOnTheLeft(svd.m_matrixU, m_workspace);
00276       }
00277       if(svd.computeV()) svd.m_matrixV.setIdentity(matrix.cols(), matrix.cols());
00278       return true;
00279     }
00280     return false;
00281   }
00282 private:
00283   typedef HouseholderQR<MatrixType> QRType;
00284   QRType m_qr;
00285   typename internal::plain_col_type<MatrixType>::type m_workspace;
00286 };
00287 
00288 template<typename MatrixType>
00289 class qr_preconditioner_impl<MatrixType, HouseholderQRPreconditioner, PreconditionIfMoreColsThanRows, true>
00290 {
00291 public:
00292   typedef typename MatrixType::Scalar Scalar;
00293   enum
00294   {
00295     RowsAtCompileTime = MatrixType::RowsAtCompileTime,
00296     ColsAtCompileTime = MatrixType::ColsAtCompileTime,
00297     MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
00298     MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime,
00299     Options = MatrixType::Options
00300   };
00301 
00302   typedef Matrix<Scalar, ColsAtCompileTime, RowsAtCompileTime, Options, MaxColsAtCompileTime, MaxRowsAtCompileTime>
00303           TransposeTypeWithSameStorageOrder;
00304 
00305   void allocate(const JacobiSVD<MatrixType, HouseholderQRPreconditioner>& svd)
00306   {
00307     if (svd.cols() != m_qr.rows() || svd.rows() != m_qr.cols())
00308     {
00309       m_qr.~QRType();
00310       ::new (&m_qr) QRType(svd.cols(), svd.rows());
00311     }
00312     if (svd.m_computeFullV) m_workspace.resize(svd.cols());
00313     else if (svd.m_computeThinV) m_workspace.resize(svd.rows());
00314     m_adjoint.resize(svd.cols(), svd.rows());
00315   }
00316 
00317   bool run(JacobiSVD<MatrixType, HouseholderQRPreconditioner>& svd, const MatrixType& matrix)
00318   {
00319     if(matrix.cols() > matrix.rows())
00320     {
00321       m_adjoint = matrix.adjoint();
00322       m_qr.compute(m_adjoint);
00323 
00324       svd.m_workMatrix = m_qr.matrixQR().block(0,0,matrix.rows(),matrix.rows()).template triangularView<Upper>().adjoint();
00325       if(svd.m_computeFullV) m_qr.householderQ().evalTo(svd.m_matrixV, m_workspace);
00326       else if(svd.m_computeThinV)
00327       {
00328         svd.m_matrixV.setIdentity(matrix.cols(), matrix.rows());
00329         m_qr.householderQ().applyThisOnTheLeft(svd.m_matrixV, m_workspace);
00330       }
00331       if(svd.computeU()) svd.m_matrixU.setIdentity(matrix.rows(), matrix.rows());
00332       return true;
00333     }
00334     else return false;
00335   }
00336 
00337 private:
00338   typedef HouseholderQR<TransposeTypeWithSameStorageOrder> QRType;
00339   QRType m_qr;
00340   TransposeTypeWithSameStorageOrder m_adjoint;
00341   typename internal::plain_row_type<MatrixType>::type m_workspace;
00342 };
00343 
00344 /*** 2x2 SVD implementation
00345  ***
00346  *** JacobiSVD consists in performing a series of 2x2 SVD subproblems
00347  ***/
00348 
00349 template<typename MatrixType, int QRPreconditioner>
00350 struct svd_precondition_2x2_block_to_be_real<MatrixType, QRPreconditioner, false>
00351 {
00352   typedef JacobiSVD<MatrixType, QRPreconditioner> SVD;
00353   static void run(typename SVD::WorkMatrixType&, SVD&, Index, Index) {}
00354 };
00355 
00356 template<typename MatrixType, int QRPreconditioner>
00357 struct svd_precondition_2x2_block_to_be_real<MatrixType, QRPreconditioner, true>
00358 {
00359   typedef JacobiSVD<MatrixType, QRPreconditioner> SVD;
00360   typedef typename MatrixType::Scalar Scalar;
00361   typedef typename MatrixType::RealScalar RealScalar;
00362   static void run(typename SVD::WorkMatrixType& work_matrix, SVD& svd, Index p, Index q)
00363   {
00364     using std::sqrt;
00365     Scalar z;
00366     JacobiRotation<Scalar> rot;
00367     RealScalar n = sqrt(numext::abs2(work_matrix.coeff(p,p)) + numext::abs2(work_matrix.coeff(q,p)));
00368     
00369     if(n==0)
00370     {
00371       z = abs(work_matrix.coeff(p,q)) / work_matrix.coeff(p,q);
00372       work_matrix.row(p) *= z;
00373       if(svd.computeU()) svd.m_matrixU.col(p) *= conj(z);
00374       if(work_matrix.coeff(q,q)!=Scalar(0))
00375       {
00376         z = abs(work_matrix.coeff(q,q)) / work_matrix.coeff(q,q);
00377         work_matrix.row(q) *= z;
00378         if(svd.computeU()) svd.m_matrixU.col(q) *= conj(z);
00379       }
00380       // otherwise the second row is already zero, so we have nothing to do.
00381     }
00382     else
00383     {
00384       rot.c() = conj(work_matrix.coeff(p,p)) / n;
00385       rot.s() = work_matrix.coeff(q,p) / n;
00386       work_matrix.applyOnTheLeft(p,q,rot);
00387       if(svd.computeU()) svd.m_matrixU.applyOnTheRight(p,q,rot.adjoint());
00388       if(work_matrix.coeff(p,q) != Scalar(0))
00389       {
00390         z = abs(work_matrix.coeff(p,q)) / work_matrix.coeff(p,q);
00391         work_matrix.col(q) *= z;
00392         if(svd.computeV()) svd.m_matrixV.col(q) *= z;
00393       }
00394       if(work_matrix.coeff(q,q) != Scalar(0))
00395       {
00396         z = abs(work_matrix.coeff(q,q)) / work_matrix.coeff(q,q);
00397         work_matrix.row(q) *= z;
00398         if(svd.computeU()) svd.m_matrixU.col(q) *= conj(z);
00399       }
00400     }
00401   }
00402 };
00403 
00404 template<typename MatrixType, typename RealScalar, typename Index>
00405 void real_2x2_jacobi_svd(const MatrixType& matrix, Index p, Index q,
00406                          JacobiRotation<RealScalar> *j_left,
00407                          JacobiRotation<RealScalar> *j_right)
00408 {
00409   using std::sqrt;
00410   using std::abs;
00411   Matrix<RealScalar,2,2> m;
00412   m << numext::real(matrix.coeff(p,p)), numext::real(matrix.coeff(p,q)),
00413        numext::real(matrix.coeff(q,p)), numext::real(matrix.coeff(q,q));
00414   JacobiRotation<RealScalar> rot1;
00415   RealScalar t = m.coeff(0,0) + m.coeff(1,1);
00416   RealScalar d = m.coeff(1,0) - m.coeff(0,1);
00417   
00418   if(d == RealScalar(0))
00419   {
00420     rot1.s() = RealScalar(0);
00421     rot1.c() = RealScalar(1);
00422   }
00423   else
00424   {
00425     // If d!=0, then t/d cannot overflow because the magnitude of the
00426     // entries forming d are not too small compared to the ones forming t.
00427     RealScalar u = t / d;
00428     RealScalar tmp = sqrt(RealScalar(1) + numext::abs2(u));
00429     rot1.s() = RealScalar(1) / tmp;
00430     rot1.c() = u / tmp;
00431   }
00432   m.applyOnTheLeft(0,1,rot1);
00433   j_right->makeJacobi(m,0,1);
00434   *j_left = rot1 * j_right->transpose();
00435 }
00436 
00437 template<typename _MatrixType, int QRPreconditioner> 
00438 struct traits<JacobiSVD<_MatrixType,QRPreconditioner> >
00439 {
00440   typedef _MatrixType MatrixType;
00441 };
00442 
00443 } // end namespace internal
00444 
00498 template<typename _MatrixType, int QRPreconditioner> class JacobiSVD
00499  : public SVDBase<JacobiSVD<_MatrixType,QRPreconditioner> >
00500 {
00501     typedef SVDBase<JacobiSVD> Base;
00502   public:
00503 
00504     typedef _MatrixType MatrixType;
00505     typedef typename MatrixType::Scalar Scalar;
00506     typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
00507     enum {
00508       RowsAtCompileTime = MatrixType::RowsAtCompileTime,
00509       ColsAtCompileTime = MatrixType::ColsAtCompileTime,
00510       DiagSizeAtCompileTime = EIGEN_SIZE_MIN_PREFER_DYNAMIC(RowsAtCompileTime,ColsAtCompileTime),
00511       MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
00512       MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime,
00513       MaxDiagSizeAtCompileTime = EIGEN_SIZE_MIN_PREFER_FIXED(MaxRowsAtCompileTime,MaxColsAtCompileTime),
00514       MatrixOptions = MatrixType::Options
00515     };
00516 
00517     typedef typename Base::MatrixUType MatrixUType;
00518     typedef typename Base::MatrixVType MatrixVType;
00519     typedef typename Base::SingularValuesType SingularValuesType;
00520     
00521     typedef typename internal::plain_row_type<MatrixType>::type RowType;
00522     typedef typename internal::plain_col_type<MatrixType>::type ColType;
00523     typedef Matrix<Scalar, DiagSizeAtCompileTime, DiagSizeAtCompileTime,
00524                    MatrixOptions, MaxDiagSizeAtCompileTime, MaxDiagSizeAtCompileTime>
00525             WorkMatrixType;
00526 
00532     JacobiSVD()
00533     {}
00534 
00535 
00542     JacobiSVD(Index p_rows, Index p_cols, unsigned int computationOptions = 0)
00543     {
00544       allocate(p_rows, p_cols, computationOptions);
00545     }
00546 
00557     explicit JacobiSVD(const MatrixType& matrix, unsigned int computationOptions = 0)
00558     {
00559       compute(matrix, computationOptions);
00560     }
00561 
00572     JacobiSVD& compute(const MatrixType& matrix, unsigned int computationOptions);
00573 
00580     JacobiSVD& compute(const MatrixType& matrix)
00581     {
00582       return compute(matrix, m_computationOptions);
00583     }
00584 
00585     using Base::computeU;
00586     using Base::computeV;
00587     using Base::rows;
00588     using Base::cols;
00589     using Base::rank;
00590 
00591   private:
00592     void allocate(Index rows, Index cols, unsigned int computationOptions);
00593 
00594   protected:
00595     using Base::m_matrixU;
00596     using Base::m_matrixV;
00597     using Base::m_singularValues;
00598     using Base::m_isInitialized;
00599     using Base::m_isAllocated;
00600     using Base::m_usePrescribedThreshold;
00601     using Base::m_computeFullU;
00602     using Base::m_computeThinU;
00603     using Base::m_computeFullV;
00604     using Base::m_computeThinV;
00605     using Base::m_computationOptions;
00606     using Base::m_nonzeroSingularValues;
00607     using Base::m_rows;
00608     using Base::m_cols;
00609     using Base::m_diagSize;
00610     using Base::m_prescribedThreshold;
00611     WorkMatrixType m_workMatrix;
00612 
00613     template<typename __MatrixType, int _QRPreconditioner, bool _IsComplex>
00614     friend struct internal::svd_precondition_2x2_block_to_be_real;
00615     template<typename __MatrixType, int _QRPreconditioner, int _Case, bool _DoAnything>
00616     friend struct internal::qr_preconditioner_impl;
00617 
00618     internal::qr_preconditioner_impl<MatrixType, QRPreconditioner, internal::PreconditionIfMoreColsThanRows> m_qr_precond_morecols;
00619     internal::qr_preconditioner_impl<MatrixType, QRPreconditioner, internal::PreconditionIfMoreRowsThanCols> m_qr_precond_morerows;
00620     MatrixType m_scaledMatrix;
00621 };
00622 
00623 template<typename MatrixType, int QRPreconditioner>
00624 void JacobiSVD<MatrixType, QRPreconditioner>::allocate(Index p_rows, Index p_cols, unsigned int computationOptions)
00625 {
00626   eigen_assert(p_rows >= 0 && p_cols >= 0);
00627 
00628   if (m_isAllocated &&
00629       p_rows == m_rows &&
00630       p_cols == m_cols &&
00631       computationOptions == m_computationOptions)
00632   {
00633     return;
00634   }
00635 
00636   m_rows = p_rows;
00637   m_cols = p_cols;
00638   m_isInitialized = false;
00639   m_isAllocated = true;
00640   m_computationOptions = computationOptions;
00641   m_computeFullU = (computationOptions & ComputeFullU) != 0;
00642   m_computeThinU = (computationOptions & ComputeThinU) != 0;
00643   m_computeFullV = (computationOptions & ComputeFullV) != 0;
00644   m_computeThinV = (computationOptions & ComputeThinV) != 0;
00645   eigen_assert(!(m_computeFullU && m_computeThinU) && "JacobiSVD: you can't ask for both full and thin U");
00646   eigen_assert(!(m_computeFullV && m_computeThinV) && "JacobiSVD: you can't ask for both full and thin V");
00647   eigen_assert(EIGEN_IMPLIES(m_computeThinU || m_computeThinV, MatrixType::ColsAtCompileTime==Dynamic) &&
00648               "JacobiSVD: thin U and V are only available when your matrix has a dynamic number of columns.");
00649   if (QRPreconditioner == FullPivHouseholderQRPreconditioner)
00650   {
00651       eigen_assert(!(m_computeThinU || m_computeThinV) &&
00652               "JacobiSVD: can't compute thin U or thin V with the FullPivHouseholderQR preconditioner. "
00653               "Use the ColPivHouseholderQR preconditioner instead.");
00654   }
00655   m_diagSize = (std::min)(m_rows, m_cols);
00656   m_singularValues.resize(m_diagSize);
00657   if(RowsAtCompileTime==Dynamic)
00658     m_matrixU.resize(m_rows, m_computeFullU ? m_rows
00659                             : m_computeThinU ? m_diagSize
00660                             : 0);
00661   if(ColsAtCompileTime==Dynamic)
00662     m_matrixV.resize(m_cols, m_computeFullV ? m_cols
00663                             : m_computeThinV ? m_diagSize
00664                             : 0);
00665   m_workMatrix.resize(m_diagSize, m_diagSize);
00666   
00667   if(m_cols>m_rows)   m_qr_precond_morecols.allocate(*this);
00668   if(m_rows>m_cols)   m_qr_precond_morerows.allocate(*this);
00669   if(m_rows!=m_cols)  m_scaledMatrix.resize(p_rows,p_cols);
00670 }
00671 
00672 template<typename MatrixType, int QRPreconditioner>
00673 JacobiSVD<MatrixType, QRPreconditioner>&
00674 JacobiSVD<MatrixType, QRPreconditioner>::compute(const MatrixType& matrix, unsigned int computationOptions)
00675 {
00676   using std::abs;
00677   allocate(matrix.rows(), matrix.cols(), computationOptions);
00678 
00679   // currently we stop when we reach precision 2*epsilon as the last bit of precision can require an unreasonable number of iterations,
00680   // only worsening the precision of U and V as we accumulate more rotations
00681   const RealScalar precision = RealScalar(2) * NumTraits<Scalar>::epsilon();
00682 
00683   // limit for very small denormal numbers to be considered zero in order to avoid infinite loops (see bug 286)
00684   // FIXME What about considerering any denormal numbers as zero, using:
00685   // const RealScalar considerAsZero = (std::numeric_limits<RealScalar>::min)();
00686   const RealScalar considerAsZero = RealScalar(2) * std::numeric_limits<RealScalar>::denorm_min();
00687 
00688   // Scaling factor to reduce over/under-flows
00689   RealScalar scale = matrix.cwiseAbs().maxCoeff();
00690   if(scale==RealScalar(0)) scale = RealScalar(1);
00691   
00692   /*** step 1. The R-SVD step: we use a QR decomposition to reduce to the case of a square matrix */
00693 
00694   if(m_rows!=m_cols)
00695   {
00696     m_scaledMatrix = matrix / scale;
00697     m_qr_precond_morecols.run(*this, m_scaledMatrix);
00698     m_qr_precond_morerows.run(*this, m_scaledMatrix);
00699   }
00700   else
00701   {
00702     m_workMatrix = matrix.block(0,0,m_diagSize,m_diagSize) / scale;
00703     if(m_computeFullU) m_matrixU.setIdentity(m_rows,m_rows);
00704     if(m_computeThinU) m_matrixU.setIdentity(m_rows,m_diagSize);
00705     if(m_computeFullV) m_matrixV.setIdentity(m_cols,m_cols);
00706     if(m_computeThinV) m_matrixV.setIdentity(m_cols, m_diagSize);
00707   }
00708 
00709   /*** step 2. The main Jacobi SVD iteration. ***/
00710 
00711   bool finished = false;
00712   while(!finished)
00713   {
00714     finished = true;
00715 
00716     // do a sweep: for all index pairs (p,q), perform SVD of the corresponding 2x2 sub-matrix
00717 
00718     for(Index p = 1; p < m_diagSize; ++p)
00719     {
00720       for(Index q = 0; q < p; ++q)
00721       {
00722         // if this 2x2 sub-matrix is not diagonal already...
00723         // notice that this comparison will evaluate to false if any NaN is involved, ensuring that NaN's don't
00724         // keep us iterating forever. Similarly, small denormal numbers are considered zero.
00725         RealScalar threshold = numext::maxi<RealScalar>(considerAsZero,
00726                    precision * numext::maxi<RealScalar>(abs(m_workMatrix.coeff(p,p)),
00727                                                         abs(m_workMatrix.coeff(q,q))));
00728         // We compare both values to threshold instead of calling max to be robust to NaN (See bug 791)
00729         if(abs(m_workMatrix.coeff(p,q))>threshold || abs(m_workMatrix.coeff(q,p)) > threshold)
00730         {
00731           finished = false;
00732 
00733           // perform SVD decomposition of 2x2 sub-matrix corresponding to indices p,q to make it diagonal
00734           internal::svd_precondition_2x2_block_to_be_real<MatrixType, QRPreconditioner>::run(m_workMatrix, *this, p, q);
00735           JacobiRotation<RealScalar> j_left, j_right;
00736           internal::real_2x2_jacobi_svd(m_workMatrix, p, q, &j_left, &j_right);
00737 
00738           // accumulate resulting Jacobi rotations
00739           m_workMatrix.applyOnTheLeft(p,q,j_left);
00740           if(computeU()) m_matrixU.applyOnTheRight(p,q,j_left.transpose());
00741 
00742           m_workMatrix.applyOnTheRight(p,q,j_right);
00743           if(computeV()) m_matrixV.applyOnTheRight(p,q,j_right);
00744         }
00745       }
00746     }
00747   }
00748 
00749   /*** step 3. The work matrix is now diagonal, so ensure it's positive so its diagonal entries are the singular values ***/
00750 
00751   for(Index i = 0; i < m_diagSize; ++i)
00752   {
00753     RealScalar a = abs(m_workMatrix.coeff(i,i));
00754     m_singularValues.coeffRef(i) = a;
00755     if(computeU() && (a!=RealScalar(0))) m_matrixU.col(i) *= m_workMatrix.coeff(i,i)/a;
00756   }
00757   
00758   m_singularValues *= scale;
00759 
00760   /*** step 4. Sort singular values in descending order and compute the number of nonzero singular values ***/
00761 
00762   m_nonzeroSingularValues = m_diagSize;
00763   for(Index i = 0; i < m_diagSize; i++)
00764   {
00765     Index pos;
00766     RealScalar maxRemainingSingularValue = m_singularValues.tail(m_diagSize-i).maxCoeff(&pos);
00767     if(maxRemainingSingularValue == RealScalar(0))
00768     {
00769       m_nonzeroSingularValues = i;
00770       break;
00771     }
00772     if(pos)
00773     {
00774       pos += i;
00775       std::swap(m_singularValues.coeffRef(i), m_singularValues.coeffRef(pos));
00776       if(computeU()) m_matrixU.col(pos).swap(m_matrixU.col(i));
00777       if(computeV()) m_matrixV.col(pos).swap(m_matrixV.col(i));
00778     }
00779   }
00780 
00781   m_isInitialized = true;
00782   return *this;
00783 }
00784 
00785 #ifndef __CUDACC__
00786 
00793 template<typename Derived>
00794 JacobiSVD<typename MatrixBase<Derived>::PlainObject>
00795 MatrixBase<Derived>::jacobiSvd(unsigned int computationOptions) const
00796 {
00797   return JacobiSVD<PlainObject>(*this, computationOptions);
00798 }
00799 #endif // __CUDACC__
00800 
00801 } // end namespace Eigen
00802 
00803 #endif // EIGEN_JACOBISVD_H
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines