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 <gael.guennebaud@inria.fr>
00005 // Copyright (C) 2009 Keir Mierle <mierle@gmail.com>
00006 // Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com>
00007 // Copyright (C) 2011 Timothy E. Holy <tim.holy@gmail.com >
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 typename MatrixType::Index Index;
00063     typedef Matrix<Scalar, RowsAtCompileTime, 1, Options, MaxRowsAtCompileTime, 1> TmpMatrixType;
00064 
00065     typedef Transpositions<RowsAtCompileTime, MaxRowsAtCompileTime> TranspositionType;
00066     typedef PermutationMatrix<RowsAtCompileTime, MaxRowsAtCompileTime> PermutationType;
00067 
00068     typedef internal::LDLT_Traits<MatrixType,UpLo> Traits;
00069 
00075     LDLT() 
00076       : m_matrix(), 
00077         m_transpositions(), 
00078         m_sign(internal::ZeroSign),
00079         m_isInitialized(false) 
00080     {}
00081 
00088     LDLT(Index size)
00089       : m_matrix(size, size),
00090         m_transpositions(size),
00091         m_temporary(size),
00092         m_sign(internal::ZeroSign),
00093         m_isInitialized(false)
00094     {}
00095 
00101     LDLT(const MatrixType& matrix)
00102       : m_matrix(matrix.rows(), matrix.cols()),
00103         m_transpositions(matrix.rows()),
00104         m_temporary(matrix.rows()),
00105         m_sign(internal::ZeroSign),
00106         m_isInitialized(false)
00107     {
00108       compute(matrix);
00109     }
00110 
00114     void setZero()
00115     {
00116       m_isInitialized = false;
00117     }
00118 
00120     inline typename Traits::MatrixU matrixU() const
00121     {
00122       eigen_assert(m_isInitialized && "LDLT is not initialized.");
00123       return Traits::getU(m_matrix);
00124     }
00125 
00127     inline typename Traits::MatrixL matrixL() const
00128     {
00129       eigen_assert(m_isInitialized && "LDLT is not initialized.");
00130       return Traits::getL(m_matrix);
00131     }
00132 
00135     inline const TranspositionType& transpositionsP() const
00136     {
00137       eigen_assert(m_isInitialized && "LDLT is not initialized.");
00138       return m_transpositions;
00139     }
00140 
00142     inline Diagonal<const MatrixType> vectorD() const
00143     {
00144       eigen_assert(m_isInitialized && "LDLT is not initialized.");
00145       return m_matrix.diagonal();
00146     }
00147 
00149     inline bool isPositive() const
00150     {
00151       eigen_assert(m_isInitialized && "LDLT is not initialized.");
00152       return m_sign == internal::PositiveSemiDef || m_sign == internal::ZeroSign;
00153     }
00154     
00155     #ifdef EIGEN2_SUPPORT
00156     inline bool isPositiveDefinite() const
00157     {
00158       return isPositive();
00159     }
00160     #endif
00161 
00163     inline bool isNegative(void) const
00164     {
00165       eigen_assert(m_isInitialized && "LDLT is not initialized.");
00166       return m_sign == internal::NegativeSemiDef || m_sign == internal::ZeroSign;
00167     }
00168 
00184     template<typename Rhs>
00185     inline const internal::solve_retval<LDLT, Rhs>
00186     solve(const MatrixBase<Rhs>& b) const
00187     {
00188       eigen_assert(m_isInitialized && "LDLT is not initialized.");
00189       eigen_assert(m_matrix.rows()==b.rows()
00190                 && "LDLT::solve(): invalid number of rows of the right hand side matrix b");
00191       return internal::solve_retval<LDLT, Rhs>(*this, b.derived());
00192     }
00193 
00194     #ifdef EIGEN2_SUPPORT
00195     template<typename OtherDerived, typename ResultType>
00196     bool solve(const MatrixBase<OtherDerived>& b, ResultType *result) const
00197     {
00198       *result = this->solve(b);
00199       return true;
00200     }
00201     #endif
00202 
00203     template<typename Derived>
00204     bool solveInPlace(MatrixBase<Derived> &bAndX) const;
00205 
00206     LDLT& compute(const MatrixType& matrix);
00207 
00208     template <typename Derived>
00209     LDLT& rankUpdate(const MatrixBase<Derived>& w, const RealScalar& alpha=1);
00210 
00215     inline const MatrixType& matrixLDLT() const
00216     {
00217       eigen_assert(m_isInitialized && "LDLT is not initialized.");
00218       return m_matrix;
00219     }
00220 
00221     MatrixType reconstructedMatrix() const;
00222 
00223     inline Index rows() const { return m_matrix.rows(); }
00224     inline Index cols() const { return m_matrix.cols(); }
00225 
00231     ComputationInfo info() const
00232     {
00233       eigen_assert(m_isInitialized && "LDLT is not initialized.");
00234       return Success;
00235     }
00236 
00237   protected:
00238     
00239     static void check_template_parameters()
00240     {
00241       EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
00242     }
00243 
00250     MatrixType m_matrix;
00251     TranspositionType m_transpositions;
00252     TmpMatrixType m_temporary;
00253     internal::SignMatrix m_sign;
00254     bool m_isInitialized;
00255 };
00256 
00257 namespace internal {
00258 
00259 template<int UpLo> struct ldlt_inplace;
00260 
00261 template<> struct ldlt_inplace<Lower>
00262 {
00263   template<typename MatrixType, typename TranspositionType, typename Workspace>
00264   static bool unblocked(MatrixType& mat, TranspositionType& transpositions, Workspace& temp, SignMatrix& sign)
00265   {
00266     using std::abs;
00267     typedef typename MatrixType::Scalar Scalar;
00268     typedef typename MatrixType::RealScalar RealScalar;
00269     typedef typename MatrixType::Index Index;
00270     eigen_assert(mat.rows()==mat.cols());
00271     const Index size = mat.rows();
00272 
00273     if (size <= 1)
00274     {
00275       transpositions.setIdentity();
00276       if (numext::real(mat.coeff(0,0)) > 0) sign = PositiveSemiDef;
00277       else if (numext::real(mat.coeff(0,0)) < 0) sign = NegativeSemiDef;
00278       else sign = ZeroSign;
00279       return true;
00280     }
00281 
00282     for (Index k = 0; k < size; ++k)
00283     {
00284       // Find largest diagonal element
00285       Index index_of_biggest_in_corner;
00286       mat.diagonal().tail(size-k).cwiseAbs().maxCoeff(&index_of_biggest_in_corner);
00287       index_of_biggest_in_corner += k;
00288 
00289       transpositions.coeffRef(k) = index_of_biggest_in_corner;
00290       if(k != index_of_biggest_in_corner)
00291       {
00292         // apply the transposition while taking care to consider only
00293         // the lower triangular part
00294         Index s = size-index_of_biggest_in_corner-1; // trailing size after the biggest element
00295         mat.row(k).head(k).swap(mat.row(index_of_biggest_in_corner).head(k));
00296         mat.col(k).tail(s).swap(mat.col(index_of_biggest_in_corner).tail(s));
00297         std::swap(mat.coeffRef(k,k),mat.coeffRef(index_of_biggest_in_corner,index_of_biggest_in_corner));
00298         for(int i=k+1;i<index_of_biggest_in_corner;++i)
00299         {
00300           Scalar tmp = mat.coeffRef(i,k);
00301           mat.coeffRef(i,k) = numext::conj(mat.coeffRef(index_of_biggest_in_corner,i));
00302           mat.coeffRef(index_of_biggest_in_corner,i) = numext::conj(tmp);
00303         }
00304         if(NumTraits<Scalar>::IsComplex)
00305           mat.coeffRef(index_of_biggest_in_corner,k) = numext::conj(mat.coeff(index_of_biggest_in_corner,k));
00306       }
00307 
00308       // partition the matrix:
00309       //       A00 |  -  |  -
00310       // lu  = A10 | A11 |  -
00311       //       A20 | A21 | A22
00312       Index rs = size - k - 1;
00313       Block<MatrixType,Dynamic,1> A21(mat,k+1,k,rs,1);
00314       Block<MatrixType,1,Dynamic> A10(mat,k,0,1,k);
00315       Block<MatrixType,Dynamic,Dynamic> A20(mat,k+1,0,rs,k);
00316 
00317       if(k>0)
00318       {
00319         temp.head(k) = mat.diagonal().real().head(k).asDiagonal() * A10.adjoint();
00320         mat.coeffRef(k,k) -= (A10 * temp.head(k)).value();
00321         if(rs>0)
00322           A21.noalias() -= A20 * temp.head(k);
00323       }
00324       
00325       // In some previous versions of Eigen (e.g., 3.2.1), the scaling was omitted if the pivot
00326       // was smaller than the cutoff value. However, soince LDLT is not rank-revealing
00327       // we should only make sure we do not introduce INF or NaN values.
00328       // LAPACK also uses 0 as the cutoff value.
00329       RealScalar realAkk = numext::real(mat.coeffRef(k,k));
00330       if((rs>0) && (abs(realAkk) > RealScalar(0)))
00331         A21 /= realAkk;
00332 
00333       if (sign == PositiveSemiDef) {
00334         if (realAkk < 0) sign = Indefinite;
00335       } else if (sign == NegativeSemiDef) {
00336         if (realAkk > 0) sign = Indefinite;
00337       } else if (sign == ZeroSign) {
00338         if (realAkk > 0) sign = PositiveSemiDef;
00339         else if (realAkk < 0) sign = NegativeSemiDef;
00340       }
00341     }
00342 
00343     return true;
00344   }
00345 
00346   // Reference for the algorithm: Davis and Hager, "Multiple Rank
00347   // Modifications of a Sparse Cholesky Factorization" (Algorithm 1)
00348   // Trivial rearrangements of their computations (Timothy E. Holy)
00349   // allow their algorithm to work for rank-1 updates even if the
00350   // original matrix is not of full rank.
00351   // Here only rank-1 updates are implemented, to reduce the
00352   // requirement for intermediate storage and improve accuracy
00353   template<typename MatrixType, typename WDerived>
00354   static bool updateInPlace(MatrixType& mat, MatrixBase<WDerived>& w, const typename MatrixType::RealScalar& sigma=1)
00355   {
00356     using numext::isfinite;
00357     typedef typename MatrixType::Scalar Scalar;
00358     typedef typename MatrixType::RealScalar RealScalar;
00359     typedef typename MatrixType::Index Index;
00360 
00361     const Index size = mat.rows();
00362     eigen_assert(mat.cols() == size && w.size()==size);
00363 
00364     RealScalar alpha = 1;
00365 
00366     // Apply the update
00367     for (Index j = 0; j < size; j++)
00368     {
00369       // Check for termination due to an original decomposition of low-rank
00370       if (!(isfinite)(alpha))
00371         break;
00372 
00373       // Update the diagonal terms
00374       RealScalar dj = numext::real(mat.coeff(j,j));
00375       Scalar wj = w.coeff(j);
00376       RealScalar swj2 = sigma*numext::abs2(wj);
00377       RealScalar gamma = dj*alpha + swj2;
00378 
00379       mat.coeffRef(j,j) += swj2/alpha;
00380       alpha += swj2/dj;
00381 
00382 
00383       // Update the terms of L
00384       Index rs = size-j-1;
00385       w.tail(rs) -= wj * mat.col(j).tail(rs);
00386       if(gamma != 0)
00387         mat.col(j).tail(rs) += (sigma*numext::conj(wj)/gamma)*w.tail(rs);
00388     }
00389     return true;
00390   }
00391 
00392   template<typename MatrixType, typename TranspositionType, typename Workspace, typename WType>
00393   static bool update(MatrixType& mat, const TranspositionType& transpositions, Workspace& tmp, const WType& w, const typename MatrixType::RealScalar& sigma=1)
00394   {
00395     // Apply the permutation to the input w
00396     tmp = transpositions * w;
00397 
00398     return ldlt_inplace<Lower>::updateInPlace(mat,tmp,sigma);
00399   }
00400 };
00401 
00402 template<> struct ldlt_inplace<Upper>
00403 {
00404   template<typename MatrixType, typename TranspositionType, typename Workspace>
00405   static EIGEN_STRONG_INLINE bool unblocked(MatrixType& mat, TranspositionType& transpositions, Workspace& temp, SignMatrix& sign)
00406   {
00407     Transpose<MatrixType> matt(mat);
00408     return ldlt_inplace<Lower>::unblocked(matt, transpositions, temp, sign);
00409   }
00410 
00411   template<typename MatrixType, typename TranspositionType, typename Workspace, typename WType>
00412   static EIGEN_STRONG_INLINE bool update(MatrixType& mat, TranspositionType& transpositions, Workspace& tmp, WType& w, const typename MatrixType::RealScalar& sigma=1)
00413   {
00414     Transpose<MatrixType> matt(mat);
00415     return ldlt_inplace<Lower>::update(matt, transpositions, tmp, w.conjugate(), sigma);
00416   }
00417 };
00418 
00419 template<typename MatrixType> struct LDLT_Traits<MatrixType,Lower>
00420 {
00421   typedef const TriangularView<const MatrixType, UnitLower> MatrixL;
00422   typedef const TriangularView<const typename MatrixType::AdjointReturnType, UnitUpper> MatrixU;
00423   static inline MatrixL getL(const MatrixType& m) { return m; }
00424   static inline MatrixU getU(const MatrixType& m) { return m.adjoint(); }
00425 };
00426 
00427 template<typename MatrixType> struct LDLT_Traits<MatrixType,Upper>
00428 {
00429   typedef const TriangularView<const typename MatrixType::AdjointReturnType, UnitLower> MatrixL;
00430   typedef const TriangularView<const MatrixType, UnitUpper> MatrixU;
00431   static inline MatrixL getL(const MatrixType& m) { return m.adjoint(); }
00432   static inline MatrixU getU(const MatrixType& m) { return m; }
00433 };
00434 
00435 } // end namespace internal
00436 
00439 template<typename MatrixType, int _UpLo>
00440 LDLT<MatrixType,_UpLo>& LDLT<MatrixType,_UpLo>::compute(const MatrixType& a)
00441 {
00442   check_template_parameters();
00443   
00444   eigen_assert(a.rows()==a.cols());
00445   const Index size = a.rows();
00446 
00447   m_matrix = a;
00448 
00449   m_transpositions.resize(size);
00450   m_isInitialized = false;
00451   m_temporary.resize(size);
00452   m_sign = internal::ZeroSign;
00453 
00454   internal::ldlt_inplace<UpLo>::unblocked(m_matrix, m_transpositions, m_temporary, m_sign);
00455 
00456   m_isInitialized = true;
00457   return *this;
00458 }
00459 
00465 template<typename MatrixType, int _UpLo>
00466 template<typename Derived>
00467 LDLT<MatrixType,_UpLo>& LDLT<MatrixType,_UpLo>::rankUpdate(const MatrixBase<Derived>& w, const typename NumTraits<typename MatrixType::Scalar>::Real& sigma)
00468 {
00469   const Index size = w.rows();
00470   if (m_isInitialized)
00471   {
00472     eigen_assert(m_matrix.rows()==size);
00473   }
00474   else
00475   {    
00476     m_matrix.resize(size,size);
00477     m_matrix.setZero();
00478     m_transpositions.resize(size);
00479     for (Index i = 0; i < size; i++)
00480       m_transpositions.coeffRef(i) = i;
00481     m_temporary.resize(size);
00482     m_sign = sigma>=0 ? internal::PositiveSemiDef : internal::NegativeSemiDef;
00483     m_isInitialized = true;
00484   }
00485 
00486   internal::ldlt_inplace<UpLo>::update(m_matrix, m_transpositions, m_temporary, w, sigma);
00487 
00488   return *this;
00489 }
00490 
00491 namespace internal {
00492 template<typename _MatrixType, int _UpLo, typename Rhs>
00493 struct solve_retval<LDLT<_MatrixType,_UpLo>, Rhs>
00494   : solve_retval_base<LDLT<_MatrixType,_UpLo>, Rhs>
00495 {
00496   typedef LDLT<_MatrixType,_UpLo> LDLTType;
00497   EIGEN_MAKE_SOLVE_HELPERS(LDLTType,Rhs)
00498 
00499   template<typename Dest> void evalTo(Dest& dst) const
00500   {
00501     eigen_assert(rhs().rows() == dec().matrixLDLT().rows());
00502     // dst = P b
00503     dst = dec().transpositionsP() * rhs();
00504 
00505     // dst = L^-1 (P b)
00506     dec().matrixL().solveInPlace(dst);
00507 
00508     // dst = D^-1 (L^-1 P b)
00509     // more precisely, use pseudo-inverse of D (see bug 241)
00510     using std::abs;
00511     using std::max;
00512     typedef typename LDLTType::MatrixType MatrixType;
00513     typedef typename LDLTType::RealScalar RealScalar;
00514     const typename Diagonal<const MatrixType>::RealReturnType vectorD(dec().vectorD());
00515     // In some previous versions, tolerance was set to the max of 1/highest and the maximal diagonal entry * epsilon
00516     // as motivated by LAPACK's xGELSS:
00517     // RealScalar tolerance = (max)(vectorD.array().abs().maxCoeff() *NumTraits<RealScalar>::epsilon(),RealScalar(1) / NumTraits<RealScalar>::highest());
00518     // However, LDLT is not rank revealing, and so adjusting the tolerance wrt to the highest
00519     // diagonal element is not well justified and to numerical issues in some cases.
00520     // Moreover, Lapack's xSYTRS routines use 0 for the tolerance.
00521     RealScalar tolerance = RealScalar(1) / NumTraits<RealScalar>::highest();
00522     
00523     for (Index i = 0; i < vectorD.size(); ++i) {
00524       if(abs(vectorD(i)) > tolerance)
00525         dst.row(i) /= vectorD(i);
00526       else
00527         dst.row(i).setZero();
00528     }
00529 
00530     // dst = L^-T (D^-1 L^-1 P b)
00531     dec().matrixU().solveInPlace(dst);
00532 
00533     // dst = P^-1 (L^-T D^-1 L^-1 P b) = A^-1 b
00534     dst = dec().transpositionsP().transpose() * dst;
00535   }
00536 };
00537 }
00538 
00552 template<typename MatrixType,int _UpLo>
00553 template<typename Derived>
00554 bool LDLT<MatrixType,_UpLo>::solveInPlace(MatrixBase<Derived> &bAndX) const
00555 {
00556   eigen_assert(m_isInitialized && "LDLT is not initialized.");
00557   eigen_assert(m_matrix.rows() == bAndX.rows());
00558 
00559   bAndX = this->solve(bAndX);
00560 
00561   return true;
00562 }
00563 
00567 template<typename MatrixType, int _UpLo>
00568 MatrixType LDLT<MatrixType,_UpLo>::reconstructedMatrix() const
00569 {
00570   eigen_assert(m_isInitialized && "LDLT is not initialized.");
00571   const Index size = m_matrix.rows();
00572   MatrixType res(size,size);
00573 
00574   // P
00575   res.setIdentity();
00576   res = transpositionsP() * res;
00577   // L^* P
00578   res = matrixU() * res;
00579   // D(L^*P)
00580   res = vectorD().real().asDiagonal() * res;
00581   // L(DL^*P)
00582   res = matrixL() * res;
00583   // P^T (LDL^*P)
00584   res = transpositionsP().transpose() * res;
00585 
00586   return res;
00587 }
00588 
00592 template<typename MatrixType, unsigned int UpLo>
00593 inline const LDLT<typename SelfAdjointView<MatrixType, UpLo>::PlainObject, UpLo>
00594 SelfAdjointView<MatrixType, UpLo>::ldlt() const
00595 {
00596   return LDLT<PlainObject,UpLo>(m_matrix);
00597 }
00598 
00602 template<typename Derived>
00603 inline const LDLT<typename MatrixBase<Derived>::PlainObject>
00604 MatrixBase<Derived>::ldlt() const
00605 {
00606   return LDLT<PlainObject>(derived());
00607 }
00608 
00609 } // end namespace Eigen
00610 
00611 #endif // EIGEN_LDLT_H


turtlebot_exploration_3d
Author(s): Bona , Shawn
autogenerated on Thu Jun 6 2019 20:58:58