Home | History | Annotate | Download | only in PardisoSupport
      1 /*
      2  Copyright (c) 2011, Intel Corporation. All rights reserved.
      3 
      4  Redistribution and use in source and binary forms, with or without modification,
      5  are permitted provided that the following conditions are met:
      6 
      7  * Redistributions of source code must retain the above copyright notice, this
      8    list of conditions and the following disclaimer.
      9  * Redistributions in binary form must reproduce the above copyright notice,
     10    this list of conditions and the following disclaimer in the documentation
     11    and/or other materials provided with the distribution.
     12  * Neither the name of Intel Corporation nor the names of its contributors may
     13    be used to endorse or promote products derived from this software without
     14    specific prior written permission.
     15 
     16  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
     17  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     18  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     19  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
     20  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     21  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     22  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
     23  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     25  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26 
     27  ********************************************************************************
     28  *   Content : Eigen bindings to Intel(R) MKL PARDISO
     29  ********************************************************************************
     30 */
     31 
     32 #ifndef EIGEN_PARDISOSUPPORT_H
     33 #define EIGEN_PARDISOSUPPORT_H
     34 
     35 namespace Eigen {
     36 
     37 template<typename _MatrixType> class PardisoLU;
     38 template<typename _MatrixType, int Options=Upper> class PardisoLLT;
     39 template<typename _MatrixType, int Options=Upper> class PardisoLDLT;
     40 
     41 namespace internal
     42 {
     43   template<typename Index>
     44   struct pardiso_run_selector
     45   {
     46     static Index run( _MKL_DSS_HANDLE_t pt, Index maxfct, Index mnum, Index type, Index phase, Index n, void *a,
     47                       Index *ia, Index *ja, Index *perm, Index nrhs, Index *iparm, Index msglvl, void *b, void *x)
     48     {
     49       Index error = 0;
     50       ::pardiso(pt, &maxfct, &mnum, &type, &phase, &n, a, ia, ja, perm, &nrhs, iparm, &msglvl, b, x, &error);
     51       return error;
     52     }
     53   };
     54   template<>
     55   struct pardiso_run_selector<long long int>
     56   {
     57     typedef long long int Index;
     58     static Index run( _MKL_DSS_HANDLE_t pt, Index maxfct, Index mnum, Index type, Index phase, Index n, void *a,
     59                       Index *ia, Index *ja, Index *perm, Index nrhs, Index *iparm, Index msglvl, void *b, void *x)
     60     {
     61       Index error = 0;
     62       ::pardiso_64(pt, &maxfct, &mnum, &type, &phase, &n, a, ia, ja, perm, &nrhs, iparm, &msglvl, b, x, &error);
     63       return error;
     64     }
     65   };
     66 
     67   template<class Pardiso> struct pardiso_traits;
     68 
     69   template<typename _MatrixType>
     70   struct pardiso_traits< PardisoLU<_MatrixType> >
     71   {
     72     typedef _MatrixType MatrixType;
     73     typedef typename _MatrixType::Scalar Scalar;
     74     typedef typename _MatrixType::RealScalar RealScalar;
     75     typedef typename _MatrixType::Index Index;
     76   };
     77 
     78   template<typename _MatrixType, int Options>
     79   struct pardiso_traits< PardisoLLT<_MatrixType, Options> >
     80   {
     81     typedef _MatrixType MatrixType;
     82     typedef typename _MatrixType::Scalar Scalar;
     83     typedef typename _MatrixType::RealScalar RealScalar;
     84     typedef typename _MatrixType::Index Index;
     85   };
     86 
     87   template<typename _MatrixType, int Options>
     88   struct pardiso_traits< PardisoLDLT<_MatrixType, Options> >
     89   {
     90     typedef _MatrixType MatrixType;
     91     typedef typename _MatrixType::Scalar Scalar;
     92     typedef typename _MatrixType::RealScalar RealScalar;
     93     typedef typename _MatrixType::Index Index;
     94   };
     95 
     96 }
     97 
     98 template<class Derived>
     99 class PardisoImpl
    100 {
    101     typedef internal::pardiso_traits<Derived> Traits;
    102   public:
    103     typedef typename Traits::MatrixType MatrixType;
    104     typedef typename Traits::Scalar Scalar;
    105     typedef typename Traits::RealScalar RealScalar;
    106     typedef typename Traits::Index Index;
    107     typedef SparseMatrix<Scalar,RowMajor,Index> SparseMatrixType;
    108     typedef Matrix<Scalar,Dynamic,1> VectorType;
    109     typedef Matrix<Index, 1, MatrixType::ColsAtCompileTime> IntRowVectorType;
    110     typedef Matrix<Index, MatrixType::RowsAtCompileTime, 1> IntColVectorType;
    111     enum {
    112       ScalarIsComplex = NumTraits<Scalar>::IsComplex
    113     };
    114 
    115     PardisoImpl()
    116     {
    117       eigen_assert((sizeof(Index) >= sizeof(_INTEGER_t) && sizeof(Index) <= 8) && "Non-supported index type");
    118       m_iparm.setZero();
    119       m_msglvl = 0; // No output
    120       m_initialized = false;
    121     }
    122 
    123     ~PardisoImpl()
    124     {
    125       pardisoRelease();
    126     }
    127 
    128     inline Index cols() const { return m_size; }
    129     inline Index rows() const { return m_size; }
    130 
    131     /** \brief Reports whether previous computation was successful.
    132       *
    133       * \returns \c Success if computation was succesful,
    134       *          \c NumericalIssue if the matrix appears to be negative.
    135       */
    136     ComputationInfo info() const
    137     {
    138       eigen_assert(m_initialized && "Decomposition is not initialized.");
    139       return m_info;
    140     }
    141 
    142     /** \warning for advanced usage only.
    143       * \returns a reference to the parameter array controlling PARDISO.
    144       * See the PARDISO manual to know how to use it. */
    145     Array<Index,64,1>& pardisoParameterArray()
    146     {
    147       return m_iparm;
    148     }
    149 
    150     /** Performs a symbolic decomposition on the sparcity of \a matrix.
    151       *
    152       * This function is particularly useful when solving for several problems having the same structure.
    153       *
    154       * \sa factorize()
    155       */
    156     Derived& analyzePattern(const MatrixType& matrix);
    157 
    158     /** Performs a numeric decomposition of \a matrix
    159       *
    160       * The given matrix must has the same sparcity than the matrix on which the symbolic decomposition has been performed.
    161       *
    162       * \sa analyzePattern()
    163       */
    164     Derived& factorize(const MatrixType& matrix);
    165 
    166     Derived& compute(const MatrixType& matrix);
    167 
    168     /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A.
    169       *
    170       * \sa compute()
    171       */
    172     template<typename Rhs>
    173     inline const internal::solve_retval<PardisoImpl, Rhs>
    174     solve(const MatrixBase<Rhs>& b) const
    175     {
    176       eigen_assert(m_initialized && "Pardiso solver is not initialized.");
    177       eigen_assert(rows()==b.rows()
    178                 && "PardisoImpl::solve(): invalid number of rows of the right hand side matrix b");
    179       return internal::solve_retval<PardisoImpl, Rhs>(*this, b.derived());
    180     }
    181 
    182     /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A.
    183       *
    184       * \sa compute()
    185       */
    186     template<typename Rhs>
    187     inline const internal::sparse_solve_retval<PardisoImpl, Rhs>
    188     solve(const SparseMatrixBase<Rhs>& b) const
    189     {
    190       eigen_assert(m_initialized && "Pardiso solver is not initialized.");
    191       eigen_assert(rows()==b.rows()
    192                 && "PardisoImpl::solve(): invalid number of rows of the right hand side matrix b");
    193       return internal::sparse_solve_retval<PardisoImpl, Rhs>(*this, b.derived());
    194     }
    195 
    196     Derived& derived()
    197     {
    198       return *static_cast<Derived*>(this);
    199     }
    200     const Derived& derived() const
    201     {
    202       return *static_cast<const Derived*>(this);
    203     }
    204 
    205     template<typename BDerived, typename XDerived>
    206     bool _solve(const MatrixBase<BDerived> &b, MatrixBase<XDerived>& x) const;
    207 
    208     /** \internal */
    209     template<typename Rhs, typename DestScalar, int DestOptions, typename DestIndex>
    210     void _solve_sparse(const Rhs& b, SparseMatrix<DestScalar,DestOptions,DestIndex> &dest) const
    211     {
    212       eigen_assert(m_size==b.rows());
    213 
    214       // we process the sparse rhs per block of NbColsAtOnce columns temporarily stored into a dense matrix.
    215       static const int NbColsAtOnce = 4;
    216       int rhsCols = b.cols();
    217       int size = b.rows();
    218       // Pardiso cannot solve in-place,
    219       // so we need two temporaries
    220       Eigen::Matrix<DestScalar,Dynamic,Dynamic,ColMajor> tmp_rhs(size,rhsCols);
    221       Eigen::Matrix<DestScalar,Dynamic,Dynamic,ColMajor> tmp_res(size,rhsCols);
    222       for(int k=0; k<rhsCols; k+=NbColsAtOnce)
    223       {
    224         int actualCols = std::min<int>(rhsCols-k, NbColsAtOnce);
    225         tmp_rhs.leftCols(actualCols) = b.middleCols(k,actualCols);
    226         tmp_res.leftCols(actualCols) = derived().solve(tmp_rhs.leftCols(actualCols));
    227         dest.middleCols(k,actualCols) = tmp_res.leftCols(actualCols).sparseView();
    228       }
    229     }
    230 
    231   protected:
    232     void pardisoRelease()
    233     {
    234       if(m_initialized) // Factorization ran at least once
    235       {
    236         internal::pardiso_run_selector<Index>::run(m_pt, 1, 1, m_type, -1, m_size, 0, 0, 0, m_perm.data(), 0,
    237                                                    m_iparm.data(), m_msglvl, 0, 0);
    238       }
    239     }
    240 
    241     void pardisoInit(int type)
    242     {
    243       m_type = type;
    244       bool symmetric = abs(m_type) < 10;
    245       m_iparm[0] = 1;   // No solver default
    246       m_iparm[1] = 3;   // use Metis for the ordering
    247       m_iparm[2] = 1;   // Numbers of processors, value of OMP_NUM_THREADS
    248       m_iparm[3] = 0;   // No iterative-direct algorithm
    249       m_iparm[4] = 0;   // No user fill-in reducing permutation
    250       m_iparm[5] = 0;   // Write solution into x
    251       m_iparm[6] = 0;   // Not in use
    252       m_iparm[7] = 2;   // Max numbers of iterative refinement steps
    253       m_iparm[8] = 0;   // Not in use
    254       m_iparm[9] = 13;  // Perturb the pivot elements with 1E-13
    255       m_iparm[10] = symmetric ? 0 : 1; // Use nonsymmetric permutation and scaling MPS
    256       m_iparm[11] = 0;  // Not in use
    257       m_iparm[12] = symmetric ? 0 : 1;  // Maximum weighted matching algorithm is switched-off (default for symmetric).
    258                                         // Try m_iparm[12] = 1 in case of inappropriate accuracy
    259       m_iparm[13] = 0;  // Output: Number of perturbed pivots
    260       m_iparm[14] = 0;  // Not in use
    261       m_iparm[15] = 0;  // Not in use
    262       m_iparm[16] = 0;  // Not in use
    263       m_iparm[17] = -1; // Output: Number of nonzeros in the factor LU
    264       m_iparm[18] = -1; // Output: Mflops for LU factorization
    265       m_iparm[19] = 0;  // Output: Numbers of CG Iterations
    266 
    267       m_iparm[20] = 0;  // 1x1 pivoting
    268       m_iparm[26] = 0;  // No matrix checker
    269       m_iparm[27] = (sizeof(RealScalar) == 4) ? 1 : 0;
    270       m_iparm[34] = 1;  // C indexing
    271       m_iparm[59] = 1;  // Automatic switch between In-Core and Out-of-Core modes
    272     }
    273 
    274   protected:
    275     // cached data to reduce reallocation, etc.
    276 
    277     void manageErrorCode(Index error)
    278     {
    279       switch(error)
    280       {
    281         case 0:
    282           m_info = Success;
    283           break;
    284         case -4:
    285         case -7:
    286           m_info = NumericalIssue;
    287           break;
    288         default:
    289           m_info = InvalidInput;
    290       }
    291     }
    292 
    293     mutable SparseMatrixType m_matrix;
    294     ComputationInfo m_info;
    295     bool m_initialized, m_analysisIsOk, m_factorizationIsOk;
    296     Index m_type, m_msglvl;
    297     mutable void *m_pt[64];
    298     mutable Array<Index,64,1> m_iparm;
    299     mutable IntColVectorType m_perm;
    300     Index m_size;
    301 
    302   private:
    303     PardisoImpl(PardisoImpl &) {}
    304 };
    305 
    306 template<class Derived>
    307 Derived& PardisoImpl<Derived>::compute(const MatrixType& a)
    308 {
    309   m_size = a.rows();
    310   eigen_assert(a.rows() == a.cols());
    311 
    312   pardisoRelease();
    313   memset(m_pt, 0, sizeof(m_pt));
    314   m_perm.setZero(m_size);
    315   derived().getMatrix(a);
    316 
    317   Index error;
    318   error = internal::pardiso_run_selector<Index>::run(m_pt, 1, 1, m_type, 12, m_size,
    319                                                      m_matrix.valuePtr(), m_matrix.outerIndexPtr(), m_matrix.innerIndexPtr(),
    320                                                      m_perm.data(), 0, m_iparm.data(), m_msglvl, NULL, NULL);
    321 
    322   manageErrorCode(error);
    323   m_analysisIsOk = true;
    324   m_factorizationIsOk = true;
    325   m_initialized = true;
    326   return derived();
    327 }
    328 
    329 template<class Derived>
    330 Derived& PardisoImpl<Derived>::analyzePattern(const MatrixType& a)
    331 {
    332   m_size = a.rows();
    333   eigen_assert(m_size == a.cols());
    334 
    335   pardisoRelease();
    336   memset(m_pt, 0, sizeof(m_pt));
    337   m_perm.setZero(m_size);
    338   derived().getMatrix(a);
    339 
    340   Index error;
    341   error = internal::pardiso_run_selector<Index>::run(m_pt, 1, 1, m_type, 11, m_size,
    342                                                      m_matrix.valuePtr(), m_matrix.outerIndexPtr(), m_matrix.innerIndexPtr(),
    343                                                      m_perm.data(), 0, m_iparm.data(), m_msglvl, NULL, NULL);
    344 
    345   manageErrorCode(error);
    346   m_analysisIsOk = true;
    347   m_factorizationIsOk = false;
    348   m_initialized = true;
    349   return derived();
    350 }
    351 
    352 template<class Derived>
    353 Derived& PardisoImpl<Derived>::factorize(const MatrixType& a)
    354 {
    355   eigen_assert(m_analysisIsOk && "You must first call analyzePattern()");
    356   eigen_assert(m_size == a.rows() && m_size == a.cols());
    357 
    358   derived().getMatrix(a);
    359 
    360   Index error;
    361   error = internal::pardiso_run_selector<Index>::run(m_pt, 1, 1, m_type, 22, m_size,
    362                                                      m_matrix.valuePtr(), m_matrix.outerIndexPtr(), m_matrix.innerIndexPtr(),
    363                                                      m_perm.data(), 0, m_iparm.data(), m_msglvl, NULL, NULL);
    364 
    365   manageErrorCode(error);
    366   m_factorizationIsOk = true;
    367   return derived();
    368 }
    369 
    370 template<class Base>
    371 template<typename BDerived,typename XDerived>
    372 bool PardisoImpl<Base>::_solve(const MatrixBase<BDerived> &b, MatrixBase<XDerived>& x) const
    373 {
    374   if(m_iparm[0] == 0) // Factorization was not computed
    375     return false;
    376 
    377   //Index n = m_matrix.rows();
    378   Index nrhs = Index(b.cols());
    379   eigen_assert(m_size==b.rows());
    380   eigen_assert(((MatrixBase<BDerived>::Flags & RowMajorBit) == 0 || nrhs == 1) && "Row-major right hand sides are not supported");
    381   eigen_assert(((MatrixBase<XDerived>::Flags & RowMajorBit) == 0 || nrhs == 1) && "Row-major matrices of unknowns are not supported");
    382   eigen_assert(((nrhs == 1) || b.outerStride() == b.rows()));
    383 
    384 
    385 //  switch (transposed) {
    386 //    case SvNoTrans    : m_iparm[11] = 0 ; break;
    387 //    case SvTranspose  : m_iparm[11] = 2 ; break;
    388 //    case SvAdjoint    : m_iparm[11] = 1 ; break;
    389 //    default:
    390 //      //std::cerr << "Eigen: transposition  option \"" << transposed << "\" not supported by the PARDISO backend\n";
    391 //      m_iparm[11] = 0;
    392 //  }
    393 
    394   Scalar* rhs_ptr = const_cast<Scalar*>(b.derived().data());
    395   Matrix<Scalar,Dynamic,Dynamic,ColMajor> tmp;
    396 
    397   // Pardiso cannot solve in-place
    398   if(rhs_ptr == x.derived().data())
    399   {
    400     tmp = b;
    401     rhs_ptr = tmp.data();
    402   }
    403 
    404   Index error;
    405   error = internal::pardiso_run_selector<Index>::run(m_pt, 1, 1, m_type, 33, m_size,
    406                                                      m_matrix.valuePtr(), m_matrix.outerIndexPtr(), m_matrix.innerIndexPtr(),
    407                                                      m_perm.data(), nrhs, m_iparm.data(), m_msglvl,
    408                                                      rhs_ptr, x.derived().data());
    409 
    410   return error==0;
    411 }
    412 
    413 
    414 /** \ingroup PardisoSupport_Module
    415   * \class PardisoLU
    416   * \brief A sparse direct LU factorization and solver based on the PARDISO library
    417   *
    418   * This class allows to solve for A.X = B sparse linear problems via a direct LU factorization
    419   * using the Intel MKL PARDISO library. The sparse matrix A must be squared and invertible.
    420   * The vectors or matrices 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   *
    424   * \sa \ref TutorialSparseDirectSolvers
    425   */
    426 template<typename MatrixType>
    427 class PardisoLU : public PardisoImpl< PardisoLU<MatrixType> >
    428 {
    429   protected:
    430     typedef PardisoImpl< PardisoLU<MatrixType> > Base;
    431     typedef typename Base::Scalar Scalar;
    432     typedef typename Base::RealScalar RealScalar;
    433     using Base::pardisoInit;
    434     using Base::m_matrix;
    435     friend class PardisoImpl< PardisoLU<MatrixType> >;
    436 
    437   public:
    438 
    439     using Base::compute;
    440     using Base::solve;
    441 
    442     PardisoLU()
    443       : Base()
    444     {
    445       pardisoInit(Base::ScalarIsComplex ? 13 : 11);
    446     }
    447 
    448     PardisoLU(const MatrixType& matrix)
    449       : Base()
    450     {
    451       pardisoInit(Base::ScalarIsComplex ? 13 : 11);
    452       compute(matrix);
    453     }
    454   protected:
    455     void getMatrix(const MatrixType& matrix)
    456     {
    457       m_matrix = matrix;
    458     }
    459 
    460   private:
    461     PardisoLU(PardisoLU& ) {}
    462 };
    463 
    464 /** \ingroup PardisoSupport_Module
    465   * \class PardisoLLT
    466   * \brief A sparse direct Cholesky (LLT) factorization and solver based on the PARDISO library
    467   *
    468   * This class allows to solve for A.X = B sparse linear problems via a LL^T Cholesky factorization
    469   * using the Intel MKL PARDISO library. The sparse matrix A must be selfajoint and positive definite.
    470   * The vectors or matrices X and B can be either dense or sparse.
    471   *
    472   * \tparam MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
    473   * \tparam UpLo can be any bitwise combination of Upper, Lower. The default is Upper, meaning only the upper triangular part has to be used.
    474   *         Upper|Lower can be used to tell both triangular parts can be used as input.
    475   *
    476   * \sa \ref TutorialSparseDirectSolvers
    477   */
    478 template<typename MatrixType, int _UpLo>
    479 class PardisoLLT : public PardisoImpl< PardisoLLT<MatrixType,_UpLo> >
    480 {
    481   protected:
    482     typedef PardisoImpl< PardisoLLT<MatrixType,_UpLo> > Base;
    483     typedef typename Base::Scalar Scalar;
    484     typedef typename Base::Index Index;
    485     typedef typename Base::RealScalar RealScalar;
    486     using Base::pardisoInit;
    487     using Base::m_matrix;
    488     friend class PardisoImpl< PardisoLLT<MatrixType,_UpLo> >;
    489 
    490   public:
    491 
    492     enum { UpLo = _UpLo };
    493     using Base::compute;
    494     using Base::solve;
    495 
    496     PardisoLLT()
    497       : Base()
    498     {
    499       pardisoInit(Base::ScalarIsComplex ? 4 : 2);
    500     }
    501 
    502     PardisoLLT(const MatrixType& matrix)
    503       : Base()
    504     {
    505       pardisoInit(Base::ScalarIsComplex ? 4 : 2);
    506       compute(matrix);
    507     }
    508 
    509   protected:
    510 
    511     void getMatrix(const MatrixType& matrix)
    512     {
    513       // PARDISO supports only upper, row-major matrices
    514       PermutationMatrix<Dynamic,Dynamic,Index> p_null;
    515       m_matrix.resize(matrix.rows(), matrix.cols());
    516       m_matrix.template selfadjointView<Upper>() = matrix.template selfadjointView<UpLo>().twistedBy(p_null);
    517     }
    518 
    519   private:
    520     PardisoLLT(PardisoLLT& ) {}
    521 };
    522 
    523 /** \ingroup PardisoSupport_Module
    524   * \class PardisoLDLT
    525   * \brief A sparse direct Cholesky (LDLT) factorization and solver based on the PARDISO library
    526   *
    527   * This class allows to solve for A.X = B sparse linear problems via a LDL^T Cholesky factorization
    528   * using the Intel MKL PARDISO library. The sparse matrix A is assumed to be selfajoint and positive definite.
    529   * For complex matrices, A can also be symmetric only, see the \a Options template parameter.
    530   * The vectors or matrices X and B can be either dense or sparse.
    531   *
    532   * \tparam MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
    533   * \tparam Options can be any bitwise combination of Upper, Lower, and Symmetric. The default is Upper, meaning only the upper triangular part has to be used.
    534   *         Symmetric can be used for symmetric, non-selfadjoint complex matrices, the default being to assume a selfadjoint matrix.
    535   *         Upper|Lower can be used to tell both triangular parts can be used as input.
    536   *
    537   * \sa \ref TutorialSparseDirectSolvers
    538   */
    539 template<typename MatrixType, int Options>
    540 class PardisoLDLT : public PardisoImpl< PardisoLDLT<MatrixType,Options> >
    541 {
    542   protected:
    543     typedef PardisoImpl< PardisoLDLT<MatrixType,Options> > Base;
    544     typedef typename Base::Scalar Scalar;
    545     typedef typename Base::Index Index;
    546     typedef typename Base::RealScalar RealScalar;
    547     using Base::pardisoInit;
    548     using Base::m_matrix;
    549     friend class PardisoImpl< PardisoLDLT<MatrixType,Options> >;
    550 
    551   public:
    552 
    553     using Base::compute;
    554     using Base::solve;
    555     enum { UpLo = Options&(Upper|Lower) };
    556 
    557     PardisoLDLT()
    558       : Base()
    559     {
    560       pardisoInit(Base::ScalarIsComplex ? ( bool(Options&Symmetric) ? 6 : -4 ) : -2);
    561     }
    562 
    563     PardisoLDLT(const MatrixType& matrix)
    564       : Base()
    565     {
    566       pardisoInit(Base::ScalarIsComplex ? ( bool(Options&Symmetric) ? 6 : -4 ) : -2);
    567       compute(matrix);
    568     }
    569 
    570     void getMatrix(const MatrixType& matrix)
    571     {
    572       // PARDISO supports only upper, row-major matrices
    573       PermutationMatrix<Dynamic,Dynamic,Index> p_null;
    574       m_matrix.resize(matrix.rows(), matrix.cols());
    575       m_matrix.template selfadjointView<Upper>() = matrix.template selfadjointView<UpLo>().twistedBy(p_null);
    576     }
    577 
    578   private:
    579     PardisoLDLT(PardisoLDLT& ) {}
    580 };
    581 
    582 namespace internal {
    583 
    584 template<typename _Derived, typename Rhs>
    585 struct solve_retval<PardisoImpl<_Derived>, Rhs>
    586   : solve_retval_base<PardisoImpl<_Derived>, Rhs>
    587 {
    588   typedef PardisoImpl<_Derived> Dec;
    589   EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs)
    590 
    591   template<typename Dest> void evalTo(Dest& dst) const
    592   {
    593     dec()._solve(rhs(),dst);
    594   }
    595 };
    596 
    597 template<typename Derived, typename Rhs>
    598 struct sparse_solve_retval<PardisoImpl<Derived>, Rhs>
    599   : sparse_solve_retval_base<PardisoImpl<Derived>, Rhs>
    600 {
    601   typedef PardisoImpl<Derived> Dec;
    602   EIGEN_MAKE_SPARSE_SOLVE_HELPERS(Dec,Rhs)
    603 
    604   template<typename Dest> void evalTo(Dest& dst) const
    605   {
    606     dec().derived()._solve_sparse(rhs(),dst);
    607   }
    608 };
    609 
    610 } // end namespace internal
    611 
    612 } // end namespace Eigen
    613 
    614 #endif // EIGEN_PARDISOSUPPORT_H
    615