MOAB  4.9.3pre
LDLT.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) 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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines