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