• 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) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@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_PASTIXSUPPORT_H
11 #define EIGEN_PASTIXSUPPORT_H
12 
13 namespace Eigen {
14 
15 /** \ingroup PaStiXSupport_Module
16   * \brief Interface to the PaStix solver
17   *
18   * This class is used to solve the linear systems A.X = B via the PaStix library.
19   * The matrix can be either real or complex, symmetric or not.
20   *
21   * \sa TutorialSparseDirectSolvers
22   */
23 template<typename _MatrixType, bool IsStrSym = false> class PastixLU;
24 template<typename _MatrixType, int Options> class PastixLLT;
25 template<typename _MatrixType, int Options> class PastixLDLT;
26 
27 namespace internal
28 {
29 
30   template<class Pastix> struct pastix_traits;
31 
32   template<typename _MatrixType>
33   struct pastix_traits< PastixLU<_MatrixType> >
34   {
35     typedef _MatrixType MatrixType;
36     typedef typename _MatrixType::Scalar Scalar;
37     typedef typename _MatrixType::RealScalar RealScalar;
38     typedef typename _MatrixType::Index Index;
39   };
40 
41   template<typename _MatrixType, int Options>
42   struct pastix_traits< PastixLLT<_MatrixType,Options> >
43   {
44     typedef _MatrixType MatrixType;
45     typedef typename _MatrixType::Scalar Scalar;
46     typedef typename _MatrixType::RealScalar RealScalar;
47     typedef typename _MatrixType::Index Index;
48   };
49 
50   template<typename _MatrixType, int Options>
51   struct pastix_traits< PastixLDLT<_MatrixType,Options> >
52   {
53     typedef _MatrixType MatrixType;
54     typedef typename _MatrixType::Scalar Scalar;
55     typedef typename _MatrixType::RealScalar RealScalar;
56     typedef typename _MatrixType::Index Index;
57   };
58 
59   void eigen_pastix(pastix_data_t **pastix_data, int pastix_comm, int n, int *ptr, int *idx, float *vals, int *perm, int * invp, float *x, int nbrhs, int *iparm, double *dparm)
60   {
61     if (n == 0) { ptr = NULL; idx = NULL; vals = NULL; }
62     if (nbrhs == 0) {x = NULL; nbrhs=1;}
63     s_pastix(pastix_data, pastix_comm, n, ptr, idx, vals, perm, invp, x, nbrhs, iparm, dparm);
64   }
65 
66   void eigen_pastix(pastix_data_t **pastix_data, int pastix_comm, int n, int *ptr, int *idx, double *vals, int *perm, int * invp, double *x, int nbrhs, int *iparm, double *dparm)
67   {
68     if (n == 0) { ptr = NULL; idx = NULL; vals = NULL; }
69     if (nbrhs == 0) {x = NULL; nbrhs=1;}
70     d_pastix(pastix_data, pastix_comm, n, ptr, idx, vals, perm, invp, x, nbrhs, iparm, dparm);
71   }
72 
73   void eigen_pastix(pastix_data_t **pastix_data, int pastix_comm, int n, int *ptr, int *idx, std::complex<float> *vals, int *perm, int * invp, std::complex<float> *x, int nbrhs, int *iparm, double *dparm)
74   {
75     if (n == 0) { ptr = NULL; idx = NULL; vals = NULL; }
76     if (nbrhs == 0) {x = NULL; nbrhs=1;}
77     c_pastix(pastix_data, pastix_comm, n, ptr, idx, reinterpret_cast<COMPLEX*>(vals), perm, invp, reinterpret_cast<COMPLEX*>(x), nbrhs, iparm, dparm);
78   }
79 
80   void eigen_pastix(pastix_data_t **pastix_data, int pastix_comm, int n, int *ptr, int *idx, std::complex<double> *vals, int *perm, int * invp, std::complex<double> *x, int nbrhs, int *iparm, double *dparm)
81   {
82     if (n == 0) { ptr = NULL; idx = NULL; vals = NULL; }
83     if (nbrhs == 0) {x = NULL; nbrhs=1;}
84     z_pastix(pastix_data, pastix_comm, n, ptr, idx, reinterpret_cast<DCOMPLEX*>(vals), perm, invp, reinterpret_cast<DCOMPLEX*>(x), nbrhs, iparm, dparm);
85   }
86 
87   // Convert the matrix  to Fortran-style Numbering
88   template <typename MatrixType>
89   void c_to_fortran_numbering (MatrixType& mat)
90   {
91     if ( !(mat.outerIndexPtr()[0]) )
92     {
93       int i;
94       for(i = 0; i <= mat.rows(); ++i)
95         ++mat.outerIndexPtr()[i];
96       for(i = 0; i < mat.nonZeros(); ++i)
97         ++mat.innerIndexPtr()[i];
98     }
99   }
100 
101   // Convert to C-style Numbering
102   template <typename MatrixType>
103   void fortran_to_c_numbering (MatrixType& mat)
104   {
105     // Check the Numbering
106     if ( mat.outerIndexPtr()[0] == 1 )
107     { // Convert to C-style numbering
108       int i;
109       for(i = 0; i <= mat.rows(); ++i)
110         --mat.outerIndexPtr()[i];
111       for(i = 0; i < mat.nonZeros(); ++i)
112         --mat.innerIndexPtr()[i];
113     }
114   }
115 }
116 
117 // This is the base class to interface with PaStiX functions.
118 // Users should not used this class directly.
119 template <class Derived>
120 class PastixBase : internal::noncopyable
121 {
122   public:
123     typedef typename internal::pastix_traits<Derived>::MatrixType _MatrixType;
124     typedef _MatrixType MatrixType;
125     typedef typename MatrixType::Scalar Scalar;
126     typedef typename MatrixType::RealScalar RealScalar;
127     typedef typename MatrixType::Index Index;
128     typedef Matrix<Scalar,Dynamic,1> Vector;
129     typedef SparseMatrix<Scalar, ColMajor> ColSpMatrix;
130 
131   public:
132 
133     PastixBase() : m_initisOk(false), m_analysisIsOk(false), m_factorizationIsOk(false), m_isInitialized(false), m_pastixdata(0), m_size(0)
134     {
135       init();
136     }
137 
138     ~PastixBase()
139     {
140       clean();
141     }
142 
143     /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A.
144       *
145       * \sa compute()
146       */
147     template<typename Rhs>
148     inline const internal::solve_retval<PastixBase, Rhs>
149     solve(const MatrixBase<Rhs>& b) const
150     {
151       eigen_assert(m_isInitialized && "Pastix solver is not initialized.");
152       eigen_assert(rows()==b.rows()
153                 && "PastixBase::solve(): invalid number of rows of the right hand side matrix b");
154       return internal::solve_retval<PastixBase, Rhs>(*this, b.derived());
155     }
156 
157     template<typename Rhs,typename Dest>
158     bool _solve (const MatrixBase<Rhs> &b, MatrixBase<Dest> &x) const;
159 
160     /** \internal */
161     template<typename Rhs, typename DestScalar, int DestOptions, typename DestIndex>
162     void _solve_sparse(const Rhs& b, SparseMatrix<DestScalar,DestOptions,DestIndex> &dest) const
163     {
164       eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()");
165       eigen_assert(rows()==b.rows());
166 
167       // we process the sparse rhs per block of NbColsAtOnce columns temporarily stored into a dense matrix.
168       static const int NbColsAtOnce = 1;
169       int rhsCols = b.cols();
170       int size = b.rows();
171       Eigen::Matrix<DestScalar,Dynamic,Dynamic> tmp(size,rhsCols);
172       for(int k=0; k<rhsCols; k+=NbColsAtOnce)
173       {
174         int actualCols = std::min<int>(rhsCols-k, NbColsAtOnce);
175         tmp.leftCols(actualCols) = b.middleCols(k,actualCols);
176         tmp.leftCols(actualCols) = derived().solve(tmp.leftCols(actualCols));
177         dest.middleCols(k,actualCols) = tmp.leftCols(actualCols).sparseView();
178       }
179     }
180 
181     Derived& derived()
182     {
183       return *static_cast<Derived*>(this);
184     }
185     const Derived& derived() const
186     {
187       return *static_cast<const Derived*>(this);
188     }
189 
190     /** Returns a reference to the integer vector IPARM of PaStiX parameters
191       * to modify the default parameters.
192       * The statistics related to the different phases of factorization and solve are saved here as well
193       * \sa analyzePattern() factorize()
194       */
195     Array<Index,IPARM_SIZE,1>& iparm()
196     {
197       return m_iparm;
198     }
199 
200     /** Return a reference to a particular index parameter of the IPARM vector
201      * \sa iparm()
202      */
203 
204     int& iparm(int idxparam)
205     {
206       return m_iparm(idxparam);
207     }
208 
209      /** Returns a reference to the double vector DPARM of PaStiX parameters
210       * The statistics related to the different phases of factorization and solve are saved here as well
211       * \sa analyzePattern() factorize()
212       */
213     Array<RealScalar,IPARM_SIZE,1>& dparm()
214     {
215       return m_dparm;
216     }
217 
218 
219     /** Return a reference to a particular index parameter of the DPARM vector
220      * \sa dparm()
221      */
222     double& dparm(int idxparam)
223     {
224       return m_dparm(idxparam);
225     }
226 
227     inline Index cols() const { return m_size; }
228     inline Index rows() const { return m_size; }
229 
230      /** \brief Reports whether previous computation was successful.
231       *
232       * \returns \c Success if computation was succesful,
233       *          \c NumericalIssue if the PaStiX reports a problem
234       *          \c InvalidInput if the input matrix is invalid
235       *
236       * \sa iparm()
237       */
238     ComputationInfo info() const
239     {
240       eigen_assert(m_isInitialized && "Decomposition is not initialized.");
241       return m_info;
242     }
243 
244     /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A.
245       *
246       * \sa compute()
247       */
248     template<typename Rhs>
249     inline const internal::sparse_solve_retval<PastixBase, Rhs>
250     solve(const SparseMatrixBase<Rhs>& b) const
251     {
252       eigen_assert(m_isInitialized && "Pastix LU, LLT or LDLT is not initialized.");
253       eigen_assert(rows()==b.rows()
254                 && "PastixBase::solve(): invalid number of rows of the right hand side matrix b");
255       return internal::sparse_solve_retval<PastixBase, Rhs>(*this, b.derived());
256     }
257 
258   protected:
259 
260     // Initialize the Pastix data structure, check the matrix
261     void init();
262 
263     // Compute the ordering and the symbolic factorization
264     void analyzePattern(ColSpMatrix& mat);
265 
266     // Compute the numerical factorization
267     void factorize(ColSpMatrix& mat);
268 
269     // Free all the data allocated by Pastix
270     void clean()
271     {
272       eigen_assert(m_initisOk && "The Pastix structure should be allocated first");
273       m_iparm(IPARM_START_TASK) = API_TASK_CLEAN;
274       m_iparm(IPARM_END_TASK) = API_TASK_CLEAN;
275       internal::eigen_pastix(&m_pastixdata, MPI_COMM_WORLD, 0, 0, 0, (Scalar*)0,
276                              m_perm.data(), m_invp.data(), 0, 0, m_iparm.data(), m_dparm.data());
277     }
278 
279     void compute(ColSpMatrix& mat);
280 
281     int m_initisOk;
282     int m_analysisIsOk;
283     int m_factorizationIsOk;
284     bool m_isInitialized;
285     mutable ComputationInfo m_info;
286     mutable pastix_data_t *m_pastixdata; // Data structure for pastix
287     mutable int m_comm; // The MPI communicator identifier
288     mutable Matrix<int,IPARM_SIZE,1> m_iparm; // integer vector for the input parameters
289     mutable Matrix<double,DPARM_SIZE,1> m_dparm; // Scalar vector for the input parameters
290     mutable Matrix<Index,Dynamic,1> m_perm;  // Permutation vector
291     mutable Matrix<Index,Dynamic,1> m_invp;  // Inverse permutation vector
292     mutable int m_size; // Size of the matrix
293 };
294 
295  /** Initialize the PaStiX data structure.
296    *A first call to this function fills iparm and dparm with the default PaStiX parameters
297    * \sa iparm() dparm()
298    */
299 template <class Derived>
300 void PastixBase<Derived>::init()
301 {
302   m_size = 0;
303   m_iparm.setZero(IPARM_SIZE);
304   m_dparm.setZero(DPARM_SIZE);
305 
306   m_iparm(IPARM_MODIFY_PARAMETER) = API_NO;
307   pastix(&m_pastixdata, MPI_COMM_WORLD,
308          0, 0, 0, 0,
309          0, 0, 0, 1, m_iparm.data(), m_dparm.data());
310 
311   m_iparm[IPARM_MATRIX_VERIFICATION] = API_NO;
312   m_iparm[IPARM_VERBOSE]             = 2;
313   m_iparm[IPARM_ORDERING]            = API_ORDER_SCOTCH;
314   m_iparm[IPARM_INCOMPLETE]          = API_NO;
315   m_iparm[IPARM_OOC_LIMIT]           = 2000;
316   m_iparm[IPARM_RHS_MAKING]          = API_RHS_B;
317   m_iparm(IPARM_MATRIX_VERIFICATION) = API_NO;
318 
319   m_iparm(IPARM_START_TASK) = API_TASK_INIT;
320   m_iparm(IPARM_END_TASK) = API_TASK_INIT;
321   internal::eigen_pastix(&m_pastixdata, MPI_COMM_WORLD, 0, 0, 0, (Scalar*)0,
322                          0, 0, 0, 0, m_iparm.data(), m_dparm.data());
323 
324   // Check the returned error
325   if(m_iparm(IPARM_ERROR_NUMBER)) {
326     m_info = InvalidInput;
327     m_initisOk = false;
328   }
329   else {
330     m_info = Success;
331     m_initisOk = true;
332   }
333 }
334 
335 template <class Derived>
336 void PastixBase<Derived>::compute(ColSpMatrix& mat)
337 {
338   eigen_assert(mat.rows() == mat.cols() && "The input matrix should be squared");
339 
340   analyzePattern(mat);
341   factorize(mat);
342 
343   m_iparm(IPARM_MATRIX_VERIFICATION) = API_NO;
344   m_isInitialized = m_factorizationIsOk;
345 }
346 
347 
348 template <class Derived>
349 void PastixBase<Derived>::analyzePattern(ColSpMatrix& mat)
350 {
351   eigen_assert(m_initisOk && "The initialization of PaSTiX failed");
352 
353   // clean previous calls
354   if(m_size>0)
355     clean();
356 
357   m_size = mat.rows();
358   m_perm.resize(m_size);
359   m_invp.resize(m_size);
360 
361   m_iparm(IPARM_START_TASK) = API_TASK_ORDERING;
362   m_iparm(IPARM_END_TASK) = API_TASK_ANALYSE;
363   internal::eigen_pastix(&m_pastixdata, MPI_COMM_WORLD, m_size, mat.outerIndexPtr(), mat.innerIndexPtr(),
364                mat.valuePtr(), m_perm.data(), m_invp.data(), 0, 0, m_iparm.data(), m_dparm.data());
365 
366   // Check the returned error
367   if(m_iparm(IPARM_ERROR_NUMBER))
368   {
369     m_info = NumericalIssue;
370     m_analysisIsOk = false;
371   }
372   else
373   {
374     m_info = Success;
375     m_analysisIsOk = true;
376   }
377 }
378 
379 template <class Derived>
380 void PastixBase<Derived>::factorize(ColSpMatrix& mat)
381 {
382 //   if(&m_cpyMat != &mat) m_cpyMat = mat;
383   eigen_assert(m_analysisIsOk && "The analysis phase should be called before the factorization phase");
384   m_iparm(IPARM_START_TASK) = API_TASK_NUMFACT;
385   m_iparm(IPARM_END_TASK) = API_TASK_NUMFACT;
386   m_size = mat.rows();
387 
388   internal::eigen_pastix(&m_pastixdata, MPI_COMM_WORLD, m_size, mat.outerIndexPtr(), mat.innerIndexPtr(),
389                mat.valuePtr(), m_perm.data(), m_invp.data(), 0, 0, m_iparm.data(), m_dparm.data());
390 
391   // Check the returned error
392   if(m_iparm(IPARM_ERROR_NUMBER))
393   {
394     m_info = NumericalIssue;
395     m_factorizationIsOk = false;
396     m_isInitialized = false;
397   }
398   else
399   {
400     m_info = Success;
401     m_factorizationIsOk = true;
402     m_isInitialized = true;
403   }
404 }
405 
406 /* Solve the system */
407 template<typename Base>
408 template<typename Rhs,typename Dest>
409 bool PastixBase<Base>::_solve (const MatrixBase<Rhs> &b, MatrixBase<Dest> &x) const
410 {
411   eigen_assert(m_isInitialized && "The matrix should be factorized first");
412   EIGEN_STATIC_ASSERT((Dest::Flags&RowMajorBit)==0,
413                      THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES);
414   int rhs = 1;
415 
416   x = b; /* on return, x is overwritten by the computed solution */
417 
418   for (int i = 0; i < b.cols(); i++){
419     m_iparm[IPARM_START_TASK]          = API_TASK_SOLVE;
420     m_iparm[IPARM_END_TASK]            = API_TASK_REFINE;
421 
422     internal::eigen_pastix(&m_pastixdata, MPI_COMM_WORLD, x.rows(), 0, 0, 0,
423                            m_perm.data(), m_invp.data(), &x(0, i), rhs, m_iparm.data(), m_dparm.data());
424   }
425 
426   // Check the returned error
427   m_info = m_iparm(IPARM_ERROR_NUMBER)==0 ? Success : NumericalIssue;
428 
429   return m_iparm(IPARM_ERROR_NUMBER)==0;
430 }
431 
432 /** \ingroup PaStiXSupport_Module
433   * \class PastixLU
434   * \brief Sparse direct LU solver based on PaStiX library
435   *
436   * This class is used to solve the linear systems A.X = B with a supernodal LU
437   * factorization in the PaStiX library. The matrix A should be squared and nonsingular
438   * PaStiX requires that the matrix A has a symmetric structural pattern.
439   * This interface can symmetrize the input matrix otherwise.
440   * The vectors or matrices X and B can be either dense or sparse.
441   *
442   * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
443   * \tparam IsStrSym Indicates if the input matrix has a symmetric pattern, default is false
444   * NOTE : Note that if the analysis and factorization phase are called separately,
445   * the input matrix will be symmetrized at each call, hence it is advised to
446   * symmetrize the matrix in a end-user program and set \p IsStrSym to true
447   *
448   * \sa \ref TutorialSparseDirectSolvers
449   *
450   */
451 template<typename _MatrixType, bool IsStrSym>
452 class PastixLU : public PastixBase< PastixLU<_MatrixType> >
453 {
454   public:
455     typedef _MatrixType MatrixType;
456     typedef PastixBase<PastixLU<MatrixType> > Base;
457     typedef typename Base::ColSpMatrix ColSpMatrix;
458     typedef typename MatrixType::Index Index;
459 
460   public:
461     PastixLU() : Base()
462     {
463       init();
464     }
465 
466     PastixLU(const MatrixType& matrix):Base()
467     {
468       init();
469       compute(matrix);
470     }
471     /** Compute the LU supernodal factorization of \p matrix.
472       * iparm and dparm can be used to tune the PaStiX parameters.
473       * see the PaStiX user's manual
474       * \sa analyzePattern() factorize()
475       */
476     void compute (const MatrixType& matrix)
477     {
478       m_structureIsUptodate = false;
479       ColSpMatrix temp;
480       grabMatrix(matrix, temp);
481       Base::compute(temp);
482     }
483     /** Compute the LU symbolic factorization of \p matrix using its sparsity pattern.
484       * Several ordering methods can be used at this step. See the PaStiX user's manual.
485       * The result of this operation can be used with successive matrices having the same pattern as \p matrix
486       * \sa factorize()
487       */
488     void analyzePattern(const MatrixType& matrix)
489     {
490       m_structureIsUptodate = false;
491       ColSpMatrix temp;
492       grabMatrix(matrix, temp);
493       Base::analyzePattern(temp);
494     }
495 
496     /** Compute the LU supernodal factorization of \p matrix
497       * WARNING The matrix \p matrix should have the same structural pattern
498       * as the same used in the analysis phase.
499       * \sa analyzePattern()
500       */
501     void factorize(const MatrixType& matrix)
502     {
503       ColSpMatrix temp;
504       grabMatrix(matrix, temp);
505       Base::factorize(temp);
506     }
507   protected:
508 
509     void init()
510     {
511       m_structureIsUptodate = false;
512       m_iparm(IPARM_SYM) = API_SYM_NO;
513       m_iparm(IPARM_FACTORIZATION) = API_FACT_LU;
514     }
515 
516     void grabMatrix(const MatrixType& matrix, ColSpMatrix& out)
517     {
518       if(IsStrSym)
519         out = matrix;
520       else
521       {
522         if(!m_structureIsUptodate)
523         {
524           // update the transposed structure
525           m_transposedStructure = matrix.transpose();
526 
527           // Set the elements of the matrix to zero
528           for (Index j=0; j<m_transposedStructure.outerSize(); ++j)
529             for(typename ColSpMatrix::InnerIterator it(m_transposedStructure, j); it; ++it)
530               it.valueRef() = 0.0;
531 
532           m_structureIsUptodate = true;
533         }
534 
535         out = m_transposedStructure + matrix;
536       }
537       internal::c_to_fortran_numbering(out);
538     }
539 
540     using Base::m_iparm;
541     using Base::m_dparm;
542 
543     ColSpMatrix m_transposedStructure;
544     bool m_structureIsUptodate;
545 };
546 
547 /** \ingroup PaStiXSupport_Module
548   * \class PastixLLT
549   * \brief A sparse direct supernodal Cholesky (LLT) factorization and solver based on the PaStiX library
550   *
551   * This class is used to solve the linear systems A.X = B via a LL^T supernodal Cholesky factorization
552   * available in the PaStiX library. The matrix A should be symmetric and positive definite
553   * WARNING Selfadjoint complex matrices are not supported in the current version of PaStiX
554   * The vectors or matrices X and B can be either dense or sparse
555   *
556   * \tparam MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
557   * \tparam UpLo The part of the matrix to use : Lower or Upper. The default is Lower as required by PaStiX
558   *
559   * \sa \ref TutorialSparseDirectSolvers
560   */
561 template<typename _MatrixType, int _UpLo>
562 class PastixLLT : public PastixBase< PastixLLT<_MatrixType, _UpLo> >
563 {
564   public:
565     typedef _MatrixType MatrixType;
566     typedef PastixBase<PastixLLT<MatrixType, _UpLo> > Base;
567     typedef typename Base::ColSpMatrix ColSpMatrix;
568 
569   public:
570     enum { UpLo = _UpLo };
571     PastixLLT() : Base()
572     {
573       init();
574     }
575 
576     PastixLLT(const MatrixType& matrix):Base()
577     {
578       init();
579       compute(matrix);
580     }
581 
582     /** Compute the L factor of the LL^T supernodal factorization of \p matrix
583       * \sa analyzePattern() factorize()
584       */
585     void compute (const MatrixType& matrix)
586     {
587       ColSpMatrix temp;
588       grabMatrix(matrix, temp);
589       Base::compute(temp);
590     }
591 
592      /** Compute the LL^T symbolic factorization of \p matrix using its sparsity pattern
593       * The result of this operation can be used with successive matrices having the same pattern as \p matrix
594       * \sa factorize()
595       */
596     void analyzePattern(const MatrixType& matrix)
597     {
598       ColSpMatrix temp;
599       grabMatrix(matrix, temp);
600       Base::analyzePattern(temp);
601     }
602       /** Compute the LL^T supernodal numerical factorization of \p matrix
603         * \sa analyzePattern()
604         */
605     void factorize(const MatrixType& matrix)
606     {
607       ColSpMatrix temp;
608       grabMatrix(matrix, temp);
609       Base::factorize(temp);
610     }
611   protected:
612     using Base::m_iparm;
613 
614     void init()
615     {
616       m_iparm(IPARM_SYM) = API_SYM_YES;
617       m_iparm(IPARM_FACTORIZATION) = API_FACT_LLT;
618     }
619 
620     void grabMatrix(const MatrixType& matrix, ColSpMatrix& out)
621     {
622       // Pastix supports only lower, column-major matrices
623       out.template selfadjointView<Lower>() = matrix.template selfadjointView<UpLo>();
624       internal::c_to_fortran_numbering(out);
625     }
626 };
627 
628 /** \ingroup PaStiXSupport_Module
629   * \class PastixLDLT
630   * \brief A sparse direct supernodal Cholesky (LLT) factorization and solver based on the PaStiX library
631   *
632   * This class is used to solve the linear systems A.X = B via a LDL^T supernodal Cholesky factorization
633   * available in the PaStiX library. The matrix A should be symmetric and positive definite
634   * WARNING Selfadjoint complex matrices are not supported in the current version of PaStiX
635   * The vectors or matrices X and B can be either dense or sparse
636   *
637   * \tparam MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
638   * \tparam UpLo The part of the matrix to use : Lower or Upper. The default is Lower as required by PaStiX
639   *
640   * \sa \ref TutorialSparseDirectSolvers
641   */
642 template<typename _MatrixType, int _UpLo>
643 class PastixLDLT : public PastixBase< PastixLDLT<_MatrixType, _UpLo> >
644 {
645   public:
646     typedef _MatrixType MatrixType;
647     typedef PastixBase<PastixLDLT<MatrixType, _UpLo> > Base;
648     typedef typename Base::ColSpMatrix ColSpMatrix;
649 
650   public:
651     enum { UpLo = _UpLo };
652     PastixLDLT():Base()
653     {
654       init();
655     }
656 
657     PastixLDLT(const MatrixType& matrix):Base()
658     {
659       init();
660       compute(matrix);
661     }
662 
663     /** Compute the L and D factors of the LDL^T factorization of \p matrix
664       * \sa analyzePattern() factorize()
665       */
666     void compute (const MatrixType& matrix)
667     {
668       ColSpMatrix temp;
669       grabMatrix(matrix, temp);
670       Base::compute(temp);
671     }
672 
673     /** Compute the LDL^T symbolic factorization of \p matrix using its sparsity pattern
674       * The result of this operation can be used with successive matrices having the same pattern as \p matrix
675       * \sa factorize()
676       */
677     void analyzePattern(const MatrixType& matrix)
678     {
679       ColSpMatrix temp;
680       grabMatrix(matrix, temp);
681       Base::analyzePattern(temp);
682     }
683     /** Compute the LDL^T supernodal numerical factorization of \p matrix
684       *
685       */
686     void factorize(const MatrixType& matrix)
687     {
688       ColSpMatrix temp;
689       grabMatrix(matrix, temp);
690       Base::factorize(temp);
691     }
692 
693   protected:
694     using Base::m_iparm;
695 
696     void init()
697     {
698       m_iparm(IPARM_SYM) = API_SYM_YES;
699       m_iparm(IPARM_FACTORIZATION) = API_FACT_LDLT;
700     }
701 
702     void grabMatrix(const MatrixType& matrix, ColSpMatrix& out)
703     {
704       // Pastix supports only lower, column-major matrices
705       out.template selfadjointView<Lower>() = matrix.template selfadjointView<UpLo>();
706       internal::c_to_fortran_numbering(out);
707     }
708 };
709 
710 namespace internal {
711 
712 template<typename _MatrixType, typename Rhs>
713 struct solve_retval<PastixBase<_MatrixType>, Rhs>
714   : solve_retval_base<PastixBase<_MatrixType>, Rhs>
715 {
716   typedef PastixBase<_MatrixType> Dec;
717   EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs)
718 
719   template<typename Dest> void evalTo(Dest& dst) const
720   {
721     dec()._solve(rhs(),dst);
722   }
723 };
724 
725 template<typename _MatrixType, typename Rhs>
726 struct sparse_solve_retval<PastixBase<_MatrixType>, Rhs>
727   : sparse_solve_retval_base<PastixBase<_MatrixType>, Rhs>
728 {
729   typedef PastixBase<_MatrixType> Dec;
730   EIGEN_MAKE_SPARSE_SOLVE_HELPERS(Dec,Rhs)
731 
732   template<typename Dest> void evalTo(Dest& dst) const
733   {
734     dec()._solve_sparse(rhs(),dst);
735   }
736 };
737 
738 } // end namespace internal
739 
740 } // end namespace Eigen
741 
742 #endif
743