| #ifndef EIGEN_ACCELERATESUPPORT_H | |
| #define EIGEN_ACCELERATESUPPORT_H | |
| #include <Accelerate/Accelerate.h> | |
| #include <Eigen/Sparse> | |
| namespace Eigen { | |
| template <typename MatrixType_, int UpLo_, SparseFactorization_t Solver_, bool EnforceSquare_> | |
| class AccelerateImpl; | |
| /** \ingroup AccelerateSupport_Module | |
| * \class AccelerateLLT | |
| * \brief A direct Cholesky (LLT) factorization and solver based on Accelerate | |
| * | |
| * \warning Only single and double precision real scalar types are supported by Accelerate | |
| * | |
| * \tparam MatrixType_ the type of the sparse matrix A, it must be a SparseMatrix<> | |
| * \tparam UpLo_ additional information about the matrix structure. Default is Lower. | |
| * | |
| * \sa \ref TutorialSparseSolverConcept, class AccelerateLLT | |
| */ | |
| template <typename MatrixType, int UpLo = Lower> | |
| using AccelerateLLT = AccelerateImpl<MatrixType, UpLo | Symmetric, SparseFactorizationCholesky, true>; | |
| /** \ingroup AccelerateSupport_Module | |
| * \class AccelerateLDLT | |
| * \brief The default Cholesky (LDLT) factorization and solver based on Accelerate | |
| * | |
| * \warning Only single and double precision real scalar types are supported by Accelerate | |
| * | |
| * \tparam MatrixType_ the type of the sparse matrix A, it must be a SparseMatrix<> | |
| * \tparam UpLo_ additional information about the matrix structure. Default is Lower. | |
| * | |
| * \sa \ref TutorialSparseSolverConcept, class AccelerateLDLT | |
| */ | |
| template <typename MatrixType, int UpLo = Lower> | |
| using AccelerateLDLT = AccelerateImpl<MatrixType, UpLo | Symmetric, SparseFactorizationLDLT, true>; | |
| /** \ingroup AccelerateSupport_Module | |
| * \class AccelerateLDLTUnpivoted | |
| * \brief A direct Cholesky-like LDL^T factorization and solver based on Accelerate with only 1x1 pivots and no pivoting | |
| * | |
| * \warning Only single and double precision real scalar types are supported by Accelerate | |
| * | |
| * \tparam MatrixType_ the type of the sparse matrix A, it must be a SparseMatrix<> | |
| * \tparam UpLo_ additional information about the matrix structure. Default is Lower. | |
| * | |
| * \sa \ref TutorialSparseSolverConcept, class AccelerateLDLTUnpivoted | |
| */ | |
| template <typename MatrixType, int UpLo = Lower> | |
| using AccelerateLDLTUnpivoted = AccelerateImpl<MatrixType, UpLo | Symmetric, SparseFactorizationLDLTUnpivoted, true>; | |
| /** \ingroup AccelerateSupport_Module | |
| * \class AccelerateLDLTSBK | |
| * \brief A direct Cholesky (LDLT) factorization and solver based on Accelerate with Supernode Bunch-Kaufman and static | |
| * pivoting | |
| * | |
| * \warning Only single and double precision real scalar types are supported by Accelerate | |
| * | |
| * \tparam MatrixType_ the type of the sparse matrix A, it must be a SparseMatrix<> | |
| * \tparam UpLo_ additional information about the matrix structure. Default is Lower. | |
| * | |
| * \sa \ref TutorialSparseSolverConcept, class AccelerateLDLTSBK | |
| */ | |
| template <typename MatrixType, int UpLo = Lower> | |
| using AccelerateLDLTSBK = AccelerateImpl<MatrixType, UpLo | Symmetric, SparseFactorizationLDLTSBK, true>; | |
| /** \ingroup AccelerateSupport_Module | |
| * \class AccelerateLDLTTPP | |
| * \brief A direct Cholesky (LDLT) factorization and solver based on Accelerate with full threshold partial pivoting | |
| * | |
| * \warning Only single and double precision real scalar types are supported by Accelerate | |
| * | |
| * \tparam MatrixType_ the type of the sparse matrix A, it must be a SparseMatrix<> | |
| * \tparam UpLo_ additional information about the matrix structure. Default is Lower. | |
| * | |
| * \sa \ref TutorialSparseSolverConcept, class AccelerateLDLTTPP | |
| */ | |
| template <typename MatrixType, int UpLo = Lower> | |
| using AccelerateLDLTTPP = AccelerateImpl<MatrixType, UpLo | Symmetric, SparseFactorizationLDLTTPP, true>; | |
| /** \ingroup AccelerateSupport_Module | |
| * \class AccelerateQR | |
| * \brief A QR factorization and solver based on Accelerate | |
| * | |
| * \warning Only single and double precision real scalar types are supported by Accelerate | |
| * | |
| * \tparam MatrixType_ the type of the sparse matrix A, it must be a SparseMatrix<> | |
| * | |
| * \sa \ref TutorialSparseSolverConcept, class AccelerateQR | |
| */ | |
| template <typename MatrixType> | |
| using AccelerateQR = AccelerateImpl<MatrixType, 0, SparseFactorizationQR, false>; | |
| /** \ingroup AccelerateSupport_Module | |
| * \class AccelerateCholeskyAtA | |
| * \brief A QR factorization and solver based on Accelerate without storing Q (equivalent to A^TA = R^T R) | |
| * | |
| * \warning Only single and double precision real scalar types are supported by Accelerate | |
| * | |
| * \tparam MatrixType_ the type of the sparse matrix A, it must be a SparseMatrix<> | |
| * | |
| * \sa \ref TutorialSparseSolverConcept, class AccelerateCholeskyAtA | |
| */ | |
| template <typename MatrixType> | |
| using AccelerateCholeskyAtA = AccelerateImpl<MatrixType, 0, SparseFactorizationCholeskyAtA, false>; | |
| namespace internal { | |
| template <typename T> | |
| struct AccelFactorizationDeleter { | |
| void operator()(T* sym) { | |
| if (sym) { | |
| SparseCleanup(*sym); | |
| delete sym; | |
| sym = nullptr; | |
| } | |
| } | |
| }; | |
| template <typename DenseVecT, typename DenseMatT, typename SparseMatT, typename NumFactT> | |
| struct SparseTypesTraitBase { | |
| typedef DenseVecT AccelDenseVector; | |
| typedef DenseMatT AccelDenseMatrix; | |
| typedef SparseMatT AccelSparseMatrix; | |
| typedef SparseOpaqueSymbolicFactorization SymbolicFactorization; | |
| typedef NumFactT NumericFactorization; | |
| typedef AccelFactorizationDeleter<SymbolicFactorization> SymbolicFactorizationDeleter; | |
| typedef AccelFactorizationDeleter<NumericFactorization> NumericFactorizationDeleter; | |
| }; | |
| template <typename Scalar> | |
| struct SparseTypesTrait {}; | |
| template <> | |
| struct SparseTypesTrait<double> : SparseTypesTraitBase<DenseVector_Double, DenseMatrix_Double, SparseMatrix_Double, | |
| SparseOpaqueFactorization_Double> {}; | |
| template <> | |
| struct SparseTypesTrait<float> | |
| : SparseTypesTraitBase<DenseVector_Float, DenseMatrix_Float, SparseMatrix_Float, SparseOpaqueFactorization_Float> { | |
| }; | |
| } // end namespace internal | |
| template <typename MatrixType_, int UpLo_, SparseFactorization_t Solver_, bool EnforceSquare_> | |
| class AccelerateImpl : public SparseSolverBase<AccelerateImpl<MatrixType_, UpLo_, Solver_, EnforceSquare_> > { | |
| protected: | |
| using Base = SparseSolverBase<AccelerateImpl>; | |
| using Base::derived; | |
| using Base::m_isInitialized; | |
| public: | |
| using Base::_solve_impl; | |
| typedef MatrixType_ MatrixType; | |
| typedef typename MatrixType::Scalar Scalar; | |
| typedef typename MatrixType::StorageIndex StorageIndex; | |
| enum { ColsAtCompileTime = Dynamic, MaxColsAtCompileTime = Dynamic }; | |
| enum { UpLo = UpLo_ }; | |
| using AccelDenseVector = typename internal::SparseTypesTrait<Scalar>::AccelDenseVector; | |
| using AccelDenseMatrix = typename internal::SparseTypesTrait<Scalar>::AccelDenseMatrix; | |
| using AccelSparseMatrix = typename internal::SparseTypesTrait<Scalar>::AccelSparseMatrix; | |
| using SymbolicFactorization = typename internal::SparseTypesTrait<Scalar>::SymbolicFactorization; | |
| using NumericFactorization = typename internal::SparseTypesTrait<Scalar>::NumericFactorization; | |
| using SymbolicFactorizationDeleter = typename internal::SparseTypesTrait<Scalar>::SymbolicFactorizationDeleter; | |
| using NumericFactorizationDeleter = typename internal::SparseTypesTrait<Scalar>::NumericFactorizationDeleter; | |
| AccelerateImpl() { | |
| m_isInitialized = false; | |
| auto check_flag_set = [](int value, int flag) { return ((value & flag) == flag); }; | |
| if (check_flag_set(UpLo_, Symmetric)) { | |
| m_sparseKind = SparseSymmetric; | |
| m_triType = (UpLo_ & Lower) ? SparseLowerTriangle : SparseUpperTriangle; | |
| } else if (check_flag_set(UpLo_, UnitLower)) { | |
| m_sparseKind = SparseUnitTriangular; | |
| m_triType = SparseLowerTriangle; | |
| } else if (check_flag_set(UpLo_, UnitUpper)) { | |
| m_sparseKind = SparseUnitTriangular; | |
| m_triType = SparseUpperTriangle; | |
| } else if (check_flag_set(UpLo_, StrictlyLower)) { | |
| m_sparseKind = SparseTriangular; | |
| m_triType = SparseLowerTriangle; | |
| } else if (check_flag_set(UpLo_, StrictlyUpper)) { | |
| m_sparseKind = SparseTriangular; | |
| m_triType = SparseUpperTriangle; | |
| } else if (check_flag_set(UpLo_, Lower)) { | |
| m_sparseKind = SparseTriangular; | |
| m_triType = SparseLowerTriangle; | |
| } else if (check_flag_set(UpLo_, Upper)) { | |
| m_sparseKind = SparseTriangular; | |
| m_triType = SparseUpperTriangle; | |
| } else { | |
| m_sparseKind = SparseOrdinary; | |
| m_triType = (UpLo_ & Lower) ? SparseLowerTriangle : SparseUpperTriangle; | |
| } | |
| m_order = SparseOrderDefault; | |
| } | |
| explicit AccelerateImpl(const MatrixType& matrix) : AccelerateImpl() { compute(matrix); } | |
| ~AccelerateImpl() {} | |
| inline Index cols() const { return m_nCols; } | |
| inline Index rows() const { return m_nRows; } | |
| ComputationInfo info() const { | |
| eigen_assert(m_isInitialized && "Decomposition is not initialized."); | |
| return m_info; | |
| } | |
| void analyzePattern(const MatrixType& matrix); | |
| void factorize(const MatrixType& matrix); | |
| void compute(const MatrixType& matrix); | |
| template <typename Rhs, typename Dest> | |
| void _solve_impl(const MatrixBase<Rhs>& b, MatrixBase<Dest>& dest) const; | |
| /** Sets the ordering algorithm to use. */ | |
| void setOrder(SparseOrder_t order) { m_order = order; } | |
| private: | |
| template <typename T> | |
| void buildAccelSparseMatrix(const SparseMatrix<T>& a, AccelSparseMatrix& A, std::vector<long>& columnStarts) { | |
| const Index nColumnsStarts = a.cols() + 1; | |
| columnStarts.resize(nColumnsStarts); | |
| for (Index i = 0; i < nColumnsStarts; i++) columnStarts[i] = a.outerIndexPtr()[i]; | |
| SparseAttributes_t attributes{}; | |
| attributes.transpose = false; | |
| attributes.triangle = m_triType; | |
| attributes.kind = m_sparseKind; | |
| SparseMatrixStructure structure{}; | |
| structure.attributes = attributes; | |
| structure.rowCount = static_cast<int>(a.rows()); | |
| structure.columnCount = static_cast<int>(a.cols()); | |
| structure.blockSize = 1; | |
| structure.columnStarts = columnStarts.data(); | |
| structure.rowIndices = const_cast<int*>(a.innerIndexPtr()); | |
| A.structure = structure; | |
| A.data = const_cast<T*>(a.valuePtr()); | |
| } | |
| void doAnalysis(AccelSparseMatrix& A) { | |
| m_numericFactorization.reset(nullptr); | |
| SparseSymbolicFactorOptions opts{}; | |
| opts.control = SparseDefaultControl; | |
| opts.orderMethod = m_order; | |
| opts.order = nullptr; | |
| opts.ignoreRowsAndColumns = nullptr; | |
| opts.malloc = malloc; | |
| opts.free = free; | |
| opts.reportError = nullptr; | |
| m_symbolicFactorization.reset(new SymbolicFactorization(SparseFactor(Solver_, A.structure, opts))); | |
| SparseStatus_t status = m_symbolicFactorization->status; | |
| updateInfoStatus(status); | |
| if (status != SparseStatusOK) m_symbolicFactorization.reset(nullptr); | |
| } | |
| void doFactorization(AccelSparseMatrix& A) { | |
| SparseStatus_t status = SparseStatusReleased; | |
| if (m_symbolicFactorization) { | |
| m_numericFactorization.reset(new NumericFactorization(SparseFactor(*m_symbolicFactorization, A))); | |
| status = m_numericFactorization->status; | |
| if (status != SparseStatusOK) m_numericFactorization.reset(nullptr); | |
| } | |
| updateInfoStatus(status); | |
| } | |
| protected: | |
| void updateInfoStatus(SparseStatus_t status) const { | |
| switch (status) { | |
| case SparseStatusOK: | |
| m_info = Success; | |
| break; | |
| case SparseFactorizationFailed: | |
| case SparseMatrixIsSingular: | |
| m_info = NumericalIssue; | |
| break; | |
| case SparseInternalError: | |
| case SparseParameterError: | |
| case SparseStatusReleased: | |
| default: | |
| m_info = InvalidInput; | |
| break; | |
| } | |
| } | |
| mutable ComputationInfo m_info; | |
| Index m_nRows, m_nCols; | |
| std::unique_ptr<SymbolicFactorization, SymbolicFactorizationDeleter> m_symbolicFactorization; | |
| std::unique_ptr<NumericFactorization, NumericFactorizationDeleter> m_numericFactorization; | |
| SparseKind_t m_sparseKind; | |
| SparseTriangle_t m_triType; | |
| SparseOrder_t m_order; | |
| }; | |
| /** Computes the symbolic and numeric decomposition of matrix \a a */ | |
| template <typename MatrixType_, int UpLo_, SparseFactorization_t Solver_, bool EnforceSquare_> | |
| void AccelerateImpl<MatrixType_, UpLo_, Solver_, EnforceSquare_>::compute(const MatrixType& a) { | |
| if (EnforceSquare_) eigen_assert(a.rows() == a.cols()); | |
| m_nRows = a.rows(); | |
| m_nCols = a.cols(); | |
| AccelSparseMatrix A{}; | |
| std::vector<long> columnStarts; | |
| buildAccelSparseMatrix(a, A, columnStarts); | |
| doAnalysis(A); | |
| if (m_symbolicFactorization) doFactorization(A); | |
| m_isInitialized = true; | |
| } | |
| /** Performs a symbolic decomposition on the sparsity pattern of matrix \a a. | |
| * | |
| * This function is particularly useful when solving for several problems having the same structure. | |
| * | |
| * \sa factorize() | |
| */ | |
| template <typename MatrixType_, int UpLo_, SparseFactorization_t Solver_, bool EnforceSquare_> | |
| void AccelerateImpl<MatrixType_, UpLo_, Solver_, EnforceSquare_>::analyzePattern(const MatrixType& a) { | |
| if (EnforceSquare_) eigen_assert(a.rows() == a.cols()); | |
| m_nRows = a.rows(); | |
| m_nCols = a.cols(); | |
| AccelSparseMatrix A{}; | |
| std::vector<long> columnStarts; | |
| buildAccelSparseMatrix(a, A, columnStarts); | |
| doAnalysis(A); | |
| m_isInitialized = true; | |
| } | |
| /** Performs a numeric decomposition of matrix \a a. | |
| * | |
| * The given matrix must have the same sparsity pattern as the matrix on which the symbolic decomposition has been | |
| * performed. | |
| * | |
| * \sa analyzePattern() | |
| */ | |
| template <typename MatrixType_, int UpLo_, SparseFactorization_t Solver_, bool EnforceSquare_> | |
| void AccelerateImpl<MatrixType_, UpLo_, Solver_, EnforceSquare_>::factorize(const MatrixType& a) { | |
| eigen_assert(m_symbolicFactorization && "You must first call analyzePattern()"); | |
| eigen_assert(m_nRows == a.rows() && m_nCols == a.cols()); | |
| if (EnforceSquare_) eigen_assert(a.rows() == a.cols()); | |
| AccelSparseMatrix A{}; | |
| std::vector<long> columnStarts; | |
| buildAccelSparseMatrix(a, A, columnStarts); | |
| doFactorization(A); | |
| } | |
| template <typename MatrixType_, int UpLo_, SparseFactorization_t Solver_, bool EnforceSquare_> | |
| template <typename Rhs, typename Dest> | |
| void AccelerateImpl<MatrixType_, UpLo_, Solver_, EnforceSquare_>::_solve_impl(const MatrixBase<Rhs>& b, | |
| MatrixBase<Dest>& x) const { | |
| if (!m_numericFactorization) { | |
| m_info = InvalidInput; | |
| return; | |
| } | |
| eigen_assert(m_nRows == b.rows()); | |
| eigen_assert(((b.cols() == 1) || b.outerStride() == b.rows())); | |
| SparseStatus_t status = SparseStatusOK; | |
| Scalar* b_ptr = const_cast<Scalar*>(b.derived().data()); | |
| Scalar* x_ptr = const_cast<Scalar*>(x.derived().data()); | |
| AccelDenseMatrix xmat{}; | |
| xmat.attributes = SparseAttributes_t(); | |
| xmat.columnCount = static_cast<int>(x.cols()); | |
| xmat.rowCount = static_cast<int>(x.rows()); | |
| xmat.columnStride = xmat.rowCount; | |
| xmat.data = x_ptr; | |
| AccelDenseMatrix bmat{}; | |
| bmat.attributes = SparseAttributes_t(); | |
| bmat.columnCount = static_cast<int>(b.cols()); | |
| bmat.rowCount = static_cast<int>(b.rows()); | |
| bmat.columnStride = bmat.rowCount; | |
| bmat.data = b_ptr; | |
| SparseSolve(*m_numericFactorization, bmat, xmat); | |
| updateInfoStatus(status); | |
| } | |
| } // end namespace Eigen | |
| #endif // EIGEN_ACCELERATESUPPORT_H |