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