1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2008-2012 Gael Guennebaud <gael.guennebaud@inria.fr>
5 //
6 // This Source Code Form is subject to the terms of the Mozilla
7 // Public License v. 2.0. If a copy of the MPL was not distributed
8 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 
10 #ifndef EIGEN_SIMPLICIAL_CHOLESKY_H
11 #define EIGEN_SIMPLICIAL_CHOLESKY_H
12 
13 namespace Eigen {
14 
15 enum SimplicialCholeskyMode {
16   SimplicialCholeskyLLT,
17   SimplicialCholeskyLDLT
18 };
19 
20 /** \ingroup SparseCholesky_Module
21   * \brief A direct sparse Cholesky factorizations
22   *
23   * These classes provide LL^T and LDL^T Cholesky factorizations of sparse matrices that are
24   * selfadjoint and positive definite. The factorization allows for solving A.X = B where
25   * X and B can be either dense or sparse.
26   *
27   * In order to reduce the fill-in, a symmetric permutation P is applied prior to the factorization
28   * such that the factorized matrix is P A P^-1.
29   *
30   * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
31   * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower
32   *               or Upper. Default is Lower.
33   *
34   */
35 template<typename Derived>
36 class SimplicialCholeskyBase : internal::noncopyable
37 {
38   public:
39     typedef typename internal::traits<Derived>::MatrixType MatrixType;
40     typedef typename internal::traits<Derived>::OrderingType OrderingType;
41     enum { UpLo = internal::traits<Derived>::UpLo };
42     typedef typename MatrixType::Scalar Scalar;
43     typedef typename MatrixType::RealScalar RealScalar;
44     typedef typename MatrixType::Index Index;
45     typedef SparseMatrix<Scalar,ColMajor,Index> CholMatrixType;
46     typedef Matrix<Scalar,Dynamic,1> VectorType;
47 
48   public:
49 
50     /** Default constructor */
SimplicialCholeskyBase()51     SimplicialCholeskyBase()
52       : m_info(Success), m_isInitialized(false), m_shiftOffset(0), m_shiftScale(1)
53     {}
54 
SimplicialCholeskyBase(const MatrixType & matrix)55     SimplicialCholeskyBase(const MatrixType& matrix)
56       : m_info(Success), m_isInitialized(false), m_shiftOffset(0), m_shiftScale(1)
57     {
58       derived().compute(matrix);
59     }
60 
~SimplicialCholeskyBase()61     ~SimplicialCholeskyBase()
62     {
63     }
64 
derived()65     Derived& derived() { return *static_cast<Derived*>(this); }
derived()66     const Derived& derived() const { return *static_cast<const Derived*>(this); }
67 
cols()68     inline Index cols() const { return m_matrix.cols(); }
rows()69     inline Index rows() const { return m_matrix.rows(); }
70 
71     /** \brief Reports whether previous computation was successful.
72       *
73       * \returns \c Success if computation was succesful,
74       *          \c NumericalIssue if the matrix.appears to be negative.
75       */
info()76     ComputationInfo info() const
77     {
78       eigen_assert(m_isInitialized && "Decomposition is not initialized.");
79       return m_info;
80     }
81 
82     /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A.
83       *
84       * \sa compute()
85       */
86     template<typename Rhs>
87     inline const internal::solve_retval<SimplicialCholeskyBase, Rhs>
solve(const MatrixBase<Rhs> & b)88     solve(const MatrixBase<Rhs>& b) const
89     {
90       eigen_assert(m_isInitialized && "Simplicial LLT or LDLT is not initialized.");
91       eigen_assert(rows()==b.rows()
92                 && "SimplicialCholeskyBase::solve(): invalid number of rows of the right hand side matrix b");
93       return internal::solve_retval<SimplicialCholeskyBase, Rhs>(*this, b.derived());
94     }
95 
96     /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A.
97       *
98       * \sa compute()
99       */
100     template<typename Rhs>
101     inline const internal::sparse_solve_retval<SimplicialCholeskyBase, Rhs>
solve(const SparseMatrixBase<Rhs> & b)102     solve(const SparseMatrixBase<Rhs>& b) const
103     {
104       eigen_assert(m_isInitialized && "Simplicial LLT or LDLT is not initialized.");
105       eigen_assert(rows()==b.rows()
106                 && "SimplicialCholesky::solve(): invalid number of rows of the right hand side matrix b");
107       return internal::sparse_solve_retval<SimplicialCholeskyBase, Rhs>(*this, b.derived());
108     }
109 
110     /** \returns the permutation P
111       * \sa permutationPinv() */
permutationP()112     const PermutationMatrix<Dynamic,Dynamic,Index>& permutationP() const
113     { return m_P; }
114 
115     /** \returns the inverse P^-1 of the permutation P
116       * \sa permutationP() */
permutationPinv()117     const PermutationMatrix<Dynamic,Dynamic,Index>& permutationPinv() const
118     { return m_Pinv; }
119 
120     /** Sets the shift parameters that will be used to adjust the diagonal coefficients during the numerical factorization.
121       *
122       * During the numerical factorization, the diagonal coefficients are transformed by the following linear model:\n
123       * \c d_ii = \a offset + \a scale * \c d_ii
124       *
125       * The default is the identity transformation with \a offset=0, and \a scale=1.
126       *
127       * \returns a reference to \c *this.
128       */
129     Derived& setShift(const RealScalar& offset, const RealScalar& scale = 1)
130     {
131       m_shiftOffset = offset;
132       m_shiftScale = scale;
133       return derived();
134     }
135 
136 #ifndef EIGEN_PARSED_BY_DOXYGEN
137     /** \internal */
138     template<typename Stream>
dumpMemory(Stream & s)139     void dumpMemory(Stream& s)
140     {
141       int total = 0;
142       s << "  L:        " << ((total+=(m_matrix.cols()+1) * sizeof(int) + m_matrix.nonZeros()*(sizeof(int)+sizeof(Scalar))) >> 20) << "Mb" << "\n";
143       s << "  diag:     " << ((total+=m_diag.size() * sizeof(Scalar)) >> 20) << "Mb" << "\n";
144       s << "  tree:     " << ((total+=m_parent.size() * sizeof(int)) >> 20) << "Mb" << "\n";
145       s << "  nonzeros: " << ((total+=m_nonZerosPerCol.size() * sizeof(int)) >> 20) << "Mb" << "\n";
146       s << "  perm:     " << ((total+=m_P.size() * sizeof(int)) >> 20) << "Mb" << "\n";
147       s << "  perm^-1:  " << ((total+=m_Pinv.size() * sizeof(int)) >> 20) << "Mb" << "\n";
148       s << "  TOTAL:    " << (total>> 20) << "Mb" << "\n";
149     }
150 
151     /** \internal */
152     template<typename Rhs,typename Dest>
_solve(const MatrixBase<Rhs> & b,MatrixBase<Dest> & dest)153     void _solve(const MatrixBase<Rhs> &b, MatrixBase<Dest> &dest) const
154     {
155       eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()");
156       eigen_assert(m_matrix.rows()==b.rows());
157 
158       if(m_info!=Success)
159         return;
160 
161       if(m_P.size()>0)
162         dest = m_P * b;
163       else
164         dest = b;
165 
166       if(m_matrix.nonZeros()>0) // otherwise L==I
167         derived().matrixL().solveInPlace(dest);
168 
169       if(m_diag.size()>0)
170         dest = m_diag.asDiagonal().inverse() * dest;
171 
172       if (m_matrix.nonZeros()>0) // otherwise U==I
173         derived().matrixU().solveInPlace(dest);
174 
175       if(m_P.size()>0)
176         dest = m_Pinv * dest;
177     }
178 
179 #endif // EIGEN_PARSED_BY_DOXYGEN
180 
181   protected:
182 
183     /** Computes the sparse Cholesky decomposition of \a matrix */
184     template<bool DoLDLT>
compute(const MatrixType & matrix)185     void compute(const MatrixType& matrix)
186     {
187       eigen_assert(matrix.rows()==matrix.cols());
188       Index size = matrix.cols();
189       CholMatrixType ap(size,size);
190       ordering(matrix, ap);
191       analyzePattern_preordered(ap, DoLDLT);
192       factorize_preordered<DoLDLT>(ap);
193     }
194 
195     template<bool DoLDLT>
factorize(const MatrixType & a)196     void factorize(const MatrixType& a)
197     {
198       eigen_assert(a.rows()==a.cols());
199       int size = a.cols();
200       CholMatrixType ap(size,size);
201       ap.template selfadjointView<Upper>() = a.template selfadjointView<UpLo>().twistedBy(m_P);
202       factorize_preordered<DoLDLT>(ap);
203     }
204 
205     template<bool DoLDLT>
206     void factorize_preordered(const CholMatrixType& a);
207 
analyzePattern(const MatrixType & a,bool doLDLT)208     void analyzePattern(const MatrixType& a, bool doLDLT)
209     {
210       eigen_assert(a.rows()==a.cols());
211       int size = a.cols();
212       CholMatrixType ap(size,size);
213       ordering(a, ap);
214       analyzePattern_preordered(ap,doLDLT);
215     }
216     void analyzePattern_preordered(const CholMatrixType& a, bool doLDLT);
217 
218     void ordering(const MatrixType& a, CholMatrixType& ap);
219 
220     /** keeps off-diagonal entries; drops diagonal entries */
221     struct keep_diag {
operatorkeep_diag222       inline bool operator() (const Index& row, const Index& col, const Scalar&) const
223       {
224         return row!=col;
225       }
226     };
227 
228     mutable ComputationInfo m_info;
229     bool m_isInitialized;
230     bool m_factorizationIsOk;
231     bool m_analysisIsOk;
232 
233     CholMatrixType m_matrix;
234     VectorType m_diag;                                // the diagonal coefficients (LDLT mode)
235     VectorXi m_parent;                                // elimination tree
236     VectorXi m_nonZerosPerCol;
237     PermutationMatrix<Dynamic,Dynamic,Index> m_P;     // the permutation
238     PermutationMatrix<Dynamic,Dynamic,Index> m_Pinv;  // the inverse permutation
239 
240     RealScalar m_shiftOffset;
241     RealScalar m_shiftScale;
242 };
243 
244 template<typename _MatrixType, int _UpLo = Lower, typename _Ordering = AMDOrdering<typename _MatrixType::Index> > class SimplicialLLT;
245 template<typename _MatrixType, int _UpLo = Lower, typename _Ordering = AMDOrdering<typename _MatrixType::Index> > class SimplicialLDLT;
246 template<typename _MatrixType, int _UpLo = Lower, typename _Ordering = AMDOrdering<typename _MatrixType::Index> > class SimplicialCholesky;
247 
248 namespace internal {
249 
250 template<typename _MatrixType, int _UpLo, typename _Ordering> struct traits<SimplicialLLT<_MatrixType,_UpLo,_Ordering> >
251 {
252   typedef _MatrixType MatrixType;
253   typedef _Ordering OrderingType;
254   enum { UpLo = _UpLo };
255   typedef typename MatrixType::Scalar                         Scalar;
256   typedef typename MatrixType::Index                          Index;
257   typedef SparseMatrix<Scalar, ColMajor, Index>               CholMatrixType;
258   typedef SparseTriangularView<CholMatrixType, Eigen::Lower>  MatrixL;
259   typedef SparseTriangularView<typename CholMatrixType::AdjointReturnType, Eigen::Upper>   MatrixU;
260   static inline MatrixL getL(const MatrixType& m) { return m; }
261   static inline MatrixU getU(const MatrixType& m) { return m.adjoint(); }
262 };
263 
264 template<typename _MatrixType,int _UpLo, typename _Ordering> struct traits<SimplicialLDLT<_MatrixType,_UpLo,_Ordering> >
265 {
266   typedef _MatrixType MatrixType;
267   typedef _Ordering OrderingType;
268   enum { UpLo = _UpLo };
269   typedef typename MatrixType::Scalar                             Scalar;
270   typedef typename MatrixType::Index                              Index;
271   typedef SparseMatrix<Scalar, ColMajor, Index>                   CholMatrixType;
272   typedef SparseTriangularView<CholMatrixType, Eigen::UnitLower>  MatrixL;
273   typedef SparseTriangularView<typename CholMatrixType::AdjointReturnType, Eigen::UnitUpper> MatrixU;
274   static inline MatrixL getL(const MatrixType& m) { return m; }
275   static inline MatrixU getU(const MatrixType& m) { return m.adjoint(); }
276 };
277 
278 template<typename _MatrixType, int _UpLo, typename _Ordering> struct traits<SimplicialCholesky<_MatrixType,_UpLo,_Ordering> >
279 {
280   typedef _MatrixType MatrixType;
281   typedef _Ordering OrderingType;
282   enum { UpLo = _UpLo };
283 };
284 
285 }
286 
287 /** \ingroup SparseCholesky_Module
288   * \class SimplicialLLT
289   * \brief A direct sparse LLT Cholesky factorizations
290   *
291   * This class provides a LL^T Cholesky factorizations of sparse matrices that are
292   * selfadjoint and positive definite. The factorization allows for solving A.X = B where
293   * X and B can be either dense or sparse.
294   *
295   * In order to reduce the fill-in, a symmetric permutation P is applied prior to the factorization
296   * such that the factorized matrix is P A P^-1.
297   *
298   * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
299   * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower
300   *               or Upper. Default is Lower.
301   * \tparam _Ordering The ordering method to use, either AMDOrdering<> or NaturalOrdering<>. Default is AMDOrdering<>
302   *
303   * \sa class SimplicialLDLT, class AMDOrdering, class NaturalOrdering
304   */
305 template<typename _MatrixType, int _UpLo, typename _Ordering>
306     class SimplicialLLT : public SimplicialCholeskyBase<SimplicialLLT<_MatrixType,_UpLo,_Ordering> >
307 {
308 public:
309     typedef _MatrixType MatrixType;
310     enum { UpLo = _UpLo };
311     typedef SimplicialCholeskyBase<SimplicialLLT> Base;
312     typedef typename MatrixType::Scalar Scalar;
313     typedef typename MatrixType::RealScalar RealScalar;
314     typedef typename MatrixType::Index Index;
315     typedef SparseMatrix<Scalar,ColMajor,Index> CholMatrixType;
316     typedef Matrix<Scalar,Dynamic,1> VectorType;
317     typedef internal::traits<SimplicialLLT> Traits;
318     typedef typename Traits::MatrixL  MatrixL;
319     typedef typename Traits::MatrixU  MatrixU;
320 public:
321     /** Default constructor */
322     SimplicialLLT() : Base() {}
323     /** Constructs and performs the LLT factorization of \a matrix */
324     SimplicialLLT(const MatrixType& matrix)
325         : Base(matrix) {}
326 
327     /** \returns an expression of the factor L */
328     inline const MatrixL matrixL() const {
329         eigen_assert(Base::m_factorizationIsOk && "Simplicial LLT not factorized");
330         return Traits::getL(Base::m_matrix);
331     }
332 
333     /** \returns an expression of the factor U (= L^*) */
334     inline const MatrixU matrixU() const {
335         eigen_assert(Base::m_factorizationIsOk && "Simplicial LLT not factorized");
336         return Traits::getU(Base::m_matrix);
337     }
338 
339     /** Computes the sparse Cholesky decomposition of \a matrix */
340     SimplicialLLT& compute(const MatrixType& matrix)
341     {
342       Base::template compute<false>(matrix);
343       return *this;
344     }
345 
346     /** Performs a symbolic decomposition on the sparcity of \a matrix.
347       *
348       * This function is particularly useful when solving for several problems having the same structure.
349       *
350       * \sa factorize()
351       */
352     void analyzePattern(const MatrixType& a)
353     {
354       Base::analyzePattern(a, false);
355     }
356 
357     /** Performs a numeric decomposition of \a matrix
358       *
359       * The given matrix must has the same sparcity than the matrix on which the symbolic decomposition has been performed.
360       *
361       * \sa analyzePattern()
362       */
363     void factorize(const MatrixType& a)
364     {
365       Base::template factorize<false>(a);
366     }
367 
368     /** \returns the determinant of the underlying matrix from the current factorization */
369     Scalar determinant() const
370     {
371       Scalar detL = Base::m_matrix.diagonal().prod();
372       return numext::abs2(detL);
373     }
374 };
375 
376 /** \ingroup SparseCholesky_Module
377   * \class SimplicialLDLT
378   * \brief A direct sparse LDLT Cholesky factorizations without square root.
379   *
380   * This class provides a LDL^T Cholesky factorizations without square root of sparse matrices that are
381   * selfadjoint and positive definite. The factorization allows for solving A.X = B where
382   * X and B can be either dense or sparse.
383   *
384   * In order to reduce the fill-in, a symmetric permutation P is applied prior to the factorization
385   * such that the factorized matrix is P A P^-1.
386   *
387   * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
388   * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower
389   *               or Upper. Default is Lower.
390   * \tparam _Ordering The ordering method to use, either AMDOrdering<> or NaturalOrdering<>. Default is AMDOrdering<>
391   *
392   * \sa class SimplicialLLT, class AMDOrdering, class NaturalOrdering
393   */
394 template<typename _MatrixType, int _UpLo, typename _Ordering>
395     class SimplicialLDLT : public SimplicialCholeskyBase<SimplicialLDLT<_MatrixType,_UpLo,_Ordering> >
396 {
397 public:
398     typedef _MatrixType MatrixType;
399     enum { UpLo = _UpLo };
400     typedef SimplicialCholeskyBase<SimplicialLDLT> Base;
401     typedef typename MatrixType::Scalar Scalar;
402     typedef typename MatrixType::RealScalar RealScalar;
403     typedef typename MatrixType::Index Index;
404     typedef SparseMatrix<Scalar,ColMajor,Index> CholMatrixType;
405     typedef Matrix<Scalar,Dynamic,1> VectorType;
406     typedef internal::traits<SimplicialLDLT> Traits;
407     typedef typename Traits::MatrixL  MatrixL;
408     typedef typename Traits::MatrixU  MatrixU;
409 public:
410     /** Default constructor */
411     SimplicialLDLT() : Base() {}
412 
413     /** Constructs and performs the LLT factorization of \a matrix */
414     SimplicialLDLT(const MatrixType& matrix)
415         : Base(matrix) {}
416 
417     /** \returns a vector expression of the diagonal D */
418     inline const VectorType vectorD() const {
419         eigen_assert(Base::m_factorizationIsOk && "Simplicial LDLT not factorized");
420         return Base::m_diag;
421     }
422     /** \returns an expression of the factor L */
423     inline const MatrixL matrixL() const {
424         eigen_assert(Base::m_factorizationIsOk && "Simplicial LDLT not factorized");
425         return Traits::getL(Base::m_matrix);
426     }
427 
428     /** \returns an expression of the factor U (= L^*) */
429     inline const MatrixU matrixU() const {
430         eigen_assert(Base::m_factorizationIsOk && "Simplicial LDLT not factorized");
431         return Traits::getU(Base::m_matrix);
432     }
433 
434     /** Computes the sparse Cholesky decomposition of \a matrix */
435     SimplicialLDLT& compute(const MatrixType& matrix)
436     {
437       Base::template compute<true>(matrix);
438       return *this;
439     }
440 
441     /** Performs a symbolic decomposition on the sparcity of \a matrix.
442       *
443       * This function is particularly useful when solving for several problems having the same structure.
444       *
445       * \sa factorize()
446       */
447     void analyzePattern(const MatrixType& a)
448     {
449       Base::analyzePattern(a, true);
450     }
451 
452     /** Performs a numeric decomposition of \a matrix
453       *
454       * The given matrix must has the same sparcity than the matrix on which the symbolic decomposition has been performed.
455       *
456       * \sa analyzePattern()
457       */
458     void factorize(const MatrixType& a)
459     {
460       Base::template factorize<true>(a);
461     }
462 
463     /** \returns the determinant of the underlying matrix from the current factorization */
464     Scalar determinant() const
465     {
466       return Base::m_diag.prod();
467     }
468 };
469 
470 /** \deprecated use SimplicialLDLT or class SimplicialLLT
471   * \ingroup SparseCholesky_Module
472   * \class SimplicialCholesky
473   *
474   * \sa class SimplicialLDLT, class SimplicialLLT
475   */
476 template<typename _MatrixType, int _UpLo, typename _Ordering>
477     class SimplicialCholesky : public SimplicialCholeskyBase<SimplicialCholesky<_MatrixType,_UpLo,_Ordering> >
478 {
479 public:
480     typedef _MatrixType MatrixType;
481     enum { UpLo = _UpLo };
482     typedef SimplicialCholeskyBase<SimplicialCholesky> Base;
483     typedef typename MatrixType::Scalar Scalar;
484     typedef typename MatrixType::RealScalar RealScalar;
485     typedef typename MatrixType::Index Index;
486     typedef SparseMatrix<Scalar,ColMajor,Index> CholMatrixType;
487     typedef Matrix<Scalar,Dynamic,1> VectorType;
488     typedef internal::traits<SimplicialCholesky> Traits;
489     typedef internal::traits<SimplicialLDLT<MatrixType,UpLo> > LDLTTraits;
490     typedef internal::traits<SimplicialLLT<MatrixType,UpLo>  > LLTTraits;
491   public:
492     SimplicialCholesky() : Base(), m_LDLT(true) {}
493 
494     SimplicialCholesky(const MatrixType& matrix)
495       : Base(), m_LDLT(true)
496     {
497       compute(matrix);
498     }
499 
500     SimplicialCholesky& setMode(SimplicialCholeskyMode mode)
501     {
502       switch(mode)
503       {
504       case SimplicialCholeskyLLT:
505         m_LDLT = false;
506         break;
507       case SimplicialCholeskyLDLT:
508         m_LDLT = true;
509         break;
510       default:
511         break;
512       }
513 
514       return *this;
515     }
516 
517     inline const VectorType vectorD() const {
518         eigen_assert(Base::m_factorizationIsOk && "Simplicial Cholesky not factorized");
519         return Base::m_diag;
520     }
521     inline const CholMatrixType rawMatrix() const {
522         eigen_assert(Base::m_factorizationIsOk && "Simplicial Cholesky not factorized");
523         return Base::m_matrix;
524     }
525 
526     /** Computes the sparse Cholesky decomposition of \a matrix */
527     SimplicialCholesky& compute(const MatrixType& matrix)
528     {
529       if(m_LDLT)
530         Base::template compute<true>(matrix);
531       else
532         Base::template compute<false>(matrix);
533       return *this;
534     }
535 
536     /** Performs a symbolic decomposition on the sparcity of \a matrix.
537       *
538       * This function is particularly useful when solving for several problems having the same structure.
539       *
540       * \sa factorize()
541       */
542     void analyzePattern(const MatrixType& a)
543     {
544       Base::analyzePattern(a, m_LDLT);
545     }
546 
547     /** Performs a numeric decomposition of \a matrix
548       *
549       * The given matrix must has the same sparcity than the matrix on which the symbolic decomposition has been performed.
550       *
551       * \sa analyzePattern()
552       */
553     void factorize(const MatrixType& a)
554     {
555       if(m_LDLT)
556         Base::template factorize<true>(a);
557       else
558         Base::template factorize<false>(a);
559     }
560 
561     /** \internal */
562     template<typename Rhs,typename Dest>
563     void _solve(const MatrixBase<Rhs> &b, MatrixBase<Dest> &dest) const
564     {
565       eigen_assert(Base::m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()");
566       eigen_assert(Base::m_matrix.rows()==b.rows());
567 
568       if(Base::m_info!=Success)
569         return;
570 
571       if(Base::m_P.size()>0)
572         dest = Base::m_P * b;
573       else
574         dest = b;
575 
576       if(Base::m_matrix.nonZeros()>0) // otherwise L==I
577       {
578         if(m_LDLT)
579           LDLTTraits::getL(Base::m_matrix).solveInPlace(dest);
580         else
581           LLTTraits::getL(Base::m_matrix).solveInPlace(dest);
582       }
583 
584       if(Base::m_diag.size()>0)
585         dest = Base::m_diag.asDiagonal().inverse() * dest;
586 
587       if (Base::m_matrix.nonZeros()>0) // otherwise I==I
588       {
589         if(m_LDLT)
590           LDLTTraits::getU(Base::m_matrix).solveInPlace(dest);
591         else
592           LLTTraits::getU(Base::m_matrix).solveInPlace(dest);
593       }
594 
595       if(Base::m_P.size()>0)
596         dest = Base::m_Pinv * dest;
597     }
598 
599     Scalar determinant() const
600     {
601       if(m_LDLT)
602       {
603         return Base::m_diag.prod();
604       }
605       else
606       {
607         Scalar detL = Diagonal<const CholMatrixType>(Base::m_matrix).prod();
608         return numext::abs2(detL);
609       }
610     }
611 
612   protected:
613     bool m_LDLT;
614 };
615 
616 template<typename Derived>
617 void SimplicialCholeskyBase<Derived>::ordering(const MatrixType& a, CholMatrixType& ap)
618 {
619   eigen_assert(a.rows()==a.cols());
620   const Index size = a.rows();
621   // Note that amd compute the inverse permutation
622   {
623     CholMatrixType C;
624     C = a.template selfadjointView<UpLo>();
625 
626     OrderingType ordering;
627     ordering(C,m_Pinv);
628   }
629 
630   if(m_Pinv.size()>0)
631     m_P = m_Pinv.inverse();
632   else
633     m_P.resize(0);
634 
635   ap.resize(size,size);
636   ap.template selfadjointView<Upper>() = a.template selfadjointView<UpLo>().twistedBy(m_P);
637 }
638 
639 namespace internal {
640 
641 template<typename Derived, typename Rhs>
642 struct solve_retval<SimplicialCholeskyBase<Derived>, Rhs>
643   : solve_retval_base<SimplicialCholeskyBase<Derived>, Rhs>
644 {
645   typedef SimplicialCholeskyBase<Derived> Dec;
646   EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs)
647 
648   template<typename Dest> void evalTo(Dest& dst) const
649   {
650     dec().derived()._solve(rhs(),dst);
651   }
652 };
653 
654 template<typename Derived, typename Rhs>
655 struct sparse_solve_retval<SimplicialCholeskyBase<Derived>, Rhs>
656   : sparse_solve_retval_base<SimplicialCholeskyBase<Derived>, Rhs>
657 {
658   typedef SimplicialCholeskyBase<Derived> Dec;
659   EIGEN_MAKE_SPARSE_SOLVE_HELPERS(Dec,Rhs)
660 
661   template<typename Dest> void evalTo(Dest& dst) const
662   {
663     this->defaultEvalTo(dst);
664   }
665 };
666 
667 } // end namespace internal
668 
669 } // end namespace Eigen
670 
671 #endif // EIGEN_SIMPLICIAL_CHOLESKY_H
672