| // This file is part of Eigen, a lightweight C++ template library |
| // for linear algebra. |
| // |
| // Copyright (C) 2008-2015 Gael Guennebaud <gael.guennebaud@inria.fr> |
| // |
| // This Source Code Form is subject to the terms of the Mozilla |
| // Public License v. 2.0. If a copy of the MPL was not distributed |
| // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. |
| |
| #ifndef EIGEN_SUPERLUSUPPORT_H |
| #define EIGEN_SUPERLUSUPPORT_H |
| |
| // IWYU pragma: private |
| #include "./InternalHeaderCheck.h" |
| |
| namespace Eigen { |
| |
| #if defined(SUPERLU_MAJOR_VERSION) && (SUPERLU_MAJOR_VERSION >= 5) |
| #define DECL_GSSVX(PREFIX, FLOATTYPE, KEYTYPE) \ |
| extern "C" { \ |
| extern void PREFIX##gssvx(superlu_options_t *, SuperMatrix *, int *, int *, int *, char *, FLOATTYPE *, FLOATTYPE *, \ |
| SuperMatrix *, SuperMatrix *, void *, int, SuperMatrix *, SuperMatrix *, FLOATTYPE *, \ |
| FLOATTYPE *, FLOATTYPE *, FLOATTYPE *, GlobalLU_t *, mem_usage_t *, SuperLUStat_t *, \ |
| int *); \ |
| } \ |
| inline float SuperLU_gssvx(superlu_options_t *options, SuperMatrix *A, int *perm_c, int *perm_r, int *etree, \ |
| char *equed, FLOATTYPE *R, FLOATTYPE *C, SuperMatrix *L, SuperMatrix *U, void *work, \ |
| int lwork, SuperMatrix *B, SuperMatrix *X, FLOATTYPE *recip_pivot_growth, \ |
| FLOATTYPE *rcond, FLOATTYPE *ferr, FLOATTYPE *berr, SuperLUStat_t *stats, int *info, \ |
| KEYTYPE) { \ |
| mem_usage_t mem_usage; \ |
| GlobalLU_t gLU; \ |
| PREFIX##gssvx(options, A, perm_c, perm_r, etree, equed, R, C, L, U, work, lwork, B, X, recip_pivot_growth, rcond, \ |
| ferr, berr, &gLU, &mem_usage, stats, info); \ |
| return mem_usage.for_lu; /* bytes used by the factor storage */ \ |
| } |
| #else // version < 5.0 |
| #define DECL_GSSVX(PREFIX, FLOATTYPE, KEYTYPE) \ |
| extern "C" { \ |
| extern void PREFIX##gssvx(superlu_options_t *, SuperMatrix *, int *, int *, int *, char *, FLOATTYPE *, FLOATTYPE *, \ |
| SuperMatrix *, SuperMatrix *, void *, int, SuperMatrix *, SuperMatrix *, FLOATTYPE *, \ |
| FLOATTYPE *, FLOATTYPE *, FLOATTYPE *, mem_usage_t *, SuperLUStat_t *, int *); \ |
| } \ |
| inline float SuperLU_gssvx(superlu_options_t *options, SuperMatrix *A, int *perm_c, int *perm_r, int *etree, \ |
| char *equed, FLOATTYPE *R, FLOATTYPE *C, SuperMatrix *L, SuperMatrix *U, void *work, \ |
| int lwork, SuperMatrix *B, SuperMatrix *X, FLOATTYPE *recip_pivot_growth, \ |
| FLOATTYPE *rcond, FLOATTYPE *ferr, FLOATTYPE *berr, SuperLUStat_t *stats, int *info, \ |
| KEYTYPE) { \ |
| mem_usage_t mem_usage; \ |
| PREFIX##gssvx(options, A, perm_c, perm_r, etree, equed, R, C, L, U, work, lwork, B, X, recip_pivot_growth, rcond, \ |
| ferr, berr, &mem_usage, stats, info); \ |
| return mem_usage.for_lu; /* bytes used by the factor storage */ \ |
| } |
| #endif |
| |
| DECL_GSSVX(s, float, float) |
| DECL_GSSVX(c, float, std::complex<float>) |
| DECL_GSSVX(d, double, double) |
| DECL_GSSVX(z, double, std::complex<double>) |
| |
| #ifdef MILU_ALPHA |
| #define EIGEN_SUPERLU_HAS_ILU |
| #endif |
| |
| #ifdef EIGEN_SUPERLU_HAS_ILU |
| |
| // similarly for the incomplete factorization using gsisx |
| #define DECL_GSISX(PREFIX, FLOATTYPE, KEYTYPE) \ |
| extern "C" { \ |
| extern void PREFIX##gsisx(superlu_options_t *, SuperMatrix *, int *, int *, int *, char *, FLOATTYPE *, FLOATTYPE *, \ |
| SuperMatrix *, SuperMatrix *, void *, int, SuperMatrix *, SuperMatrix *, FLOATTYPE *, \ |
| FLOATTYPE *, mem_usage_t *, SuperLUStat_t *, int *); \ |
| } \ |
| inline float SuperLU_gsisx(superlu_options_t *options, SuperMatrix *A, int *perm_c, int *perm_r, int *etree, \ |
| char *equed, FLOATTYPE *R, FLOATTYPE *C, SuperMatrix *L, SuperMatrix *U, void *work, \ |
| int lwork, SuperMatrix *B, SuperMatrix *X, FLOATTYPE *recip_pivot_growth, \ |
| FLOATTYPE *rcond, SuperLUStat_t *stats, int *info, KEYTYPE) { \ |
| mem_usage_t mem_usage; \ |
| PREFIX##gsisx(options, A, perm_c, perm_r, etree, equed, R, C, L, U, work, lwork, B, X, recip_pivot_growth, rcond, \ |
| &mem_usage, stats, info); \ |
| return mem_usage.for_lu; /* bytes used by the factor storage */ \ |
| } |
| |
| DECL_GSISX(s, float, float) |
| DECL_GSISX(c, float, std::complex<float>) |
| DECL_GSISX(d, double, double) |
| DECL_GSISX(z, double, std::complex<double>) |
| |
| #endif |
| |
| template <typename MatrixType> |
| struct SluMatrixMapHelper; |
| |
| /** \internal |
| * |
| * A wrapper class for SuperLU matrices. It supports only compressed sparse matrices |
| * and dense matrices. Supernodal and other fancy format are not supported by this wrapper. |
| * |
| * This wrapper class mainly aims to avoids the need of dynamic allocation of the storage structure. |
| */ |
| struct SluMatrix : SuperMatrix { |
| SluMatrix() { Store = &storage; } |
| |
| SluMatrix(const SluMatrix &other) : SuperMatrix(other) { |
| Store = &storage; |
| storage = other.storage; |
| } |
| |
| SluMatrix &operator=(const SluMatrix &other) { |
| SuperMatrix::operator=(static_cast<const SuperMatrix &>(other)); |
| Store = &storage; |
| storage = other.storage; |
| return *this; |
| } |
| |
| struct { |
| union { |
| int nnz; |
| int lda; |
| }; |
| void *values; |
| int *innerInd; |
| int *outerInd; |
| } storage; |
| |
| void setStorageType(Stype_t t) { |
| Stype = t; |
| if (t == SLU_NC || t == SLU_NR || t == SLU_DN) |
| Store = &storage; |
| else { |
| eigen_assert(false && "storage type not supported"); |
| Store = 0; |
| } |
| } |
| |
| template <typename Scalar> |
| void setScalarType() { |
| if (internal::is_same<Scalar, float>::value) |
| Dtype = SLU_S; |
| else if (internal::is_same<Scalar, double>::value) |
| Dtype = SLU_D; |
| else if (internal::is_same<Scalar, std::complex<float> >::value) |
| Dtype = SLU_C; |
| else if (internal::is_same<Scalar, std::complex<double> >::value) |
| Dtype = SLU_Z; |
| else { |
| eigen_assert(false && "Scalar type not supported by SuperLU"); |
| } |
| } |
| |
| template <typename MatrixType> |
| static SluMatrix Map(MatrixBase<MatrixType> &_mat) { |
| MatrixType &mat(_mat.derived()); |
| eigen_assert(((MatrixType::Flags & RowMajorBit) != RowMajorBit) && |
| "row-major dense matrices are not supported by SuperLU"); |
| SluMatrix res; |
| res.setStorageType(SLU_DN); |
| res.setScalarType<typename MatrixType::Scalar>(); |
| res.Mtype = SLU_GE; |
| |
| res.nrow = internal::convert_index<int>(mat.rows()); |
| res.ncol = internal::convert_index<int>(mat.cols()); |
| |
| res.storage.lda = internal::convert_index<int>(MatrixType::IsVectorAtCompileTime ? mat.size() : mat.outerStride()); |
| res.storage.values = (void *)(mat.data()); |
| return res; |
| } |
| |
| template <typename MatrixType> |
| static SluMatrix Map(SparseMatrixBase<MatrixType> &a_mat) { |
| MatrixType &mat(a_mat.derived()); |
| SluMatrix res; |
| if ((MatrixType::Flags & RowMajorBit) == RowMajorBit) { |
| res.setStorageType(SLU_NR); |
| res.nrow = internal::convert_index<int>(mat.cols()); |
| res.ncol = internal::convert_index<int>(mat.rows()); |
| } else { |
| res.setStorageType(SLU_NC); |
| res.nrow = internal::convert_index<int>(mat.rows()); |
| res.ncol = internal::convert_index<int>(mat.cols()); |
| } |
| |
| res.Mtype = SLU_GE; |
| |
| res.storage.nnz = internal::convert_index<int>(mat.nonZeros()); |
| res.storage.values = mat.valuePtr(); |
| res.storage.innerInd = mat.innerIndexPtr(); |
| res.storage.outerInd = mat.outerIndexPtr(); |
| |
| res.setScalarType<typename MatrixType::Scalar>(); |
| |
| // FIXME the following is not very accurate |
| if (int(MatrixType::Flags) & int(Upper)) res.Mtype = SLU_TRU; |
| if (int(MatrixType::Flags) & int(Lower)) res.Mtype = SLU_TRL; |
| |
| eigen_assert(((int(MatrixType::Flags) & int(SelfAdjoint)) == 0) && |
| "SelfAdjoint matrix shape not supported by SuperLU"); |
| |
| return res; |
| } |
| }; |
| |
| template <typename Scalar, int Rows, int Cols, int Options, int MRows, int MCols> |
| struct SluMatrixMapHelper<Matrix<Scalar, Rows, Cols, Options, MRows, MCols> > { |
| typedef Matrix<Scalar, Rows, Cols, Options, MRows, MCols> MatrixType; |
| static void run(MatrixType &mat, SluMatrix &res) { |
| eigen_assert(((Options & RowMajor) != RowMajor) && "row-major dense matrices is not supported by SuperLU"); |
| res.setStorageType(SLU_DN); |
| res.setScalarType<Scalar>(); |
| res.Mtype = SLU_GE; |
| |
| res.nrow = mat.rows(); |
| res.ncol = mat.cols(); |
| |
| res.storage.lda = mat.outerStride(); |
| res.storage.values = mat.data(); |
| } |
| }; |
| |
| template <typename Derived> |
| struct SluMatrixMapHelper<SparseMatrixBase<Derived> > { |
| typedef Derived MatrixType; |
| static void run(MatrixType &mat, SluMatrix &res) { |
| if ((MatrixType::Flags & RowMajorBit) == RowMajorBit) { |
| res.setStorageType(SLU_NR); |
| res.nrow = mat.cols(); |
| res.ncol = mat.rows(); |
| } else { |
| res.setStorageType(SLU_NC); |
| res.nrow = mat.rows(); |
| res.ncol = mat.cols(); |
| } |
| |
| res.Mtype = SLU_GE; |
| |
| res.storage.nnz = mat.nonZeros(); |
| res.storage.values = mat.valuePtr(); |
| res.storage.innerInd = mat.innerIndexPtr(); |
| res.storage.outerInd = mat.outerIndexPtr(); |
| |
| res.setScalarType<typename MatrixType::Scalar>(); |
| |
| // FIXME the following is not very accurate |
| if (MatrixType::Flags & Upper) res.Mtype = SLU_TRU; |
| if (MatrixType::Flags & Lower) res.Mtype = SLU_TRL; |
| |
| eigen_assert(((MatrixType::Flags & SelfAdjoint) == 0) && "SelfAdjoint matrix shape not supported by SuperLU"); |
| } |
| }; |
| |
| namespace internal { |
| |
| template <typename MatrixType> |
| SluMatrix asSluMatrix(MatrixType &mat) { |
| return SluMatrix::Map(mat); |
| } |
| |
| /** View a Super LU matrix as an Eigen expression */ |
| template <typename Scalar, int Flags, typename Index> |
| Map<SparseMatrix<Scalar, Flags, Index> > map_superlu(SluMatrix &sluMat) { |
| eigen_assert(((Flags & RowMajor) == RowMajor && sluMat.Stype == SLU_NR) || |
| ((Flags & ColMajor) == ColMajor && sluMat.Stype == SLU_NC)); |
| |
| Index outerSize = (Flags & RowMajor) == RowMajor ? sluMat.ncol : sluMat.nrow; |
| |
| return Map<SparseMatrix<Scalar, Flags, Index> >(sluMat.nrow, sluMat.ncol, sluMat.storage.outerInd[outerSize], |
| sluMat.storage.outerInd, sluMat.storage.innerInd, |
| reinterpret_cast<Scalar *>(sluMat.storage.values)); |
| } |
| |
| } // end namespace internal |
| |
| /** \ingroup SuperLUSupport_Module |
| * \class SuperLUBase |
| * \brief The base class for the direct and incomplete LU factorization of SuperLU |
| */ |
| template <typename MatrixType_, typename Derived> |
| class SuperLUBase : public SparseSolverBase<Derived> { |
| protected: |
| typedef SparseSolverBase<Derived> Base; |
| using Base::derived; |
| using Base::m_isInitialized; |
| |
| public: |
| typedef MatrixType_ MatrixType; |
| typedef typename MatrixType::Scalar Scalar; |
| typedef typename MatrixType::RealScalar RealScalar; |
| typedef typename MatrixType::StorageIndex StorageIndex; |
| typedef Matrix<Scalar, Dynamic, 1> Vector; |
| typedef Matrix<int, 1, MatrixType::ColsAtCompileTime> IntRowVectorType; |
| typedef Matrix<int, MatrixType::RowsAtCompileTime, 1> IntColVectorType; |
| typedef Map<PermutationMatrix<Dynamic, Dynamic, int> > PermutationMap; |
| typedef SparseMatrix<Scalar> LUMatrixType; |
| enum { ColsAtCompileTime = MatrixType::ColsAtCompileTime, MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime }; |
| |
| public: |
| SuperLUBase() {} |
| |
| ~SuperLUBase() { clearFactors(); } |
| |
| inline Index rows() const { return m_matrix.rows(); } |
| inline Index cols() const { return m_matrix.cols(); } |
| |
| /** \returns a reference to the Super LU option object to configure the Super LU algorithms. */ |
| inline superlu_options_t &options() { return m_sluOptions; } |
| |
| /** \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; |
| } |
| |
| /** Computes the sparse Cholesky decomposition of \a matrix */ |
| void compute(const MatrixType &matrix) { |
| derived().analyzePattern(matrix); |
| derived().factorize(matrix); |
| } |
| |
| /** 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() |
| */ |
| void analyzePattern(const MatrixType & /*matrix*/) { |
| m_isInitialized = true; |
| m_info = Success; |
| m_analysisIsOk = true; |
| m_factorizationIsOk = false; |
| } |
| |
| template <typename Stream> |
| void dumpMemory(Stream & /*s*/) {} |
| |
| protected: |
| void initFactorization(const MatrixType &a) { |
| set_default_options(&this->m_sluOptions); |
| |
| const Index size = a.rows(); |
| m_matrix = a; |
| |
| m_sluA = internal::asSluMatrix(m_matrix); |
| clearFactors(); |
| |
| m_p.resize(size); |
| m_q.resize(size); |
| m_sluRscale.resize(size); |
| m_sluCscale.resize(size); |
| m_sluEtree.resize(size); |
| |
| // set empty B and X |
| m_sluB.setStorageType(SLU_DN); |
| m_sluB.setScalarType<Scalar>(); |
| m_sluB.Mtype = SLU_GE; |
| m_sluB.storage.values = 0; |
| m_sluB.nrow = 0; |
| m_sluB.ncol = 0; |
| m_sluB.storage.lda = internal::convert_index<int>(size); |
| m_sluX = m_sluB; |
| |
| m_extractedDataAreDirty = true; |
| } |
| |
| void init() { |
| m_info = InvalidInput; |
| m_isInitialized = false; |
| m_sluL.Store = 0; |
| m_sluU.Store = 0; |
| } |
| |
| void extractData() const; |
| |
| void clearFactors() { |
| if (m_sluL.Store) Destroy_SuperNode_Matrix(&m_sluL); |
| if (m_sluU.Store) Destroy_CompCol_Matrix(&m_sluU); |
| |
| m_sluL.Store = 0; |
| m_sluU.Store = 0; |
| |
| memset(&m_sluL, 0, sizeof m_sluL); |
| memset(&m_sluU, 0, sizeof m_sluU); |
| } |
| |
| // cached data to reduce reallocation, etc. |
| mutable LUMatrixType m_l; |
| mutable LUMatrixType m_u; |
| mutable IntColVectorType m_p; |
| mutable IntRowVectorType m_q; |
| |
| mutable LUMatrixType m_matrix; // copy of the factorized matrix |
| mutable SluMatrix m_sluA; |
| mutable SuperMatrix m_sluL, m_sluU; |
| mutable SluMatrix m_sluB, m_sluX; |
| mutable SuperLUStat_t m_sluStat; |
| mutable superlu_options_t m_sluOptions; |
| mutable std::vector<int> m_sluEtree; |
| mutable Matrix<RealScalar, Dynamic, 1> m_sluRscale, m_sluCscale; |
| mutable Matrix<RealScalar, Dynamic, 1> m_sluFerr, m_sluBerr; |
| mutable char m_sluEqued; |
| |
| mutable ComputationInfo m_info; |
| int m_factorizationIsOk; |
| int m_analysisIsOk; |
| mutable bool m_extractedDataAreDirty; |
| |
| private: |
| SuperLUBase(SuperLUBase &) {} |
| }; |
| |
| /** \ingroup SuperLUSupport_Module |
| * \class SuperLU |
| * \brief A sparse direct LU factorization and solver based on the SuperLU library |
| * |
| * This class allows to solve for A.X = B sparse linear problems via a direct LU factorization |
| * using the SuperLU library. The sparse matrix A must be squared and invertible. The vectors or matrices |
| * X and B can be either dense or sparse. |
| * |
| * \tparam MatrixType_ the type of the sparse matrix A, it must be a SparseMatrix<> |
| * |
| * \warning This class is only for the 4.x versions of SuperLU. The 3.x and 5.x versions are not supported. |
| * |
| * \implsparsesolverconcept |
| * |
| * \sa \ref TutorialSparseSolverConcept, class SparseLU |
| */ |
| template <typename MatrixType_> |
| class SuperLU : public SuperLUBase<MatrixType_, SuperLU<MatrixType_> > { |
| public: |
| typedef SuperLUBase<MatrixType_, SuperLU> Base; |
| typedef MatrixType_ MatrixType; |
| typedef typename Base::Scalar Scalar; |
| typedef typename Base::RealScalar RealScalar; |
| typedef typename Base::StorageIndex StorageIndex; |
| typedef typename Base::IntRowVectorType IntRowVectorType; |
| typedef typename Base::IntColVectorType IntColVectorType; |
| typedef typename Base::PermutationMap PermutationMap; |
| typedef typename Base::LUMatrixType LUMatrixType; |
| typedef TriangularView<LUMatrixType, Lower | UnitDiag> LMatrixType; |
| typedef TriangularView<LUMatrixType, Upper> UMatrixType; |
| |
| public: |
| using Base::_solve_impl; |
| |
| SuperLU() : Base() { init(); } |
| |
| explicit SuperLU(const MatrixType &matrix) : Base() { |
| init(); |
| Base::compute(matrix); |
| } |
| |
| ~SuperLU() {} |
| |
| /** 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() |
| */ |
| void analyzePattern(const MatrixType &matrix) { |
| m_info = InvalidInput; |
| m_isInitialized = false; |
| Base::analyzePattern(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() |
| */ |
| void factorize(const MatrixType &matrix); |
| |
| /** \internal */ |
| template <typename Rhs, typename Dest> |
| void _solve_impl(const MatrixBase<Rhs> &b, MatrixBase<Dest> &dest) const; |
| |
| inline const LMatrixType &matrixL() const { |
| if (m_extractedDataAreDirty) this->extractData(); |
| return m_l; |
| } |
| |
| inline const UMatrixType &matrixU() const { |
| if (m_extractedDataAreDirty) this->extractData(); |
| return m_u; |
| } |
| |
| inline const IntColVectorType &permutationP() const { |
| if (m_extractedDataAreDirty) this->extractData(); |
| return m_p; |
| } |
| |
| inline const IntRowVectorType &permutationQ() const { |
| if (m_extractedDataAreDirty) this->extractData(); |
| return m_q; |
| } |
| |
| Scalar determinant() const; |
| |
| protected: |
| using Base::m_l; |
| using Base::m_matrix; |
| using Base::m_p; |
| using Base::m_q; |
| using Base::m_sluA; |
| using Base::m_sluB; |
| using Base::m_sluBerr; |
| using Base::m_sluCscale; |
| using Base::m_sluEqued; |
| using Base::m_sluEtree; |
| using Base::m_sluFerr; |
| using Base::m_sluL; |
| using Base::m_sluOptions; |
| using Base::m_sluRscale; |
| using Base::m_sluStat; |
| using Base::m_sluU; |
| using Base::m_sluX; |
| using Base::m_u; |
| |
| using Base::m_analysisIsOk; |
| using Base::m_extractedDataAreDirty; |
| using Base::m_factorizationIsOk; |
| using Base::m_info; |
| using Base::m_isInitialized; |
| |
| void init() { |
| Base::init(); |
| |
| set_default_options(&this->m_sluOptions); |
| m_sluOptions.PrintStat = NO; |
| m_sluOptions.ConditionNumber = NO; |
| m_sluOptions.Trans = NOTRANS; |
| m_sluOptions.ColPerm = COLAMD; |
| } |
| |
| private: |
| SuperLU(SuperLU &) {} |
| }; |
| |
| template <typename MatrixType> |
| void SuperLU<MatrixType>::factorize(const MatrixType &a) { |
| eigen_assert(m_analysisIsOk && "You must first call analyzePattern()"); |
| if (!m_analysisIsOk) { |
| m_info = InvalidInput; |
| return; |
| } |
| |
| this->initFactorization(a); |
| |
| m_sluOptions.ColPerm = COLAMD; |
| int info = 0; |
| RealScalar recip_pivot_growth, rcond; |
| RealScalar ferr, berr; |
| |
| StatInit(&m_sluStat); |
| SuperLU_gssvx(&m_sluOptions, &m_sluA, m_q.data(), m_p.data(), &m_sluEtree[0], &m_sluEqued, &m_sluRscale[0], |
| &m_sluCscale[0], &m_sluL, &m_sluU, NULL, 0, &m_sluB, &m_sluX, &recip_pivot_growth, &rcond, &ferr, &berr, |
| &m_sluStat, &info, Scalar()); |
| StatFree(&m_sluStat); |
| |
| m_extractedDataAreDirty = true; |
| |
| // FIXME how to better check for errors ??? |
| m_info = info == 0 ? Success : NumericalIssue; |
| m_factorizationIsOk = true; |
| } |
| |
| template <typename MatrixType> |
| template <typename Rhs, typename Dest> |
| void SuperLU<MatrixType>::_solve_impl(const MatrixBase<Rhs> &b, MatrixBase<Dest> &x) const { |
| eigen_assert(m_factorizationIsOk && |
| "The decomposition is not in a valid state for solving, you must first call either compute() or " |
| "analyzePattern()/factorize()"); |
| |
| const Index rhsCols = b.cols(); |
| eigen_assert(m_matrix.rows() == b.rows()); |
| |
| m_sluOptions.Trans = NOTRANS; |
| m_sluOptions.Fact = FACTORED; |
| m_sluOptions.IterRefine = NOREFINE; |
| |
| m_sluFerr.resize(rhsCols); |
| m_sluBerr.resize(rhsCols); |
| |
| Ref<const Matrix<typename Rhs::Scalar, Dynamic, Dynamic, ColMajor> > b_ref(b); |
| Ref<const Matrix<typename Dest::Scalar, Dynamic, Dynamic, ColMajor> > x_ref(x); |
| |
| m_sluB = SluMatrix::Map(b_ref.const_cast_derived()); |
| m_sluX = SluMatrix::Map(x_ref.const_cast_derived()); |
| |
| typename Rhs::PlainObject b_cpy; |
| if (m_sluEqued != 'N') { |
| b_cpy = b; |
| m_sluB = SluMatrix::Map(b_cpy.const_cast_derived()); |
| } |
| |
| StatInit(&m_sluStat); |
| int info = 0; |
| RealScalar recip_pivot_growth, rcond; |
| SuperLU_gssvx(&m_sluOptions, &m_sluA, m_q.data(), m_p.data(), &m_sluEtree[0], &m_sluEqued, &m_sluRscale[0], |
| &m_sluCscale[0], &m_sluL, &m_sluU, NULL, 0, &m_sluB, &m_sluX, &recip_pivot_growth, &rcond, |
| &m_sluFerr[0], &m_sluBerr[0], &m_sluStat, &info, Scalar()); |
| StatFree(&m_sluStat); |
| |
| if (x.derived().data() != x_ref.data()) x = x_ref; |
| |
| m_info = info == 0 ? Success : NumericalIssue; |
| } |
| |
| // the code of this extractData() function has been adapted from the SuperLU's Matlab support code, |
| // |
| // Copyright (c) 1994 by Xerox Corporation. All rights reserved. |
| // |
| // THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY |
| // EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. |
| // |
| template <typename MatrixType, typename Derived> |
| void SuperLUBase<MatrixType, Derived>::extractData() const { |
| eigen_assert(m_factorizationIsOk && |
| "The decomposition is not in a valid state for extracting factors, you must first call either compute() " |
| "or analyzePattern()/factorize()"); |
| if (m_extractedDataAreDirty) { |
| int upper; |
| int fsupc, istart, nsupr; |
| int lastl = 0, lastu = 0; |
| SCformat *Lstore = static_cast<SCformat *>(m_sluL.Store); |
| NCformat *Ustore = static_cast<NCformat *>(m_sluU.Store); |
| Scalar *SNptr; |
| |
| const Index size = m_matrix.rows(); |
| m_l.resize(size, size); |
| m_l.resizeNonZeros(Lstore->nnz); |
| m_u.resize(size, size); |
| m_u.resizeNonZeros(Ustore->nnz); |
| |
| int *Lcol = m_l.outerIndexPtr(); |
| int *Lrow = m_l.innerIndexPtr(); |
| Scalar *Lval = m_l.valuePtr(); |
| |
| int *Ucol = m_u.outerIndexPtr(); |
| int *Urow = m_u.innerIndexPtr(); |
| Scalar *Uval = m_u.valuePtr(); |
| |
| Ucol[0] = 0; |
| Ucol[0] = 0; |
| |
| /* for each supernode */ |
| for (int k = 0; k <= Lstore->nsuper; ++k) { |
| fsupc = L_FST_SUPC(k); |
| istart = L_SUB_START(fsupc); |
| nsupr = L_SUB_START(fsupc + 1) - istart; |
| upper = 1; |
| |
| /* for each column in the supernode */ |
| for (int j = fsupc; j < L_FST_SUPC(k + 1); ++j) { |
| SNptr = &((Scalar *)Lstore->nzval)[L_NZ_START(j)]; |
| |
| /* Extract U */ |
| for (int i = U_NZ_START(j); i < U_NZ_START(j + 1); ++i) { |
| Uval[lastu] = ((Scalar *)Ustore->nzval)[i]; |
| /* Matlab doesn't like explicit zero. */ |
| if (Uval[lastu] != 0.0) Urow[lastu++] = U_SUB(i); |
| } |
| for (int i = 0; i < upper; ++i) { |
| /* upper triangle in the supernode */ |
| Uval[lastu] = SNptr[i]; |
| /* Matlab doesn't like explicit zero. */ |
| if (Uval[lastu] != 0.0) Urow[lastu++] = L_SUB(istart + i); |
| } |
| Ucol[j + 1] = lastu; |
| |
| /* Extract L */ |
| Lval[lastl] = 1.0; /* unit diagonal */ |
| Lrow[lastl++] = L_SUB(istart + upper - 1); |
| for (int i = upper; i < nsupr; ++i) { |
| Lval[lastl] = SNptr[i]; |
| /* Matlab doesn't like explicit zero. */ |
| if (Lval[lastl] != 0.0) Lrow[lastl++] = L_SUB(istart + i); |
| } |
| Lcol[j + 1] = lastl; |
| |
| ++upper; |
| } /* for j ... */ |
| |
| } /* for k ... */ |
| |
| // squeeze the matrices : |
| m_l.resizeNonZeros(lastl); |
| m_u.resizeNonZeros(lastu); |
| |
| m_extractedDataAreDirty = false; |
| } |
| } |
| |
| template <typename MatrixType> |
| typename SuperLU<MatrixType>::Scalar SuperLU<MatrixType>::determinant() const { |
| eigen_assert(m_factorizationIsOk && |
| "The decomposition is not in a valid state for computing the determinant, you must first call either " |
| "compute() or analyzePattern()/factorize()"); |
| |
| if (m_extractedDataAreDirty) this->extractData(); |
| |
| Scalar det = Scalar(1); |
| for (int j = 0; j < m_u.cols(); ++j) { |
| if (m_u.outerIndexPtr()[j + 1] - m_u.outerIndexPtr()[j] > 0) { |
| int lastId = m_u.outerIndexPtr()[j + 1] - 1; |
| eigen_assert(m_u.innerIndexPtr()[lastId] <= j); |
| if (m_u.innerIndexPtr()[lastId] == j) det *= m_u.valuePtr()[lastId]; |
| } |
| } |
| if (PermutationMap(m_p.data(), m_p.size()).determinant() * PermutationMap(m_q.data(), m_q.size()).determinant() < 0) |
| det = -det; |
| if (m_sluEqued != 'N') |
| return det / m_sluRscale.prod() / m_sluCscale.prod(); |
| else |
| return det; |
| } |
| |
| #ifdef EIGEN_PARSED_BY_DOXYGEN |
| #define EIGEN_SUPERLU_HAS_ILU |
| #endif |
| |
| #ifdef EIGEN_SUPERLU_HAS_ILU |
| |
| /** \ingroup SuperLUSupport_Module |
| * \class SuperILU |
| * \brief A sparse direct \b incomplete LU factorization and solver based on the SuperLU library |
| * |
| * This class allows to solve for an approximate solution of A.X = B sparse linear problems via an incomplete LU |
| * factorization using the SuperLU library. This class is aimed to be used as a preconditioner of the iterative linear |
| * solvers. |
| * |
| * \warning This class is only for the 4.x versions of SuperLU. The 3.x and 5.x versions are not supported. |
| * |
| * \tparam MatrixType_ the type of the sparse matrix A, it must be a SparseMatrix<> |
| * |
| * \implsparsesolverconcept |
| * |
| * \sa \ref TutorialSparseSolverConcept, class IncompleteLUT, class ConjugateGradient, class BiCGSTAB |
| */ |
| |
| template <typename MatrixType_> |
| class SuperILU : public SuperLUBase<MatrixType_, SuperILU<MatrixType_> > { |
| public: |
| typedef SuperLUBase<MatrixType_, SuperILU> Base; |
| typedef MatrixType_ MatrixType; |
| typedef typename Base::Scalar Scalar; |
| typedef typename Base::RealScalar RealScalar; |
| |
| public: |
| using Base::_solve_impl; |
| |
| SuperILU() : Base() { init(); } |
| |
| SuperILU(const MatrixType &matrix) : Base() { |
| init(); |
| Base::compute(matrix); |
| } |
| |
| ~SuperILU() {} |
| |
| /** 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() |
| */ |
| void analyzePattern(const MatrixType &matrix) { Base::analyzePattern(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() |
| */ |
| void factorize(const MatrixType &matrix); |
| |
| #ifndef EIGEN_PARSED_BY_DOXYGEN |
| /** \internal */ |
| template <typename Rhs, typename Dest> |
| void _solve_impl(const MatrixBase<Rhs> &b, MatrixBase<Dest> &dest) const; |
| #endif // EIGEN_PARSED_BY_DOXYGEN |
| |
| protected: |
| using Base::m_l; |
| using Base::m_matrix; |
| using Base::m_p; |
| using Base::m_q; |
| using Base::m_sluA; |
| using Base::m_sluB; |
| using Base::m_sluBerr; |
| using Base::m_sluCscale; |
| using Base::m_sluEqued; |
| using Base::m_sluEtree; |
| using Base::m_sluFerr; |
| using Base::m_sluL; |
| using Base::m_sluOptions; |
| using Base::m_sluRscale; |
| using Base::m_sluStat; |
| using Base::m_sluU; |
| using Base::m_sluX; |
| using Base::m_u; |
| |
| using Base::m_analysisIsOk; |
| using Base::m_extractedDataAreDirty; |
| using Base::m_factorizationIsOk; |
| using Base::m_info; |
| using Base::m_isInitialized; |
| |
| void init() { |
| Base::init(); |
| |
| ilu_set_default_options(&m_sluOptions); |
| m_sluOptions.PrintStat = NO; |
| m_sluOptions.ConditionNumber = NO; |
| m_sluOptions.Trans = NOTRANS; |
| m_sluOptions.ColPerm = MMD_AT_PLUS_A; |
| |
| // no attempt to preserve column sum |
| m_sluOptions.ILU_MILU = SILU; |
| // only basic ILU(k) support -- no direct control over memory consumption |
| // better to use ILU_DropRule = DROP_BASIC | DROP_AREA |
| // and set ILU_FillFactor to max memory growth |
| m_sluOptions.ILU_DropRule = DROP_BASIC; |
| m_sluOptions.ILU_DropTol = NumTraits<Scalar>::dummy_precision() * 10; |
| } |
| |
| private: |
| SuperILU(SuperILU &) {} |
| }; |
| |
| template <typename MatrixType> |
| void SuperILU<MatrixType>::factorize(const MatrixType &a) { |
| eigen_assert(m_analysisIsOk && "You must first call analyzePattern()"); |
| if (!m_analysisIsOk) { |
| m_info = InvalidInput; |
| return; |
| } |
| |
| this->initFactorization(a); |
| |
| int info = 0; |
| RealScalar recip_pivot_growth, rcond; |
| |
| StatInit(&m_sluStat); |
| SuperLU_gsisx(&m_sluOptions, &m_sluA, m_q.data(), m_p.data(), &m_sluEtree[0], &m_sluEqued, &m_sluRscale[0], |
| &m_sluCscale[0], &m_sluL, &m_sluU, NULL, 0, &m_sluB, &m_sluX, &recip_pivot_growth, &rcond, &m_sluStat, |
| &info, Scalar()); |
| StatFree(&m_sluStat); |
| |
| // FIXME how to better check for errors ??? |
| m_info = info == 0 ? Success : NumericalIssue; |
| m_factorizationIsOk = true; |
| } |
| |
| #ifndef EIGEN_PARSED_BY_DOXYGEN |
| template <typename MatrixType> |
| template <typename Rhs, typename Dest> |
| void SuperILU<MatrixType>::_solve_impl(const MatrixBase<Rhs> &b, MatrixBase<Dest> &x) const { |
| eigen_assert(m_factorizationIsOk && |
| "The decomposition is not in a valid state for solving, you must first call either compute() or " |
| "analyzePattern()/factorize()"); |
| |
| const int rhsCols = b.cols(); |
| eigen_assert(m_matrix.rows() == b.rows()); |
| |
| m_sluOptions.Trans = NOTRANS; |
| m_sluOptions.Fact = FACTORED; |
| m_sluOptions.IterRefine = NOREFINE; |
| |
| m_sluFerr.resize(rhsCols); |
| m_sluBerr.resize(rhsCols); |
| |
| Ref<const Matrix<typename Rhs::Scalar, Dynamic, Dynamic, ColMajor> > b_ref(b); |
| Ref<const Matrix<typename Dest::Scalar, Dynamic, Dynamic, ColMajor> > x_ref(x); |
| |
| m_sluB = SluMatrix::Map(b_ref.const_cast_derived()); |
| m_sluX = SluMatrix::Map(x_ref.const_cast_derived()); |
| |
| typename Rhs::PlainObject b_cpy; |
| if (m_sluEqued != 'N') { |
| b_cpy = b; |
| m_sluB = SluMatrix::Map(b_cpy.const_cast_derived()); |
| } |
| |
| int info = 0; |
| RealScalar recip_pivot_growth, rcond; |
| |
| StatInit(&m_sluStat); |
| SuperLU_gsisx(&m_sluOptions, &m_sluA, m_q.data(), m_p.data(), &m_sluEtree[0], &m_sluEqued, &m_sluRscale[0], |
| &m_sluCscale[0], &m_sluL, &m_sluU, NULL, 0, &m_sluB, &m_sluX, &recip_pivot_growth, &rcond, &m_sluStat, |
| &info, Scalar()); |
| StatFree(&m_sluStat); |
| |
| if (x.derived().data() != x_ref.data()) x = x_ref; |
| |
| m_info = info == 0 ? Success : NumericalIssue; |
| } |
| #endif |
| |
| #endif |
| |
| } // end namespace Eigen |
| |
| #endif // EIGEN_SUPERLUSUPPORT_H |