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