MOAB
4.9.3pre
|
00001 // This file is part of Eigen, a lightweight C++ template library 00002 // for linear algebra. 00003 // 00004 // Copyright (C) 2008-2011 Gael Guennebaud <[email protected]> 00005 // Copyright (C) 2009 Keir Mierle <[email protected]> 00006 // Copyright (C) 2009 Benoit Jacob <[email protected]> 00007 // Copyright (C) 2011 Timothy E. Holy <[email protected] > 00008 // 00009 // This Source Code Form is subject to the terms of the Mozilla 00010 // Public License v. 2.0. If a copy of the MPL was not distributed 00011 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 00012 00013 #ifndef EIGEN_LDLT_H 00014 #define EIGEN_LDLT_H 00015 00016 namespace Eigen { 00017 00018 namespace internal { 00019 template<typename MatrixType, int UpLo> struct LDLT_Traits; 00020 00021 // PositiveSemiDef means positive semi-definite and non-zero; same for NegativeSemiDef 00022 enum SignMatrix { PositiveSemiDef, NegativeSemiDef, ZeroSign, Indefinite }; 00023 } 00024 00048 template<typename _MatrixType, int _UpLo> class LDLT 00049 { 00050 public: 00051 typedef _MatrixType MatrixType; 00052 enum { 00053 RowsAtCompileTime = MatrixType::RowsAtCompileTime, 00054 ColsAtCompileTime = MatrixType::ColsAtCompileTime, 00055 Options = MatrixType::Options & ~RowMajorBit, // these are the options for the TmpMatrixType, we need a ColMajor matrix here! 00056 MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, 00057 MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, 00058 UpLo = _UpLo 00059 }; 00060 typedef typename MatrixType::Scalar Scalar; 00061 typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar; 00062 typedef Eigen::Index Index; 00063 typedef typename MatrixType::StorageIndex StorageIndex; 00064 typedef Matrix<Scalar, RowsAtCompileTime, 1, Options, MaxRowsAtCompileTime, 1> TmpMatrixType; 00065 00066 typedef Transpositions<RowsAtCompileTime, MaxRowsAtCompileTime> TranspositionType; 00067 typedef PermutationMatrix<RowsAtCompileTime, MaxRowsAtCompileTime> PermutationType; 00068 00069 typedef internal::LDLT_Traits<MatrixType,UpLo> Traits; 00070 00076 LDLT() 00077 : m_matrix(), 00078 m_transpositions(), 00079 m_sign(internal::ZeroSign), 00080 m_isInitialized(false) 00081 {} 00082 00089 explicit LDLT(Index size) 00090 : m_matrix(size, size), 00091 m_transpositions(size), 00092 m_temporary(size), 00093 m_sign(internal::ZeroSign), 00094 m_isInitialized(false) 00095 {} 00096 00102 template<typename InputType> 00103 explicit LDLT(const EigenBase<InputType>& matrix) 00104 : m_matrix(matrix.rows(), matrix.cols()), 00105 m_transpositions(matrix.rows()), 00106 m_temporary(matrix.rows()), 00107 m_sign(internal::ZeroSign), 00108 m_isInitialized(false) 00109 { 00110 compute(matrix.derived()); 00111 } 00112 00116 void setZero() 00117 { 00118 m_isInitialized = false; 00119 } 00120 00122 inline typename Traits::MatrixU matrixU() const 00123 { 00124 eigen_assert(m_isInitialized && "LDLT is not initialized."); 00125 return Traits::getU(m_matrix); 00126 } 00127 00129 inline typename Traits::MatrixL matrixL() const 00130 { 00131 eigen_assert(m_isInitialized && "LDLT is not initialized."); 00132 return Traits::getL(m_matrix); 00133 } 00134 00137 inline const TranspositionType& transpositionsP() const 00138 { 00139 eigen_assert(m_isInitialized && "LDLT is not initialized."); 00140 return m_transpositions; 00141 } 00142 00144 inline Diagonal<const MatrixType> vectorD() const 00145 { 00146 eigen_assert(m_isInitialized && "LDLT is not initialized."); 00147 return m_matrix.diagonal(); 00148 } 00149 00151 inline bool isPositive() const 00152 { 00153 eigen_assert(m_isInitialized && "LDLT is not initialized."); 00154 return m_sign == internal::PositiveSemiDef || m_sign == internal::ZeroSign; 00155 } 00156 00158 inline bool isNegative(void) const 00159 { 00160 eigen_assert(m_isInitialized && "LDLT is not initialized."); 00161 return m_sign == internal::NegativeSemiDef || m_sign == internal::ZeroSign; 00162 } 00163 00179 template<typename Rhs> 00180 inline const Solve<LDLT, Rhs> 00181 solve(const MatrixBase<Rhs>& b) const 00182 { 00183 eigen_assert(m_isInitialized && "LDLT is not initialized."); 00184 eigen_assert(m_matrix.rows()==b.rows() 00185 && "LDLT::solve(): invalid number of rows of the right hand side matrix b"); 00186 return Solve<LDLT, Rhs>(*this, b.derived()); 00187 } 00188 00189 template<typename Derived> 00190 bool solveInPlace(MatrixBase<Derived> &bAndX) const; 00191 00192 template<typename InputType> 00193 LDLT& compute(const EigenBase<InputType>& matrix); 00194 00195 template <typename Derived> 00196 LDLT& rankUpdate(const MatrixBase<Derived>& w, const RealScalar& alpha=1); 00197 00202 inline const MatrixType& matrixLDLT() const 00203 { 00204 eigen_assert(m_isInitialized && "LDLT is not initialized."); 00205 return m_matrix; 00206 } 00207 00208 MatrixType reconstructedMatrix() const; 00209 00210 inline Index rows() const { return m_matrix.rows(); } 00211 inline Index cols() const { return m_matrix.cols(); } 00212 00218 ComputationInfo info() const 00219 { 00220 eigen_assert(m_isInitialized && "LDLT is not initialized."); 00221 return Success; 00222 } 00223 00224 #ifndef EIGEN_PARSED_BY_DOXYGEN 00225 template<typename RhsType, typename DstType> 00226 EIGEN_DEVICE_FUNC 00227 void _solve_impl(const RhsType &rhs, DstType &dst) const; 00228 #endif 00229 00230 protected: 00231 00232 static void check_template_parameters() 00233 { 00234 EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); 00235 } 00236 00243 MatrixType m_matrix; 00244 TranspositionType m_transpositions; 00245 TmpMatrixType m_temporary; 00246 internal::SignMatrix m_sign; 00247 bool m_isInitialized; 00248 }; 00249 00250 namespace internal { 00251 00252 template<int UpLo> struct ldlt_inplace; 00253 00254 template<> struct ldlt_inplace<Lower> 00255 { 00256 template<typename MatrixType, typename TranspositionType, typename Workspace> 00257 static bool unblocked(MatrixType& mat, TranspositionType& transpositions, Workspace& temp, SignMatrix& sign) 00258 { 00259 using std::abs; 00260 typedef typename MatrixType::Scalar Scalar; 00261 typedef typename MatrixType::RealScalar RealScalar; 00262 typedef typename TranspositionType::StorageIndex IndexType; 00263 eigen_assert(mat.rows()==mat.cols()); 00264 const Index size = mat.rows(); 00265 00266 if (size <= 1) 00267 { 00268 transpositions.setIdentity(); 00269 if (numext::real(mat.coeff(0,0)) > 0) sign = PositiveSemiDef; 00270 else if (numext::real(mat.coeff(0,0)) < 0) sign = NegativeSemiDef; 00271 else sign = ZeroSign; 00272 return true; 00273 } 00274 00275 for (Index k = 0; k < size; ++k) 00276 { 00277 // Find largest diagonal element 00278 Index index_of_biggest_in_corner; 00279 mat.diagonal().tail(size-k).cwiseAbs().maxCoeff(&index_of_biggest_in_corner); 00280 index_of_biggest_in_corner += k; 00281 00282 transpositions.coeffRef(k) = IndexType(index_of_biggest_in_corner); 00283 if(k != index_of_biggest_in_corner) 00284 { 00285 // apply the transposition while taking care to consider only 00286 // the lower triangular part 00287 Index s = size-index_of_biggest_in_corner-1; // trailing size after the biggest element 00288 mat.row(k).head(k).swap(mat.row(index_of_biggest_in_corner).head(k)); 00289 mat.col(k).tail(s).swap(mat.col(index_of_biggest_in_corner).tail(s)); 00290 std::swap(mat.coeffRef(k,k),mat.coeffRef(index_of_biggest_in_corner,index_of_biggest_in_corner)); 00291 for(Index i=k+1;i<index_of_biggest_in_corner;++i) 00292 { 00293 Scalar tmp = mat.coeffRef(i,k); 00294 mat.coeffRef(i,k) = numext::conj(mat.coeffRef(index_of_biggest_in_corner,i)); 00295 mat.coeffRef(index_of_biggest_in_corner,i) = numext::conj(tmp); 00296 } 00297 if(NumTraits<Scalar>::IsComplex) 00298 mat.coeffRef(index_of_biggest_in_corner,k) = numext::conj(mat.coeff(index_of_biggest_in_corner,k)); 00299 } 00300 00301 // partition the matrix: 00302 // A00 | - | - 00303 // lu = A10 | A11 | - 00304 // A20 | A21 | A22 00305 Index rs = size - k - 1; 00306 Block<MatrixType,Dynamic,1> A21(mat,k+1,k,rs,1); 00307 Block<MatrixType,1,Dynamic> A10(mat,k,0,1,k); 00308 Block<MatrixType,Dynamic,Dynamic> A20(mat,k+1,0,rs,k); 00309 00310 if(k>0) 00311 { 00312 temp.head(k) = mat.diagonal().real().head(k).asDiagonal() * A10.adjoint(); 00313 mat.coeffRef(k,k) -= (A10 * temp.head(k)).value(); 00314 if(rs>0) 00315 A21.noalias() -= A20 * temp.head(k); 00316 } 00317 00318 // In some previous versions of Eigen (e.g., 3.2.1), the scaling was omitted if the pivot 00319 // was smaller than the cutoff value. However, since LDLT is not rank-revealing 00320 // we should only make sure that we do not introduce INF or NaN values. 00321 // Remark that LAPACK also uses 0 as the cutoff value. 00322 RealScalar realAkk = numext::real(mat.coeffRef(k,k)); 00323 if((rs>0) && (abs(realAkk) > RealScalar(0))) 00324 A21 /= realAkk; 00325 00326 if (sign == PositiveSemiDef) { 00327 if (realAkk < 0) sign = Indefinite; 00328 } else if (sign == NegativeSemiDef) { 00329 if (realAkk > 0) sign = Indefinite; 00330 } else if (sign == ZeroSign) { 00331 if (realAkk > 0) sign = PositiveSemiDef; 00332 else if (realAkk < 0) sign = NegativeSemiDef; 00333 } 00334 } 00335 00336 return true; 00337 } 00338 00339 // Reference for the algorithm: Davis and Hager, "Multiple Rank 00340 // Modifications of a Sparse Cholesky Factorization" (Algorithm 1) 00341 // Trivial rearrangements of their computations (Timothy E. Holy) 00342 // allow their algorithm to work for rank-1 updates even if the 00343 // original matrix is not of full rank. 00344 // Here only rank-1 updates are implemented, to reduce the 00345 // requirement for intermediate storage and improve accuracy 00346 template<typename MatrixType, typename WDerived> 00347 static bool updateInPlace(MatrixType& mat, MatrixBase<WDerived>& w, const typename MatrixType::RealScalar& sigma=1) 00348 { 00349 using numext::isfinite; 00350 typedef typename MatrixType::Scalar Scalar; 00351 typedef typename MatrixType::RealScalar RealScalar; 00352 00353 const Index size = mat.rows(); 00354 eigen_assert(mat.cols() == size && w.size()==size); 00355 00356 RealScalar alpha = 1; 00357 00358 // Apply the update 00359 for (Index j = 0; j < size; j++) 00360 { 00361 // Check for termination due to an original decomposition of low-rank 00362 if (!(isfinite)(alpha)) 00363 break; 00364 00365 // Update the diagonal terms 00366 RealScalar dj = numext::real(mat.coeff(j,j)); 00367 Scalar wj = w.coeff(j); 00368 RealScalar swj2 = sigma*numext::abs2(wj); 00369 RealScalar gamma = dj*alpha + swj2; 00370 00371 mat.coeffRef(j,j) += swj2/alpha; 00372 alpha += swj2/dj; 00373 00374 00375 // Update the terms of L 00376 Index rs = size-j-1; 00377 w.tail(rs) -= wj * mat.col(j).tail(rs); 00378 if(gamma != 0) 00379 mat.col(j).tail(rs) += (sigma*numext::conj(wj)/gamma)*w.tail(rs); 00380 } 00381 return true; 00382 } 00383 00384 template<typename MatrixType, typename TranspositionType, typename Workspace, typename WType> 00385 static bool update(MatrixType& mat, const TranspositionType& transpositions, Workspace& tmp, const WType& w, const typename MatrixType::RealScalar& sigma=1) 00386 { 00387 // Apply the permutation to the input w 00388 tmp = transpositions * w; 00389 00390 return ldlt_inplace<Lower>::updateInPlace(mat,tmp,sigma); 00391 } 00392 }; 00393 00394 template<> struct ldlt_inplace<Upper> 00395 { 00396 template<typename MatrixType, typename TranspositionType, typename Workspace> 00397 static EIGEN_STRONG_INLINE bool unblocked(MatrixType& mat, TranspositionType& transpositions, Workspace& temp, SignMatrix& sign) 00398 { 00399 Transpose<MatrixType> matt(mat); 00400 return ldlt_inplace<Lower>::unblocked(matt, transpositions, temp, sign); 00401 } 00402 00403 template<typename MatrixType, typename TranspositionType, typename Workspace, typename WType> 00404 static EIGEN_STRONG_INLINE bool update(MatrixType& mat, TranspositionType& transpositions, Workspace& tmp, WType& w, const typename MatrixType::RealScalar& sigma=1) 00405 { 00406 Transpose<MatrixType> matt(mat); 00407 return ldlt_inplace<Lower>::update(matt, transpositions, tmp, w.conjugate(), sigma); 00408 } 00409 }; 00410 00411 template<typename MatrixType> struct LDLT_Traits<MatrixType,Lower> 00412 { 00413 typedef const TriangularView<const MatrixType, UnitLower> MatrixL; 00414 typedef const TriangularView<const typename MatrixType::AdjointReturnType, UnitUpper> MatrixU; 00415 static inline MatrixL getL(const MatrixType& m) { return MatrixL(m); } 00416 static inline MatrixU getU(const MatrixType& m) { return MatrixU(m.adjoint()); } 00417 }; 00418 00419 template<typename MatrixType> struct LDLT_Traits<MatrixType,Upper> 00420 { 00421 typedef const TriangularView<const typename MatrixType::AdjointReturnType, UnitLower> MatrixL; 00422 typedef const TriangularView<const MatrixType, UnitUpper> MatrixU; 00423 static inline MatrixL getL(const MatrixType& m) { return MatrixL(m.adjoint()); } 00424 static inline MatrixU getU(const MatrixType& m) { return MatrixU(m); } 00425 }; 00426 00427 } // end namespace internal 00428 00431 template<typename MatrixType, int _UpLo> 00432 template<typename InputType> 00433 LDLT<MatrixType,_UpLo>& LDLT<MatrixType,_UpLo>::compute(const EigenBase<InputType>& a) 00434 { 00435 check_template_parameters(); 00436 00437 eigen_assert(a.rows()==a.cols()); 00438 const Index size = a.rows(); 00439 00440 m_matrix = a.derived(); 00441 00442 m_transpositions.resize(size); 00443 m_isInitialized = false; 00444 m_temporary.resize(size); 00445 m_sign = internal::ZeroSign; 00446 00447 internal::ldlt_inplace<UpLo>::unblocked(m_matrix, m_transpositions, m_temporary, m_sign); 00448 00449 m_isInitialized = true; 00450 return *this; 00451 } 00452 00458 template<typename MatrixType, int _UpLo> 00459 template<typename Derived> 00460 LDLT<MatrixType,_UpLo>& LDLT<MatrixType,_UpLo>::rankUpdate(const MatrixBase<Derived>& w, const typename LDLT<MatrixType,_UpLo>::RealScalar& sigma) 00461 { 00462 typedef typename TranspositionType::StorageIndex IndexType; 00463 const Index size = w.rows(); 00464 if (m_isInitialized) 00465 { 00466 eigen_assert(m_matrix.rows()==size); 00467 } 00468 else 00469 { 00470 m_matrix.resize(size,size); 00471 m_matrix.setZero(); 00472 m_transpositions.resize(size); 00473 for (Index i = 0; i < size; i++) 00474 m_transpositions.coeffRef(i) = IndexType(i); 00475 m_temporary.resize(size); 00476 m_sign = sigma>=0 ? internal::PositiveSemiDef : internal::NegativeSemiDef; 00477 m_isInitialized = true; 00478 } 00479 00480 internal::ldlt_inplace<UpLo>::update(m_matrix, m_transpositions, m_temporary, w, sigma); 00481 00482 return *this; 00483 } 00484 00485 #ifndef EIGEN_PARSED_BY_DOXYGEN 00486 template<typename _MatrixType, int _UpLo> 00487 template<typename RhsType, typename DstType> 00488 void LDLT<_MatrixType,_UpLo>::_solve_impl(const RhsType &rhs, DstType &dst) const 00489 { 00490 eigen_assert(rhs.rows() == rows()); 00491 // dst = P b 00492 dst = m_transpositions * rhs; 00493 00494 // dst = L^-1 (P b) 00495 matrixL().solveInPlace(dst); 00496 00497 // dst = D^-1 (L^-1 P b) 00498 // more precisely, use pseudo-inverse of D (see bug 241) 00499 using std::abs; 00500 const typename Diagonal<const MatrixType>::RealReturnType vecD(vectorD()); 00501 // In some previous versions, tolerance was set to the max of 1/highest and the maximal diagonal entry * epsilon 00502 // as motivated by LAPACK's xGELSS: 00503 // RealScalar tolerance = numext::maxi(vecD.array().abs().maxCoeff() * NumTraits<RealScalar>::epsilon(),RealScalar(1) / NumTraits<RealScalar>::highest()); 00504 // However, LDLT is not rank revealing, and so adjusting the tolerance wrt to the highest 00505 // diagonal element is not well justified and leads to numerical issues in some cases. 00506 // Moreover, Lapack's xSYTRS routines use 0 for the tolerance. 00507 RealScalar tolerance = RealScalar(1) / NumTraits<RealScalar>::highest(); 00508 00509 for (Index i = 0; i < vecD.size(); ++i) 00510 { 00511 if(abs(vecD(i)) > tolerance) 00512 dst.row(i) /= vecD(i); 00513 else 00514 dst.row(i).setZero(); 00515 } 00516 00517 // dst = L^-T (D^-1 L^-1 P b) 00518 matrixU().solveInPlace(dst); 00519 00520 // dst = P^-1 (L^-T D^-1 L^-1 P b) = A^-1 b 00521 dst = m_transpositions.transpose() * dst; 00522 } 00523 #endif 00524 00538 template<typename MatrixType,int _UpLo> 00539 template<typename Derived> 00540 bool LDLT<MatrixType,_UpLo>::solveInPlace(MatrixBase<Derived> &bAndX) const 00541 { 00542 eigen_assert(m_isInitialized && "LDLT is not initialized."); 00543 eigen_assert(m_matrix.rows() == bAndX.rows()); 00544 00545 bAndX = this->solve(bAndX); 00546 00547 return true; 00548 } 00549 00553 template<typename MatrixType, int _UpLo> 00554 MatrixType LDLT<MatrixType,_UpLo>::reconstructedMatrix() const 00555 { 00556 eigen_assert(m_isInitialized && "LDLT is not initialized."); 00557 const Index size = m_matrix.rows(); 00558 MatrixType res(size,size); 00559 00560 // P 00561 res.setIdentity(); 00562 res = transpositionsP() * res; 00563 // L^* P 00564 res = matrixU() * res; 00565 // D(L^*P) 00566 res = vectorD().real().asDiagonal() * res; 00567 // L(DL^*P) 00568 res = matrixL() * res; 00569 // P^T (LDL^*P) 00570 res = transpositionsP().transpose() * res; 00571 00572 return res; 00573 } 00574 00575 #ifndef __CUDACC__ 00576 00580 template<typename MatrixType, unsigned int UpLo> 00581 inline const LDLT<typename SelfAdjointView<MatrixType, UpLo>::PlainObject, UpLo> 00582 SelfAdjointView<MatrixType, UpLo>::ldlt() const 00583 { 00584 return LDLT<PlainObject,UpLo>(m_matrix); 00585 } 00586 00591 template<typename Derived> 00592 inline const LDLT<typename MatrixBase<Derived>::PlainObject> 00593 MatrixBase<Derived>::ldlt() const 00594 { 00595 return LDLT<PlainObject>(derived()); 00596 } 00597 #endif // __CUDACC__ 00598 00599 } // end namespace Eigen 00600 00601 #endif // EIGEN_LDLT_H