LLT.h 18 KB
Newer Older
LM's avatar
LM committed
1 2 3 4 5
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
//
Don Gagne's avatar
Don Gagne committed
6 7 8
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
LM's avatar
LM committed
9 10 11 12

#ifndef EIGEN_LLT_H
#define EIGEN_LLT_H

13
namespace Eigen {
Don Gagne's avatar
Don Gagne committed
14

LM's avatar
LM committed
15 16 17 18
namespace internal{
template<typename MatrixType, int UpLo> struct LLT_Traits;
}

Don Gagne's avatar
Don Gagne committed
19
/** \ingroup Cholesky_Module
LM's avatar
LM committed
20 21 22 23 24
  *
  * \class LLT
  *
  * \brief Standard Cholesky decomposition (LL^T) of a matrix and associated features
  *
25 26 27
  * \tparam _MatrixType the type of the matrix of which we are computing the LL^T Cholesky decomposition
  * \tparam _UpLo the triangular part that will be used for the decompositon: Lower (default) or Upper.
  *               The other triangular part won't be read.
LM's avatar
LM committed
28 29 30 31 32 33 34 35 36 37 38 39 40
  *
  * This class performs a LL^T Cholesky decomposition of a symmetric, positive definite
  * matrix A such that A = LL^* = U^*U, where L is lower triangular.
  *
  * While the Cholesky decomposition is particularly useful to solve selfadjoint problems like  D^*D x = b,
  * for that purpose, we recommend the Cholesky decomposition without square root which is more stable
  * and even faster. Nevertheless, this standard Cholesky decomposition remains useful in many other
  * situations like generalised eigen problems with hermitian matrices.
  *
  * Remember that Cholesky decompositions are not rank-revealing. This LLT decomposition is only stable on positive definite matrices,
  * use LDLT instead for the semidefinite case. Also, do not use a Cholesky decomposition to determine whether a system of equations
  * has a solution.
  *
Don Gagne's avatar
Don Gagne committed
41 42
  * Example: \include LLT_example.cpp
  * Output: \verbinclude LLT_example.out
43 44 45 46 47 48 49 50 51 52 53 54
  *
  * \b Performance: for best performance, it is recommended to use a column-major storage format
  * with the Lower triangular part (the default), or, equivalently, a row-major storage format
  * with the Upper triangular part. Otherwise, you might get a 20% slowdown for the full factorization
  * step, and rank-updates can be up to 3 times slower.
  *
  * This class supports the \link InplaceDecomposition inplace decomposition \endlink mechanism.
  *
  * Note that during the decomposition, only the lower (or upper, as defined by _UpLo) triangular part of A is considered.
  * Therefore, the strict lower part does not have to store correct values.
  *
  * \sa MatrixBase::llt(), SelfAdjointView::llt(), class LDLT
LM's avatar
LM committed
55 56 57 58 59 60 61 62 63 64 65 66
  */
template<typename _MatrixType, int _UpLo> class LLT
{
  public:
    typedef _MatrixType MatrixType;
    enum {
      RowsAtCompileTime = MatrixType::RowsAtCompileTime,
      ColsAtCompileTime = MatrixType::ColsAtCompileTime,
      MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
    };
    typedef typename MatrixType::Scalar Scalar;
    typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
67 68
    typedef Eigen::Index Index; ///< \deprecated since Eigen 3.3
    typedef typename MatrixType::StorageIndex StorageIndex;
LM's avatar
LM committed
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91

    enum {
      PacketSize = internal::packet_traits<Scalar>::size,
      AlignmentMask = int(PacketSize)-1,
      UpLo = _UpLo
    };

    typedef internal::LLT_Traits<MatrixType,UpLo> Traits;

    /**
      * \brief Default Constructor.
      *
      * The default constructor is useful in cases in which the user intends to
      * perform decompositions via LLT::compute(const MatrixType&).
      */
    LLT() : m_matrix(), m_isInitialized(false) {}

    /** \brief Default Constructor with memory preallocation
      *
      * Like the default constructor but with preallocation of the internal data
      * according to the specified problem \a size.
      * \sa LLT()
      */
92
    explicit LLT(Index size) : m_matrix(size, size),
LM's avatar
LM committed
93 94
                    m_isInitialized(false) {}

95 96
    template<typename InputType>
    explicit LLT(const EigenBase<InputType>& matrix)
LM's avatar
LM committed
97 98 99
      : m_matrix(matrix.rows(), matrix.cols()),
        m_isInitialized(false)
    {
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
      compute(matrix.derived());
    }

    /** \brief Constructs a LDLT factorization from a given matrix
      *
      * This overloaded constructor is provided for \link InplaceDecomposition inplace decomposition \endlink when
      * \c MatrixType is a Eigen::Ref.
      *
      * \sa LLT(const EigenBase&)
      */
    template<typename InputType>
    explicit LLT(EigenBase<InputType>& matrix)
      : m_matrix(matrix.derived()),
        m_isInitialized(false)
    {
      compute(matrix.derived());
LM's avatar
LM committed
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
    }

    /** \returns a view of the upper triangular matrix U */
    inline typename Traits::MatrixU matrixU() const
    {
      eigen_assert(m_isInitialized && "LLT is not initialized.");
      return Traits::getU(m_matrix);
    }

    /** \returns a view of the lower triangular matrix L */
    inline typename Traits::MatrixL matrixL() const
    {
      eigen_assert(m_isInitialized && "LLT is not initialized.");
      return Traits::getL(m_matrix);
    }

    /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A.
      *
      * Since this LLT class assumes anyway that the matrix A is invertible, the solution
      * theoretically exists and is unique regardless of b.
      *
      * Example: \include LLT_solve.cpp
      * Output: \verbinclude LLT_solve.out
      *
140
      * \sa solveInPlace(), MatrixBase::llt(), SelfAdjointView::llt()
LM's avatar
LM committed
141 142
      */
    template<typename Rhs>
143
    inline const Solve<LLT, Rhs>
LM's avatar
LM committed
144 145 146 147 148
    solve(const MatrixBase<Rhs>& b) const
    {
      eigen_assert(m_isInitialized && "LLT is not initialized.");
      eigen_assert(m_matrix.rows()==b.rows()
                && "LLT::solve(): invalid number of rows of the right hand side matrix b");
149
      return Solve<LLT, Rhs>(*this, b.derived());
LM's avatar
LM committed
150 151 152
    }

    template<typename Derived>
153
    void solveInPlace(const MatrixBase<Derived> &bAndX) const;
LM's avatar
LM committed
154

155 156 157 158 159 160 161 162 163 164 165 166
    template<typename InputType>
    LLT& compute(const EigenBase<InputType>& matrix);

    /** \returns an estimate of the reciprocal condition number of the matrix of
      *  which \c *this is the Cholesky decomposition.
      */
    RealScalar rcond() const
    {
      eigen_assert(m_isInitialized && "LLT is not initialized.");
      eigen_assert(m_info == Success && "LLT failed because matrix appears to be negative");
      return internal::rcond_estimate_helper(m_l1_norm, *this);
    }
LM's avatar
LM committed
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183

    /** \returns the LLT decomposition matrix
      *
      * TODO: document the storage layout
      */
    inline const MatrixType& matrixLLT() const
    {
      eigen_assert(m_isInitialized && "LLT is not initialized.");
      return m_matrix;
    }

    MatrixType reconstructedMatrix() const;


    /** \brief Reports whether previous computation was successful.
      *
      * \returns \c Success if computation was succesful,
184
      *          \c NumericalIssue if the matrix.appears not to be positive definite.
LM's avatar
LM committed
185 186 187 188 189 190 191
      */
    ComputationInfo info() const
    {
      eigen_assert(m_isInitialized && "LLT is not initialized.");
      return m_info;
    }

192 193 194 195 196 197 198
    /** \returns the adjoint of \c *this, that is, a const reference to the decomposition itself as the underlying matrix is self-adjoint.
      *
      * This method is provided for compatibility with other matrix decompositions, thus enabling generic code such as:
      * \code x = decomposition.adjoint().solve(b) \endcode
      */
    const LLT& adjoint() const { return *this; };

LM's avatar
LM committed
199 200 201
    inline Index rows() const { return m_matrix.rows(); }
    inline Index cols() const { return m_matrix.cols(); }

Don Gagne's avatar
Don Gagne committed
202 203 204
    template<typename VectorType>
    LLT rankUpdate(const VectorType& vec, const RealScalar& sigma = 1);

205 206 207 208 209 210
    #ifndef EIGEN_PARSED_BY_DOXYGEN
    template<typename RhsType, typename DstType>
    EIGEN_DEVICE_FUNC
    void _solve_impl(const RhsType &rhs, DstType &dst) const;
    #endif

LM's avatar
LM committed
211
  protected:
212

213 214 215 216
    static void check_template_parameters()
    {
      EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
    }
217

LM's avatar
LM committed
218 219 220 221 222
    /** \internal
      * Used to compute and store L
      * The strict upper part is not used and even not initialized.
      */
    MatrixType m_matrix;
223
    RealScalar m_l1_norm;
LM's avatar
LM committed
224 225 226 227 228 229
    bool m_isInitialized;
    ComputationInfo m_info;
};

namespace internal {

Don Gagne's avatar
Don Gagne committed
230 231 232
template<typename Scalar, int UpLo> struct llt_inplace;

template<typename MatrixType, typename VectorType>
233
static Index llt_rank_update_lower(MatrixType& mat, const VectorType& vec, const typename MatrixType::RealScalar& sigma)
Don Gagne's avatar
Don Gagne committed
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
{
  using std::sqrt;
  typedef typename MatrixType::Scalar Scalar;
  typedef typename MatrixType::RealScalar RealScalar;
  typedef typename MatrixType::ColXpr ColXpr;
  typedef typename internal::remove_all<ColXpr>::type ColXprCleaned;
  typedef typename ColXprCleaned::SegmentReturnType ColXprSegment;
  typedef Matrix<Scalar,Dynamic,1> TempVectorType;
  typedef typename TempVectorType::SegmentReturnType TempVecSegment;

  Index n = mat.cols();
  eigen_assert(mat.rows()==n && vec.size()==n);

  TempVectorType temp;

  if(sigma>0)
  {
    // This version is based on Givens rotations.
    // It is faster than the other one below, but only works for updates,
    // i.e., for sigma > 0
    temp = sqrt(sigma) * vec;

    for(Index i=0; i<n; ++i)
    {
      JacobiRotation<Scalar> g;
      g.makeGivens(mat(i,i), -temp(i), &mat(i,i));

      Index rs = n-i-1;
      if(rs>0)
      {
        ColXprSegment x(mat.col(i).tail(rs));
        TempVecSegment y(temp.tail(rs));
        apply_rotation_in_the_plane(x, y, g);
      }
    }
  }
  else
  {
    temp = vec;
    RealScalar beta = 1;
    for(Index j=0; j<n; ++j)
    {
      RealScalar Ljj = numext::real(mat.coeff(j,j));
      RealScalar dj = numext::abs2(Ljj);
      Scalar wj = temp.coeff(j);
      RealScalar swj2 = sigma*numext::abs2(wj);
      RealScalar gamma = dj*beta + swj2;

      RealScalar x = dj + swj2/beta;
      if (x<=RealScalar(0))
        return j;
      RealScalar nLjj = sqrt(x);
      mat.coeffRef(j,j) = nLjj;
      beta += swj2/dj;

      // Update the terms of L
      Index rs = n-j-1;
      if(rs)
      {
        temp.tail(rs) -= (wj/Ljj) * mat.col(j).tail(rs);
        if(gamma != 0)
          mat.col(j).tail(rs) = (nLjj/Ljj) * mat.col(j).tail(rs) + (nLjj * sigma*numext::conj(wj)/gamma)*temp.tail(rs);
      }
    }
  }
  return -1;
}
LM's avatar
LM committed
301

Don Gagne's avatar
Don Gagne committed
302
template<typename Scalar> struct llt_inplace<Scalar, Lower>
LM's avatar
LM committed
303
{
Don Gagne's avatar
Don Gagne committed
304
  typedef typename NumTraits<Scalar>::Real RealScalar;
LM's avatar
LM committed
305
  template<typename MatrixType>
306
  static Index unblocked(MatrixType& mat)
LM's avatar
LM committed
307
  {
Don Gagne's avatar
Don Gagne committed
308
    using std::sqrt;
309

LM's avatar
LM committed
310 311 312 313 314 315 316 317 318 319
    eigen_assert(mat.rows()==mat.cols());
    const Index size = mat.rows();
    for(Index k = 0; k < size; ++k)
    {
      Index rs = size-k-1; // remaining size

      Block<MatrixType,Dynamic,1> A21(mat,k+1,k,rs,1);
      Block<MatrixType,1,Dynamic> A10(mat,k,0,1,k);
      Block<MatrixType,Dynamic,Dynamic> A20(mat,k+1,0,rs,k);

Don Gagne's avatar
Don Gagne committed
320
      RealScalar x = numext::real(mat.coeff(k,k));
LM's avatar
LM committed
321 322 323 324 325
      if (k>0) x -= A10.squaredNorm();
      if (x<=RealScalar(0))
        return k;
      mat.coeffRef(k,k) = x = sqrt(x);
      if (k>0 && rs>0) A21.noalias() -= A20 * A10.adjoint();
326
      if (rs>0) A21 /= x;
LM's avatar
LM committed
327 328 329 330 331
    }
    return -1;
  }

  template<typename MatrixType>
332
  static Index blocked(MatrixType& m)
LM's avatar
LM committed
333 334 335 336 337 338 339 340
  {
    eigen_assert(m.rows()==m.cols());
    Index size = m.rows();
    if(size<32)
      return unblocked(m);

    Index blockSize = size/8;
    blockSize = (blockSize/16)*16;
Don Gagne's avatar
Don Gagne committed
341
    blockSize = (std::min)((std::max)(blockSize,Index(8)), Index(128));
LM's avatar
LM committed
342 343 344 345 346 347 348

    for (Index k=0; k<size; k+=blockSize)
    {
      // partition the matrix:
      //       A00 |  -  |  -
      // lu  = A10 | A11 |  -
      //       A20 | A21 | A22
Don Gagne's avatar
Don Gagne committed
349
      Index bs = (std::min)(blockSize, size-k);
LM's avatar
LM committed
350 351 352 353 354 355 356 357
      Index rs = size - k - bs;
      Block<MatrixType,Dynamic,Dynamic> A11(m,k,   k,   bs,bs);
      Block<MatrixType,Dynamic,Dynamic> A21(m,k+bs,k,   rs,bs);
      Block<MatrixType,Dynamic,Dynamic> A22(m,k+bs,k+bs,rs,rs);

      Index ret;
      if((ret=unblocked(A11))>=0) return k+ret;
      if(rs>0) A11.adjoint().template triangularView<Upper>().template solveInPlace<OnTheRight>(A21);
358
      if(rs>0) A22.template selfadjointView<Lower>().rankUpdate(A21,typename NumTraits<RealScalar>::Literal(-1)); // bottleneck
LM's avatar
LM committed
359 360 361 362
    }
    return -1;
  }

Don Gagne's avatar
Don Gagne committed
363
  template<typename MatrixType, typename VectorType>
364
  static Index rankUpdate(MatrixType& mat, const VectorType& vec, const RealScalar& sigma)
Don Gagne's avatar
Don Gagne committed
365 366 367 368
  {
    return Eigen::internal::llt_rank_update_lower(mat, vec, sigma);
  }
};
369

Don Gagne's avatar
Don Gagne committed
370
template<typename Scalar> struct llt_inplace<Scalar, Upper>
LM's avatar
LM committed
371
{
Don Gagne's avatar
Don Gagne committed
372 373
  typedef typename NumTraits<Scalar>::Real RealScalar;

LM's avatar
LM committed
374
  template<typename MatrixType>
375
  static EIGEN_STRONG_INLINE Index unblocked(MatrixType& mat)
LM's avatar
LM committed
376 377
  {
    Transpose<MatrixType> matt(mat);
Don Gagne's avatar
Don Gagne committed
378
    return llt_inplace<Scalar, Lower>::unblocked(matt);
LM's avatar
LM committed
379 380
  }
  template<typename MatrixType>
381
  static EIGEN_STRONG_INLINE Index blocked(MatrixType& mat)
LM's avatar
LM committed
382 383
  {
    Transpose<MatrixType> matt(mat);
Don Gagne's avatar
Don Gagne committed
384 385 386
    return llt_inplace<Scalar, Lower>::blocked(matt);
  }
  template<typename MatrixType, typename VectorType>
387
  static Index rankUpdate(MatrixType& mat, const VectorType& vec, const RealScalar& sigma)
Don Gagne's avatar
Don Gagne committed
388 389 390
  {
    Transpose<MatrixType> matt(mat);
    return llt_inplace<Scalar, Lower>::rankUpdate(matt, vec.conjugate(), sigma);
LM's avatar
LM committed
391 392 393 394 395
  }
};

template<typename MatrixType> struct LLT_Traits<MatrixType,Lower>
{
Don Gagne's avatar
Don Gagne committed
396 397
  typedef const TriangularView<const MatrixType, Lower> MatrixL;
  typedef const TriangularView<const typename MatrixType::AdjointReturnType, Upper> MatrixU;
398 399
  static inline MatrixL getL(const MatrixType& m) { return MatrixL(m); }
  static inline MatrixU getU(const MatrixType& m) { return MatrixU(m.adjoint()); }
LM's avatar
LM committed
400
  static bool inplace_decomposition(MatrixType& m)
Don Gagne's avatar
Don Gagne committed
401
  { return llt_inplace<typename MatrixType::Scalar, Lower>::blocked(m)==-1; }
LM's avatar
LM committed
402 403 404 405
};

template<typename MatrixType> struct LLT_Traits<MatrixType,Upper>
{
Don Gagne's avatar
Don Gagne committed
406 407
  typedef const TriangularView<const typename MatrixType::AdjointReturnType, Lower> MatrixL;
  typedef const TriangularView<const MatrixType, Upper> MatrixU;
408 409
  static inline MatrixL getL(const MatrixType& m) { return MatrixL(m.adjoint()); }
  static inline MatrixU getU(const MatrixType& m) { return MatrixU(m); }
LM's avatar
LM committed
410
  static bool inplace_decomposition(MatrixType& m)
Don Gagne's avatar
Don Gagne committed
411
  { return llt_inplace<typename MatrixType::Scalar, Upper>::blocked(m)==-1; }
LM's avatar
LM committed
412 413 414 415 416 417 418
};

} // end namespace internal

/** Computes / recomputes the Cholesky decomposition A = LL^* = U^*U of \a matrix
  *
  * \returns a reference to *this
Don Gagne's avatar
Don Gagne committed
419 420 421
  *
  * Example: \include TutorialLinAlgComputeTwice.cpp
  * Output: \verbinclude TutorialLinAlgComputeTwice.out
LM's avatar
LM committed
422 423
  */
template<typename MatrixType, int _UpLo>
424 425
template<typename InputType>
LLT<MatrixType,_UpLo>& LLT<MatrixType,_UpLo>::compute(const EigenBase<InputType>& a)
LM's avatar
LM committed
426
{
427
  check_template_parameters();
428

Don Gagne's avatar
Don Gagne committed
429
  eigen_assert(a.rows()==a.cols());
LM's avatar
LM committed
430 431
  const Index size = a.rows();
  m_matrix.resize(size, size);
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
  if (!internal::is_same_dense(m_matrix, a.derived()))
    m_matrix = a.derived();

  // Compute matrix L1 norm = max abs column sum.
  m_l1_norm = RealScalar(0);
  // TODO move this code to SelfAdjointView
  for (Index col = 0; col < size; ++col) {
    RealScalar abs_col_sum;
    if (_UpLo == Lower)
      abs_col_sum = m_matrix.col(col).tail(size - col).template lpNorm<1>() + m_matrix.row(col).head(col).template lpNorm<1>();
    else
      abs_col_sum = m_matrix.col(col).head(col).template lpNorm<1>() + m_matrix.row(col).tail(size - col).template lpNorm<1>();
    if (abs_col_sum > m_l1_norm)
      m_l1_norm = abs_col_sum;
  }
LM's avatar
LM committed
447 448 449 450 451 452 453 454

  m_isInitialized = true;
  bool ok = Traits::inplace_decomposition(m_matrix);
  m_info = ok ? Success : NumericalIssue;

  return *this;
}

Don Gagne's avatar
Don Gagne committed
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473
/** Performs a rank one update (or dowdate) of the current decomposition.
  * If A = LL^* before the rank one update,
  * then after it we have LL^* = A + sigma * v v^* where \a v must be a vector
  * of same dimension.
  */
template<typename _MatrixType, int _UpLo>
template<typename VectorType>
LLT<_MatrixType,_UpLo> LLT<_MatrixType,_UpLo>::rankUpdate(const VectorType& v, const RealScalar& sigma)
{
  EIGEN_STATIC_ASSERT_VECTOR_ONLY(VectorType);
  eigen_assert(v.size()==m_matrix.cols());
  eigen_assert(m_isInitialized);
  if(internal::llt_inplace<typename MatrixType::Scalar, UpLo>::rankUpdate(m_matrix,v,sigma)>=0)
    m_info = NumericalIssue;
  else
    m_info = Success;

  return *this;
}
LM's avatar
LM committed
474

475 476 477 478 479 480 481
#ifndef EIGEN_PARSED_BY_DOXYGEN
template<typename _MatrixType,int _UpLo>
template<typename RhsType, typename DstType>
void LLT<_MatrixType,_UpLo>::_solve_impl(const RhsType &rhs, DstType &dst) const
{
  dst = rhs;
  solveInPlace(dst);
LM's avatar
LM committed
482
}
483
#endif
LM's avatar
LM committed
484 485

/** \internal use x = llt_object.solve(x);
486
  *
LM's avatar
LM committed
487 488 489 490
  * This is the \em in-place version of solve().
  *
  * \param bAndX represents both the right-hand side matrix b and result x.
  *
491
  * This version avoids a copy when the right hand side matrix b is not needed anymore.
LM's avatar
LM committed
492
  *
493 494
  * \warning The parameter is only marked 'const' to make the C++ compiler accept a temporary expression here.
  * This function will const_cast it, so constness isn't honored here.
LM's avatar
LM committed
495 496 497 498 499
  *
  * \sa LLT::solve(), MatrixBase::llt()
  */
template<typename MatrixType, int _UpLo>
template<typename Derived>
500
void LLT<MatrixType,_UpLo>::solveInPlace(const MatrixBase<Derived> &bAndX) const
LM's avatar
LM committed
501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519
{
  eigen_assert(m_isInitialized && "LLT is not initialized.");
  eigen_assert(m_matrix.rows()==bAndX.rows());
  matrixL().solveInPlace(bAndX);
  matrixU().solveInPlace(bAndX);
}

/** \returns the matrix represented by the decomposition,
 * i.e., it returns the product: L L^*.
 * This function is provided for debug purpose. */
template<typename MatrixType, int _UpLo>
MatrixType LLT<MatrixType,_UpLo>::reconstructedMatrix() const
{
  eigen_assert(m_isInitialized && "LLT is not initialized.");
  return matrixL() * matrixL().adjoint().toDenseMatrix();
}

/** \cholesky_module
  * \returns the LLT decomposition of \c *this
520
  * \sa SelfAdjointView::llt()
LM's avatar
LM committed
521 522 523 524 525 526 527 528 529 530
  */
template<typename Derived>
inline const LLT<typename MatrixBase<Derived>::PlainObject>
MatrixBase<Derived>::llt() const
{
  return LLT<PlainObject>(derived());
}

/** \cholesky_module
  * \returns the LLT decomposition of \c *this
531
  * \sa SelfAdjointView::llt()
LM's avatar
LM committed
532 533 534 535 536 537 538 539
  */
template<typename MatrixType, unsigned int UpLo>
inline const LLT<typename SelfAdjointView<MatrixType, UpLo>::PlainObject, UpLo>
SelfAdjointView<MatrixType, UpLo>::llt() const
{
  return LLT<PlainObject,UpLo>(m_matrix);
}

Don Gagne's avatar
Don Gagne committed
540 541
} // end namespace Eigen

LM's avatar
LM committed
542
#endif // EIGEN_LLT_H