|  | #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 |