• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2008-2010 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 /*
11 
12 NOTE: the _symbolic, and _numeric functions has been adapted from
13       the LDL library:
14 
15 LDL Copyright (c) 2005 by Timothy A. Davis.  All Rights Reserved.
16 
17 LDL License:
18 
19     Your use or distribution of LDL or any modified version of
20     LDL implies that you agree to this License.
21 
22     This library is free software; you can redistribute it and/or
23     modify it under the terms of the GNU Lesser General Public
24     License as published by the Free Software Foundation; either
25     version 2.1 of the License, or (at your option) any later version.
26 
27     This library is distributed in the hope that it will be useful,
28     but WITHOUT ANY WARRANTY; without even the implied warranty of
29     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
30     Lesser General Public License for more details.
31 
32     You should have received a copy of the GNU Lesser General Public
33     License along with this library; if not, write to the Free Software
34     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
35     USA
36 
37     Permission is hereby granted to use or copy this program under the
38     terms of the GNU LGPL, provided that the Copyright, this License,
39     and the Availability of the original version is retained on all copies.
40     User documentation of any code that uses this code or any modified
41     version of this code must cite the Copyright, this License, the
42     Availability note, and "Used by permission." Permission to modify
43     the code and to distribute modified code is granted, provided the
44     Copyright, this License, and the Availability note are retained,
45     and a notice that the code was modified is included.
46  */
47 
48 #include "../Core/util/NonMPL2.h"
49 
50 #ifndef EIGEN_SIMPLICIAL_CHOLESKY_H
51 #define EIGEN_SIMPLICIAL_CHOLESKY_H
52 
53 namespace Eigen {
54 
55 enum SimplicialCholeskyMode {
56   SimplicialCholeskyLLT,
57   SimplicialCholeskyLDLT
58 };
59 
60 /** \ingroup SparseCholesky_Module
61   * \brief A direct sparse Cholesky factorizations
62   *
63   * These classes provide LL^T and LDL^T Cholesky factorizations of sparse matrices that are
64   * selfadjoint and positive definite. The factorization allows for solving A.X = B where
65   * X and B can be either dense or sparse.
66   *
67   * In order to reduce the fill-in, a symmetric permutation P is applied prior to the factorization
68   * such that the factorized matrix is P A P^-1.
69   *
70   * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
71   * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower
72   *               or Upper. Default is Lower.
73   *
74   */
75 template<typename Derived>
76 class SimplicialCholeskyBase : internal::noncopyable
77 {
78   public:
79     typedef typename internal::traits<Derived>::MatrixType MatrixType;
80     enum { UpLo = internal::traits<Derived>::UpLo };
81     typedef typename MatrixType::Scalar Scalar;
82     typedef typename MatrixType::RealScalar RealScalar;
83     typedef typename MatrixType::Index Index;
84     typedef SparseMatrix<Scalar,ColMajor,Index> CholMatrixType;
85     typedef Matrix<Scalar,Dynamic,1> VectorType;
86 
87   public:
88 
89     /** Default constructor */
SimplicialCholeskyBase()90     SimplicialCholeskyBase()
91       : m_info(Success), m_isInitialized(false), m_shiftOffset(0), m_shiftScale(1)
92     {}
93 
SimplicialCholeskyBase(const MatrixType & matrix)94     SimplicialCholeskyBase(const MatrixType& matrix)
95       : m_info(Success), m_isInitialized(false), m_shiftOffset(0), m_shiftScale(1)
96     {
97       derived().compute(matrix);
98     }
99 
~SimplicialCholeskyBase()100     ~SimplicialCholeskyBase()
101     {
102     }
103 
derived()104     Derived& derived() { return *static_cast<Derived*>(this); }
derived()105     const Derived& derived() const { return *static_cast<const Derived*>(this); }
106 
cols()107     inline Index cols() const { return m_matrix.cols(); }
rows()108     inline Index rows() const { return m_matrix.rows(); }
109 
110     /** \brief Reports whether previous computation was successful.
111       *
112       * \returns \c Success if computation was succesful,
113       *          \c NumericalIssue if the matrix.appears to be negative.
114       */
info()115     ComputationInfo info() const
116     {
117       eigen_assert(m_isInitialized && "Decomposition is not initialized.");
118       return m_info;
119     }
120 
121     /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A.
122       *
123       * \sa compute()
124       */
125     template<typename Rhs>
126     inline const internal::solve_retval<SimplicialCholeskyBase, Rhs>
solve(const MatrixBase<Rhs> & b)127     solve(const MatrixBase<Rhs>& b) const
128     {
129       eigen_assert(m_isInitialized && "Simplicial LLT or LDLT is not initialized.");
130       eigen_assert(rows()==b.rows()
131                 && "SimplicialCholeskyBase::solve(): invalid number of rows of the right hand side matrix b");
132       return internal::solve_retval<SimplicialCholeskyBase, Rhs>(*this, b.derived());
133     }
134 
135     /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A.
136       *
137       * \sa compute()
138       */
139     template<typename Rhs>
140     inline const internal::sparse_solve_retval<SimplicialCholeskyBase, Rhs>
solve(const SparseMatrixBase<Rhs> & b)141     solve(const SparseMatrixBase<Rhs>& b) const
142     {
143       eigen_assert(m_isInitialized && "Simplicial LLT or LDLT is not initialized.");
144       eigen_assert(rows()==b.rows()
145                 && "SimplicialCholesky::solve(): invalid number of rows of the right hand side matrix b");
146       return internal::sparse_solve_retval<SimplicialCholeskyBase, Rhs>(*this, b.derived());
147     }
148 
149     /** \returns the permutation P
150       * \sa permutationPinv() */
permutationP()151     const PermutationMatrix<Dynamic,Dynamic,Index>& permutationP() const
152     { return m_P; }
153 
154     /** \returns the inverse P^-1 of the permutation P
155       * \sa permutationP() */
permutationPinv()156     const PermutationMatrix<Dynamic,Dynamic,Index>& permutationPinv() const
157     { return m_Pinv; }
158 
159     /** Sets the shift parameters that will be used to adjust the diagonal coefficients during the numerical factorization.
160       *
161       * During the numerical factorization, the diagonal coefficients are transformed by the following linear model:\n
162       * \c d_ii = \a offset + \a scale * \c d_ii
163       *
164       * The default is the identity transformation with \a offset=0, and \a scale=1.
165       *
166       * \returns a reference to \c *this.
167       */
168     Derived& setShift(const RealScalar& offset, const RealScalar& scale = 1)
169     {
170       m_shiftOffset = offset;
171       m_shiftScale = scale;
172       return derived();
173     }
174 
175 #ifndef EIGEN_PARSED_BY_DOXYGEN
176     /** \internal */
177     template<typename Stream>
dumpMemory(Stream & s)178     void dumpMemory(Stream& s)
179     {
180       int total = 0;
181       s << "  L:        " << ((total+=(m_matrix.cols()+1) * sizeof(int) + m_matrix.nonZeros()*(sizeof(int)+sizeof(Scalar))) >> 20) << "Mb" << "\n";
182       s << "  diag:     " << ((total+=m_diag.size() * sizeof(Scalar)) >> 20) << "Mb" << "\n";
183       s << "  tree:     " << ((total+=m_parent.size() * sizeof(int)) >> 20) << "Mb" << "\n";
184       s << "  nonzeros: " << ((total+=m_nonZerosPerCol.size() * sizeof(int)) >> 20) << "Mb" << "\n";
185       s << "  perm:     " << ((total+=m_P.size() * sizeof(int)) >> 20) << "Mb" << "\n";
186       s << "  perm^-1:  " << ((total+=m_Pinv.size() * sizeof(int)) >> 20) << "Mb" << "\n";
187       s << "  TOTAL:    " << (total>> 20) << "Mb" << "\n";
188     }
189 
190     /** \internal */
191     template<typename Rhs,typename Dest>
_solve(const MatrixBase<Rhs> & b,MatrixBase<Dest> & dest)192     void _solve(const MatrixBase<Rhs> &b, MatrixBase<Dest> &dest) const
193     {
194       eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()");
195       eigen_assert(m_matrix.rows()==b.rows());
196 
197       if(m_info!=Success)
198         return;
199 
200       if(m_P.size()>0)
201         dest = m_P * b;
202       else
203         dest = b;
204 
205       if(m_matrix.nonZeros()>0) // otherwise L==I
206         derived().matrixL().solveInPlace(dest);
207 
208       if(m_diag.size()>0)
209         dest = m_diag.asDiagonal().inverse() * dest;
210 
211       if (m_matrix.nonZeros()>0) // otherwise U==I
212         derived().matrixU().solveInPlace(dest);
213 
214       if(m_P.size()>0)
215         dest = m_Pinv * dest;
216     }
217 
218     /** \internal */
219     template<typename Rhs, typename DestScalar, int DestOptions, typename DestIndex>
_solve_sparse(const Rhs & b,SparseMatrix<DestScalar,DestOptions,DestIndex> & dest)220     void _solve_sparse(const Rhs& b, SparseMatrix<DestScalar,DestOptions,DestIndex> &dest) const
221     {
222       eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()");
223       eigen_assert(m_matrix.rows()==b.rows());
224 
225       // we process the sparse rhs per block of NbColsAtOnce columns temporarily stored into a dense matrix.
226       static const int NbColsAtOnce = 4;
227       int rhsCols = b.cols();
228       int size = b.rows();
229       Eigen::Matrix<DestScalar,Dynamic,Dynamic> tmp(size,rhsCols);
230       for(int k=0; k<rhsCols; k+=NbColsAtOnce)
231       {
232         int actualCols = std::min<int>(rhsCols-k, NbColsAtOnce);
233         tmp.leftCols(actualCols) = b.middleCols(k,actualCols);
234         tmp.leftCols(actualCols) = derived().solve(tmp.leftCols(actualCols));
235         dest.middleCols(k,actualCols) = tmp.leftCols(actualCols).sparseView();
236       }
237     }
238 
239 #endif // EIGEN_PARSED_BY_DOXYGEN
240 
241   protected:
242 
243     /** Computes the sparse Cholesky decomposition of \a matrix */
244     template<bool DoLDLT>
compute(const MatrixType & matrix)245     void compute(const MatrixType& matrix)
246     {
247       eigen_assert(matrix.rows()==matrix.cols());
248       Index size = matrix.cols();
249       CholMatrixType ap(size,size);
250       ordering(matrix, ap);
251       analyzePattern_preordered(ap, DoLDLT);
252       factorize_preordered<DoLDLT>(ap);
253     }
254 
255     template<bool DoLDLT>
factorize(const MatrixType & a)256     void factorize(const MatrixType& a)
257     {
258       eigen_assert(a.rows()==a.cols());
259       int size = a.cols();
260       CholMatrixType ap(size,size);
261       ap.template selfadjointView<Upper>() = a.template selfadjointView<UpLo>().twistedBy(m_P);
262       factorize_preordered<DoLDLT>(ap);
263     }
264 
265     template<bool DoLDLT>
266     void factorize_preordered(const CholMatrixType& a);
267 
analyzePattern(const MatrixType & a,bool doLDLT)268     void analyzePattern(const MatrixType& a, bool doLDLT)
269     {
270       eigen_assert(a.rows()==a.cols());
271       int size = a.cols();
272       CholMatrixType ap(size,size);
273       ordering(a, ap);
274       analyzePattern_preordered(ap,doLDLT);
275     }
276     void analyzePattern_preordered(const CholMatrixType& a, bool doLDLT);
277 
278     void ordering(const MatrixType& a, CholMatrixType& ap);
279 
280     /** keeps off-diagonal entries; drops diagonal entries */
281     struct keep_diag {
operatorkeep_diag282       inline bool operator() (const Index& row, const Index& col, const Scalar&) const
283       {
284         return row!=col;
285       }
286     };
287 
288     mutable ComputationInfo m_info;
289     bool m_isInitialized;
290     bool m_factorizationIsOk;
291     bool m_analysisIsOk;
292 
293     CholMatrixType m_matrix;
294     VectorType m_diag;                                // the diagonal coefficients (LDLT mode)
295     VectorXi m_parent;                                // elimination tree
296     VectorXi m_nonZerosPerCol;
297     PermutationMatrix<Dynamic,Dynamic,Index> m_P;     // the permutation
298     PermutationMatrix<Dynamic,Dynamic,Index> m_Pinv;  // the inverse permutation
299 
300     RealScalar m_shiftOffset;
301     RealScalar m_shiftScale;
302 };
303 
304 template<typename _MatrixType, int _UpLo = Lower> class SimplicialLLT;
305 template<typename _MatrixType, int _UpLo = Lower> class SimplicialLDLT;
306 template<typename _MatrixType, int _UpLo = Lower> class SimplicialCholesky;
307 
308 namespace internal {
309 
310 template<typename _MatrixType, int _UpLo> struct traits<SimplicialLLT<_MatrixType,_UpLo> >
311 {
312   typedef _MatrixType MatrixType;
313   enum { UpLo = _UpLo };
314   typedef typename MatrixType::Scalar                         Scalar;
315   typedef typename MatrixType::Index                          Index;
316   typedef SparseMatrix<Scalar, ColMajor, Index>               CholMatrixType;
317   typedef SparseTriangularView<CholMatrixType, Eigen::Lower>  MatrixL;
318   typedef SparseTriangularView<typename CholMatrixType::AdjointReturnType, Eigen::Upper>   MatrixU;
319   static inline MatrixL getL(const MatrixType& m) { return m; }
320   static inline MatrixU getU(const MatrixType& m) { return m.adjoint(); }
321 };
322 
323 template<typename _MatrixType,int _UpLo> struct traits<SimplicialLDLT<_MatrixType,_UpLo> >
324 {
325   typedef _MatrixType MatrixType;
326   enum { UpLo = _UpLo };
327   typedef typename MatrixType::Scalar                             Scalar;
328   typedef typename MatrixType::Index                              Index;
329   typedef SparseMatrix<Scalar, ColMajor, Index>                   CholMatrixType;
330   typedef SparseTriangularView<CholMatrixType, Eigen::UnitLower>  MatrixL;
331   typedef SparseTriangularView<typename CholMatrixType::AdjointReturnType, Eigen::UnitUpper> MatrixU;
332   static inline MatrixL getL(const MatrixType& m) { return m; }
333   static inline MatrixU getU(const MatrixType& m) { return m.adjoint(); }
334 };
335 
336 template<typename _MatrixType, int _UpLo> struct traits<SimplicialCholesky<_MatrixType,_UpLo> >
337 {
338   typedef _MatrixType MatrixType;
339   enum { UpLo = _UpLo };
340 };
341 
342 }
343 
344 /** \ingroup SparseCholesky_Module
345   * \class SimplicialLLT
346   * \brief A direct sparse LLT Cholesky factorizations
347   *
348   * This class provides a LL^T Cholesky factorizations of sparse matrices that are
349   * selfadjoint and positive definite. The factorization allows for solving A.X = B where
350   * X and B can be either dense or sparse.
351   *
352   * In order to reduce the fill-in, a symmetric permutation P is applied prior to the factorization
353   * such that the factorized matrix is P A P^-1.
354   *
355   * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
356   * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower
357   *               or Upper. Default is Lower.
358   *
359   * \sa class SimplicialLDLT
360   */
361 template<typename _MatrixType, int _UpLo>
362     class SimplicialLLT : public SimplicialCholeskyBase<SimplicialLLT<_MatrixType,_UpLo> >
363 {
364 public:
365     typedef _MatrixType MatrixType;
366     enum { UpLo = _UpLo };
367     typedef SimplicialCholeskyBase<SimplicialLLT> Base;
368     typedef typename MatrixType::Scalar Scalar;
369     typedef typename MatrixType::RealScalar RealScalar;
370     typedef typename MatrixType::Index Index;
371     typedef SparseMatrix<Scalar,ColMajor,Index> CholMatrixType;
372     typedef Matrix<Scalar,Dynamic,1> VectorType;
373     typedef internal::traits<SimplicialLLT> Traits;
374     typedef typename Traits::MatrixL  MatrixL;
375     typedef typename Traits::MatrixU  MatrixU;
376 public:
377     /** Default constructor */
378     SimplicialLLT() : Base() {}
379     /** Constructs and performs the LLT factorization of \a matrix */
380     SimplicialLLT(const MatrixType& matrix)
381         : Base(matrix) {}
382 
383     /** \returns an expression of the factor L */
384     inline const MatrixL matrixL() const {
385         eigen_assert(Base::m_factorizationIsOk && "Simplicial LLT not factorized");
386         return Traits::getL(Base::m_matrix);
387     }
388 
389     /** \returns an expression of the factor U (= L^*) */
390     inline const MatrixU matrixU() const {
391         eigen_assert(Base::m_factorizationIsOk && "Simplicial LLT not factorized");
392         return Traits::getU(Base::m_matrix);
393     }
394 
395     /** Computes the sparse Cholesky decomposition of \a matrix */
396     SimplicialLLT& compute(const MatrixType& matrix)
397     {
398       Base::template compute<false>(matrix);
399       return *this;
400     }
401 
402     /** Performs a symbolic decomposition on the sparcity of \a matrix.
403       *
404       * This function is particularly useful when solving for several problems having the same structure.
405       *
406       * \sa factorize()
407       */
408     void analyzePattern(const MatrixType& a)
409     {
410       Base::analyzePattern(a, false);
411     }
412 
413     /** Performs a numeric decomposition of \a matrix
414       *
415       * The given matrix must has the same sparcity than the matrix on which the symbolic decomposition has been performed.
416       *
417       * \sa analyzePattern()
418       */
419     void factorize(const MatrixType& a)
420     {
421       Base::template factorize<false>(a);
422     }
423 
424     /** \returns the determinant of the underlying matrix from the current factorization */
425     Scalar determinant() const
426     {
427       Scalar detL = Base::m_matrix.diagonal().prod();
428       return internal::abs2(detL);
429     }
430 };
431 
432 /** \ingroup SparseCholesky_Module
433   * \class SimplicialLDLT
434   * \brief A direct sparse LDLT Cholesky factorizations without square root.
435   *
436   * This class provides a LDL^T Cholesky factorizations without square root of sparse matrices that are
437   * selfadjoint and positive definite. The factorization allows for solving A.X = B where
438   * X and B can be either dense or sparse.
439   *
440   * In order to reduce the fill-in, a symmetric permutation P is applied prior to the factorization
441   * such that the factorized matrix is P A P^-1.
442   *
443   * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
444   * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower
445   *               or Upper. Default is Lower.
446   *
447   * \sa class SimplicialLLT
448   */
449 template<typename _MatrixType, int _UpLo>
450     class SimplicialLDLT : public SimplicialCholeskyBase<SimplicialLDLT<_MatrixType,_UpLo> >
451 {
452 public:
453     typedef _MatrixType MatrixType;
454     enum { UpLo = _UpLo };
455     typedef SimplicialCholeskyBase<SimplicialLDLT> Base;
456     typedef typename MatrixType::Scalar Scalar;
457     typedef typename MatrixType::RealScalar RealScalar;
458     typedef typename MatrixType::Index Index;
459     typedef SparseMatrix<Scalar,ColMajor,Index> CholMatrixType;
460     typedef Matrix<Scalar,Dynamic,1> VectorType;
461     typedef internal::traits<SimplicialLDLT> Traits;
462     typedef typename Traits::MatrixL  MatrixL;
463     typedef typename Traits::MatrixU  MatrixU;
464 public:
465     /** Default constructor */
466     SimplicialLDLT() : Base() {}
467 
468     /** Constructs and performs the LLT factorization of \a matrix */
469     SimplicialLDLT(const MatrixType& matrix)
470         : Base(matrix) {}
471 
472     /** \returns a vector expression of the diagonal D */
473     inline const VectorType vectorD() const {
474         eigen_assert(Base::m_factorizationIsOk && "Simplicial LDLT not factorized");
475         return Base::m_diag;
476     }
477     /** \returns an expression of the factor L */
478     inline const MatrixL matrixL() const {
479         eigen_assert(Base::m_factorizationIsOk && "Simplicial LDLT not factorized");
480         return Traits::getL(Base::m_matrix);
481     }
482 
483     /** \returns an expression of the factor U (= L^*) */
484     inline const MatrixU matrixU() const {
485         eigen_assert(Base::m_factorizationIsOk && "Simplicial LDLT not factorized");
486         return Traits::getU(Base::m_matrix);
487     }
488 
489     /** Computes the sparse Cholesky decomposition of \a matrix */
490     SimplicialLDLT& compute(const MatrixType& matrix)
491     {
492       Base::template compute<true>(matrix);
493       return *this;
494     }
495 
496     /** Performs a symbolic decomposition on the sparcity of \a matrix.
497       *
498       * This function is particularly useful when solving for several problems having the same structure.
499       *
500       * \sa factorize()
501       */
502     void analyzePattern(const MatrixType& a)
503     {
504       Base::analyzePattern(a, true);
505     }
506 
507     /** Performs a numeric decomposition of \a matrix
508       *
509       * The given matrix must has the same sparcity than the matrix on which the symbolic decomposition has been performed.
510       *
511       * \sa analyzePattern()
512       */
513     void factorize(const MatrixType& a)
514     {
515       Base::template factorize<true>(a);
516     }
517 
518     /** \returns the determinant of the underlying matrix from the current factorization */
519     Scalar determinant() const
520     {
521       return Base::m_diag.prod();
522     }
523 };
524 
525 /** \deprecated use SimplicialLDLT or class SimplicialLLT
526   * \ingroup SparseCholesky_Module
527   * \class SimplicialCholesky
528   *
529   * \sa class SimplicialLDLT, class SimplicialLLT
530   */
531 template<typename _MatrixType, int _UpLo>
532     class SimplicialCholesky : public SimplicialCholeskyBase<SimplicialCholesky<_MatrixType,_UpLo> >
533 {
534 public:
535     typedef _MatrixType MatrixType;
536     enum { UpLo = _UpLo };
537     typedef SimplicialCholeskyBase<SimplicialCholesky> Base;
538     typedef typename MatrixType::Scalar Scalar;
539     typedef typename MatrixType::RealScalar RealScalar;
540     typedef typename MatrixType::Index Index;
541     typedef SparseMatrix<Scalar,ColMajor,Index> CholMatrixType;
542     typedef Matrix<Scalar,Dynamic,1> VectorType;
543     typedef internal::traits<SimplicialCholesky> Traits;
544     typedef internal::traits<SimplicialLDLT<MatrixType,UpLo> > LDLTTraits;
545     typedef internal::traits<SimplicialLLT<MatrixType,UpLo>  > LLTTraits;
546   public:
547     SimplicialCholesky() : Base(), m_LDLT(true) {}
548 
549     SimplicialCholesky(const MatrixType& matrix)
550       : Base(), m_LDLT(true)
551     {
552       compute(matrix);
553     }
554 
555     SimplicialCholesky& setMode(SimplicialCholeskyMode mode)
556     {
557       switch(mode)
558       {
559       case SimplicialCholeskyLLT:
560         m_LDLT = false;
561         break;
562       case SimplicialCholeskyLDLT:
563         m_LDLT = true;
564         break;
565       default:
566         break;
567       }
568 
569       return *this;
570     }
571 
572     inline const VectorType vectorD() const {
573         eigen_assert(Base::m_factorizationIsOk && "Simplicial Cholesky not factorized");
574         return Base::m_diag;
575     }
576     inline const CholMatrixType rawMatrix() const {
577         eigen_assert(Base::m_factorizationIsOk && "Simplicial Cholesky not factorized");
578         return Base::m_matrix;
579     }
580 
581     /** Computes the sparse Cholesky decomposition of \a matrix */
582     SimplicialCholesky& compute(const MatrixType& matrix)
583     {
584       if(m_LDLT)
585         Base::template compute<true>(matrix);
586       else
587         Base::template compute<false>(matrix);
588       return *this;
589     }
590 
591     /** Performs a symbolic decomposition on the sparcity of \a matrix.
592       *
593       * This function is particularly useful when solving for several problems having the same structure.
594       *
595       * \sa factorize()
596       */
597     void analyzePattern(const MatrixType& a)
598     {
599       Base::analyzePattern(a, m_LDLT);
600     }
601 
602     /** Performs a numeric decomposition of \a matrix
603       *
604       * The given matrix must has the same sparcity than the matrix on which the symbolic decomposition has been performed.
605       *
606       * \sa analyzePattern()
607       */
608     void factorize(const MatrixType& a)
609     {
610       if(m_LDLT)
611         Base::template factorize<true>(a);
612       else
613         Base::template factorize<false>(a);
614     }
615 
616     /** \internal */
617     template<typename Rhs,typename Dest>
618     void _solve(const MatrixBase<Rhs> &b, MatrixBase<Dest> &dest) const
619     {
620       eigen_assert(Base::m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()");
621       eigen_assert(Base::m_matrix.rows()==b.rows());
622 
623       if(Base::m_info!=Success)
624         return;
625 
626       if(Base::m_P.size()>0)
627         dest = Base::m_P * b;
628       else
629         dest = b;
630 
631       if(Base::m_matrix.nonZeros()>0) // otherwise L==I
632       {
633         if(m_LDLT)
634           LDLTTraits::getL(Base::m_matrix).solveInPlace(dest);
635         else
636           LLTTraits::getL(Base::m_matrix).solveInPlace(dest);
637       }
638 
639       if(Base::m_diag.size()>0)
640         dest = Base::m_diag.asDiagonal().inverse() * dest;
641 
642       if (Base::m_matrix.nonZeros()>0) // otherwise I==I
643       {
644         if(m_LDLT)
645           LDLTTraits::getU(Base::m_matrix).solveInPlace(dest);
646         else
647           LLTTraits::getU(Base::m_matrix).solveInPlace(dest);
648       }
649 
650       if(Base::m_P.size()>0)
651         dest = Base::m_Pinv * dest;
652     }
653 
654     Scalar determinant() const
655     {
656       if(m_LDLT)
657       {
658         return Base::m_diag.prod();
659       }
660       else
661       {
662         Scalar detL = Diagonal<const CholMatrixType>(Base::m_matrix).prod();
663         return internal::abs2(detL);
664       }
665     }
666 
667   protected:
668     bool m_LDLT;
669 };
670 
671 template<typename Derived>
672 void SimplicialCholeskyBase<Derived>::ordering(const MatrixType& a, CholMatrixType& ap)
673 {
674   eigen_assert(a.rows()==a.cols());
675   const Index size = a.rows();
676   // TODO allows to configure the permutation
677   // Note that amd compute the inverse permutation
678   {
679     CholMatrixType C;
680     C = a.template selfadjointView<UpLo>();
681     // remove diagonal entries:
682     // seems not to be needed
683     // C.prune(keep_diag());
684     internal::minimum_degree_ordering(C, m_Pinv);
685   }
686 
687   if(m_Pinv.size()>0)
688     m_P = m_Pinv.inverse();
689   else
690     m_P.resize(0);
691 
692   ap.resize(size,size);
693   ap.template selfadjointView<Upper>() = a.template selfadjointView<UpLo>().twistedBy(m_P);
694 }
695 
696 template<typename Derived>
697 void SimplicialCholeskyBase<Derived>::analyzePattern_preordered(const CholMatrixType& ap, bool doLDLT)
698 {
699   const Index size = ap.rows();
700   m_matrix.resize(size, size);
701   m_parent.resize(size);
702   m_nonZerosPerCol.resize(size);
703 
704   ei_declare_aligned_stack_constructed_variable(Index, tags, size, 0);
705 
706   for(Index k = 0; k < size; ++k)
707   {
708     /* L(k,:) pattern: all nodes reachable in etree from nz in A(0:k-1,k) */
709     m_parent[k] = -1;             /* parent of k is not yet known */
710     tags[k] = k;                  /* mark node k as visited */
711     m_nonZerosPerCol[k] = 0;      /* count of nonzeros in column k of L */
712     for(typename CholMatrixType::InnerIterator it(ap,k); it; ++it)
713     {
714       Index i = it.index();
715       if(i < k)
716       {
717         /* follow path from i to root of etree, stop at flagged node */
718         for(; tags[i] != k; i = m_parent[i])
719         {
720           /* find parent of i if not yet determined */
721           if (m_parent[i] == -1)
722             m_parent[i] = k;
723           m_nonZerosPerCol[i]++;        /* L (k,i) is nonzero */
724           tags[i] = k;                  /* mark i as visited */
725         }
726       }
727     }
728   }
729 
730   /* construct Lp index array from m_nonZerosPerCol column counts */
731   Index* Lp = m_matrix.outerIndexPtr();
732   Lp[0] = 0;
733   for(Index k = 0; k < size; ++k)
734     Lp[k+1] = Lp[k] + m_nonZerosPerCol[k] + (doLDLT ? 0 : 1);
735 
736   m_matrix.resizeNonZeros(Lp[size]);
737 
738   m_isInitialized     = true;
739   m_info              = Success;
740   m_analysisIsOk      = true;
741   m_factorizationIsOk = false;
742 }
743 
744 
745 template<typename Derived>
746 template<bool DoLDLT>
747 void SimplicialCholeskyBase<Derived>::factorize_preordered(const CholMatrixType& ap)
748 {
749   eigen_assert(m_analysisIsOk && "You must first call analyzePattern()");
750   eigen_assert(ap.rows()==ap.cols());
751   const Index size = ap.rows();
752   eigen_assert(m_parent.size()==size);
753   eigen_assert(m_nonZerosPerCol.size()==size);
754 
755   const Index* Lp = m_matrix.outerIndexPtr();
756   Index* Li = m_matrix.innerIndexPtr();
757   Scalar* Lx = m_matrix.valuePtr();
758 
759   ei_declare_aligned_stack_constructed_variable(Scalar, y, size, 0);
760   ei_declare_aligned_stack_constructed_variable(Index,  pattern, size, 0);
761   ei_declare_aligned_stack_constructed_variable(Index,  tags, size, 0);
762 
763   bool ok = true;
764   m_diag.resize(DoLDLT ? size : 0);
765 
766   for(Index k = 0; k < size; ++k)
767   {
768     // compute nonzero pattern of kth row of L, in topological order
769     y[k] = 0.0;                     // Y(0:k) is now all zero
770     Index top = size;               // stack for pattern is empty
771     tags[k] = k;                    // mark node k as visited
772     m_nonZerosPerCol[k] = 0;        // count of nonzeros in column k of L
773     for(typename MatrixType::InnerIterator it(ap,k); it; ++it)
774     {
775       Index i = it.index();
776       if(i <= k)
777       {
778         y[i] += internal::conj(it.value());            /* scatter A(i,k) into Y (sum duplicates) */
779         Index len;
780         for(len = 0; tags[i] != k; i = m_parent[i])
781         {
782           pattern[len++] = i;     /* L(k,i) is nonzero */
783           tags[i] = k;            /* mark i as visited */
784         }
785         while(len > 0)
786           pattern[--top] = pattern[--len];
787       }
788     }
789 
790     /* compute numerical values kth row of L (a sparse triangular solve) */
791 
792     RealScalar d = internal::real(y[k]) * m_shiftScale + m_shiftOffset;    // get D(k,k), apply the shift function, and clear Y(k)
793     y[k] = 0.0;
794     for(; top < size; ++top)
795     {
796       Index i = pattern[top];       /* pattern[top:n-1] is pattern of L(:,k) */
797       Scalar yi = y[i];             /* get and clear Y(i) */
798       y[i] = 0.0;
799 
800       /* the nonzero entry L(k,i) */
801       Scalar l_ki;
802       if(DoLDLT)
803         l_ki = yi / m_diag[i];
804       else
805         yi = l_ki = yi / Lx[Lp[i]];
806 
807       Index p2 = Lp[i] + m_nonZerosPerCol[i];
808       Index p;
809       for(p = Lp[i] + (DoLDLT ? 0 : 1); p < p2; ++p)
810         y[Li[p]] -= internal::conj(Lx[p]) * yi;
811       d -= internal::real(l_ki * internal::conj(yi));
812       Li[p] = k;                          /* store L(k,i) in column form of L */
813       Lx[p] = l_ki;
814       ++m_nonZerosPerCol[i];              /* increment count of nonzeros in col i */
815     }
816     if(DoLDLT)
817     {
818       m_diag[k] = d;
819       if(d == RealScalar(0))
820       {
821         ok = false;                         /* failure, D(k,k) is zero */
822         break;
823       }
824     }
825     else
826     {
827       Index p = Lp[k] + m_nonZerosPerCol[k]++;
828       Li[p] = k ;                /* store L(k,k) = sqrt (d) in column k */
829       if(d <= RealScalar(0)) {
830         ok = false;              /* failure, matrix is not positive definite */
831         break;
832       }
833       Lx[p] = internal::sqrt(d) ;
834     }
835   }
836 
837   m_info = ok ? Success : NumericalIssue;
838   m_factorizationIsOk = true;
839 }
840 
841 namespace internal {
842 
843 template<typename Derived, typename Rhs>
844 struct solve_retval<SimplicialCholeskyBase<Derived>, Rhs>
845   : solve_retval_base<SimplicialCholeskyBase<Derived>, Rhs>
846 {
847   typedef SimplicialCholeskyBase<Derived> Dec;
848   EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs)
849 
850   template<typename Dest> void evalTo(Dest& dst) const
851   {
852     dec().derived()._solve(rhs(),dst);
853   }
854 };
855 
856 template<typename Derived, typename Rhs>
857 struct sparse_solve_retval<SimplicialCholeskyBase<Derived>, Rhs>
858   : sparse_solve_retval_base<SimplicialCholeskyBase<Derived>, Rhs>
859 {
860   typedef SimplicialCholeskyBase<Derived> Dec;
861   EIGEN_MAKE_SPARSE_SOLVE_HELPERS(Dec,Rhs)
862 
863   template<typename Dest> void evalTo(Dest& dst) const
864   {
865     dec().derived()._solve_sparse(rhs(),dst);
866   }
867 };
868 
869 } // end namespace internal
870 
871 } // end namespace Eigen
872 
873 #endif // EIGEN_SIMPLICIAL_CHOLESKY_H
874