| // This file is part of Eigen, a lightweight C++ template library | |
| // for linear algebra. | |
| // | |
| // 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/. | |
| // SPDX-FileCopyrightText: The Eigen Authors | |
| // SPDX-License-Identifier: MPL-2.0 | |
| #ifndef EIGEN_STRUCTURED_KRONECKER_SPARSE_VIEW_H | |
| #define EIGEN_STRUCTURED_KRONECKER_SPARSE_VIEW_H | |
| // IWYU pragma: private | |
| #include "./InternalHeaderCheck.h" | |
| namespace Eigen { | |
| namespace internal { | |
| /** \internal The widest StorageIndex of the sparse leaves of \a Factor, \c int | |
| * when it has none. */ | |
| template <typename Factor, int Kind = kron_factor_kind<Factor>()> | |
| struct kron_view_storage_index { | |
| using type = int; | |
| }; | |
| template <typename Scalar, int Options, typename StorageIndex> | |
| struct kron_view_storage_index<SparseMatrix<Scalar, Options, StorageIndex>, kKronSparseFactor> { | |
| using type = StorageIndex; | |
| }; | |
| template <typename LhsMatrix, typename RhsMatrix> | |
| struct kron_view_storage_index<KroneckerOperator<LhsMatrix, RhsMatrix>, kKronKroneckerFactor> | |
| : promote_index_type<typename kron_view_storage_index<LhsMatrix>::type, | |
| typename kron_view_storage_index<RhsMatrix>::type> {}; | |
| template <typename LhsMatrix, typename RhsMatrix> | |
| struct kron_view_storage_index<KroneckerSum<LhsMatrix, RhsMatrix>, kKronSumFactor> | |
| : promote_index_type<typename kron_view_storage_index<LhsMatrix>::type, | |
| typename kron_view_storage_index<RhsMatrix>::type> {}; | |
| template <typename OperatorType, int Options> | |
| struct traits<KroneckerSparseView<OperatorType, Options>> { | |
| using Scalar = typename OperatorType::Scalar; | |
| using StorageKind = Sparse; | |
| using XprKind = MatrixXpr; | |
| // The index type of the plain matrices Eigen evaluates the view into (eval(), | |
| // product temporaries), which the user does not choose. | |
| using StorageIndex = typename kron_view_storage_index<OperatorType>::type; | |
| static constexpr int RowsAtCompileTime = OperatorType::RowsAtCompileTime; | |
| static constexpr int ColsAtCompileTime = OperatorType::ColsAtCompileTime; | |
| static constexpr int MaxRowsAtCompileTime = OperatorType::MaxRowsAtCompileTime; | |
| static constexpr int MaxColsAtCompileTime = OperatorType::MaxColsAtCompileTime; | |
| // Nested by reference like a SparseMatrix: the view owns a copy of the | |
| // operator, which a by-value nesting would copy into every expression. | |
| static constexpr unsigned int Flags = (unsigned(Options) & RowMajorBit) | NestByRefBit; | |
| }; | |
| /** \internal The factor type the view stores for \a Factor: sparse leaves in | |
| * the view's storage order, so that every inner vector is a contiguous | |
| * iteration; every other kind as it is. */ | |
| template <typename Factor, int Options, int Kind = kron_factor_kind<Factor>()> | |
| struct kron_view_factor { | |
| using type = Factor; | |
| static const Factor& convert(const Factor& f) { return f; } | |
| }; | |
| template <typename Scalar, int FactorOptions, typename StorageIndex, int Options> | |
| struct kron_view_factor<SparseMatrix<Scalar, FactorOptions, StorageIndex>, Options, kKronSparseFactor> { | |
| using type = SparseMatrix<Scalar, Options & RowMajorBit ? RowMajor : ColMajor, StorageIndex>; | |
| // A same-order copy keeps the factor's entry order, and a compressed matrix | |
| // may hold unsorted inner vectors; the iterators need them sorted. | |
| static type convert(const SparseMatrix<Scalar, FactorOptions, StorageIndex>& f) { | |
| type g(f); | |
| if (g.innerIndicesAreSorted() != g.outerSize()) g.sortInnerIndices(); | |
| return g; | |
| } | |
| }; | |
| template <typename LhsMatrix, typename RhsMatrix, int Options> | |
| struct kron_view_factor<KroneckerOperator<LhsMatrix, RhsMatrix>, Options, kKronKroneckerFactor> { | |
| using Lhs = kron_view_factor<LhsMatrix, Options>; | |
| using Rhs = kron_view_factor<RhsMatrix, Options>; | |
| using type = KroneckerOperator<typename Lhs::type, typename Rhs::type>; | |
| static type convert(const KroneckerOperator<LhsMatrix, RhsMatrix>& f) { | |
| return type(Lhs::convert(f.lhs()), Rhs::convert(f.rhs())); | |
| } | |
| }; | |
| template <typename LhsMatrix, typename RhsMatrix, int Options> | |
| struct kron_view_factor<KroneckerSum<LhsMatrix, RhsMatrix>, Options, kKronSumFactor> { | |
| using Lhs = kron_view_factor<LhsMatrix, Options>; | |
| using Rhs = kron_view_factor<RhsMatrix, Options>; | |
| using type = KroneckerSum<typename Lhs::type, typename Rhs::type>; | |
| static type convert(const KroneckerSum<LhsMatrix, RhsMatrix>& f) { | |
| return type(Lhs::convert(f.lhs()), Rhs::convert(f.rhs())); | |
| } | |
| }; | |
| /** \internal Iterates the stored entries of inner vector \a outer of a factor -- | |
| * column \a outer when \a RowMajor is false, row \a outer otherwise -- in | |
| * increasing inner index. Dense factor: every entry. */ | |
| template <typename Factor, bool RowMajor, int Kind = kron_factor_kind<Factor>()> | |
| class kron_view_iterator { | |
| public: | |
| using Scalar = typename Factor::Scalar; | |
| kron_view_iterator(const Factor& f, Index outer) | |
| : m_f(&f), m_outer(outer), m_inner(0), m_end(RowMajor ? f.cols() : f.rows()) {} | |
| explicit operator bool() const { return m_inner < m_end; } | |
| kron_view_iterator& operator++() { | |
| ++m_inner; | |
| return *this; | |
| } | |
| Index index() const { return m_inner; } | |
| Scalar value() const { return RowMajor ? m_f->coeff(m_outer, m_inner) : m_f->coeff(m_inner, m_outer); } | |
| private: | |
| const Factor* m_f; | |
| Index m_outer, m_inner, m_end; | |
| }; | |
| // Diagonal and identity factors: at most the diagonal entry. | |
| template <typename Factor, bool RowMajor> | |
| class kron_view_iterator<Factor, RowMajor, kKronDiagonalFactor> { | |
| public: | |
| using Scalar = typename Factor::Scalar; | |
| kron_view_iterator(const Factor& f, Index outer) : m_f(&f), m_outer(outer), m_valid(true) {} | |
| explicit operator bool() const { return m_valid; } | |
| kron_view_iterator& operator++() { | |
| m_valid = false; | |
| return *this; | |
| } | |
| Index index() const { return m_outer; } | |
| Scalar value() const { return m_f->diagonal().coeff(m_outer); } | |
| private: | |
| const Factor* m_f; | |
| Index m_outer; | |
| bool m_valid; | |
| }; | |
| template <typename Factor, bool RowMajor> | |
| class kron_view_iterator<Factor, RowMajor, kKronIdentityFactor> { | |
| public: | |
| using Scalar = typename Factor::Scalar; | |
| kron_view_iterator(const Factor& f, Index outer) | |
| : m_outer(outer), m_valid(outer < numext::mini(f.rows(), f.cols())) {} | |
| explicit operator bool() const { return m_valid; } | |
| kron_view_iterator& operator++() { | |
| m_valid = false; | |
| return *this; | |
| } | |
| Index index() const { return m_outer; } | |
| Scalar value() const { return Scalar(1); } | |
| private: | |
| Index m_outer; | |
| bool m_valid; | |
| }; | |
| // Sparse factor, compressed and stored in the view's order (see | |
| // kron_view_factor). Raw pointers rather than the matrix's InnerIterator keep | |
| // the iterator assignable, which the Kronecker iterator needs to restart it. | |
| template <typename Factor, bool RowMajor> | |
| class kron_view_iterator<Factor, RowMajor, kKronSparseFactor> { | |
| public: | |
| using Scalar = typename Factor::Scalar; | |
| static_assert(bool(Factor::IsRowMajor) == RowMajor, "the view converts sparse factors to its storage order"); | |
| kron_view_iterator(const Factor& f, Index outer) | |
| : m_values(f.valuePtr()), | |
| m_indices(f.innerIndexPtr()), | |
| m_pos(f.outerIndexPtr()[outer]), | |
| m_end(f.outerIndexPtr()[outer + 1]) { | |
| eigen_internal_assert(f.isCompressed()); | |
| } | |
| explicit operator bool() const { return m_pos < m_end; } | |
| kron_view_iterator& operator++() { | |
| ++m_pos; | |
| return *this; | |
| } | |
| Index index() const { return m_indices[m_pos]; } | |
| Scalar value() const { return m_values[m_pos]; } | |
| private: | |
| const Scalar* m_values; | |
| const typename Factor::StorageIndex* m_indices; | |
| Index m_pos, m_end; | |
| }; | |
| /** \internal Kronecker factor K = L (x) R: inner vector kL * outR + kR of K, with | |
| * outR and inR the outer and inner sizes of R, is the product of inner vectors | |
| * kL of L and kR of R; their entries meet at inner index iL * inR + iR, | |
| * increasing when the loop over L is outermost. */ | |
| template <typename LhsMatrix, typename RhsMatrix, bool RowMajor> | |
| class kron_view_iterator<KroneckerOperator<LhsMatrix, RhsMatrix>, RowMajor, kKronKroneckerFactor> { | |
| public: | |
| using Factor = KroneckerOperator<LhsMatrix, RhsMatrix>; | |
| using Scalar = typename Factor::Scalar; | |
| kron_view_iterator(const Factor& f, Index outer) | |
| : m_rhs(&f.rhs()), | |
| m_outerR(outer % outerSize(f.rhs())), | |
| m_innerR(RowMajor ? f.rhs().cols() : f.rhs().rows()), | |
| m_itL(f.lhs(), outer / outerSize(f.rhs())), | |
| m_itR(f.rhs(), m_outerR), | |
| m_nonEmptyR(bool(m_itR)) {} | |
| explicit operator bool() const { return m_nonEmptyR && bool(m_itL); } | |
| kron_view_iterator& operator++() { | |
| ++m_itR; | |
| if (!m_itR) { | |
| ++m_itL; | |
| if (m_itL) m_itR = RhsIterator(*m_rhs, m_outerR); | |
| } | |
| return *this; | |
| } | |
| Index index() const { return m_itL.index() * m_innerR + m_itR.index(); } | |
| Scalar value() const { return m_itL.value() * m_itR.value(); } | |
| private: | |
| using LhsIterator = kron_view_iterator<LhsMatrix, RowMajor>; | |
| using RhsIterator = kron_view_iterator<RhsMatrix, RowMajor>; | |
| template <typename F> | |
| static Index outerSize(const F& f) { | |
| return RowMajor ? f.rows() : f.cols(); | |
| } | |
| const RhsMatrix* m_rhs; | |
| Index m_outerR, m_innerR; | |
| LhsIterator m_itL; | |
| RhsIterator m_itR; | |
| bool m_nonEmptyR; | |
| }; | |
| /** \internal Kronecker sum S = L (+) R with n2 the size of R: inner vector | |
| * kL * n2 + kR merges the entries of L (x) I, at iL * n2 + kR for the stored iL | |
| * of inner vector kL of L, with those of I (x) R, at kL * n2 + iR for the stored | |
| * iR of inner vector kR of R; the two streams meet on the diagonal. */ | |
| template <typename LhsMatrix, typename RhsMatrix, bool RowMajor> | |
| class kron_view_iterator<KroneckerSum<LhsMatrix, RhsMatrix>, RowMajor, kKronSumFactor> { | |
| public: | |
| using Factor = KroneckerSum<LhsMatrix, RhsMatrix>; | |
| using Scalar = typename Factor::Scalar; | |
| kron_view_iterator(const Factor& f, Index outer) | |
| : m_n2(f.rhs().rows()), | |
| m_outerL(outer / m_n2), | |
| m_outerR(outer % m_n2), | |
| m_itL(f.lhs(), m_outerL), | |
| m_itR(f.rhs(), m_outerR) {} | |
| explicit operator bool() const { return bool(m_itL) || bool(m_itR); } | |
| kron_view_iterator& operator++() { | |
| const Index current = index(); | |
| if (indexL() == current) ++m_itL; | |
| if (indexR() == current) ++m_itR; | |
| return *this; | |
| } | |
| Index index() const { return numext::mini(indexL(), indexR()); } | |
| // The values of the materialization (A (x) I) + (I (x) B), signed zeros | |
| // included: a + b on the diagonal, a + 0 and 0 + b off it. | |
| Scalar value() const { | |
| const Index l = indexL(), r = indexR(); | |
| if (l == r) return m_itL.value() + m_itR.value(); | |
| return l < r ? m_itL.value() + Scalar(0) : Scalar(0) + m_itR.value(); | |
| } | |
| private: | |
| using LhsIterator = kron_view_iterator<LhsMatrix, RowMajor>; | |
| using RhsIterator = kron_view_iterator<RhsMatrix, RowMajor>; | |
| Index indexL() const { return m_itL ? m_itL.index() * m_n2 + m_outerR : NumTraits<Index>::highest(); } | |
| Index indexR() const { return m_itR ? m_outerL * m_n2 + m_itR.index() : NumTraits<Index>::highest(); } | |
| Index m_n2, m_outerL, m_outerR; | |
| LhsIterator m_itL; | |
| RhsIterator m_itR; | |
| }; | |
| /** \internal The stored-entry count of the view: exact for Kronecker products, | |
| * an upper bound for Kronecker sums (whose two terms share the diagonal). */ | |
| template <typename Factor, int Kind = kron_factor_kind<Factor>()> | |
| struct kron_view_nonzeros { | |
| static Index run(const Factor& f) { return kron_factor_ops<Factor>::innerNonZeros(f, false).sum(); } | |
| }; | |
| template <typename LhsMatrix, typename RhsMatrix> | |
| struct kron_view_nonzeros<KroneckerOperator<LhsMatrix, RhsMatrix>, kKronKroneckerFactor> { | |
| static Index run(const KroneckerOperator<LhsMatrix, RhsMatrix>& f) { | |
| return kron_view_nonzeros<LhsMatrix>::run(f.lhs()) * kron_view_nonzeros<RhsMatrix>::run(f.rhs()); | |
| } | |
| }; | |
| template <typename LhsMatrix, typename RhsMatrix> | |
| struct kron_view_nonzeros<KroneckerSum<LhsMatrix, RhsMatrix>, kKronSumFactor> { | |
| static Index run(const KroneckerSum<LhsMatrix, RhsMatrix>& f) { | |
| return kron_view_nonzeros<LhsMatrix>::run(f.lhs()) * f.rhs().rows() + | |
| f.lhs().rows() * kron_view_nonzeros<RhsMatrix>::run(f.rhs()); | |
| } | |
| }; | |
| } // namespace internal | |
| /** \ingroup StructuredMatrices_Module | |
| * \class KroneckerSparseView | |
| * \brief A \ref KroneckerOperator or \ref KroneckerSum as a lazy sparse | |
| * expression. | |
| * | |
| * The view is a \c SparseMatrixBase expression whose inner vectors are | |
| * iterated straight from the factors, so the operator takes part in sparse | |
| * expressions, products and assignments without being materialized first. | |
| * A product follows Eigen's cost model for its operands like any sparse | |
| * expression: a sparse-sparse product, or one with a row-major dense | |
| * right-hand side, revisits every inner vector of the view and evaluates it | |
| * into a temporary first when an entry costs more to recompute than to read | |
| * (complex scalars, whose multiply is dearer than a read). | |
| * \code | |
| * auto L = makeKroneckerSum(Dy, Dx); // 2-D Laplacian | |
| * SparseMatrix<double> M = Id - tau * L.sparseView(); // assembled once, no temporary for L | |
| * SparseMatrix<double> P = L.sparseView() * S; // sparse-sparse product | |
| * \endcode | |
| * Inner vector \c kA*n2' + kB of \f$ A \otimes B \f$ (\c n2' the outer size of | |
| * \c B) is the product of inner vectors \c kA of \c A and \c kB of \c B, so an | |
| * iterator walks the stored entries of two factor inner vectors; for | |
| * \f$ A \oplus B \f$ it merges the entries of \f$ A \otimes I \f$ and | |
| * \f$ I \otimes B \f$. The view stores exactly the entries a sparse | |
| * materialization would: every stored entry of a factor, explicit zeros | |
| * included, and nothing is pruned. It is the operand for sparse expressions | |
| * and assembly; a product with a dense right-hand side is faster through the | |
| * operator itself, which applies whole factors instead of one entry at a time. | |
| * | |
| * The view owns a copy of the operator, with sparse factors converted to its | |
| * storage order \a Options (\c ColMajor or \c RowMajor, which must match the | |
| * other operands of a sparse binary expression). Like a \c SparseMatrix it is | |
| * nested by reference in the expressions built from it, so an expression must | |
| * not outlive a temporary view. Its \c StorageIndex, the index type of the | |
| * temporaries Eigen evaluates it into, is the widest of its sparse factors' | |
| * (\c int without any) and must hold its dimensions and stored-entry count; | |
| * 64-bit sparse factors give a 64-bit view. Its \c InnerIterator is also the | |
| * interface the coefficient-reading preconditioners take, e.g. | |
| * \c DiagonalPreconditioner::compute(view). The view is not a matrix type for | |
| * the iterative solvers themselves, which bind theirs through \c Ref; give them | |
| * the operator (matrix-free, \c IdentityPreconditioner) or a materialized | |
| * \c SparseMatrix. | |
| * | |
| * \tparam OperatorType the \ref KroneckerOperator or \ref KroneckerSum type. | |
| * \tparam Options \c ColMajor or \c RowMajor, the storage order of the view. | |
| * | |
| * \sa KroneckerOperator::sparseView(), KroneckerSum::sparseView() | |
| */ | |
| template <typename OperatorType, int Options> | |
| class KroneckerSparseView : public SparseMatrixBase<KroneckerSparseView<OperatorType, Options>> { | |
| using ViewFactor = internal::kron_view_factor<OperatorType, Options>; | |
| public: | |
| using Base = SparseMatrixBase<KroneckerSparseView>; | |
| EIGEN_SPARSE_PUBLIC_INTERFACE(KroneckerSparseView) | |
| using ViewOperator = typename ViewFactor::type; | |
| static constexpr bool RowMajorView = (unsigned(Options) & RowMajorBit) != 0; | |
| explicit KroneckerSparseView(const OperatorType& op) : m_op(ViewFactor::convert(op)) {} | |
| Index rows() const { return m_op.rows(); } | |
| Index cols() const { return m_op.cols(); } | |
| /** \returns the operator the view iterates, with its sparse factors in the | |
| * view's storage order. */ | |
| const ViewOperator& nestedOperator() const { return m_op; } | |
| /** Iterates the stored entries of an inner vector in increasing inner index. */ | |
| class InnerIterator { | |
| public: | |
| InnerIterator(const KroneckerSparseView& view, Index outer) : m_it(view.m_op, outer), m_outer(outer) {} | |
| InnerIterator& operator++() { | |
| ++m_it; | |
| return *this; | |
| } | |
| operator bool() const { return bool(m_it); } | |
| Index index() const { return m_it.index(); } | |
| Index outer() const { return m_outer; } | |
| Index row() const { return RowMajorView ? m_outer : index(); } | |
| Index col() const { return RowMajorView ? index() : m_outer; } | |
| Scalar value() const { return m_it.value(); } | |
| private: | |
| internal::kron_view_iterator<ViewOperator, RowMajorView> m_it; | |
| Index m_outer; | |
| }; | |
| private: | |
| ViewOperator m_op; | |
| }; | |
| namespace internal { | |
| template <typename OperatorType, int Options> | |
| struct evaluator<KroneckerSparseView<OperatorType, Options>> | |
| : evaluator_base<KroneckerSparseView<OperatorType, Options>> { | |
| using XprType = KroneckerSparseView<OperatorType, Options>; | |
| using Scalar = typename XprType::Scalar; | |
| static constexpr int CoeffReadCost = NumTraits<Scalar>::MulCost; | |
| static constexpr unsigned int Flags = traits<XprType>::Flags; | |
| class InnerIterator : public XprType::InnerIterator { | |
| public: | |
| InnerIterator(const evaluator& eval, Index outer) : XprType::InnerIterator(eval.m_view, outer) {} | |
| }; | |
| explicit evaluator(const XprType& xpr) : m_view(xpr) {} | |
| Index nonZerosEstimate() const { | |
| return kron_view_nonzeros<typename XprType::ViewOperator>::run(m_view.nestedOperator()); | |
| } | |
| const XprType& m_view; | |
| }; | |
| } // namespace internal | |
| } // namespace Eigen | |
| #endif // EIGEN_STRUCTURED_KRONECKER_SPARSE_VIEW_H |