xref: /aosp_15_r20/external/eigen/Eigen/src/CholmodSupport/CholmodSupport.h (revision bf2c37156dfe67e5dfebd6d394bad8b2ab5804d4)
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2008-2010 Gael Guennebaud <[email protected]>
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 supported 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,SuiteSparse_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   // swap stype for rowmajor matrices (only works for real matrices)
128   EIGEN_STATIC_ASSERT((_Options & RowMajorBit) == 0 || NumTraits<_Scalar>::IsComplex == 0, THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES);
129   if(_Options & RowMajorBit) res.stype *=-1;
130 
131   return res;
132 }
133 
134 /** Returns a view of the Eigen \b dense matrix \a mat as Cholmod dense matrix.
135   * The data are not copied but shared. */
136 template<typename Derived>
137 cholmod_dense viewAsCholmod(MatrixBase<Derived>& mat)
138 {
139   EIGEN_STATIC_ASSERT((internal::traits<Derived>::Flags&RowMajorBit)==0,THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES);
140   typedef typename Derived::Scalar Scalar;
141 
142   cholmod_dense res;
143   res.nrow   = mat.rows();
144   res.ncol   = mat.cols();
145   res.nzmax  = res.nrow * res.ncol;
146   res.d      = Derived::IsVectorAtCompileTime ? mat.derived().size() : mat.derived().outerStride();
147   res.x      = (void*)(mat.derived().data());
148   res.z      = 0;
149 
150   internal::cholmod_configure_matrix<Scalar>::run(res);
151 
152   return res;
153 }
154 
155 /** Returns a view of the Cholmod sparse matrix \a cm as an Eigen sparse matrix.
156   * The data are not copied but shared. */
157 template<typename Scalar, int Flags, typename StorageIndex>
158 MappedSparseMatrix<Scalar,Flags,StorageIndex> viewAsEigen(cholmod_sparse& cm)
159 {
160   return MappedSparseMatrix<Scalar,Flags,StorageIndex>
161          (cm.nrow, cm.ncol, static_cast<StorageIndex*>(cm.p)[cm.ncol],
162           static_cast<StorageIndex*>(cm.p), static_cast<StorageIndex*>(cm.i),static_cast<Scalar*>(cm.x) );
163 }
164 
165 namespace internal {
166 
167 // template specializations for int and long that call the correct cholmod method
168 
169 #define EIGEN_CHOLMOD_SPECIALIZE0(ret, name) \
170     template<typename _StorageIndex> inline ret cm_ ## name       (cholmod_common &Common) { return cholmod_ ## name   (&Common); } \
171     template<>                       inline ret cm_ ## name<SuiteSparse_long> (cholmod_common &Common) { return cholmod_l_ ## name (&Common); }
172 
173 #define EIGEN_CHOLMOD_SPECIALIZE1(ret, name, t1, a1) \
174     template<typename _StorageIndex> inline ret cm_ ## name       (t1& a1, cholmod_common &Common) { return cholmod_ ## name   (&a1, &Common); } \
175     template<>                       inline ret cm_ ## name<SuiteSparse_long> (t1& a1, cholmod_common &Common) { return cholmod_l_ ## name (&a1, &Common); }
176 
177 EIGEN_CHOLMOD_SPECIALIZE0(int, start)
178 EIGEN_CHOLMOD_SPECIALIZE0(int, finish)
179 
180 EIGEN_CHOLMOD_SPECIALIZE1(int, free_factor, cholmod_factor*, L)
181 EIGEN_CHOLMOD_SPECIALIZE1(int, free_dense,  cholmod_dense*,  X)
182 EIGEN_CHOLMOD_SPECIALIZE1(int, free_sparse, cholmod_sparse*, A)
183 
184 EIGEN_CHOLMOD_SPECIALIZE1(cholmod_factor*, analyze, cholmod_sparse, A)
185 
186 template<typename _StorageIndex> inline cholmod_dense*  cm_solve         (int sys, cholmod_factor& L, cholmod_dense&  B, cholmod_common &Common) { return cholmod_solve     (sys, &L, &B, &Common); }
187 template<>                       inline cholmod_dense*  cm_solve<SuiteSparse_long>   (int sys, cholmod_factor& L, cholmod_dense&  B, cholmod_common &Common) { return cholmod_l_solve   (sys, &L, &B, &Common); }
188 
189 template<typename _StorageIndex> inline cholmod_sparse* cm_spsolve       (int sys, cholmod_factor& L, cholmod_sparse& B, cholmod_common &Common) { return cholmod_spsolve   (sys, &L, &B, &Common); }
190 template<>                       inline cholmod_sparse* cm_spsolve<SuiteSparse_long> (int sys, cholmod_factor& L, cholmod_sparse& B, cholmod_common &Common) { return cholmod_l_spsolve (sys, &L, &B, &Common); }
191 
192 template<typename _StorageIndex>
193 inline int  cm_factorize_p       (cholmod_sparse*  A, double beta[2], _StorageIndex* fset, std::size_t fsize, cholmod_factor* L, cholmod_common &Common) { return cholmod_factorize_p   (A, beta, fset, fsize, L, &Common); }
194 template<>
195 inline int  cm_factorize_p<SuiteSparse_long> (cholmod_sparse*  A, double beta[2], SuiteSparse_long* fset,          std::size_t fsize, cholmod_factor* L, cholmod_common &Common) { return cholmod_l_factorize_p (A, beta, fset, fsize, L, &Common); }
196 
197 #undef EIGEN_CHOLMOD_SPECIALIZE0
198 #undef EIGEN_CHOLMOD_SPECIALIZE1
199 
200 }  // namespace internal
201 
202 
203 enum CholmodMode {
204   CholmodAuto, CholmodSimplicialLLt, CholmodSupernodalLLt, CholmodLDLt
205 };
206 
207 
208 /** \ingroup CholmodSupport_Module
209   * \class CholmodBase
210   * \brief The base class for the direct Cholesky factorization of Cholmod
211   * \sa class CholmodSupernodalLLT, class CholmodSimplicialLDLT, class CholmodSimplicialLLT
212   */
213 template<typename _MatrixType, int _UpLo, typename Derived>
214 class CholmodBase : public SparseSolverBase<Derived>
215 {
216   protected:
217     typedef SparseSolverBase<Derived> Base;
218     using Base::derived;
219     using Base::m_isInitialized;
220   public:
221     typedef _MatrixType MatrixType;
222     enum { UpLo = _UpLo };
223     typedef typename MatrixType::Scalar Scalar;
224     typedef typename MatrixType::RealScalar RealScalar;
225     typedef MatrixType CholMatrixType;
226     typedef typename MatrixType::StorageIndex StorageIndex;
227     enum {
228       ColsAtCompileTime = MatrixType::ColsAtCompileTime,
229       MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
230     };
231 
232   public:
233 
234     CholmodBase()
235       : m_cholmodFactor(0), m_info(Success), m_factorizationIsOk(false), m_analysisIsOk(false)
236     {
237       EIGEN_STATIC_ASSERT((internal::is_same<double,RealScalar>::value), CHOLMOD_SUPPORTS_DOUBLE_PRECISION_ONLY);
238       m_shiftOffset[0] = m_shiftOffset[1] = 0.0;
239       internal::cm_start<StorageIndex>(m_cholmod);
240     }
241 
242     explicit CholmodBase(const MatrixType& matrix)
243       : m_cholmodFactor(0), m_info(Success), m_factorizationIsOk(false), m_analysisIsOk(false)
244     {
245       EIGEN_STATIC_ASSERT((internal::is_same<double,RealScalar>::value), CHOLMOD_SUPPORTS_DOUBLE_PRECISION_ONLY);
246       m_shiftOffset[0] = m_shiftOffset[1] = 0.0;
247       internal::cm_start<StorageIndex>(m_cholmod);
248       compute(matrix);
249     }
250 
251     ~CholmodBase()
252     {
253       if(m_cholmodFactor)
254         internal::cm_free_factor<StorageIndex>(m_cholmodFactor, m_cholmod);
255       internal::cm_finish<StorageIndex>(m_cholmod);
256     }
257 
258     inline StorageIndex cols() const { return internal::convert_index<StorageIndex, Index>(m_cholmodFactor->n); }
259     inline StorageIndex rows() const { return internal::convert_index<StorageIndex, Index>(m_cholmodFactor->n); }
260 
261     /** \brief Reports whether previous computation was successful.
262       *
263       * \returns \c Success if computation was successful,
264       *          \c NumericalIssue if the matrix.appears to be negative.
265       */
266     ComputationInfo info() const
267     {
268       eigen_assert(m_isInitialized && "Decomposition is not initialized.");
269       return m_info;
270     }
271 
272     /** Computes the sparse Cholesky decomposition of \a matrix */
273     Derived& compute(const MatrixType& matrix)
274     {
275       analyzePattern(matrix);
276       factorize(matrix);
277       return derived();
278     }
279 
280     /** Performs a symbolic decomposition on the sparsity pattern of \a matrix.
281       *
282       * This function is particularly useful when solving for several problems having the same structure.
283       *
284       * \sa factorize()
285       */
286     void analyzePattern(const MatrixType& matrix)
287     {
288       if(m_cholmodFactor)
289       {
290         internal::cm_free_factor<StorageIndex>(m_cholmodFactor, m_cholmod);
291         m_cholmodFactor = 0;
292       }
293       cholmod_sparse A = viewAsCholmod(matrix.template selfadjointView<UpLo>());
294       m_cholmodFactor = internal::cm_analyze<StorageIndex>(A, m_cholmod);
295 
296       this->m_isInitialized = true;
297       this->m_info = Success;
298       m_analysisIsOk = true;
299       m_factorizationIsOk = false;
300     }
301 
302     /** Performs a numeric decomposition of \a matrix
303       *
304       * The given matrix must have the same sparsity pattern as the matrix on which the symbolic decomposition has been performed.
305       *
306       * \sa analyzePattern()
307       */
308     void factorize(const MatrixType& matrix)
309     {
310       eigen_assert(m_analysisIsOk && "You must first call analyzePattern()");
311       cholmod_sparse A = viewAsCholmod(matrix.template selfadjointView<UpLo>());
312       internal::cm_factorize_p<StorageIndex>(&A, m_shiftOffset, 0, 0, m_cholmodFactor, m_cholmod);
313 
314       // If the factorization failed, minor is the column at which it did. On success minor == n.
315       this->m_info = (m_cholmodFactor->minor == m_cholmodFactor->n ? Success : NumericalIssue);
316       m_factorizationIsOk = true;
317     }
318 
319     /** Returns a reference to the Cholmod's configuration structure to get a full control over the performed operations.
320      *  See the Cholmod user guide for details. */
321     cholmod_common& cholmod() { return m_cholmod; }
322 
323     #ifndef EIGEN_PARSED_BY_DOXYGEN
324     /** \internal */
325     template<typename Rhs,typename Dest>
326     void _solve_impl(const MatrixBase<Rhs> &b, MatrixBase<Dest> &dest) const
327     {
328       eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()");
329       const Index size = m_cholmodFactor->n;
330       EIGEN_UNUSED_VARIABLE(size);
331       eigen_assert(size==b.rows());
332 
333       // Cholmod needs column-major storage without inner-stride, which corresponds to the default behavior of Ref.
334       Ref<const Matrix<typename Rhs::Scalar,Dynamic,Dynamic,ColMajor> > b_ref(b.derived());
335 
336       cholmod_dense b_cd = viewAsCholmod(b_ref);
337       cholmod_dense* x_cd = internal::cm_solve<StorageIndex>(CHOLMOD_A, *m_cholmodFactor, b_cd, m_cholmod);
338       if(!x_cd)
339       {
340         this->m_info = NumericalIssue;
341         return;
342       }
343       // TODO optimize this copy by swapping when possible (be careful with alignment, etc.)
344       // NOTE Actually, the copy can be avoided by calling cholmod_solve2 instead of cholmod_solve
345       dest = Matrix<Scalar,Dest::RowsAtCompileTime,Dest::ColsAtCompileTime>::Map(reinterpret_cast<Scalar*>(x_cd->x),b.rows(),b.cols());
346       internal::cm_free_dense<StorageIndex>(x_cd, m_cholmod);
347     }
348 
349     /** \internal */
350     template<typename RhsDerived, typename DestDerived>
351     void _solve_impl(const SparseMatrixBase<RhsDerived> &b, SparseMatrixBase<DestDerived> &dest) const
352     {
353       eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()");
354       const Index size = m_cholmodFactor->n;
355       EIGEN_UNUSED_VARIABLE(size);
356       eigen_assert(size==b.rows());
357 
358       // note: cs stands for Cholmod Sparse
359       Ref<SparseMatrix<typename RhsDerived::Scalar,ColMajor,typename RhsDerived::StorageIndex> > b_ref(b.const_cast_derived());
360       cholmod_sparse b_cs = viewAsCholmod(b_ref);
361       cholmod_sparse* x_cs = internal::cm_spsolve<StorageIndex>(CHOLMOD_A, *m_cholmodFactor, b_cs, m_cholmod);
362       if(!x_cs)
363       {
364         this->m_info = NumericalIssue;
365         return;
366       }
367       // TODO optimize this copy by swapping when possible (be careful with alignment, etc.)
368       // NOTE cholmod_spsolve in fact just calls the dense solver for blocks of 4 columns at a time (similar to Eigen's sparse solver)
369       dest.derived() = viewAsEigen<typename DestDerived::Scalar,ColMajor,typename DestDerived::StorageIndex>(*x_cs);
370       internal::cm_free_sparse<StorageIndex>(x_cs, m_cholmod);
371     }
372     #endif // EIGEN_PARSED_BY_DOXYGEN
373 
374 
375     /** Sets the shift parameter that will be used to adjust the diagonal coefficients during the numerical factorization.
376       *
377       * During the numerical factorization, an offset term is added to the diagonal coefficients:\n
378       * \c d_ii = \a offset + \c d_ii
379       *
380       * The default is \a offset=0.
381       *
382       * \returns a reference to \c *this.
383       */
384     Derived& setShift(const RealScalar& offset)
385     {
386       m_shiftOffset[0] = double(offset);
387       return derived();
388     }
389 
390     /** \returns the determinant of the underlying matrix from the current factorization */
391     Scalar determinant() const
392     {
393       using std::exp;
394       return exp(logDeterminant());
395     }
396 
397     /** \returns the log determinant of the underlying matrix from the current factorization */
398     Scalar logDeterminant() const
399     {
400       using std::log;
401       using numext::real;
402       eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()");
403 
404       RealScalar logDet = 0;
405       Scalar *x = static_cast<Scalar*>(m_cholmodFactor->x);
406       if (m_cholmodFactor->is_super)
407       {
408         // Supernodal factorization stored as a packed list of dense column-major blocs,
409         // as described by the following structure:
410 
411         // super[k] == index of the first column of the j-th super node
412         StorageIndex *super = static_cast<StorageIndex*>(m_cholmodFactor->super);
413         // pi[k] == offset to the description of row indices
414         StorageIndex *pi = static_cast<StorageIndex*>(m_cholmodFactor->pi);
415         // px[k] == offset to the respective dense block
416         StorageIndex *px = static_cast<StorageIndex*>(m_cholmodFactor->px);
417 
418         Index nb_super_nodes = m_cholmodFactor->nsuper;
419         for (Index k=0; k < nb_super_nodes; ++k)
420         {
421           StorageIndex ncols = super[k + 1] - super[k];
422           StorageIndex nrows = pi[k + 1] - pi[k];
423 
424           Map<const Array<Scalar,1,Dynamic>, 0, InnerStride<> > sk(x + px[k], ncols, InnerStride<>(nrows+1));
425           logDet += sk.real().log().sum();
426         }
427       }
428       else
429       {
430         // Simplicial factorization stored as standard CSC matrix.
431         StorageIndex *p = static_cast<StorageIndex*>(m_cholmodFactor->p);
432         Index size = m_cholmodFactor->n;
433         for (Index k=0; k<size; ++k)
434           logDet += log(real( x[p[k]] ));
435       }
436       if (m_cholmodFactor->is_ll)
437         logDet *= 2.0;
438       return logDet;
439     };
440 
441     template<typename Stream>
442     void dumpMemory(Stream& /*s*/)
443     {}
444 
445   protected:
446     mutable cholmod_common m_cholmod;
447     cholmod_factor* m_cholmodFactor;
448     double m_shiftOffset[2];
449     mutable ComputationInfo m_info;
450     int m_factorizationIsOk;
451     int m_analysisIsOk;
452 };
453 
454 /** \ingroup CholmodSupport_Module
455   * \class CholmodSimplicialLLT
456   * \brief A simplicial direct Cholesky (LLT) factorization and solver based on Cholmod
457   *
458   * This class allows to solve for A.X = B sparse linear problems via a simplicial LL^T Cholesky factorization
459   * using the Cholmod library.
460   * This simplicial variant is equivalent to Eigen's built-in SimplicialLLT class. Therefore, it has little practical interest.
461   * The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices
462   * X and B can be either dense or sparse.
463   *
464   * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
465   * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower
466   *               or Upper. Default is Lower.
467   *
468   * \implsparsesolverconcept
469   *
470   * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed.
471   *
472   * \warning Only double precision real and complex scalar types are supported by Cholmod.
473   *
474   * \sa \ref TutorialSparseSolverConcept, class CholmodSupernodalLLT, class SimplicialLLT
475   */
476 template<typename _MatrixType, int _UpLo = Lower>
477 class CholmodSimplicialLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLLT<_MatrixType, _UpLo> >
478 {
479     typedef CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLLT> Base;
480     using Base::m_cholmod;
481 
482   public:
483 
484     typedef _MatrixType MatrixType;
485 
486     CholmodSimplicialLLT() : Base() { init(); }
487 
488     CholmodSimplicialLLT(const MatrixType& matrix) : Base()
489     {
490       init();
491       this->compute(matrix);
492     }
493 
494     ~CholmodSimplicialLLT() {}
495   protected:
496     void init()
497     {
498       m_cholmod.final_asis = 0;
499       m_cholmod.supernodal = CHOLMOD_SIMPLICIAL;
500       m_cholmod.final_ll = 1;
501     }
502 };
503 
504 
505 /** \ingroup CholmodSupport_Module
506   * \class CholmodSimplicialLDLT
507   * \brief A simplicial direct Cholesky (LDLT) factorization and solver based on Cholmod
508   *
509   * This class allows to solve for A.X = B sparse linear problems via a simplicial LDL^T Cholesky factorization
510   * using the Cholmod library.
511   * This simplicial variant is equivalent to Eigen's built-in SimplicialLDLT class. Therefore, it has little practical interest.
512   * The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices
513   * X and B can be either dense or sparse.
514   *
515   * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
516   * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower
517   *               or Upper. Default is Lower.
518   *
519   * \implsparsesolverconcept
520   *
521   * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed.
522   *
523   * \warning Only double precision real and complex scalar types are supported by Cholmod.
524   *
525   * \sa \ref TutorialSparseSolverConcept, class CholmodSupernodalLLT, class SimplicialLDLT
526   */
527 template<typename _MatrixType, int _UpLo = Lower>
528 class CholmodSimplicialLDLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLDLT<_MatrixType, _UpLo> >
529 {
530     typedef CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLDLT> Base;
531     using Base::m_cholmod;
532 
533   public:
534 
535     typedef _MatrixType MatrixType;
536 
537     CholmodSimplicialLDLT() : Base() { init(); }
538 
539     CholmodSimplicialLDLT(const MatrixType& matrix) : Base()
540     {
541       init();
542       this->compute(matrix);
543     }
544 
545     ~CholmodSimplicialLDLT() {}
546   protected:
547     void init()
548     {
549       m_cholmod.final_asis = 1;
550       m_cholmod.supernodal = CHOLMOD_SIMPLICIAL;
551     }
552 };
553 
554 /** \ingroup CholmodSupport_Module
555   * \class CholmodSupernodalLLT
556   * \brief A supernodal Cholesky (LLT) factorization and solver based on Cholmod
557   *
558   * This class allows to solve for A.X = B sparse linear problems via a supernodal LL^T Cholesky factorization
559   * using the Cholmod library.
560   * This supernodal variant performs best on dense enough problems, e.g., 3D FEM, or very high order 2D FEM.
561   * The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices
562   * X and B can be either dense or sparse.
563   *
564   * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
565   * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower
566   *               or Upper. Default is Lower.
567   *
568   * \implsparsesolverconcept
569   *
570   * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed.
571   *
572   * \warning Only double precision real and complex scalar types are supported by Cholmod.
573   *
574   * \sa \ref TutorialSparseSolverConcept
575   */
576 template<typename _MatrixType, int _UpLo = Lower>
577 class CholmodSupernodalLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSupernodalLLT<_MatrixType, _UpLo> >
578 {
579     typedef CholmodBase<_MatrixType, _UpLo, CholmodSupernodalLLT> Base;
580     using Base::m_cholmod;
581 
582   public:
583 
584     typedef _MatrixType MatrixType;
585 
586     CholmodSupernodalLLT() : Base() { init(); }
587 
588     CholmodSupernodalLLT(const MatrixType& matrix) : Base()
589     {
590       init();
591       this->compute(matrix);
592     }
593 
594     ~CholmodSupernodalLLT() {}
595   protected:
596     void init()
597     {
598       m_cholmod.final_asis = 1;
599       m_cholmod.supernodal = CHOLMOD_SUPERNODAL;
600     }
601 };
602 
603 /** \ingroup CholmodSupport_Module
604   * \class CholmodDecomposition
605   * \brief A general Cholesky factorization and solver based on Cholmod
606   *
607   * This class allows to solve for A.X = B sparse linear problems via a LL^T or LDL^T Cholesky factorization
608   * using the Cholmod library. The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices
609   * X and B can be either dense or sparse.
610   *
611   * This variant permits to change the underlying Cholesky method at runtime.
612   * On the other hand, it does not provide access to the result of the factorization.
613   * The default is to let Cholmod automatically choose between a simplicial and supernodal factorization.
614   *
615   * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
616   * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower
617   *               or Upper. Default is Lower.
618   *
619   * \implsparsesolverconcept
620   *
621   * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed.
622   *
623   * \warning Only double precision real and complex scalar types are supported by Cholmod.
624   *
625   * \sa \ref TutorialSparseSolverConcept
626   */
627 template<typename _MatrixType, int _UpLo = Lower>
628 class CholmodDecomposition : public CholmodBase<_MatrixType, _UpLo, CholmodDecomposition<_MatrixType, _UpLo> >
629 {
630     typedef CholmodBase<_MatrixType, _UpLo, CholmodDecomposition> Base;
631     using Base::m_cholmod;
632 
633   public:
634 
635     typedef _MatrixType MatrixType;
636 
637     CholmodDecomposition() : Base() { init(); }
638 
639     CholmodDecomposition(const MatrixType& matrix) : Base()
640     {
641       init();
642       this->compute(matrix);
643     }
644 
645     ~CholmodDecomposition() {}
646 
647     void setMode(CholmodMode mode)
648     {
649       switch(mode)
650       {
651         case CholmodAuto:
652           m_cholmod.final_asis = 1;
653           m_cholmod.supernodal = CHOLMOD_AUTO;
654           break;
655         case CholmodSimplicialLLt:
656           m_cholmod.final_asis = 0;
657           m_cholmod.supernodal = CHOLMOD_SIMPLICIAL;
658           m_cholmod.final_ll = 1;
659           break;
660         case CholmodSupernodalLLt:
661           m_cholmod.final_asis = 1;
662           m_cholmod.supernodal = CHOLMOD_SUPERNODAL;
663           break;
664         case CholmodLDLt:
665           m_cholmod.final_asis = 1;
666           m_cholmod.supernodal = CHOLMOD_SIMPLICIAL;
667           break;
668         default:
669           break;
670       }
671     }
672   protected:
673     void init()
674     {
675       m_cholmod.final_asis = 1;
676       m_cholmod.supernodal = CHOLMOD_AUTO;
677     }
678 };
679 
680 } // end namespace Eigen
681 
682 #endif // EIGEN_CHOLMODSUPPORT_H
683