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 /** \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     Derived& derived()
    161     {
    162       return *static_cast<Derived*>(this);
    163     }
    164     const Derived& derived() const
    165     {
    166       return *static_cast<const Derived*>(this);
    167     }
    168 
    169     /** Returns a reference to the integer vector IPARM of PaStiX parameters
    170       * to modify the default parameters.
    171       * The statistics related to the different phases of factorization and solve are saved here as well
    172       * \sa analyzePattern() factorize()
    173       */
    174     Array<Index,IPARM_SIZE,1>& iparm()
    175     {
    176       return m_iparm;
    177     }
    178 
    179     /** Return a reference to a particular index parameter of the IPARM vector
    180      * \sa iparm()
    181      */
    182 
    183     int& iparm(int idxparam)
    184     {
    185       return m_iparm(idxparam);
    186     }
    187 
    188      /** Returns a reference to the double vector DPARM of PaStiX parameters
    189       * The statistics related to the different phases of factorization and solve are saved here as well
    190       * \sa analyzePattern() factorize()
    191       */
    192     Array<RealScalar,IPARM_SIZE,1>& dparm()
    193     {
    194       return m_dparm;
    195     }
    196 
    197 
    198     /** Return a reference to a particular index parameter of the DPARM vector
    199      * \sa dparm()
    200      */
    201     double& dparm(int idxparam)
    202     {
    203       return m_dparm(idxparam);
    204     }
    205 
    206     inline Index cols() const { return m_size; }
    207     inline Index rows() const { return m_size; }
    208 
    209      /** \brief Reports whether previous computation was successful.
    210       *
    211       * \returns \c Success if computation was succesful,
    212       *          \c NumericalIssue if the PaStiX reports a problem
    213       *          \c InvalidInput if the input matrix is invalid
    214       *
    215       * \sa iparm()
    216       */
    217     ComputationInfo info() const
    218     {
    219       eigen_assert(m_isInitialized && "Decomposition is not initialized.");
    220       return m_info;
    221     }
    222 
    223     /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A.
    224       *
    225       * \sa compute()
    226       */
    227     template<typename Rhs>
    228     inline const internal::sparse_solve_retval<PastixBase, Rhs>
    229     solve(const SparseMatrixBase<Rhs>& b) const
    230     {
    231       eigen_assert(m_isInitialized && "Pastix LU, LLT or LDLT is not initialized.");
    232       eigen_assert(rows()==b.rows()
    233                 && "PastixBase::solve(): invalid number of rows of the right hand side matrix b");
    234       return internal::sparse_solve_retval<PastixBase, Rhs>(*this, b.derived());
    235     }
    236 
    237   protected:
    238 
    239     // Initialize the Pastix data structure, check the matrix
    240     void init();
    241 
    242     // Compute the ordering and the symbolic factorization
    243     void analyzePattern(ColSpMatrix& mat);
    244 
    245     // Compute the numerical factorization
    246     void factorize(ColSpMatrix& mat);
    247 
    248     // Free all the data allocated by Pastix
    249     void clean()
    250     {
    251       eigen_assert(m_initisOk && "The Pastix structure should be allocated first");
    252       m_iparm(IPARM_START_TASK) = API_TASK_CLEAN;
    253       m_iparm(IPARM_END_TASK) = API_TASK_CLEAN;
    254       internal::eigen_pastix(&m_pastixdata, MPI_COMM_WORLD, 0, 0, 0, (Scalar*)0,
    255                              m_perm.data(), m_invp.data(), 0, 0, m_iparm.data(), m_dparm.data());
    256     }
    257 
    258     void compute(ColSpMatrix& mat);
    259 
    260     int m_initisOk;
    261     int m_analysisIsOk;
    262     int m_factorizationIsOk;
    263     bool m_isInitialized;
    264     mutable ComputationInfo m_info;
    265     mutable pastix_data_t *m_pastixdata; // Data structure for pastix
    266     mutable int m_comm; // The MPI communicator identifier
    267     mutable Matrix<int,IPARM_SIZE,1> m_iparm; // integer vector for the input parameters
    268     mutable Matrix<double,DPARM_SIZE,1> m_dparm; // Scalar vector for the input parameters
    269     mutable Matrix<Index,Dynamic,1> m_perm;  // Permutation vector
    270     mutable Matrix<Index,Dynamic,1> m_invp;  // Inverse permutation vector
    271     mutable int m_size; // Size of the matrix
    272 };
    273 
    274  /** Initialize the PaStiX data structure.
    275    *A first call to this function fills iparm and dparm with the default PaStiX parameters
    276    * \sa iparm() dparm()
    277    */
    278 template <class Derived>
    279 void PastixBase<Derived>::init()
    280 {
    281   m_size = 0;
    282   m_iparm.setZero(IPARM_SIZE);
    283   m_dparm.setZero(DPARM_SIZE);
    284 
    285   m_iparm(IPARM_MODIFY_PARAMETER) = API_NO;
    286   pastix(&m_pastixdata, MPI_COMM_WORLD,
    287          0, 0, 0, 0,
    288          0, 0, 0, 1, m_iparm.data(), m_dparm.data());
    289 
    290   m_iparm[IPARM_MATRIX_VERIFICATION] = API_NO;
    291   m_iparm[IPARM_VERBOSE]             = 2;
    292   m_iparm[IPARM_ORDERING]            = API_ORDER_SCOTCH;
    293   m_iparm[IPARM_INCOMPLETE]          = API_NO;
    294   m_iparm[IPARM_OOC_LIMIT]           = 2000;
    295   m_iparm[IPARM_RHS_MAKING]          = API_RHS_B;
    296   m_iparm(IPARM_MATRIX_VERIFICATION) = API_NO;
    297 
    298   m_iparm(IPARM_START_TASK) = API_TASK_INIT;
    299   m_iparm(IPARM_END_TASK) = API_TASK_INIT;
    300   internal::eigen_pastix(&m_pastixdata, MPI_COMM_WORLD, 0, 0, 0, (Scalar*)0,
    301                          0, 0, 0, 0, m_iparm.data(), m_dparm.data());
    302 
    303   // Check the returned error
    304   if(m_iparm(IPARM_ERROR_NUMBER)) {
    305     m_info = InvalidInput;
    306     m_initisOk = false;
    307   }
    308   else {
    309     m_info = Success;
    310     m_initisOk = true;
    311   }
    312 }
    313 
    314 template <class Derived>
    315 void PastixBase<Derived>::compute(ColSpMatrix& mat)
    316 {
    317   eigen_assert(mat.rows() == mat.cols() && "The input matrix should be squared");
    318 
    319   analyzePattern(mat);
    320   factorize(mat);
    321 
    322   m_iparm(IPARM_MATRIX_VERIFICATION) = API_NO;
    323   m_isInitialized = m_factorizationIsOk;
    324 }
    325 
    326 
    327 template <class Derived>
    328 void PastixBase<Derived>::analyzePattern(ColSpMatrix& mat)
    329 {
    330   eigen_assert(m_initisOk && "The initialization of PaSTiX failed");
    331 
    332   // clean previous calls
    333   if(m_size>0)
    334     clean();
    335 
    336   m_size = mat.rows();
    337   m_perm.resize(m_size);
    338   m_invp.resize(m_size);
    339 
    340   m_iparm(IPARM_START_TASK) = API_TASK_ORDERING;
    341   m_iparm(IPARM_END_TASK) = API_TASK_ANALYSE;
    342   internal::eigen_pastix(&m_pastixdata, MPI_COMM_WORLD, m_size, mat.outerIndexPtr(), mat.innerIndexPtr(),
    343                mat.valuePtr(), m_perm.data(), m_invp.data(), 0, 0, m_iparm.data(), m_dparm.data());
    344 
    345   // Check the returned error
    346   if(m_iparm(IPARM_ERROR_NUMBER))
    347   {
    348     m_info = NumericalIssue;
    349     m_analysisIsOk = false;
    350   }
    351   else
    352   {
    353     m_info = Success;
    354     m_analysisIsOk = true;
    355   }
    356 }
    357 
    358 template <class Derived>
    359 void PastixBase<Derived>::factorize(ColSpMatrix& mat)
    360 {
    361 //   if(&m_cpyMat != &mat) m_cpyMat = mat;
    362   eigen_assert(m_analysisIsOk && "The analysis phase should be called before the factorization phase");
    363   m_iparm(IPARM_START_TASK) = API_TASK_NUMFACT;
    364   m_iparm(IPARM_END_TASK) = API_TASK_NUMFACT;
    365   m_size = mat.rows();
    366 
    367   internal::eigen_pastix(&m_pastixdata, MPI_COMM_WORLD, m_size, mat.outerIndexPtr(), mat.innerIndexPtr(),
    368                mat.valuePtr(), m_perm.data(), m_invp.data(), 0, 0, m_iparm.data(), m_dparm.data());
    369 
    370   // Check the returned error
    371   if(m_iparm(IPARM_ERROR_NUMBER))
    372   {
    373     m_info = NumericalIssue;
    374     m_factorizationIsOk = false;
    375     m_isInitialized = false;
    376   }
    377   else
    378   {
    379     m_info = Success;
    380     m_factorizationIsOk = true;
    381     m_isInitialized = true;
    382   }
    383 }
    384 
    385 /* Solve the system */
    386 template<typename Base>
    387 template<typename Rhs,typename Dest>
    388 bool PastixBase<Base>::_solve (const MatrixBase<Rhs> &b, MatrixBase<Dest> &x) const
    389 {
    390   eigen_assert(m_isInitialized && "The matrix should be factorized first");
    391   EIGEN_STATIC_ASSERT((Dest::Flags&RowMajorBit)==0,
    392                      THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES);
    393   int rhs = 1;
    394 
    395   x = b; /* on return, x is overwritten by the computed solution */
    396 
    397   for (int i = 0; i < b.cols(); i++){
    398     m_iparm[IPARM_START_TASK]          = API_TASK_SOLVE;
    399     m_iparm[IPARM_END_TASK]            = API_TASK_REFINE;
    400 
    401     internal::eigen_pastix(&m_pastixdata, MPI_COMM_WORLD, x.rows(), 0, 0, 0,
    402                            m_perm.data(), m_invp.data(), &x(0, i), rhs, m_iparm.data(), m_dparm.data());
    403   }
    404 
    405   // Check the returned error
    406   m_info = m_iparm(IPARM_ERROR_NUMBER)==0 ? Success : NumericalIssue;
    407 
    408   return m_iparm(IPARM_ERROR_NUMBER)==0;
    409 }
    410 
    411 /** \ingroup PaStiXSupport_Module
    412   * \class PastixLU
    413   * \brief Sparse direct LU solver based on PaStiX library
    414   *
    415   * This class is used to solve the linear systems A.X = B with a supernodal LU
    416   * factorization in the PaStiX library. The matrix A should be squared and nonsingular
    417   * PaStiX requires that the matrix A has a symmetric structural pattern.
    418   * This interface can symmetrize the input matrix otherwise.
    419   * The vectors or matrices X and B can be either dense or sparse.
    420   *
    421   * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
    422   * \tparam IsStrSym Indicates if the input matrix has a symmetric pattern, default is false
    423   * NOTE : Note that if the analysis and factorization phase are called separately,
    424   * the input matrix will be symmetrized at each call, hence it is advised to
    425   * symmetrize the matrix in a end-user program and set \p IsStrSym to true
    426   *
    427   * \sa \ref TutorialSparseDirectSolvers
    428   *
    429   */
    430 template<typename _MatrixType, bool IsStrSym>
    431 class PastixLU : public PastixBase< PastixLU<_MatrixType> >
    432 {
    433   public:
    434     typedef _MatrixType MatrixType;
    435     typedef PastixBase<PastixLU<MatrixType> > Base;
    436     typedef typename Base::ColSpMatrix ColSpMatrix;
    437     typedef typename MatrixType::Index Index;
    438 
    439   public:
    440     PastixLU() : Base()
    441     {
    442       init();
    443     }
    444 
    445     PastixLU(const MatrixType& matrix):Base()
    446     {
    447       init();
    448       compute(matrix);
    449     }
    450     /** Compute the LU supernodal factorization of \p matrix.
    451       * iparm and dparm can be used to tune the PaStiX parameters.
    452       * see the PaStiX user's manual
    453       * \sa analyzePattern() factorize()
    454       */
    455     void compute (const MatrixType& matrix)
    456     {
    457       m_structureIsUptodate = false;
    458       ColSpMatrix temp;
    459       grabMatrix(matrix, temp);
    460       Base::compute(temp);
    461     }
    462     /** Compute the LU symbolic factorization of \p matrix using its sparsity pattern.
    463       * Several ordering methods can be used at this step. See the PaStiX user's manual.
    464       * The result of this operation can be used with successive matrices having the same pattern as \p matrix
    465       * \sa factorize()
    466       */
    467     void analyzePattern(const MatrixType& matrix)
    468     {
    469       m_structureIsUptodate = false;
    470       ColSpMatrix temp;
    471       grabMatrix(matrix, temp);
    472       Base::analyzePattern(temp);
    473     }
    474 
    475     /** Compute the LU supernodal factorization of \p matrix
    476       * WARNING The matrix \p matrix should have the same structural pattern
    477       * as the same used in the analysis phase.
    478       * \sa analyzePattern()
    479       */
    480     void factorize(const MatrixType& matrix)
    481     {
    482       ColSpMatrix temp;
    483       grabMatrix(matrix, temp);
    484       Base::factorize(temp);
    485     }
    486   protected:
    487 
    488     void init()
    489     {
    490       m_structureIsUptodate = false;
    491       m_iparm(IPARM_SYM) = API_SYM_NO;
    492       m_iparm(IPARM_FACTORIZATION) = API_FACT_LU;
    493     }
    494 
    495     void grabMatrix(const MatrixType& matrix, ColSpMatrix& out)
    496     {
    497       if(IsStrSym)
    498         out = matrix;
    499       else
    500       {
    501         if(!m_structureIsUptodate)
    502         {
    503           // update the transposed structure
    504           m_transposedStructure = matrix.transpose();
    505 
    506           // Set the elements of the matrix to zero
    507           for (Index j=0; j<m_transposedStructure.outerSize(); ++j)
    508             for(typename ColSpMatrix::InnerIterator it(m_transposedStructure, j); it; ++it)
    509               it.valueRef() = 0.0;
    510 
    511           m_structureIsUptodate = true;
    512         }
    513 
    514         out = m_transposedStructure + matrix;
    515       }
    516       internal::c_to_fortran_numbering(out);
    517     }
    518 
    519     using Base::m_iparm;
    520     using Base::m_dparm;
    521 
    522     ColSpMatrix m_transposedStructure;
    523     bool m_structureIsUptodate;
    524 };
    525 
    526 /** \ingroup PaStiXSupport_Module
    527   * \class PastixLLT
    528   * \brief A sparse direct supernodal Cholesky (LLT) factorization and solver based on the PaStiX library
    529   *
    530   * This class is used to solve the linear systems A.X = B via a LL^T supernodal Cholesky factorization
    531   * available in the PaStiX library. The matrix A should be symmetric and positive definite
    532   * WARNING Selfadjoint complex matrices are not supported in the current version of PaStiX
    533   * The vectors or matrices X and B can be either dense or sparse
    534   *
    535   * \tparam MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
    536   * \tparam UpLo The part of the matrix to use : Lower or Upper. The default is Lower as required by PaStiX
    537   *
    538   * \sa \ref TutorialSparseDirectSolvers
    539   */
    540 template<typename _MatrixType, int _UpLo>
    541 class PastixLLT : public PastixBase< PastixLLT<_MatrixType, _UpLo> >
    542 {
    543   public:
    544     typedef _MatrixType MatrixType;
    545     typedef PastixBase<PastixLLT<MatrixType, _UpLo> > Base;
    546     typedef typename Base::ColSpMatrix ColSpMatrix;
    547 
    548   public:
    549     enum { UpLo = _UpLo };
    550     PastixLLT() : Base()
    551     {
    552       init();
    553     }
    554 
    555     PastixLLT(const MatrixType& matrix):Base()
    556     {
    557       init();
    558       compute(matrix);
    559     }
    560 
    561     /** Compute the L factor of the LL^T supernodal factorization of \p matrix
    562       * \sa analyzePattern() factorize()
    563       */
    564     void compute (const MatrixType& matrix)
    565     {
    566       ColSpMatrix temp;
    567       grabMatrix(matrix, temp);
    568       Base::compute(temp);
    569     }
    570 
    571      /** Compute the LL^T symbolic factorization of \p matrix using its sparsity pattern
    572       * The result of this operation can be used with successive matrices having the same pattern as \p matrix
    573       * \sa factorize()
    574       */
    575     void analyzePattern(const MatrixType& matrix)
    576     {
    577       ColSpMatrix temp;
    578       grabMatrix(matrix, temp);
    579       Base::analyzePattern(temp);
    580     }
    581       /** Compute the LL^T supernodal numerical factorization of \p matrix
    582         * \sa analyzePattern()
    583         */
    584     void factorize(const MatrixType& matrix)
    585     {
    586       ColSpMatrix temp;
    587       grabMatrix(matrix, temp);
    588       Base::factorize(temp);
    589     }
    590   protected:
    591     using Base::m_iparm;
    592 
    593     void init()
    594     {
    595       m_iparm(IPARM_SYM) = API_SYM_YES;
    596       m_iparm(IPARM_FACTORIZATION) = API_FACT_LLT;
    597     }
    598 
    599     void grabMatrix(const MatrixType& matrix, ColSpMatrix& out)
    600     {
    601       // Pastix supports only lower, column-major matrices
    602       out.template selfadjointView<Lower>() = matrix.template selfadjointView<UpLo>();
    603       internal::c_to_fortran_numbering(out);
    604     }
    605 };
    606 
    607 /** \ingroup PaStiXSupport_Module
    608   * \class PastixLDLT
    609   * \brief A sparse direct supernodal Cholesky (LLT) factorization and solver based on the PaStiX library
    610   *
    611   * This class is used to solve the linear systems A.X = B via a LDL^T supernodal Cholesky factorization
    612   * available in the PaStiX library. The matrix A should be symmetric and positive definite
    613   * WARNING Selfadjoint complex matrices are not supported in the current version of PaStiX
    614   * The vectors or matrices X and B can be either dense or sparse
    615   *
    616   * \tparam MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
    617   * \tparam UpLo The part of the matrix to use : Lower or Upper. The default is Lower as required by PaStiX
    618   *
    619   * \sa \ref TutorialSparseDirectSolvers
    620   */
    621 template<typename _MatrixType, int _UpLo>
    622 class PastixLDLT : public PastixBase< PastixLDLT<_MatrixType, _UpLo> >
    623 {
    624   public:
    625     typedef _MatrixType MatrixType;
    626     typedef PastixBase<PastixLDLT<MatrixType, _UpLo> > Base;
    627     typedef typename Base::ColSpMatrix ColSpMatrix;
    628 
    629   public:
    630     enum { UpLo = _UpLo };
    631     PastixLDLT():Base()
    632     {
    633       init();
    634     }
    635 
    636     PastixLDLT(const MatrixType& matrix):Base()
    637     {
    638       init();
    639       compute(matrix);
    640     }
    641 
    642     /** Compute the L and D factors of the LDL^T factorization of \p matrix
    643       * \sa analyzePattern() factorize()
    644       */
    645     void compute (const MatrixType& matrix)
    646     {
    647       ColSpMatrix temp;
    648       grabMatrix(matrix, temp);
    649       Base::compute(temp);
    650     }
    651 
    652     /** Compute the LDL^T symbolic factorization of \p matrix using its sparsity pattern
    653       * The result of this operation can be used with successive matrices having the same pattern as \p matrix
    654       * \sa factorize()
    655       */
    656     void analyzePattern(const MatrixType& matrix)
    657     {
    658       ColSpMatrix temp;
    659       grabMatrix(matrix, temp);
    660       Base::analyzePattern(temp);
    661     }
    662     /** Compute the LDL^T supernodal numerical factorization of \p matrix
    663       *
    664       */
    665     void factorize(const MatrixType& matrix)
    666     {
    667       ColSpMatrix temp;
    668       grabMatrix(matrix, temp);
    669       Base::factorize(temp);
    670     }
    671 
    672   protected:
    673     using Base::m_iparm;
    674 
    675     void init()
    676     {
    677       m_iparm(IPARM_SYM) = API_SYM_YES;
    678       m_iparm(IPARM_FACTORIZATION) = API_FACT_LDLT;
    679     }
    680 
    681     void grabMatrix(const MatrixType& matrix, ColSpMatrix& out)
    682     {
    683       // Pastix supports only lower, column-major matrices
    684       out.template selfadjointView<Lower>() = matrix.template selfadjointView<UpLo>();
    685       internal::c_to_fortran_numbering(out);
    686     }
    687 };
    688 
    689 namespace internal {
    690 
    691 template<typename _MatrixType, typename Rhs>
    692 struct solve_retval<PastixBase<_MatrixType>, Rhs>
    693   : solve_retval_base<PastixBase<_MatrixType>, Rhs>
    694 {
    695   typedef PastixBase<_MatrixType> Dec;
    696   EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs)
    697 
    698   template<typename Dest> void evalTo(Dest& dst) const
    699   {
    700     dec()._solve(rhs(),dst);
    701   }
    702 };
    703 
    704 template<typename _MatrixType, typename Rhs>
    705 struct sparse_solve_retval<PastixBase<_MatrixType>, Rhs>
    706   : sparse_solve_retval_base<PastixBase<_MatrixType>, Rhs>
    707 {
    708   typedef PastixBase<_MatrixType> Dec;
    709   EIGEN_MAKE_SPARSE_SOLVE_HELPERS(Dec,Rhs)
    710 
    711   template<typename Dest> void evalTo(Dest& dst) const
    712   {
    713     this->defaultEvalTo(dst);
    714   }
    715 };
    716 
    717 } // end namespace internal
    718 
    719 } // end namespace Eigen
    720 
    721 #endif
    722