MOAB  4.9.3pre
PardisoSupport.h
Go to the documentation of this file.
00001 /*
00002  Copyright (c) 2011, Intel Corporation. All rights reserved.
00003 
00004  Redistribution and use in source and binary forms, with or without modification,
00005  are permitted provided that the following conditions are met:
00006 
00007  * Redistributions of source code must retain the above copyright notice, this
00008    list of conditions and the following disclaimer.
00009  * Redistributions in binary form must reproduce the above copyright notice,
00010    this list of conditions and the following disclaimer in the documentation
00011    and/or other materials provided with the distribution.
00012  * Neither the name of Intel Corporation nor the names of its contributors may
00013    be used to endorse or promote products derived from this software without
00014    specific prior written permission.
00015 
00016  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00017  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00018  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00019  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
00020  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00021  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00022  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
00023  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00024  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00025  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026 
00027  ********************************************************************************
00028  *   Content : Eigen bindings to Intel(R) MKL PARDISO
00029  ********************************************************************************
00030 */
00031 
00032 #ifndef EIGEN_PARDISOSUPPORT_H
00033 #define EIGEN_PARDISOSUPPORT_H
00034 
00035 namespace Eigen { 
00036 
00037 template<typename _MatrixType> class PardisoLU;
00038 template<typename _MatrixType, int Options=Upper> class PardisoLLT;
00039 template<typename _MatrixType, int Options=Upper> class PardisoLDLT;
00040 
00041 namespace internal
00042 {
00043   template<typename IndexType>
00044   struct pardiso_run_selector
00045   {
00046     static IndexType run( _MKL_DSS_HANDLE_t pt, IndexType maxfct, IndexType mnum, IndexType type, IndexType phase, IndexType n, void *a,
00047                       IndexType *ia, IndexType *ja, IndexType *perm, IndexType nrhs, IndexType *iparm, IndexType msglvl, void *b, void *x)
00048     {
00049       IndexType error = 0;
00050       ::pardiso(pt, &maxfct, &mnum, &type, &phase, &n, a, ia, ja, perm, &nrhs, iparm, &msglvl, b, x, &error);
00051       return error;
00052     }
00053   };
00054   template<>
00055   struct pardiso_run_selector<long long int>
00056   {
00057     typedef long long int IndexType;
00058     static IndexType run( _MKL_DSS_HANDLE_t pt, IndexType maxfct, IndexType mnum, IndexType type, IndexType phase, IndexType n, void *a,
00059                       IndexType *ia, IndexType *ja, IndexType *perm, IndexType nrhs, IndexType *iparm, IndexType msglvl, void *b, void *x)
00060     {
00061       IndexType error = 0;
00062       ::pardiso_64(pt, &maxfct, &mnum, &type, &phase, &n, a, ia, ja, perm, &nrhs, iparm, &msglvl, b, x, &error);
00063       return error;
00064     }
00065   };
00066 
00067   template<class Pardiso> struct pardiso_traits;
00068 
00069   template<typename _MatrixType>
00070   struct pardiso_traits< PardisoLU<_MatrixType> >
00071   {
00072     typedef _MatrixType MatrixType;
00073     typedef typename _MatrixType::Scalar Scalar;
00074     typedef typename _MatrixType::RealScalar RealScalar;
00075     typedef typename _MatrixType::StorageIndex StorageIndex;
00076   };
00077 
00078   template<typename _MatrixType, int Options>
00079   struct pardiso_traits< PardisoLLT<_MatrixType, Options> >
00080   {
00081     typedef _MatrixType MatrixType;
00082     typedef typename _MatrixType::Scalar Scalar;
00083     typedef typename _MatrixType::RealScalar RealScalar;
00084     typedef typename _MatrixType::StorageIndex StorageIndex;
00085   };
00086 
00087   template<typename _MatrixType, int Options>
00088   struct pardiso_traits< PardisoLDLT<_MatrixType, Options> >
00089   {
00090     typedef _MatrixType MatrixType;
00091     typedef typename _MatrixType::Scalar Scalar;
00092     typedef typename _MatrixType::RealScalar RealScalar;
00093     typedef typename _MatrixType::StorageIndex StorageIndex;    
00094   };
00095 
00096 } // end namespace internal
00097 
00098 template<class Derived>
00099 class PardisoImpl : public SparseSolverBase<Derived>
00100 {
00101   protected:
00102     typedef SparseSolverBase<Derived> Base;
00103     using Base::derived;
00104     using Base::m_isInitialized;
00105     
00106     typedef internal::pardiso_traits<Derived> Traits;
00107   public:
00108     using Base::_solve_impl;
00109     
00110     typedef typename Traits::MatrixType MatrixType;
00111     typedef typename Traits::Scalar Scalar;
00112     typedef typename Traits::RealScalar RealScalar;
00113     typedef typename Traits::StorageIndex StorageIndex;
00114     typedef SparseMatrix<Scalar,RowMajor,StorageIndex> SparseMatrixType;
00115     typedef Matrix<Scalar,Dynamic,1> VectorType;
00116     typedef Matrix<StorageIndex, 1, MatrixType::ColsAtCompileTime> IntRowVectorType;
00117     typedef Matrix<StorageIndex, MatrixType::RowsAtCompileTime, 1> IntColVectorType;
00118     typedef Array<StorageIndex,64,1,DontAlign> ParameterType;
00119     enum {
00120       ScalarIsComplex = NumTraits<Scalar>::IsComplex,
00121       ColsAtCompileTime = Dynamic,
00122       MaxColsAtCompileTime = Dynamic
00123     };
00124 
00125     PardisoImpl()
00126     {
00127       eigen_assert((sizeof(StorageIndex) >= sizeof(_INTEGER_t) && sizeof(StorageIndex) <= 8) && "Non-supported index type");
00128       m_iparm.setZero();
00129       m_msglvl = 0; // No output
00130       m_isInitialized = false;
00131     }
00132 
00133     ~PardisoImpl()
00134     {
00135       pardisoRelease();
00136     }
00137 
00138     inline Index cols() const { return m_size; }
00139     inline Index rows() const { return m_size; }
00140   
00146     ComputationInfo info() const
00147     {
00148       eigen_assert(m_isInitialized && "Decomposition is not initialized.");
00149       return m_info;
00150     }
00151 
00155     ParameterType& pardisoParameterArray()
00156     {
00157       return m_iparm;
00158     }
00159     
00166     Derived& analyzePattern(const MatrixType& matrix);
00167     
00174     Derived& factorize(const MatrixType& matrix);
00175 
00176     Derived& compute(const MatrixType& matrix);
00177 
00178     template<typename Rhs,typename Dest>
00179     void _solve_impl(const MatrixBase<Rhs> &b, MatrixBase<Dest> &dest) const;
00180 
00181   protected:
00182     void pardisoRelease()
00183     {
00184       if(m_isInitialized) // Factorization ran at least once
00185       {
00186         internal::pardiso_run_selector<StorageIndex>::run(m_pt, 1, 1, m_type, -1, m_size,0, 0, 0, m_perm.data(), 0,
00187                                                           m_iparm.data(), m_msglvl, NULL, NULL);
00188         m_isInitialized = false;
00189       }
00190     }
00191 
00192     void pardisoInit(int type)
00193     {
00194       m_type = type;
00195       bool symmetric = std::abs(m_type) < 10;
00196       m_iparm[0] = 1;   // No solver default
00197       m_iparm[1] = 3;   // use Metis for the ordering
00198       m_iparm[2] = 1;   // Numbers of processors, value of OMP_NUM_THREADS
00199       m_iparm[3] = 0;   // No iterative-direct algorithm
00200       m_iparm[4] = 0;   // No user fill-in reducing permutation
00201       m_iparm[5] = 0;   // Write solution into x
00202       m_iparm[6] = 0;   // Not in use
00203       m_iparm[7] = 2;   // Max numbers of iterative refinement steps
00204       m_iparm[8] = 0;   // Not in use
00205       m_iparm[9] = 13;  // Perturb the pivot elements with 1E-13
00206       m_iparm[10] = symmetric ? 0 : 1; // Use nonsymmetric permutation and scaling MPS
00207       m_iparm[11] = 0;  // Not in use
00208       m_iparm[12] = symmetric ? 0 : 1;  // Maximum weighted matching algorithm is switched-off (default for symmetric).
00209                                         // Try m_iparm[12] = 1 in case of inappropriate accuracy
00210       m_iparm[13] = 0;  // Output: Number of perturbed pivots
00211       m_iparm[14] = 0;  // Not in use
00212       m_iparm[15] = 0;  // Not in use
00213       m_iparm[16] = 0;  // Not in use
00214       m_iparm[17] = -1; // Output: Number of nonzeros in the factor LU
00215       m_iparm[18] = -1; // Output: Mflops for LU factorization
00216       m_iparm[19] = 0;  // Output: Numbers of CG Iterations
00217       
00218       m_iparm[20] = 0;  // 1x1 pivoting
00219       m_iparm[26] = 0;  // No matrix checker
00220       m_iparm[27] = (sizeof(RealScalar) == 4) ? 1 : 0;
00221       m_iparm[34] = 1;  // C indexing
00222       m_iparm[59] = 1;  // Automatic switch between In-Core and Out-of-Core modes
00223       
00224       memset(m_pt, 0, sizeof(m_pt));
00225     }
00226 
00227   protected:
00228     // cached data to reduce reallocation, etc.
00229     
00230     void manageErrorCode(Index error) const
00231     {
00232       switch(error)
00233       {
00234         case 0:
00235           m_info = Success;
00236           break;
00237         case -4:
00238         case -7:
00239           m_info = NumericalIssue;
00240           break;
00241         default:
00242           m_info = InvalidInput;
00243       }
00244     }
00245 
00246     mutable SparseMatrixType m_matrix;
00247     mutable ComputationInfo m_info;
00248     bool m_analysisIsOk, m_factorizationIsOk;
00249     Index m_type, m_msglvl;
00250     mutable void *m_pt[64];
00251     mutable ParameterType m_iparm;
00252     mutable IntColVectorType m_perm;
00253     Index m_size;
00254     
00255 };
00256 
00257 template<class Derived>
00258 Derived& PardisoImpl<Derived>::compute(const MatrixType& a)
00259 {
00260   m_size = a.rows();
00261   eigen_assert(a.rows() == a.cols());
00262 
00263   pardisoRelease();
00264   m_perm.setZero(m_size);
00265   derived().getMatrix(a);
00266   
00267   Index error;
00268   error = internal::pardiso_run_selector<StorageIndex>::run(m_pt, 1, 1, m_type, 12, m_size,
00269                                                             m_matrix.valuePtr(), m_matrix.outerIndexPtr(), m_matrix.innerIndexPtr(),
00270                                                             m_perm.data(), 0, m_iparm.data(), m_msglvl, NULL, NULL);
00271 
00272   manageErrorCode(error);
00273   m_analysisIsOk = true;
00274   m_factorizationIsOk = true;
00275   m_isInitialized = true;
00276   return derived();
00277 }
00278 
00279 template<class Derived>
00280 Derived& PardisoImpl<Derived>::analyzePattern(const MatrixType& a)
00281 {
00282   m_size = a.rows();
00283   eigen_assert(m_size == a.cols());
00284 
00285   pardisoRelease();
00286   m_perm.setZero(m_size);
00287   derived().getMatrix(a);
00288   
00289   Index error;
00290   error = internal::pardiso_run_selector<StorageIndex>::run(m_pt, 1, 1, m_type, 11, m_size,
00291                                                             m_matrix.valuePtr(), m_matrix.outerIndexPtr(), m_matrix.innerIndexPtr(),
00292                                                             m_perm.data(), 0, m_iparm.data(), m_msglvl, NULL, NULL);
00293   
00294   manageErrorCode(error);
00295   m_analysisIsOk = true;
00296   m_factorizationIsOk = false;
00297   m_isInitialized = true;
00298   return derived();
00299 }
00300 
00301 template<class Derived>
00302 Derived& PardisoImpl<Derived>::factorize(const MatrixType& a)
00303 {
00304   eigen_assert(m_analysisIsOk && "You must first call analyzePattern()");
00305   eigen_assert(m_size == a.rows() && m_size == a.cols());
00306   
00307   derived().getMatrix(a);
00308 
00309   Index error;  
00310   error = internal::pardiso_run_selector<StorageIndex>::run(m_pt, 1, 1, m_type, 22, m_size,
00311                                                             m_matrix.valuePtr(), m_matrix.outerIndexPtr(), m_matrix.innerIndexPtr(),
00312                                                             m_perm.data(), 0, m_iparm.data(), m_msglvl, NULL, NULL);
00313   
00314   manageErrorCode(error);
00315   m_factorizationIsOk = true;
00316   return derived();
00317 }
00318 
00319 template<class Derived>
00320 template<typename BDerived,typename XDerived>
00321 void PardisoImpl<Derived>::_solve_impl(const MatrixBase<BDerived> &b, MatrixBase<XDerived>& x) const
00322 {
00323   if(m_iparm[0] == 0) // Factorization was not computed
00324   {
00325     m_info = InvalidInput;
00326     return;
00327   }
00328 
00329   //Index n = m_matrix.rows();
00330   Index nrhs = Index(b.cols());
00331   eigen_assert(m_size==b.rows());
00332   eigen_assert(((MatrixBase<BDerived>::Flags & RowMajorBit) == 0 || nrhs == 1) && "Row-major right hand sides are not supported");
00333   eigen_assert(((MatrixBase<XDerived>::Flags & RowMajorBit) == 0 || nrhs == 1) && "Row-major matrices of unknowns are not supported");
00334   eigen_assert(((nrhs == 1) || b.outerStride() == b.rows()));
00335 
00336 
00337 //  switch (transposed) {
00338 //    case SvNoTrans    : m_iparm[11] = 0 ; break;
00339 //    case SvTranspose  : m_iparm[11] = 2 ; break;
00340 //    case SvAdjoint    : m_iparm[11] = 1 ; break;
00341 //    default:
00342 //      //std::cerr << "Eigen: transposition  option \"" << transposed << "\" not supported by the PARDISO backend\n";
00343 //      m_iparm[11] = 0;
00344 //  }
00345 
00346   Scalar* rhs_ptr = const_cast<Scalar*>(b.derived().data());
00347   Matrix<Scalar,Dynamic,Dynamic,ColMajor> tmp;
00348   
00349   // Pardiso cannot solve in-place
00350   if(rhs_ptr == x.derived().data())
00351   {
00352     tmp = b;
00353     rhs_ptr = tmp.data();
00354   }
00355   
00356   Index error;
00357   error = internal::pardiso_run_selector<StorageIndex>::run(m_pt, 1, 1, m_type, 33, m_size,
00358                                                             m_matrix.valuePtr(), m_matrix.outerIndexPtr(), m_matrix.innerIndexPtr(),
00359                                                             m_perm.data(), nrhs, m_iparm.data(), m_msglvl,
00360                                                             rhs_ptr, x.derived().data());
00361 
00362   manageErrorCode(error);
00363 }
00364 
00365 
00380 template<typename MatrixType>
00381 class PardisoLU : public PardisoImpl< PardisoLU<MatrixType> >
00382 {
00383   protected:
00384     typedef PardisoImpl<PardisoLU> Base;
00385     typedef typename Base::Scalar Scalar;
00386     typedef typename Base::RealScalar RealScalar;
00387     using Base::pardisoInit;
00388     using Base::m_matrix;
00389     friend class PardisoImpl< PardisoLU<MatrixType> >;
00390 
00391   public:
00392 
00393     using Base::compute;
00394     using Base::solve;
00395 
00396     PardisoLU()
00397       : Base()
00398     {
00399       pardisoInit(Base::ScalarIsComplex ? 13 : 11);
00400     }
00401 
00402     explicit PardisoLU(const MatrixType& matrix)
00403       : Base()
00404     {
00405       pardisoInit(Base::ScalarIsComplex ? 13 : 11);
00406       compute(matrix);
00407     }
00408   protected:
00409     void getMatrix(const MatrixType& matrix)
00410     {
00411       m_matrix = matrix;
00412       m_matrix.makeCompressed();
00413     }
00414 };
00415 
00432 template<typename MatrixType, int _UpLo>
00433 class PardisoLLT : public PardisoImpl< PardisoLLT<MatrixType,_UpLo> >
00434 {
00435   protected:
00436     typedef PardisoImpl< PardisoLLT<MatrixType,_UpLo> > Base;
00437     typedef typename Base::Scalar Scalar;
00438     typedef typename Base::RealScalar RealScalar;
00439     using Base::pardisoInit;
00440     using Base::m_matrix;
00441     friend class PardisoImpl< PardisoLLT<MatrixType,_UpLo> >;
00442 
00443   public:
00444 
00445     typedef typename Base::StorageIndex StorageIndex;
00446     enum { UpLo = _UpLo };
00447     using Base::compute;
00448 
00449     PardisoLLT()
00450       : Base()
00451     {
00452       pardisoInit(Base::ScalarIsComplex ? 4 : 2);
00453     }
00454 
00455     explicit PardisoLLT(const MatrixType& matrix)
00456       : Base()
00457     {
00458       pardisoInit(Base::ScalarIsComplex ? 4 : 2);
00459       compute(matrix);
00460     }
00461     
00462   protected:
00463     
00464     void getMatrix(const MatrixType& matrix)
00465     {
00466       // PARDISO supports only upper, row-major matrices
00467       PermutationMatrix<Dynamic,Dynamic,StorageIndex> p_null;
00468       m_matrix.resize(matrix.rows(), matrix.cols());
00469       m_matrix.template selfadjointView<Upper>() = matrix.template selfadjointView<UpLo>().twistedBy(p_null);
00470       m_matrix.makeCompressed();
00471     }
00472 };
00473 
00492 template<typename MatrixType, int Options>
00493 class PardisoLDLT : public PardisoImpl< PardisoLDLT<MatrixType,Options> >
00494 {
00495   protected:
00496     typedef PardisoImpl< PardisoLDLT<MatrixType,Options> > Base;
00497     typedef typename Base::Scalar Scalar;
00498     typedef typename Base::RealScalar RealScalar;
00499     using Base::pardisoInit;
00500     using Base::m_matrix;
00501     friend class PardisoImpl< PardisoLDLT<MatrixType,Options> >;
00502 
00503   public:
00504 
00505     typedef typename Base::StorageIndex StorageIndex;
00506     using Base::compute;
00507     enum { UpLo = Options&(Upper|Lower) };
00508 
00509     PardisoLDLT()
00510       : Base()
00511     {
00512       pardisoInit(Base::ScalarIsComplex ? ( bool(Options&Symmetric) ? 6 : -4 ) : -2);
00513     }
00514 
00515     explicit PardisoLDLT(const MatrixType& matrix)
00516       : Base()
00517     {
00518       pardisoInit(Base::ScalarIsComplex ? ( bool(Options&Symmetric) ? 6 : -4 ) : -2);
00519       compute(matrix);
00520     }
00521     
00522     void getMatrix(const MatrixType& matrix)
00523     {
00524       // PARDISO supports only upper, row-major matrices
00525       PermutationMatrix<Dynamic,Dynamic,StorageIndex> p_null;
00526       m_matrix.resize(matrix.rows(), matrix.cols());
00527       m_matrix.template selfadjointView<Upper>() = matrix.template selfadjointView<UpLo>().twistedBy(p_null);
00528       m_matrix.makeCompressed();
00529     }
00530 };
00531 
00532 } // end namespace Eigen
00533 
00534 #endif // EIGEN_PARDISOSUPPORT_H
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines