MOAB
4.9.3pre
|
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