|  | // This file is part of Eigen, a lightweight C++ template library | 
|  | // for linear algebra. | 
|  | // | 
|  | // Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr> | 
|  | // Copyright (C) 2012 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_SPARSELU_SUPERNODAL_MATRIX_H | 
|  | #define EIGEN_SPARSELU_SUPERNODAL_MATRIX_H | 
|  |  | 
|  | // IWYU pragma: private | 
|  | #include "./InternalHeaderCheck.h" | 
|  |  | 
|  | namespace Eigen { | 
|  | namespace internal { | 
|  |  | 
|  | /** \ingroup SparseLU_Module | 
|  | * \brief a class to manipulate the L supernodal factor from the SparseLU factorization | 
|  | * | 
|  | * This class  contain the data to easily store | 
|  | * and manipulate the supernodes during the factorization and solution phase of Sparse LU. | 
|  | * Only the lower triangular matrix has supernodes. | 
|  | * | 
|  | * NOTE : This class corresponds to the SCformat structure in SuperLU | 
|  | * | 
|  | */ | 
|  | /* TODO | 
|  | * InnerIterator as for sparsematrix | 
|  | * SuperInnerIterator to iterate through all supernodes | 
|  | * Function for triangular solve | 
|  | */ | 
|  | template <typename Scalar_, typename StorageIndex_> | 
|  | class MappedSuperNodalMatrix { | 
|  | public: | 
|  | typedef Scalar_ Scalar; | 
|  | typedef StorageIndex_ StorageIndex; | 
|  | typedef Matrix<StorageIndex, Dynamic, 1> IndexVector; | 
|  | typedef Matrix<Scalar, Dynamic, 1> ScalarVector; | 
|  |  | 
|  | public: | 
|  | MappedSuperNodalMatrix() {} | 
|  | MappedSuperNodalMatrix(Index m, Index n, ScalarVector& nzval, IndexVector& nzval_colptr, IndexVector& rowind, | 
|  | IndexVector& rowind_colptr, IndexVector& col_to_sup, IndexVector& sup_to_col) { | 
|  | setInfos(m, n, nzval, nzval_colptr, rowind, rowind_colptr, col_to_sup, sup_to_col); | 
|  | } | 
|  |  | 
|  | ~MappedSuperNodalMatrix() {} | 
|  | /** | 
|  | * Set appropriate pointers for the lower triangular supernodal matrix | 
|  | * These infos are available at the end of the numerical factorization | 
|  | * FIXME This class will be modified such that it can be use in the course | 
|  | * of the factorization. | 
|  | */ | 
|  | void setInfos(Index m, Index n, ScalarVector& nzval, IndexVector& nzval_colptr, IndexVector& rowind, | 
|  | IndexVector& rowind_colptr, IndexVector& col_to_sup, IndexVector& sup_to_col) { | 
|  | m_row = m; | 
|  | m_col = n; | 
|  | m_nzval = nzval.data(); | 
|  | m_nzval_colptr = nzval_colptr.data(); | 
|  | m_rowind = rowind.data(); | 
|  | m_rowind_colptr = rowind_colptr.data(); | 
|  | m_nsuper = col_to_sup(n); | 
|  | m_col_to_sup = col_to_sup.data(); | 
|  | m_sup_to_col = sup_to_col.data(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Number of rows | 
|  | */ | 
|  | Index rows() const { return m_row; } | 
|  |  | 
|  | /** | 
|  | * Number of columns | 
|  | */ | 
|  | Index cols() const { return m_col; } | 
|  |  | 
|  | /** | 
|  | * Return the array of nonzero values packed by column | 
|  | * | 
|  | * The size is nnz | 
|  | */ | 
|  | Scalar* valuePtr() { return m_nzval; } | 
|  |  | 
|  | const Scalar* valuePtr() const { return m_nzval; } | 
|  | /** | 
|  | * Return the pointers to the beginning of each column in \ref valuePtr() | 
|  | */ | 
|  | StorageIndex* colIndexPtr() { return m_nzval_colptr; } | 
|  |  | 
|  | const StorageIndex* colIndexPtr() const { return m_nzval_colptr; } | 
|  |  | 
|  | /** | 
|  | * Return the array of compressed row indices of all supernodes | 
|  | */ | 
|  | StorageIndex* rowIndex() { return m_rowind; } | 
|  |  | 
|  | const StorageIndex* rowIndex() const { return m_rowind; } | 
|  |  | 
|  | /** | 
|  | * Return the location in \em rowvaluePtr() which starts each column | 
|  | */ | 
|  | StorageIndex* rowIndexPtr() { return m_rowind_colptr; } | 
|  |  | 
|  | const StorageIndex* rowIndexPtr() const { return m_rowind_colptr; } | 
|  |  | 
|  | /** | 
|  | * Return the array of column-to-supernode mapping | 
|  | */ | 
|  | StorageIndex* colToSup() { return m_col_to_sup; } | 
|  |  | 
|  | const StorageIndex* colToSup() const { return m_col_to_sup; } | 
|  | /** | 
|  | * Return the array of supernode-to-column mapping | 
|  | */ | 
|  | StorageIndex* supToCol() { return m_sup_to_col; } | 
|  |  | 
|  | const StorageIndex* supToCol() const { return m_sup_to_col; } | 
|  |  | 
|  | /** | 
|  | * Return the number of supernodes | 
|  | */ | 
|  | Index nsuper() const { return m_nsuper; } | 
|  |  | 
|  | class InnerIterator; | 
|  | template <typename Dest> | 
|  | void solveInPlace(MatrixBase<Dest>& X) const; | 
|  | template <bool Conjugate, typename Dest> | 
|  | void solveTransposedInPlace(MatrixBase<Dest>& X) const; | 
|  |  | 
|  | protected: | 
|  | Index m_row;                    // Number of rows | 
|  | Index m_col;                    // Number of columns | 
|  | Index m_nsuper;                 // Number of supernodes | 
|  | Scalar* m_nzval;                // array of nonzero values packed by column | 
|  | StorageIndex* m_nzval_colptr;   // nzval_colptr[j] Stores the location in nzval[] which starts column j | 
|  | StorageIndex* m_rowind;         // Array of compressed row indices of rectangular supernodes | 
|  | StorageIndex* m_rowind_colptr;  // rowind_colptr[j] stores the location in rowind[] which starts column j | 
|  | StorageIndex* m_col_to_sup;     // col_to_sup[j] is the supernode number to which column j belongs | 
|  | StorageIndex* m_sup_to_col;     // sup_to_col[s] points to the starting column of the s-th supernode | 
|  |  | 
|  | private: | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * \brief InnerIterator class to iterate over nonzero values of the current column in the supernodal matrix L | 
|  | * | 
|  | */ | 
|  | template <typename Scalar, typename StorageIndex> | 
|  | class MappedSuperNodalMatrix<Scalar, StorageIndex>::InnerIterator { | 
|  | public: | 
|  | InnerIterator(const MappedSuperNodalMatrix& mat, Index outer) | 
|  | : m_matrix(mat), | 
|  | m_outer(outer), | 
|  | m_supno(mat.colToSup()[outer]), | 
|  | m_idval(mat.colIndexPtr()[outer]), | 
|  | m_startidval(m_idval), | 
|  | m_endidval(mat.colIndexPtr()[outer + 1]), | 
|  | m_idrow(mat.rowIndexPtr()[mat.supToCol()[mat.colToSup()[outer]]]), | 
|  | m_endidrow(mat.rowIndexPtr()[mat.supToCol()[mat.colToSup()[outer]] + 1]) {} | 
|  | inline InnerIterator& operator++() { | 
|  | m_idval++; | 
|  | m_idrow++; | 
|  | return *this; | 
|  | } | 
|  | inline Scalar value() const { return m_matrix.valuePtr()[m_idval]; } | 
|  |  | 
|  | inline Scalar& valueRef() { return const_cast<Scalar&>(m_matrix.valuePtr()[m_idval]); } | 
|  |  | 
|  | inline Index index() const { return m_matrix.rowIndex()[m_idrow]; } | 
|  | inline Index row() const { return index(); } | 
|  | inline Index col() const { return m_outer; } | 
|  |  | 
|  | inline Index supIndex() const { return m_supno; } | 
|  |  | 
|  | inline operator bool() const { | 
|  | return ((m_idval < m_endidval) && (m_idval >= m_startidval) && (m_idrow < m_endidrow)); | 
|  | } | 
|  |  | 
|  | protected: | 
|  | const MappedSuperNodalMatrix& m_matrix;  // Supernodal lower triangular matrix | 
|  | const Index m_outer;                     // Current column | 
|  | const Index m_supno;                     // Current SuperNode number | 
|  | Index m_idval;                           // Index to browse the values in the current column | 
|  | const Index m_startidval;                // Start of the column value | 
|  | const Index m_endidval;                  // End of the column value | 
|  | Index m_idrow;                           // Index to browse the row indices | 
|  | Index m_endidrow;                        // End index of row indices of the current column | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * \brief Solve with the supernode triangular matrix | 
|  | * | 
|  | */ | 
|  | template <typename Scalar, typename Index_> | 
|  | template <typename Dest> | 
|  | void MappedSuperNodalMatrix<Scalar, Index_>::solveInPlace(MatrixBase<Dest>& X) const { | 
|  | /* Explicit type conversion as the Index type of MatrixBase<Dest> may be wider than Index */ | 
|  | //    eigen_assert(X.rows() <= NumTraits<Index>::highest()); | 
|  | //    eigen_assert(X.cols() <= NumTraits<Index>::highest()); | 
|  | Index n = int(X.rows()); | 
|  | Index nrhs = Index(X.cols()); | 
|  | const Scalar* Lval = valuePtr();                                           // Nonzero values | 
|  | Matrix<Scalar, Dynamic, Dest::ColsAtCompileTime, ColMajor> work(n, nrhs);  // working vector | 
|  | work.setZero(); | 
|  | for (Index k = 0; k <= nsuper(); k++) { | 
|  | Index fsupc = supToCol()[k];                      // First column of the current supernode | 
|  | Index istart = rowIndexPtr()[fsupc];              // Pointer index to the subscript of the current column | 
|  | Index nsupr = rowIndexPtr()[fsupc + 1] - istart;  // Number of rows in the current supernode | 
|  | Index nsupc = supToCol()[k + 1] - fsupc;          // Number of columns in the current supernode | 
|  | Index nrow = nsupr - nsupc;                       // Number of rows in the non-diagonal part of the supernode | 
|  | Index irow;                                       // Current index row | 
|  |  | 
|  | if (nsupc == 1) { | 
|  | for (Index j = 0; j < nrhs; j++) { | 
|  | InnerIterator it(*this, fsupc); | 
|  | ++it;  // Skip the diagonal element | 
|  | for (; it; ++it) { | 
|  | irow = it.row(); | 
|  | X(irow, j) -= X(fsupc, j) * it.value(); | 
|  | } | 
|  | } | 
|  | } else { | 
|  | // The supernode has more than one column | 
|  | Index luptr = colIndexPtr()[fsupc]; | 
|  | Index lda = colIndexPtr()[fsupc + 1] - luptr; | 
|  |  | 
|  | // Triangular solve | 
|  | Map<const Matrix<Scalar, Dynamic, Dynamic, ColMajor>, 0, OuterStride<> > A(&(Lval[luptr]), nsupc, nsupc, | 
|  | OuterStride<>(lda)); | 
|  | typename Dest::RowsBlockXpr U = X.derived().middleRows(fsupc, nsupc); | 
|  | U = A.template triangularView<UnitLower>().solve(U); | 
|  | // Matrix-vector product | 
|  | new (&A) Map<const Matrix<Scalar, Dynamic, Dynamic, ColMajor>, 0, OuterStride<> >(&(Lval[luptr + nsupc]), nrow, | 
|  | nsupc, OuterStride<>(lda)); | 
|  | work.topRows(nrow).noalias() = A * U; | 
|  |  | 
|  | // Begin Scatter | 
|  | for (Index j = 0; j < nrhs; j++) { | 
|  | Index iptr = istart + nsupc; | 
|  | for (Index i = 0; i < nrow; i++) { | 
|  | irow = rowIndex()[iptr]; | 
|  | X(irow, j) -= work(i, j);  // Scatter operation | 
|  | work(i, j) = Scalar(0); | 
|  | iptr++; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | template <typename Scalar, typename Index_> | 
|  | template <bool Conjugate, typename Dest> | 
|  | void MappedSuperNodalMatrix<Scalar, Index_>::solveTransposedInPlace(MatrixBase<Dest>& X) const { | 
|  | using numext::conj; | 
|  | Index n = int(X.rows()); | 
|  | Index nrhs = Index(X.cols()); | 
|  | const Scalar* Lval = valuePtr();                                           // Nonzero values | 
|  | Matrix<Scalar, Dynamic, Dest::ColsAtCompileTime, ColMajor> work(n, nrhs);  // working vector | 
|  | work.setZero(); | 
|  | for (Index k = nsuper(); k >= 0; k--) { | 
|  | Index fsupc = supToCol()[k];                      // First column of the current supernode | 
|  | Index istart = rowIndexPtr()[fsupc];              // Pointer index to the subscript of the current column | 
|  | Index nsupr = rowIndexPtr()[fsupc + 1] - istart;  // Number of rows in the current supernode | 
|  | Index nsupc = supToCol()[k + 1] - fsupc;          // Number of columns in the current supernode | 
|  | Index nrow = nsupr - nsupc;                       // Number of rows in the non-diagonal part of the supernode | 
|  | Index irow;                                       // Current index row | 
|  |  | 
|  | if (nsupc == 1) { | 
|  | for (Index j = 0; j < nrhs; j++) { | 
|  | InnerIterator it(*this, fsupc); | 
|  | ++it;  // Skip the diagonal element | 
|  | for (; it; ++it) { | 
|  | irow = it.row(); | 
|  | X(fsupc, j) -= X(irow, j) * (Conjugate ? conj(it.value()) : it.value()); | 
|  | } | 
|  | } | 
|  | } else { | 
|  | // The supernode has more than one column | 
|  | Index luptr = colIndexPtr()[fsupc]; | 
|  | Index lda = colIndexPtr()[fsupc + 1] - luptr; | 
|  |  | 
|  | // Begin Gather | 
|  | for (Index j = 0; j < nrhs; j++) { | 
|  | Index iptr = istart + nsupc; | 
|  | for (Index i = 0; i < nrow; i++) { | 
|  | irow = rowIndex()[iptr]; | 
|  | work.topRows(nrow)(i, j) = X(irow, j);  // Gather operation | 
|  | iptr++; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Matrix-vector product with transposed submatrix | 
|  | Map<const Matrix<Scalar, Dynamic, Dynamic, ColMajor>, 0, OuterStride<> > A(&(Lval[luptr + nsupc]), nrow, nsupc, | 
|  | OuterStride<>(lda)); | 
|  | typename Dest::RowsBlockXpr U = X.derived().middleRows(fsupc, nsupc); | 
|  | if (Conjugate) | 
|  | U = U - A.adjoint() * work.topRows(nrow); | 
|  | else | 
|  | U = U - A.transpose() * work.topRows(nrow); | 
|  |  | 
|  | // Triangular solve (of transposed diagonal block) | 
|  | new (&A) Map<const Matrix<Scalar, Dynamic, Dynamic, ColMajor>, 0, OuterStride<> >(&(Lval[luptr]), nsupc, nsupc, | 
|  | OuterStride<>(lda)); | 
|  | if (Conjugate) | 
|  | U = A.adjoint().template triangularView<UnitUpper>().solve(U); | 
|  | else | 
|  | U = A.transpose().template triangularView<UnitUpper>().solve(U); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | }  // end namespace internal | 
|  |  | 
|  | }  // end namespace Eigen | 
|  |  | 
|  | #endif  // EIGEN_SPARSELU_MATRIX_H |