• 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 #ifndef EIGEN_CHOLMODSUPPORT_H
11 #define EIGEN_CHOLMODSUPPORT_H
12 
13 namespace Eigen {
14 
15 namespace internal {
16 
17 template<typename Scalar> struct cholmod_configure_matrix;
18 
19 template<> struct cholmod_configure_matrix<double> {
20   template<typename CholmodType>
21   static void run(CholmodType& mat) {
22     mat.xtype = CHOLMOD_REAL;
23     mat.dtype = CHOLMOD_DOUBLE;
24   }
25 };
26 
27 template<> struct cholmod_configure_matrix<std::complex<double> > {
28   template<typename CholmodType>
29   static void run(CholmodType& mat) {
30     mat.xtype = CHOLMOD_COMPLEX;
31     mat.dtype = CHOLMOD_DOUBLE;
32   }
33 };
34 
35 // Other scalar types are not yet suppotred by Cholmod
36 // template<> struct cholmod_configure_matrix<float> {
37 //   template<typename CholmodType>
38 //   static void run(CholmodType& mat) {
39 //     mat.xtype = CHOLMOD_REAL;
40 //     mat.dtype = CHOLMOD_SINGLE;
41 //   }
42 // };
43 //
44 // template<> struct cholmod_configure_matrix<std::complex<float> > {
45 //   template<typename CholmodType>
46 //   static void run(CholmodType& mat) {
47 //     mat.xtype = CHOLMOD_COMPLEX;
48 //     mat.dtype = CHOLMOD_SINGLE;
49 //   }
50 // };
51 
52 } // namespace internal
53 
54 /** Wraps the Eigen sparse matrix \a mat into a Cholmod sparse matrix object.
55   * Note that the data are shared.
56   */
57 template<typename _Scalar, int _Options, typename _StorageIndex>
58 cholmod_sparse viewAsCholmod(Ref<SparseMatrix<_Scalar,_Options,_StorageIndex> > mat)
59 {
60   cholmod_sparse res;
61   res.nzmax   = mat.nonZeros();
62   res.nrow    = mat.rows();
63   res.ncol    = mat.cols();
64   res.p       = mat.outerIndexPtr();
65   res.i       = mat.innerIndexPtr();
66   res.x       = mat.valuePtr();
67   res.z       = 0;
68   res.sorted  = 1;
69   if(mat.isCompressed())
70   {
71     res.packed  = 1;
72     res.nz = 0;
73   }
74   else
75   {
76     res.packed  = 0;
77     res.nz = mat.innerNonZeroPtr();
78   }
79 
80   res.dtype   = 0;
81   res.stype   = -1;
82 
83   if (internal::is_same<_StorageIndex,int>::value)
84   {
85     res.itype = CHOLMOD_INT;
86   }
87   else if (internal::is_same<_StorageIndex,long>::value)
88   {
89     res.itype = CHOLMOD_LONG;
90   }
91   else
92   {
93     eigen_assert(false && "Index type not supported yet");
94   }
95 
96   // setup res.xtype
97   internal::cholmod_configure_matrix<_Scalar>::run(res);
98 
99   res.stype = 0;
100 
101   return res;
102 }
103 
104 template<typename _Scalar, int _Options, typename _Index>
105 const cholmod_sparse viewAsCholmod(const SparseMatrix<_Scalar,_Options,_Index>& mat)
106 {
107   cholmod_sparse res = viewAsCholmod(Ref<SparseMatrix<_Scalar,_Options,_Index> >(mat.const_cast_derived()));
108   return res;
109 }
110 
111 template<typename _Scalar, int _Options, typename _Index>
112 const cholmod_sparse viewAsCholmod(const SparseVector<_Scalar,_Options,_Index>& mat)
113 {
114   cholmod_sparse res = viewAsCholmod(Ref<SparseMatrix<_Scalar,_Options,_Index> >(mat.const_cast_derived()));
115   return res;
116 }
117 
118 /** Returns a view of the Eigen sparse matrix \a mat as Cholmod sparse matrix.
119   * The data are not copied but shared. */
120 template<typename _Scalar, int _Options, typename _Index, unsigned int UpLo>
121 cholmod_sparse viewAsCholmod(const SparseSelfAdjointView<const SparseMatrix<_Scalar,_Options,_Index>, UpLo>& mat)
122 {
123   cholmod_sparse res = viewAsCholmod(Ref<SparseMatrix<_Scalar,_Options,_Index> >(mat.matrix().const_cast_derived()));
124 
125   if(UpLo==Upper) res.stype =  1;
126   if(UpLo==Lower) res.stype = -1;
127 
128   return res;
129 }
130 
131 /** Returns a view of the Eigen \b dense matrix \a mat as Cholmod dense matrix.
132   * The data are not copied but shared. */
133 template<typename Derived>
134 cholmod_dense viewAsCholmod(MatrixBase<Derived>& mat)
135 {
136   EIGEN_STATIC_ASSERT((internal::traits<Derived>::Flags&RowMajorBit)==0,THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES);
137   typedef typename Derived::Scalar Scalar;
138 
139   cholmod_dense res;
140   res.nrow   = mat.rows();
141   res.ncol   = mat.cols();
142   res.nzmax  = res.nrow * res.ncol;
143   res.d      = Derived::IsVectorAtCompileTime ? mat.derived().size() : mat.derived().outerStride();
144   res.x      = (void*)(mat.derived().data());
145   res.z      = 0;
146 
147   internal::cholmod_configure_matrix<Scalar>::run(res);
148 
149   return res;
150 }
151 
152 /** Returns a view of the Cholmod sparse matrix \a cm as an Eigen sparse matrix.
153   * The data are not copied but shared. */
154 template<typename Scalar, int Flags, typename StorageIndex>
155 MappedSparseMatrix<Scalar,Flags,StorageIndex> viewAsEigen(cholmod_sparse& cm)
156 {
157   return MappedSparseMatrix<Scalar,Flags,StorageIndex>
158          (cm.nrow, cm.ncol, static_cast<StorageIndex*>(cm.p)[cm.ncol],
159           static_cast<StorageIndex*>(cm.p), static_cast<StorageIndex*>(cm.i),static_cast<Scalar*>(cm.x) );
160 }
161 
162 enum CholmodMode {
163   CholmodAuto, CholmodSimplicialLLt, CholmodSupernodalLLt, CholmodLDLt
164 };
165 
166 
167 /** \ingroup CholmodSupport_Module
168   * \class CholmodBase
169   * \brief The base class for the direct Cholesky factorization of Cholmod
170   * \sa class CholmodSupernodalLLT, class CholmodSimplicialLDLT, class CholmodSimplicialLLT
171   */
172 template<typename _MatrixType, int _UpLo, typename Derived>
173 class CholmodBase : public SparseSolverBase<Derived>
174 {
175   protected:
176     typedef SparseSolverBase<Derived> Base;
177     using Base::derived;
178     using Base::m_isInitialized;
179   public:
180     typedef _MatrixType MatrixType;
181     enum { UpLo = _UpLo };
182     typedef typename MatrixType::Scalar Scalar;
183     typedef typename MatrixType::RealScalar RealScalar;
184     typedef MatrixType CholMatrixType;
185     typedef typename MatrixType::StorageIndex StorageIndex;
186     enum {
187       ColsAtCompileTime = MatrixType::ColsAtCompileTime,
188       MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
189     };
190 
191   public:
192 
193     CholmodBase()
194       : m_cholmodFactor(0), m_info(Success), m_factorizationIsOk(false), m_analysisIsOk(false)
195     {
196       EIGEN_STATIC_ASSERT((internal::is_same<double,RealScalar>::value), CHOLMOD_SUPPORTS_DOUBLE_PRECISION_ONLY);
197       m_shiftOffset[0] = m_shiftOffset[1] = 0.0;
198       cholmod_start(&m_cholmod);
199     }
200 
201     explicit CholmodBase(const MatrixType& matrix)
202       : m_cholmodFactor(0), m_info(Success), m_factorizationIsOk(false), m_analysisIsOk(false)
203     {
204       EIGEN_STATIC_ASSERT((internal::is_same<double,RealScalar>::value), CHOLMOD_SUPPORTS_DOUBLE_PRECISION_ONLY);
205       m_shiftOffset[0] = m_shiftOffset[1] = 0.0;
206       cholmod_start(&m_cholmod);
207       compute(matrix);
208     }
209 
210     ~CholmodBase()
211     {
212       if(m_cholmodFactor)
213         cholmod_free_factor(&m_cholmodFactor, &m_cholmod);
214       cholmod_finish(&m_cholmod);
215     }
216 
217     inline StorageIndex cols() const { return internal::convert_index<StorageIndex, Index>(m_cholmodFactor->n); }
218     inline StorageIndex rows() const { return internal::convert_index<StorageIndex, Index>(m_cholmodFactor->n); }
219 
220     /** \brief Reports whether previous computation was successful.
221       *
222       * \returns \c Success if computation was succesful,
223       *          \c NumericalIssue if the matrix.appears to be negative.
224       */
225     ComputationInfo info() const
226     {
227       eigen_assert(m_isInitialized && "Decomposition is not initialized.");
228       return m_info;
229     }
230 
231     /** Computes the sparse Cholesky decomposition of \a matrix */
232     Derived& compute(const MatrixType& matrix)
233     {
234       analyzePattern(matrix);
235       factorize(matrix);
236       return derived();
237     }
238 
239     /** Performs a symbolic decomposition on the sparsity pattern of \a matrix.
240       *
241       * This function is particularly useful when solving for several problems having the same structure.
242       *
243       * \sa factorize()
244       */
245     void analyzePattern(const MatrixType& matrix)
246     {
247       if(m_cholmodFactor)
248       {
249         cholmod_free_factor(&m_cholmodFactor, &m_cholmod);
250         m_cholmodFactor = 0;
251       }
252       cholmod_sparse A = viewAsCholmod(matrix.template selfadjointView<UpLo>());
253       m_cholmodFactor = cholmod_analyze(&A, &m_cholmod);
254 
255       this->m_isInitialized = true;
256       this->m_info = Success;
257       m_analysisIsOk = true;
258       m_factorizationIsOk = false;
259     }
260 
261     /** Performs a numeric decomposition of \a matrix
262       *
263       * The given matrix must have the same sparsity pattern as the matrix on which the symbolic decomposition has been performed.
264       *
265       * \sa analyzePattern()
266       */
267     void factorize(const MatrixType& matrix)
268     {
269       eigen_assert(m_analysisIsOk && "You must first call analyzePattern()");
270       cholmod_sparse A = viewAsCholmod(matrix.template selfadjointView<UpLo>());
271       cholmod_factorize_p(&A, m_shiftOffset, 0, 0, m_cholmodFactor, &m_cholmod);
272 
273       // If the factorization failed, minor is the column at which it did. On success minor == n.
274       this->m_info = (m_cholmodFactor->minor == m_cholmodFactor->n ? Success : NumericalIssue);
275       m_factorizationIsOk = true;
276     }
277 
278     /** Returns a reference to the Cholmod's configuration structure to get a full control over the performed operations.
279      *  See the Cholmod user guide for details. */
280     cholmod_common& cholmod() { return m_cholmod; }
281 
282     #ifndef EIGEN_PARSED_BY_DOXYGEN
283     /** \internal */
284     template<typename Rhs,typename Dest>
285     void _solve_impl(const MatrixBase<Rhs> &b, MatrixBase<Dest> &dest) const
286     {
287       eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()");
288       const Index size = m_cholmodFactor->n;
289       EIGEN_UNUSED_VARIABLE(size);
290       eigen_assert(size==b.rows());
291 
292       // Cholmod needs column-major stoarge without inner-stride, which corresponds to the default behavior of Ref.
293       Ref<const Matrix<typename Rhs::Scalar,Dynamic,Dynamic,ColMajor> > b_ref(b.derived());
294 
295       cholmod_dense b_cd = viewAsCholmod(b_ref);
296       cholmod_dense* x_cd = cholmod_solve(CHOLMOD_A, m_cholmodFactor, &b_cd, &m_cholmod);
297       if(!x_cd)
298       {
299         this->m_info = NumericalIssue;
300         return;
301       }
302       // TODO optimize this copy by swapping when possible (be careful with alignment, etc.)
303       dest = Matrix<Scalar,Dest::RowsAtCompileTime,Dest::ColsAtCompileTime>::Map(reinterpret_cast<Scalar*>(x_cd->x),b.rows(),b.cols());
304       cholmod_free_dense(&x_cd, &m_cholmod);
305     }
306 
307     /** \internal */
308     template<typename RhsDerived, typename DestDerived>
309     void _solve_impl(const SparseMatrixBase<RhsDerived> &b, SparseMatrixBase<DestDerived> &dest) const
310     {
311       eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()");
312       const Index size = m_cholmodFactor->n;
313       EIGEN_UNUSED_VARIABLE(size);
314       eigen_assert(size==b.rows());
315 
316       // note: cs stands for Cholmod Sparse
317       Ref<SparseMatrix<typename RhsDerived::Scalar,ColMajor,typename RhsDerived::StorageIndex> > b_ref(b.const_cast_derived());
318       cholmod_sparse b_cs = viewAsCholmod(b_ref);
319       cholmod_sparse* x_cs = cholmod_spsolve(CHOLMOD_A, m_cholmodFactor, &b_cs, &m_cholmod);
320       if(!x_cs)
321       {
322         this->m_info = NumericalIssue;
323         return;
324       }
325       // TODO optimize this copy by swapping when possible (be careful with alignment, etc.)
326       dest.derived() = viewAsEigen<typename DestDerived::Scalar,ColMajor,typename DestDerived::StorageIndex>(*x_cs);
327       cholmod_free_sparse(&x_cs, &m_cholmod);
328     }
329     #endif // EIGEN_PARSED_BY_DOXYGEN
330 
331 
332     /** Sets the shift parameter that will be used to adjust the diagonal coefficients during the numerical factorization.
333       *
334       * During the numerical factorization, an offset term is added to the diagonal coefficients:\n
335       * \c d_ii = \a offset + \c d_ii
336       *
337       * The default is \a offset=0.
338       *
339       * \returns a reference to \c *this.
340       */
341     Derived& setShift(const RealScalar& offset)
342     {
343       m_shiftOffset[0] = double(offset);
344       return derived();
345     }
346 
347     /** \returns the determinant of the underlying matrix from the current factorization */
348     Scalar determinant() const
349     {
350       using std::exp;
351       return exp(logDeterminant());
352     }
353 
354     /** \returns the log determinant of the underlying matrix from the current factorization */
355     Scalar logDeterminant() const
356     {
357       using std::log;
358       using numext::real;
359       eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()");
360 
361       RealScalar logDet = 0;
362       Scalar *x = static_cast<Scalar*>(m_cholmodFactor->x);
363       if (m_cholmodFactor->is_super)
364       {
365         // Supernodal factorization stored as a packed list of dense column-major blocs,
366         // as described by the following structure:
367 
368         // super[k] == index of the first column of the j-th super node
369         StorageIndex *super = static_cast<StorageIndex*>(m_cholmodFactor->super);
370         // pi[k] == offset to the description of row indices
371         StorageIndex *pi = static_cast<StorageIndex*>(m_cholmodFactor->pi);
372         // px[k] == offset to the respective dense block
373         StorageIndex *px = static_cast<StorageIndex*>(m_cholmodFactor->px);
374 
375         Index nb_super_nodes = m_cholmodFactor->nsuper;
376         for (Index k=0; k < nb_super_nodes; ++k)
377         {
378           StorageIndex ncols = super[k + 1] - super[k];
379           StorageIndex nrows = pi[k + 1] - pi[k];
380 
381           Map<const Array<Scalar,1,Dynamic>, 0, InnerStride<> > sk(x + px[k], ncols, InnerStride<>(nrows+1));
382           logDet += sk.real().log().sum();
383         }
384       }
385       else
386       {
387         // Simplicial factorization stored as standard CSC matrix.
388         StorageIndex *p = static_cast<StorageIndex*>(m_cholmodFactor->p);
389         Index size = m_cholmodFactor->n;
390         for (Index k=0; k<size; ++k)
391           logDet += log(real( x[p[k]] ));
392       }
393       if (m_cholmodFactor->is_ll)
394         logDet *= 2.0;
395       return logDet;
396     };
397 
398     template<typename Stream>
399     void dumpMemory(Stream& /*s*/)
400     {}
401 
402   protected:
403     mutable cholmod_common m_cholmod;
404     cholmod_factor* m_cholmodFactor;
405     double m_shiftOffset[2];
406     mutable ComputationInfo m_info;
407     int m_factorizationIsOk;
408     int m_analysisIsOk;
409 };
410 
411 /** \ingroup CholmodSupport_Module
412   * \class CholmodSimplicialLLT
413   * \brief A simplicial direct Cholesky (LLT) factorization and solver based on Cholmod
414   *
415   * This class allows to solve for A.X = B sparse linear problems via a simplicial LL^T Cholesky factorization
416   * using the Cholmod library.
417   * This simplicial variant is equivalent to Eigen's built-in SimplicialLLT class. Therefore, it has little practical interest.
418   * The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices
419   * X and B can be either dense or sparse.
420   *
421   * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
422   * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower
423   *               or Upper. Default is Lower.
424   *
425   * \implsparsesolverconcept
426   *
427   * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed.
428   *
429   * \warning Only double precision real and complex scalar types are supported by Cholmod.
430   *
431   * \sa \ref TutorialSparseSolverConcept, class CholmodSupernodalLLT, class SimplicialLLT
432   */
433 template<typename _MatrixType, int _UpLo = Lower>
434 class CholmodSimplicialLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLLT<_MatrixType, _UpLo> >
435 {
436     typedef CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLLT> Base;
437     using Base::m_cholmod;
438 
439   public:
440 
441     typedef _MatrixType MatrixType;
442 
443     CholmodSimplicialLLT() : Base() { init(); }
444 
445     CholmodSimplicialLLT(const MatrixType& matrix) : Base()
446     {
447       init();
448       this->compute(matrix);
449     }
450 
451     ~CholmodSimplicialLLT() {}
452   protected:
453     void init()
454     {
455       m_cholmod.final_asis = 0;
456       m_cholmod.supernodal = CHOLMOD_SIMPLICIAL;
457       m_cholmod.final_ll = 1;
458     }
459 };
460 
461 
462 /** \ingroup CholmodSupport_Module
463   * \class CholmodSimplicialLDLT
464   * \brief A simplicial direct Cholesky (LDLT) factorization and solver based on Cholmod
465   *
466   * This class allows to solve for A.X = B sparse linear problems via a simplicial LDL^T Cholesky factorization
467   * using the Cholmod library.
468   * This simplicial variant is equivalent to Eigen's built-in SimplicialLDLT class. Therefore, it has little practical interest.
469   * The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices
470   * X and B can be either dense or sparse.
471   *
472   * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
473   * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower
474   *               or Upper. Default is Lower.
475   *
476   * \implsparsesolverconcept
477   *
478   * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed.
479   *
480   * \warning Only double precision real and complex scalar types are supported by Cholmod.
481   *
482   * \sa \ref TutorialSparseSolverConcept, class CholmodSupernodalLLT, class SimplicialLDLT
483   */
484 template<typename _MatrixType, int _UpLo = Lower>
485 class CholmodSimplicialLDLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLDLT<_MatrixType, _UpLo> >
486 {
487     typedef CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLDLT> Base;
488     using Base::m_cholmod;
489 
490   public:
491 
492     typedef _MatrixType MatrixType;
493 
494     CholmodSimplicialLDLT() : Base() { init(); }
495 
496     CholmodSimplicialLDLT(const MatrixType& matrix) : Base()
497     {
498       init();
499       this->compute(matrix);
500     }
501 
502     ~CholmodSimplicialLDLT() {}
503   protected:
504     void init()
505     {
506       m_cholmod.final_asis = 1;
507       m_cholmod.supernodal = CHOLMOD_SIMPLICIAL;
508     }
509 };
510 
511 /** \ingroup CholmodSupport_Module
512   * \class CholmodSupernodalLLT
513   * \brief A supernodal Cholesky (LLT) factorization and solver based on Cholmod
514   *
515   * This class allows to solve for A.X = B sparse linear problems via a supernodal LL^T Cholesky factorization
516   * using the Cholmod library.
517   * This supernodal variant performs best on dense enough problems, e.g., 3D FEM, or very high order 2D FEM.
518   * The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices
519   * X and B can be either dense or sparse.
520   *
521   * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
522   * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower
523   *               or Upper. Default is Lower.
524   *
525   * \implsparsesolverconcept
526   *
527   * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed.
528   *
529   * \warning Only double precision real and complex scalar types are supported by Cholmod.
530   *
531   * \sa \ref TutorialSparseSolverConcept
532   */
533 template<typename _MatrixType, int _UpLo = Lower>
534 class CholmodSupernodalLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSupernodalLLT<_MatrixType, _UpLo> >
535 {
536     typedef CholmodBase<_MatrixType, _UpLo, CholmodSupernodalLLT> Base;
537     using Base::m_cholmod;
538 
539   public:
540 
541     typedef _MatrixType MatrixType;
542 
543     CholmodSupernodalLLT() : Base() { init(); }
544 
545     CholmodSupernodalLLT(const MatrixType& matrix) : Base()
546     {
547       init();
548       this->compute(matrix);
549     }
550 
551     ~CholmodSupernodalLLT() {}
552   protected:
553     void init()
554     {
555       m_cholmod.final_asis = 1;
556       m_cholmod.supernodal = CHOLMOD_SUPERNODAL;
557     }
558 };
559 
560 /** \ingroup CholmodSupport_Module
561   * \class CholmodDecomposition
562   * \brief A general Cholesky factorization and solver based on Cholmod
563   *
564   * This class allows to solve for A.X = B sparse linear problems via a LL^T or LDL^T Cholesky factorization
565   * using the Cholmod library. The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices
566   * X and B can be either dense or sparse.
567   *
568   * This variant permits to change the underlying Cholesky method at runtime.
569   * On the other hand, it does not provide access to the result of the factorization.
570   * The default is to let Cholmod automatically choose between a simplicial and supernodal factorization.
571   *
572   * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
573   * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower
574   *               or Upper. Default is Lower.
575   *
576   * \implsparsesolverconcept
577   *
578   * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed.
579   *
580   * \warning Only double precision real and complex scalar types are supported by Cholmod.
581   *
582   * \sa \ref TutorialSparseSolverConcept
583   */
584 template<typename _MatrixType, int _UpLo = Lower>
585 class CholmodDecomposition : public CholmodBase<_MatrixType, _UpLo, CholmodDecomposition<_MatrixType, _UpLo> >
586 {
587     typedef CholmodBase<_MatrixType, _UpLo, CholmodDecomposition> Base;
588     using Base::m_cholmod;
589 
590   public:
591 
592     typedef _MatrixType MatrixType;
593 
594     CholmodDecomposition() : Base() { init(); }
595 
596     CholmodDecomposition(const MatrixType& matrix) : Base()
597     {
598       init();
599       this->compute(matrix);
600     }
601 
602     ~CholmodDecomposition() {}
603 
604     void setMode(CholmodMode mode)
605     {
606       switch(mode)
607       {
608         case CholmodAuto:
609           m_cholmod.final_asis = 1;
610           m_cholmod.supernodal = CHOLMOD_AUTO;
611           break;
612         case CholmodSimplicialLLt:
613           m_cholmod.final_asis = 0;
614           m_cholmod.supernodal = CHOLMOD_SIMPLICIAL;
615           m_cholmod.final_ll = 1;
616           break;
617         case CholmodSupernodalLLt:
618           m_cholmod.final_asis = 1;
619           m_cholmod.supernodal = CHOLMOD_SUPERNODAL;
620           break;
621         case CholmodLDLt:
622           m_cholmod.final_asis = 1;
623           m_cholmod.supernodal = CHOLMOD_SIMPLICIAL;
624           break;
625         default:
626           break;
627       }
628     }
629   protected:
630     void init()
631     {
632       m_cholmod.final_asis = 1;
633       m_cholmod.supernodal = CHOLMOD_AUTO;
634     }
635 };
636 
637 } // end namespace Eigen
638 
639 #endif // EIGEN_CHOLMODSUPPORT_H
640