| /* |
| Copyright (c) 2011, Intel Corporation. All rights reserved. |
| |
| Redistribution and use in source and binary forms, with or without modification, |
| are permitted provided that the following conditions are met: |
| |
| * Redistributions of source code must retain the above copyright notice, this |
| list of conditions and the following disclaimer. |
| * Redistributions in binary form must reproduce the above copyright notice, |
| this list of conditions and the following disclaimer in the documentation |
| and/or other materials provided with the distribution. |
| * Neither the name of Intel Corporation nor the names of its contributors may |
| be used to endorse or promote products derived from this software without |
| specific prior written permission. |
| |
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR |
| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
| ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| ******************************************************************************** |
| * Content : Eigen bindings to Intel(R) MKL PARDISO |
| ******************************************************************************** |
| */ |
| |
| #ifndef EIGEN_PARDISOSUPPORT_H |
| #define EIGEN_PARDISOSUPPORT_H |
| |
| // IWYU pragma: private |
| #include "./InternalHeaderCheck.h" |
| |
| namespace Eigen { |
| |
| template <typename MatrixType_> |
| class PardisoLU; |
| template <typename MatrixType_, int Options = Upper> |
| class PardisoLLT; |
| template <typename MatrixType_, int Options = Upper> |
| class PardisoLDLT; |
| |
| namespace internal { |
| template <typename IndexType> |
| struct pardiso_run_selector { |
| static IndexType run(_MKL_DSS_HANDLE_t pt, IndexType maxfct, IndexType mnum, IndexType type, IndexType phase, |
| IndexType n, void* a, IndexType* ia, IndexType* ja, IndexType* perm, IndexType nrhs, |
| IndexType* iparm, IndexType msglvl, void* b, void* x) { |
| IndexType error = 0; |
| ::pardiso(pt, &maxfct, &mnum, &type, &phase, &n, a, ia, ja, perm, &nrhs, iparm, &msglvl, b, x, &error); |
| return error; |
| } |
| }; |
| template <> |
| struct pardiso_run_selector<long long int> { |
| typedef long long int IndexType; |
| static IndexType run(_MKL_DSS_HANDLE_t pt, IndexType maxfct, IndexType mnum, IndexType type, IndexType phase, |
| IndexType n, void* a, IndexType* ia, IndexType* ja, IndexType* perm, IndexType nrhs, |
| IndexType* iparm, IndexType msglvl, void* b, void* x) { |
| IndexType error = 0; |
| ::pardiso_64(pt, &maxfct, &mnum, &type, &phase, &n, a, ia, ja, perm, &nrhs, iparm, &msglvl, b, x, &error); |
| return error; |
| } |
| }; |
| |
| template <class Pardiso> |
| struct pardiso_traits; |
| |
| template <typename MatrixType_> |
| struct pardiso_traits<PardisoLU<MatrixType_> > { |
| typedef MatrixType_ MatrixType; |
| typedef typename MatrixType_::Scalar Scalar; |
| typedef typename MatrixType_::RealScalar RealScalar; |
| typedef typename MatrixType_::StorageIndex StorageIndex; |
| }; |
| |
| template <typename MatrixType_, int Options> |
| struct pardiso_traits<PardisoLLT<MatrixType_, Options> > { |
| typedef MatrixType_ MatrixType; |
| typedef typename MatrixType_::Scalar Scalar; |
| typedef typename MatrixType_::RealScalar RealScalar; |
| typedef typename MatrixType_::StorageIndex StorageIndex; |
| }; |
| |
| template <typename MatrixType_, int Options> |
| struct pardiso_traits<PardisoLDLT<MatrixType_, Options> > { |
| typedef MatrixType_ MatrixType; |
| typedef typename MatrixType_::Scalar Scalar; |
| typedef typename MatrixType_::RealScalar RealScalar; |
| typedef typename MatrixType_::StorageIndex StorageIndex; |
| }; |
| |
| } // end namespace internal |
| |
| template <class Derived> |
| class PardisoImpl : public SparseSolverBase<Derived> { |
| protected: |
| typedef SparseSolverBase<Derived> Base; |
| using Base::derived; |
| using Base::m_isInitialized; |
| |
| typedef internal::pardiso_traits<Derived> Traits; |
| |
| public: |
| using Base::_solve_impl; |
| |
| typedef typename Traits::MatrixType MatrixType; |
| typedef typename Traits::Scalar Scalar; |
| typedef typename Traits::RealScalar RealScalar; |
| typedef typename Traits::StorageIndex StorageIndex; |
| typedef SparseMatrix<Scalar, RowMajor, StorageIndex> SparseMatrixType; |
| typedef Matrix<Scalar, Dynamic, 1> VectorType; |
| typedef Matrix<StorageIndex, 1, MatrixType::ColsAtCompileTime> IntRowVectorType; |
| typedef Matrix<StorageIndex, MatrixType::RowsAtCompileTime, 1> IntColVectorType; |
| typedef Array<StorageIndex, 64, 1, DontAlign> ParameterType; |
| enum { ScalarIsComplex = NumTraits<Scalar>::IsComplex, ColsAtCompileTime = Dynamic, MaxColsAtCompileTime = Dynamic }; |
| |
| PardisoImpl() : m_analysisIsOk(false), m_factorizationIsOk(false) { |
| eigen_assert((sizeof(StorageIndex) >= sizeof(_INTEGER_t) && sizeof(StorageIndex) <= 8) && |
| "Non-supported index type"); |
| m_iparm.setZero(); |
| m_msglvl = 0; // No output |
| m_isInitialized = false; |
| } |
| |
| ~PardisoImpl() { pardisoRelease(); } |
| |
| inline Index cols() const { return m_size; } |
| inline Index rows() const { return m_size; } |
| |
| /** \brief Reports whether previous computation was successful. |
| * |
| * \returns \c Success if computation was successful, |
| * \c NumericalIssue if the matrix appears to be negative. |
| */ |
| ComputationInfo info() const { |
| eigen_assert(m_isInitialized && "Decomposition is not initialized."); |
| return m_info; |
| } |
| |
| /** \warning for advanced usage only. |
| * \returns a reference to the parameter array controlling PARDISO. |
| * See the PARDISO manual to know how to use it. */ |
| ParameterType& pardisoParameterArray() { return m_iparm; } |
| |
| /** Performs a symbolic decomposition on the sparcity of \a matrix. |
| * |
| * This function is particularly useful when solving for several problems having the same structure. |
| * |
| * \sa factorize() |
| */ |
| Derived& analyzePattern(const MatrixType& matrix); |
| |
| /** Performs a numeric decomposition of \a matrix |
| * |
| * The given matrix must has the same sparcity than the matrix on which the symbolic decomposition has been performed. |
| * |
| * \sa analyzePattern() |
| */ |
| Derived& factorize(const MatrixType& matrix); |
| |
| Derived& compute(const MatrixType& matrix); |
| |
| template <typename Rhs, typename Dest> |
| void _solve_impl(const MatrixBase<Rhs>& b, MatrixBase<Dest>& dest) const; |
| |
| protected: |
| void pardisoRelease() { |
| if (m_isInitialized) // Factorization ran at least once |
| { |
| internal::pardiso_run_selector<StorageIndex>::run(m_pt, 1, 1, m_type, -1, |
| internal::convert_index<StorageIndex>(m_size), 0, 0, 0, |
| m_perm.data(), 0, m_iparm.data(), m_msglvl, NULL, NULL); |
| m_isInitialized = false; |
| } |
| } |
| |
| void pardisoInit(int type) { |
| m_type = type; |
| bool symmetric = std::abs(m_type) < 10; |
| m_iparm[0] = 1; // No solver default |
| m_iparm[1] = 2; // use Metis for the ordering |
| m_iparm[2] = 0; // Reserved. Set to zero. (??Numbers of processors, value of OMP_NUM_THREADS??) |
| m_iparm[3] = 0; // No iterative-direct algorithm |
| m_iparm[4] = 0; // No user fill-in reducing permutation |
| m_iparm[5] = 0; // Write solution into x, b is left unchanged |
| m_iparm[6] = 0; // Not in use |
| m_iparm[7] = 2; // Max numbers of iterative refinement steps |
| m_iparm[8] = 0; // Not in use |
| m_iparm[9] = 13; // Perturb the pivot elements with 1E-13 |
| m_iparm[10] = symmetric ? 0 : 1; // Use nonsymmetric permutation and scaling MPS |
| m_iparm[11] = 0; // Not in use |
| m_iparm[12] = symmetric ? 0 : 1; // Maximum weighted matching algorithm is switched-off (default for symmetric). |
| // Try m_iparm[12] = 1 in case of inappropriate accuracy |
| m_iparm[13] = 0; // Output: Number of perturbed pivots |
| m_iparm[14] = 0; // Not in use |
| m_iparm[15] = 0; // Not in use |
| m_iparm[16] = 0; // Not in use |
| m_iparm[17] = -1; // Output: Number of nonzeros in the factor LU |
| m_iparm[18] = -1; // Output: Mflops for LU factorization |
| m_iparm[19] = 0; // Output: Numbers of CG Iterations |
| |
| m_iparm[20] = 0; // 1x1 pivoting |
| m_iparm[26] = 0; // No matrix checker |
| m_iparm[27] = (sizeof(RealScalar) == 4) ? 1 : 0; |
| m_iparm[34] = 1; // C indexing |
| m_iparm[36] = 0; // CSR |
| m_iparm[59] = 0; // 0 - In-Core ; 1 - Automatic switch between In-Core and Out-of-Core modes ; 2 - Out-of-Core |
| |
| memset(m_pt, 0, sizeof(m_pt)); |
| } |
| |
| protected: |
| // cached data to reduce reallocation, etc. |
| |
| void manageErrorCode(Index error) const { |
| switch (error) { |
| case 0: |
| m_info = Success; |
| break; |
| case -4: |
| case -7: |
| m_info = NumericalIssue; |
| break; |
| default: |
| m_info = InvalidInput; |
| } |
| } |
| |
| mutable SparseMatrixType m_matrix; |
| mutable ComputationInfo m_info; |
| bool m_analysisIsOk, m_factorizationIsOk; |
| StorageIndex m_type, m_msglvl; |
| mutable void* m_pt[64]; |
| mutable ParameterType m_iparm; |
| mutable IntColVectorType m_perm; |
| Index m_size; |
| }; |
| |
| template <class Derived> |
| Derived& PardisoImpl<Derived>::compute(const MatrixType& a) { |
| m_size = a.rows(); |
| eigen_assert(a.rows() == a.cols()); |
| |
| pardisoRelease(); |
| m_perm.setZero(m_size); |
| derived().getMatrix(a); |
| |
| Index error; |
| error = internal::pardiso_run_selector<StorageIndex>::run( |
| m_pt, 1, 1, m_type, 12, internal::convert_index<StorageIndex>(m_size), m_matrix.valuePtr(), |
| m_matrix.outerIndexPtr(), m_matrix.innerIndexPtr(), m_perm.data(), 0, m_iparm.data(), m_msglvl, NULL, NULL); |
| manageErrorCode(error); |
| m_analysisIsOk = m_info == Eigen::Success; |
| m_factorizationIsOk = m_info == Eigen::Success; |
| m_isInitialized = true; |
| return derived(); |
| } |
| |
| template <class Derived> |
| Derived& PardisoImpl<Derived>::analyzePattern(const MatrixType& a) { |
| m_size = a.rows(); |
| eigen_assert(m_size == a.cols()); |
| |
| pardisoRelease(); |
| m_perm.setZero(m_size); |
| derived().getMatrix(a); |
| |
| Index error; |
| error = internal::pardiso_run_selector<StorageIndex>::run( |
| m_pt, 1, 1, m_type, 11, internal::convert_index<StorageIndex>(m_size), m_matrix.valuePtr(), |
| m_matrix.outerIndexPtr(), m_matrix.innerIndexPtr(), m_perm.data(), 0, m_iparm.data(), m_msglvl, NULL, NULL); |
| |
| manageErrorCode(error); |
| m_analysisIsOk = m_info == Eigen::Success; |
| m_factorizationIsOk = false; |
| m_isInitialized = true; |
| return derived(); |
| } |
| |
| template <class Derived> |
| Derived& PardisoImpl<Derived>::factorize(const MatrixType& a) { |
| eigen_assert(m_analysisIsOk && "You must first call analyzePattern()"); |
| eigen_assert(m_size == a.rows() && m_size == a.cols()); |
| |
| derived().getMatrix(a); |
| |
| Index error; |
| error = internal::pardiso_run_selector<StorageIndex>::run( |
| m_pt, 1, 1, m_type, 22, internal::convert_index<StorageIndex>(m_size), m_matrix.valuePtr(), |
| m_matrix.outerIndexPtr(), m_matrix.innerIndexPtr(), m_perm.data(), 0, m_iparm.data(), m_msglvl, NULL, NULL); |
| |
| manageErrorCode(error); |
| m_factorizationIsOk = m_info == Eigen::Success; |
| return derived(); |
| } |
| |
| template <class Derived> |
| template <typename BDerived, typename XDerived> |
| void PardisoImpl<Derived>::_solve_impl(const MatrixBase<BDerived>& b, MatrixBase<XDerived>& x) const { |
| if (m_iparm[0] == 0) // Factorization was not computed |
| { |
| m_info = InvalidInput; |
| return; |
| } |
| |
| // Index n = m_matrix.rows(); |
| Index nrhs = Index(b.cols()); |
| eigen_assert(m_size == b.rows()); |
| eigen_assert(((MatrixBase<BDerived>::Flags & RowMajorBit) == 0 || nrhs == 1) && |
| "Row-major right hand sides are not supported"); |
| eigen_assert(((MatrixBase<XDerived>::Flags & RowMajorBit) == 0 || nrhs == 1) && |
| "Row-major matrices of unknowns are not supported"); |
| eigen_assert(((nrhs == 1) || b.outerStride() == b.rows())); |
| |
| // switch (transposed) { |
| // case SvNoTrans : m_iparm[11] = 0 ; break; |
| // case SvTranspose : m_iparm[11] = 2 ; break; |
| // case SvAdjoint : m_iparm[11] = 1 ; break; |
| // default: |
| // //std::cerr << "Eigen: transposition option \"" << transposed << "\" not supported by the PARDISO backend\n"; |
| // m_iparm[11] = 0; |
| // } |
| |
| Scalar* rhs_ptr = const_cast<Scalar*>(b.derived().data()); |
| Matrix<Scalar, Dynamic, Dynamic, ColMajor> tmp; |
| |
| // Pardiso cannot solve in-place |
| if (rhs_ptr == x.derived().data()) { |
| tmp = b; |
| rhs_ptr = tmp.data(); |
| } |
| |
| Index error; |
| error = internal::pardiso_run_selector<StorageIndex>::run( |
| m_pt, 1, 1, m_type, 33, internal::convert_index<StorageIndex>(m_size), m_matrix.valuePtr(), |
| m_matrix.outerIndexPtr(), m_matrix.innerIndexPtr(), m_perm.data(), internal::convert_index<StorageIndex>(nrhs), |
| m_iparm.data(), m_msglvl, rhs_ptr, x.derived().data()); |
| |
| manageErrorCode(error); |
| } |
| |
| /** \ingroup PardisoSupport_Module |
| * \class PardisoLU |
| * \brief A sparse direct LU factorization and solver based on the PARDISO library |
| * |
| * This class allows to solve for A.X = B sparse linear problems via a direct LU factorization |
| * using the Intel MKL PARDISO library. The sparse matrix A must be squared and invertible. |
| * The vectors or matrices X and B can be either dense or sparse. |
| * |
| * By default, it runs in in-core mode. To enable PARDISO's out-of-core feature, set: |
| * \code solver.pardisoParameterArray()[59] = 1; \endcode |
| * |
| * \tparam MatrixType_ the type of the sparse matrix A, it must be a SparseMatrix<> |
| * |
| * \implsparsesolverconcept |
| * |
| * \sa \ref TutorialSparseSolverConcept, class SparseLU |
| */ |
| template <typename MatrixType> |
| class PardisoLU : public PardisoImpl<PardisoLU<MatrixType> > { |
| protected: |
| typedef PardisoImpl<PardisoLU> Base; |
| using Base::m_matrix; |
| using Base::pardisoInit; |
| friend class PardisoImpl<PardisoLU<MatrixType> >; |
| |
| public: |
| typedef typename Base::Scalar Scalar; |
| typedef typename Base::RealScalar RealScalar; |
| |
| using Base::compute; |
| using Base::solve; |
| |
| PardisoLU() : Base() { pardisoInit(Base::ScalarIsComplex ? 13 : 11); } |
| |
| explicit PardisoLU(const MatrixType& matrix) : Base() { |
| pardisoInit(Base::ScalarIsComplex ? 13 : 11); |
| compute(matrix); |
| } |
| |
| protected: |
| void getMatrix(const MatrixType& matrix) { |
| m_matrix = matrix; |
| m_matrix.makeCompressed(); |
| } |
| }; |
| |
| /** \ingroup PardisoSupport_Module |
| * \class PardisoLLT |
| * \brief A sparse direct Cholesky (LLT) factorization and solver based on the PARDISO library |
| * |
| * This class allows to solve for A.X = B sparse linear problems via a LL^T Cholesky factorization |
| * using the Intel MKL PARDISO library. The sparse matrix A must be selfajoint and positive definite. |
| * The vectors or matrices X and B can be either dense or sparse. |
| * |
| * By default, it runs in in-core mode. To enable PARDISO's out-of-core feature, set: |
| * \code solver.pardisoParameterArray()[59] = 1; \endcode |
| * |
| * \tparam MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> |
| * \tparam UpLo can be any bitwise combination of Upper, Lower. The default is Upper, meaning only the upper triangular |
| * part has to be used. Upper|Lower can be used to tell both triangular parts can be used as input. |
| * |
| * \implsparsesolverconcept |
| * |
| * \sa \ref TutorialSparseSolverConcept, class SimplicialLLT |
| */ |
| template <typename MatrixType, int UpLo_> |
| class PardisoLLT : public PardisoImpl<PardisoLLT<MatrixType, UpLo_> > { |
| protected: |
| typedef PardisoImpl<PardisoLLT<MatrixType, UpLo_> > Base; |
| using Base::m_matrix; |
| using Base::pardisoInit; |
| friend class PardisoImpl<PardisoLLT<MatrixType, UpLo_> >; |
| |
| public: |
| typedef typename Base::Scalar Scalar; |
| typedef typename Base::RealScalar RealScalar; |
| typedef typename Base::StorageIndex StorageIndex; |
| enum { UpLo = UpLo_ }; |
| using Base::compute; |
| |
| PardisoLLT() : Base() { pardisoInit(Base::ScalarIsComplex ? 4 : 2); } |
| |
| explicit PardisoLLT(const MatrixType& matrix) : Base() { |
| pardisoInit(Base::ScalarIsComplex ? 4 : 2); |
| compute(matrix); |
| } |
| |
| protected: |
| void getMatrix(const MatrixType& matrix) { |
| // PARDISO supports only upper, row-major matrices |
| PermutationMatrix<Dynamic, Dynamic, StorageIndex> p_null; |
| m_matrix.resize(matrix.rows(), matrix.cols()); |
| m_matrix.template selfadjointView<Upper>() = matrix.template selfadjointView<UpLo>().twistedBy(p_null); |
| m_matrix.makeCompressed(); |
| } |
| }; |
| |
| /** \ingroup PardisoSupport_Module |
| * \class PardisoLDLT |
| * \brief A sparse direct Cholesky (LDLT) factorization and solver based on the PARDISO library |
| * |
| * This class allows to solve for A.X = B sparse linear problems via a LDL^T Cholesky factorization |
| * using the Intel MKL PARDISO library. The sparse matrix A is assumed to be selfajoint and positive definite. |
| * For complex matrices, A can also be symmetric only, see the \a Options template parameter. |
| * The vectors or matrices X and B can be either dense or sparse. |
| * |
| * By default, it runs in in-core mode. To enable PARDISO's out-of-core feature, set: |
| * \code solver.pardisoParameterArray()[59] = 1; \endcode |
| * |
| * \tparam MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> |
| * \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. Symmetric can be used for symmetric, non-selfadjoint complex matrices, the |
| * default being to assume a selfadjoint matrix. Upper|Lower can be used to tell both triangular parts can be used as |
| * input. |
| * |
| * \implsparsesolverconcept |
| * |
| * \sa \ref TutorialSparseSolverConcept, class SimplicialLDLT |
| */ |
| template <typename MatrixType, int Options> |
| class PardisoLDLT : public PardisoImpl<PardisoLDLT<MatrixType, Options> > { |
| protected: |
| typedef PardisoImpl<PardisoLDLT<MatrixType, Options> > Base; |
| using Base::m_matrix; |
| using Base::pardisoInit; |
| friend class PardisoImpl<PardisoLDLT<MatrixType, Options> >; |
| |
| public: |
| typedef typename Base::Scalar Scalar; |
| typedef typename Base::RealScalar RealScalar; |
| typedef typename Base::StorageIndex StorageIndex; |
| using Base::compute; |
| enum { UpLo = Options & (Upper | Lower) }; |
| |
| PardisoLDLT() : Base() { pardisoInit(Base::ScalarIsComplex ? (bool(Options & Symmetric) ? 6 : -4) : -2); } |
| |
| explicit PardisoLDLT(const MatrixType& matrix) : Base() { |
| pardisoInit(Base::ScalarIsComplex ? (bool(Options & Symmetric) ? 6 : -4) : -2); |
| compute(matrix); |
| } |
| |
| void getMatrix(const MatrixType& matrix) { |
| // PARDISO supports only upper, row-major matrices |
| PermutationMatrix<Dynamic, Dynamic, StorageIndex> p_null; |
| m_matrix.resize(matrix.rows(), matrix.cols()); |
| m_matrix.template selfadjointView<Upper>() = matrix.template selfadjointView<UpLo>().twistedBy(p_null); |
| m_matrix.makeCompressed(); |
| } |
| }; |
| |
| } // end namespace Eigen |
| |
| #endif // EIGEN_PARDISOSUPPORT_H |