| // 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_SCALEDPERMUTATIONMATRIX_H |
| #define EIGEN_SCALEDPERMUTATIONMATRIX_H |
| |
| // IWYU pragma: private |
| #include "./InternalHeaderCheck.h" |
| |
| namespace Eigen { |
| |
| namespace internal { |
| |
| template <typename Scalar_, int SizeAtCompileTime, int MaxSizeAtCompileTime, typename StorageIndex_> |
| struct traits<ScaledPermutationMatrix<Scalar_, SizeAtCompileTime, MaxSizeAtCompileTime, StorageIndex_>> { |
| using Scalar = Scalar_; |
| using StorageIndex = StorageIndex_; |
| // Dense, so that products and sums with dense operands promote with the existing rules; the O(n) kernels are |
| // selected by the shape (ScaledPermutationShape), as for TriangularView. |
| using StorageKind = Dense; |
| using XprKind = MatrixXpr; |
| using PermutationType = PermutationMatrix<SizeAtCompileTime, MaxSizeAtCompileTime, StorageIndex_>; |
| using ScalesType = Matrix<Scalar_, SizeAtCompileTime, 1, 0, MaxSizeAtCompileTime, 1>; |
| static constexpr int RowsAtCompileTime = SizeAtCompileTime; |
| static constexpr int ColsAtCompileTime = SizeAtCompileTime; |
| static constexpr int MaxRowsAtCompileTime = MaxSizeAtCompileTime; |
| static constexpr int MaxColsAtCompileTime = MaxSizeAtCompileTime; |
| static constexpr unsigned int Flags = NestByRefBit; |
| }; |
| |
| /** \internal The scaled permutation produced by a permutation-like and a diagonal-like operand. */ |
| template <typename Scalar, typename Lhs, typename Rhs, typename StorageIndex> |
| struct scaled_permutation_result { |
| static constexpr int Size = size_prefer_fixed(traits<Lhs>::RowsAtCompileTime, traits<Rhs>::RowsAtCompileTime); |
| static constexpr int MaxSize = |
| min_size_prefer_fixed(traits<Lhs>::MaxRowsAtCompileTime, traits<Rhs>::MaxRowsAtCompileTime); |
| using type = ScaledPermutationMatrix<Scalar, Size, MaxSize, StorageIndex>; |
| }; |
| |
| template <typename Lhs, typename Rhs, typename StorageIndex> |
| struct scaled_permutation_product_result { |
| using LhsScalar = typename traits<Lhs>::Scalar; |
| using RhsScalar = typename traits<Rhs>::Scalar; |
| using Scalar = |
| typename ScalarBinaryOpTraits<LhsScalar, RhsScalar, scalar_product_op<LhsScalar, RhsScalar>>::ReturnType; |
| using type = typename scaled_permutation_result<Scalar, Lhs, Rhs, StorageIndex>::type; |
| }; |
| |
| /** \internal indices of the inverse permutation: result(indices(k)) = k. */ |
| template <typename IndicesType, typename Result> |
| EIGEN_DEVICE_FUNC void invert_permutation_indices(const IndicesType& indices, Result& result) { |
| using StorageIndex = typename Result::Scalar; |
| for (Index k = 0; k < indices.size(); ++k) result.coeffRef(indices.coeff(k)) = StorageIndex(k); |
| } |
| |
| } // namespace internal |
| |
| /** \class ScaledPermutationBase |
| * \ingroup Core_Module |
| * |
| * \brief Base class for scaled permutation matrices |
| * |
| * A scaled permutation is the product \f$P D\f$ of a permutation matrix and a diagonal matrix: a square matrix with |
| * exactly one nonzero per row and per column. It is stored as the permutation's indices and one scale per |
| * column, so that coefficient (indices()(k), k) equals scales()(k). |
| * |
| * The set is closed under products with permutations, diagonal matrices, scalars and other scaled permutations, |
| * and under inversion and transposition; all of these cost \f$O(n)\f$ and return a plain ScaledPermutationMatrix. |
| * Products with a dense matrix scale and permute its rows or columns in \f$O(nm)\f$, and assigning to a dense matrix |
| * scatters the scales, so writing `P * D * x` or `P * D * P.inverse()` never forms an \f$n \times n\f$ intermediate. |
| * Sums with a dense matrix are lazy expressions. |
| * |
| * \sa class ScaledPermutationMatrix, class PermutationBase, class DiagonalBase |
| */ |
| template <typename Derived> |
| class ScaledPermutationBase : public EigenBase<Derived> { |
| using Traits = internal::traits<Derived>; |
| using Base = EigenBase<Derived>; |
| |
| public: |
| #ifndef EIGEN_PARSED_BY_DOXYGEN |
| using Scalar = typename Traits::Scalar; |
| using RealScalar = typename NumTraits<Scalar>::Real; |
| using StorageIndex = typename Traits::StorageIndex; |
| using StorageKind = typename Traits::StorageKind; |
| using PermutationType = typename Traits::PermutationType; |
| using ScalesType = typename Traits::ScalesType; |
| using IndicesType = typename PermutationType::IndicesType; |
| static constexpr int RowsAtCompileTime = Traits::RowsAtCompileTime; |
| static constexpr int ColsAtCompileTime = Traits::ColsAtCompileTime; |
| static constexpr int MaxRowsAtCompileTime = Traits::MaxRowsAtCompileTime; |
| static constexpr int MaxColsAtCompileTime = Traits::MaxColsAtCompileTime; |
| static constexpr int SizeAtCompileTime = internal::size_at_compile_time(RowsAtCompileTime, ColsAtCompileTime); |
| static constexpr int MaxSizeAtCompileTime = |
| internal::size_at_compile_time(MaxRowsAtCompileTime, MaxColsAtCompileTime); |
| static constexpr bool IsVectorAtCompileTime = false; |
| static constexpr unsigned int Flags = Traits::Flags; |
| using DenseMatrixType = |
| Matrix<Scalar, RowsAtCompileTime, ColsAtCompileTime, 0, MaxRowsAtCompileTime, MaxColsAtCompileTime>; |
| using PlainObject = ScaledPermutationMatrix<Scalar, RowsAtCompileTime, MaxRowsAtCompileTime, StorageIndex>; |
| using Nested = const Derived&; |
| using Base::derived; |
| #endif |
| |
| /** \returns the number of rows */ |
| EIGEN_DEVICE_FUNC constexpr Index rows() const { return indices().size(); } |
| /** \returns the number of columns */ |
| EIGEN_DEVICE_FUNC constexpr Index cols() const { return indices().size(); } |
| |
| /** \returns the permutation factor \f$P\f$ */ |
| EIGEN_DEVICE_FUNC const PermutationType& permutation() const { return derived().permutation(); } |
| /** \returns the permutation's indices: column \c k has its nonzero in row `indices()(k)` */ |
| EIGEN_DEVICE_FUNC constexpr const IndicesType& indices() const { return derived().indices(); } |
| /** \returns the scales: column \c k's nonzero equals `scales()(k)` */ |
| EIGEN_DEVICE_FUNC const ScalesType& scales() const { return derived().scales(); } |
| |
| /** \returns the coefficient at (\a row, \a col) of the represented matrix */ |
| EIGEN_DEVICE_FUNC Scalar coeff(Index row, Index col) const { |
| eigen_assert(row >= 0 && col >= 0 && row < rows() && col < cols()); |
| return Index(indices().coeff(col)) == row ? scales().coeff(col) : Scalar(0); |
| } |
| |
| /** \returns the represented matrix as a plain dense matrix */ |
| EIGEN_DEVICE_FUNC DenseMatrixType toDenseMatrix() const { return derived(); } |
| |
| #ifndef EIGEN_PARSED_BY_DOXYGEN |
| template <typename DenseDerived> |
| EIGEN_DEVICE_FUNC void evalTo(MatrixBase<DenseDerived>& other) const { |
| other.setZero(); |
| for (Index k = 0; k < rows(); ++k) other.coeffRef(indices().coeff(k), k) = scales().coeff(k); |
| } |
| #endif |
| |
| /** \returns the inverse, \f$(PD)^{-1} = D^{-1} P^{-1}\f$, which has \f$1 / \text{scales}(k)\f$ at |
| * (\c k, `indices()(k)`). The scales must be nonzero. */ |
| PlainObject inverse() const { |
| PlainObject result(rows()); |
| for (Index k = 0; k < rows(); ++k) { |
| const Index image = indices().coeff(k); |
| result.indices().coeffRef(image) = StorageIndex(k); |
| result.scales().coeffRef(image) = Scalar(1) / scales().coeff(k); |
| } |
| return result; |
| } |
| |
| /** \returns the transpose, which has `scales()(k)` at (\c k, `indices()(k)`) */ |
| PlainObject transpose() const { |
| PlainObject result(rows()); |
| for (Index k = 0; k < rows(); ++k) { |
| const Index image = indices().coeff(k); |
| result.indices().coeffRef(image) = StorageIndex(k); |
| result.scales().coeffRef(image) = scales().coeff(k); |
| } |
| return result; |
| } |
| |
| /** \returns the adjoint, the transpose with conjugated scales */ |
| PlainObject adjoint() const { |
| PlainObject result = transpose(); |
| result.scales() = result.scales().conjugate(); |
| return result; |
| } |
| |
| /** \returns the determinant, the permutation's sign times the product of the scales */ |
| Scalar determinant() const { return Scalar(RealScalar(permutation().determinant())) * scales().prod(); } |
| |
| /** \returns the dense matrix product of \c *this by the dense matrix \a other: rows of \a other are scaled and |
| * permuted. */ |
| template <typename OtherDerived> |
| EIGEN_DEVICE_FUNC const Product<Derived, OtherDerived, DefaultProduct> operator*( |
| const MatrixBase<OtherDerived>& other) const { |
| return Product<Derived, OtherDerived, DefaultProduct>(derived(), other.derived()); |
| } |
| |
| /** \returns the dense matrix product of the dense matrix \a other by \a scaled: columns of \a other are scaled |
| * and permuted. */ |
| template <typename OtherDerived> |
| EIGEN_DEVICE_FUNC friend const Product<OtherDerived, Derived, DefaultProduct> operator*( |
| const MatrixBase<OtherDerived>& other, const ScaledPermutationBase& scaled) { |
| return Product<OtherDerived, Derived, DefaultProduct>(other.derived(), scaled.derived()); |
| } |
| |
| /** \returns the dense matrix product of \c *this by the triangular or self-adjoint view \a other */ |
| template <typename OtherDerived> |
| EIGEN_DEVICE_FUNC const Product<Derived, OtherDerived, DefaultProduct> operator*( |
| const TriangularBase<OtherDerived>& other) const { |
| return Product<Derived, OtherDerived, DefaultProduct>(derived(), other.derived()); |
| } |
| |
| /** \returns the dense matrix product of the triangular or self-adjoint view \a other by \a scaled */ |
| template <typename OtherDerived> |
| EIGEN_DEVICE_FUNC friend const Product<OtherDerived, Derived, DefaultProduct> operator*( |
| const TriangularBase<OtherDerived>& other, const ScaledPermutationBase& scaled) { |
| return Product<OtherDerived, Derived, DefaultProduct>(other.derived(), scaled.derived()); |
| } |
| |
| // Closed-form products, all O(n). With S e_c = v_c e_{tau(c)} the rules are: |
| // S D: scale v_c d_c D S: scale d_{tau(c)} v_c |
| // S P: (tau(sigma(c)), v_{sigma(c)}) P S: (sigma(tau(c)), v_c) |
| // S T: (tau(tau2(c)), v_{tau2(c)} v2_c) |
| |
| /** \returns the scaled permutation \c *this times the diagonal matrix \a other */ |
| template <typename OtherDerived> |
| typename internal::scaled_permutation_product_result<Derived, OtherDerived, StorageIndex>::type operator*( |
| const DiagonalBase<OtherDerived>& other) const { |
| using Result = typename internal::scaled_permutation_product_result<Derived, OtherDerived, StorageIndex>::type; |
| eigen_assert(rows() == other.rows()); |
| return Result(indices(), scales().cwiseProduct(other.diagonal())); |
| } |
| |
| /** \returns the scaled permutation diagonal matrix \a other times \a scaled */ |
| template <typename OtherDerived> |
| friend typename internal::scaled_permutation_product_result<OtherDerived, Derived, StorageIndex>::type operator*( |
| const DiagonalBase<OtherDerived>& other, const ScaledPermutationBase& scaled) { |
| using Result = typename internal::scaled_permutation_product_result<OtherDerived, Derived, StorageIndex>::type; |
| eigen_assert(other.rows() == scaled.rows()); |
| Result result(scaled.rows()); |
| result.indices() = scaled.indices(); |
| for (Index k = 0; k < scaled.rows(); ++k) |
| result.scales().coeffRef(k) = other.diagonal().coeff(scaled.indices().coeff(k)) * scaled.scales().coeff(k); |
| return result; |
| } |
| |
| /** \returns the scaled permutation \c *this times the permutation \a other */ |
| template <typename OtherDerived> |
| PlainObject operator*(const PermutationBase<OtherDerived>& other) const { |
| eigen_assert(rows() == other.rows()); |
| PlainObject result(rows()); |
| for (Index k = 0; k < rows(); ++k) { |
| const Index source = other.indices().coeff(k); |
| result.indices().coeffRef(k) = indices().coeff(source); |
| result.scales().coeffRef(k) = scales().coeff(source); |
| } |
| return result; |
| } |
| |
| /** \returns the scaled permutation permutation \a other times \a scaled */ |
| template <typename OtherDerived> |
| friend PlainObject operator*(const PermutationBase<OtherDerived>& other, const ScaledPermutationBase& scaled) { |
| eigen_assert(other.rows() == scaled.rows()); |
| PlainObject result(scaled.rows()); |
| for (Index k = 0; k < scaled.rows(); ++k) |
| result.indices().coeffRef(k) = StorageIndex(other.indices().coeff(scaled.indices().coeff(k))); |
| result.scales() = scaled.scales(); |
| return result; |
| } |
| |
| /** \returns the scaled permutation \c *this times the inverse permutation \a other */ |
| template <typename OtherDerived> |
| PlainObject operator*(const InverseImpl<OtherDerived, PermutationStorage>& other) const { |
| eigen_assert(rows() == other.rows()); |
| IndicesType inverse(rows()); |
| internal::invert_permutation_indices(other.derived().nestedExpression().indices(), inverse); |
| PlainObject result(rows()); |
| for (Index k = 0; k < rows(); ++k) { |
| const Index source = inverse.coeff(k); |
| result.indices().coeffRef(k) = indices().coeff(source); |
| result.scales().coeffRef(k) = scales().coeff(source); |
| } |
| return result; |
| } |
| |
| /** \returns the scaled permutation inverse permutation \a other times \a scaled */ |
| template <typename OtherDerived> |
| friend PlainObject operator*(const InverseImpl<OtherDerived, PermutationStorage>& other, |
| const ScaledPermutationBase& scaled) { |
| eigen_assert(other.rows() == scaled.rows()); |
| IndicesType inverse(scaled.rows()); |
| internal::invert_permutation_indices(other.derived().nestedExpression().indices(), inverse); |
| PlainObject result(scaled.rows()); |
| for (Index k = 0; k < scaled.rows(); ++k) result.indices().coeffRef(k) = inverse.coeff(scaled.indices().coeff(k)); |
| result.scales() = scaled.scales(); |
| return result; |
| } |
| |
| /** \returns the scaled permutation \c *this times the scaled permutation \a other */ |
| template <typename OtherDerived> |
| typename internal::scaled_permutation_product_result<Derived, OtherDerived, StorageIndex>::type operator*( |
| const ScaledPermutationBase<OtherDerived>& other) const { |
| using Result = typename internal::scaled_permutation_product_result<Derived, OtherDerived, StorageIndex>::type; |
| eigen_assert(rows() == other.rows()); |
| Result result(rows()); |
| for (Index k = 0; k < rows(); ++k) { |
| const Index source = other.indices().coeff(k); |
| result.indices().coeffRef(k) = indices().coeff(source); |
| result.scales().coeffRef(k) = scales().coeff(source) * other.scales().coeff(k); |
| } |
| return result; |
| } |
| |
| /** \returns \c *this with its scales multiplied by \a alpha */ |
| PlainObject operator*(const Scalar& alpha) const { return PlainObject(indices(), scales() * alpha); } |
| |
| /** \returns \a scaled with its scales multiplied by \a alpha */ |
| friend PlainObject operator*(const Scalar& alpha, const ScaledPermutationBase& scaled) { |
| return PlainObject(scaled.indices(), alpha * scaled.scales()); |
| } |
| |
| /** \returns \c *this with its scales negated */ |
| PlainObject operator-() const { return PlainObject(indices(), -scales()); } |
| |
| // Sums with a dense matrix are lazy: the scaled permutation is read through its index-based evaluator. |
| |
| /** \returns the lazy sum of the dense matrix \a lhs and the scaled permutation \a rhs */ |
| template <typename OtherDerived> |
| EIGEN_DEVICE_FUNC friend const EIGEN_CWISE_BINARY_RETURN_TYPE(OtherDerived, Derived, internal::scalar_sum_op) |
| operator+(const MatrixBase<OtherDerived>& lhs, const ScaledPermutationBase & rhs) { |
| return EIGEN_CWISE_BINARY_RETURN_TYPE(OtherDerived, Derived, internal::scalar_sum_op)(lhs.derived(), rhs.derived()); |
| } |
| |
| /** \returns the lazy sum of the scaled permutation \a lhs and the dense matrix \a rhs */ |
| template <typename OtherDerived> |
| EIGEN_DEVICE_FUNC friend const EIGEN_CWISE_BINARY_RETURN_TYPE(Derived, OtherDerived, internal::scalar_sum_op) |
| operator+(const ScaledPermutationBase & lhs, const MatrixBase<OtherDerived>& rhs) { |
| return EIGEN_CWISE_BINARY_RETURN_TYPE(Derived, OtherDerived, internal::scalar_sum_op)(lhs.derived(), rhs.derived()); |
| } |
| |
| /** \returns the lazy difference of the dense matrix \a lhs and the scaled permutation \a rhs */ |
| template <typename OtherDerived> |
| EIGEN_DEVICE_FUNC friend const EIGEN_CWISE_BINARY_RETURN_TYPE(OtherDerived, Derived, internal::scalar_difference_op) |
| operator-(const MatrixBase<OtherDerived>& lhs, const ScaledPermutationBase & rhs) { |
| return EIGEN_CWISE_BINARY_RETURN_TYPE(OtherDerived, Derived, internal::scalar_difference_op)(lhs.derived(), |
| rhs.derived()); |
| } |
| |
| /** \returns the lazy difference of the scaled permutation \a lhs and the dense matrix \a rhs */ |
| template <typename OtherDerived> |
| EIGEN_DEVICE_FUNC friend const EIGEN_CWISE_BINARY_RETURN_TYPE(Derived, OtherDerived, internal::scalar_difference_op) |
| operator-(const ScaledPermutationBase & lhs, const MatrixBase<OtherDerived>& rhs) { |
| return EIGEN_CWISE_BINARY_RETURN_TYPE(Derived, OtherDerived, internal::scalar_difference_op)(lhs.derived(), |
| rhs.derived()); |
| } |
| }; |
| |
| /** \class ScaledPermutationMatrix |
| * \ingroup Core_Module |
| * |
| * \brief Scaled permutation matrix \f$P D\f$ with its storage |
| * |
| * \tparam Scalar_ the type of the scales |
| * \tparam SizeAtCompileTime the number of rows/cols, or Dynamic |
| * \tparam MaxSizeAtCompileTime the maximum number of rows/cols, or Dynamic; defaults to SizeAtCompileTime |
| * \tparam StorageIndex_ the integer type of the permutation's indices |
| * |
| * This is the type returned by the products of a permutation (or its inverse) and a diagonal matrix, in either |
| * order. See ScaledPermutationBase for the operations. |
| * |
| * \sa class ScaledPermutationBase, class PermutationMatrix, class DiagonalMatrix |
| */ |
| template <typename Scalar_, int SizeAtCompileTime, int MaxSizeAtCompileTime, typename StorageIndex_> |
| class ScaledPermutationMatrix |
| : public ScaledPermutationBase< |
| ScaledPermutationMatrix<Scalar_, SizeAtCompileTime, MaxSizeAtCompileTime, StorageIndex_>> { |
| using Base = ScaledPermutationBase<ScaledPermutationMatrix>; |
| using Traits = internal::traits<ScaledPermutationMatrix>; |
| |
| public: |
| #ifndef EIGEN_PARSED_BY_DOXYGEN |
| using Scalar = Scalar_; |
| using StorageIndex = StorageIndex_; |
| using PermutationType = typename Traits::PermutationType; |
| using ScalesType = typename Traits::ScalesType; |
| using IndicesType = typename PermutationType::IndicesType; |
| #endif |
| |
| /** Default constructor; the matrix is uninitialized. */ |
| EIGEN_DEVICE_FUNC ScaledPermutationMatrix() = default; |
| |
| /** Constructs an uninitialized scaled permutation of the given size. */ |
| EIGEN_DEVICE_FUNC explicit ScaledPermutationMatrix(Index size) : m_permutation(size), m_scales(size) {} |
| |
| /** Constructs the product \a permutation times \a diagonal. */ |
| template <typename PermutationDerived, typename DiagonalDerived> |
| EIGEN_DEVICE_FUNC ScaledPermutationMatrix(const PermutationBase<PermutationDerived>& permutation, |
| const DiagonalBase<DiagonalDerived>& diagonal) |
| : m_permutation(permutation), m_scales(diagonal.diagonal()) { |
| eigen_assert(permutation.rows() == diagonal.rows()); |
| } |
| |
| /** Constructs the scaled permutation with the given \a indices and \a scales. */ |
| template <typename IndicesDerived, typename ScalesDerived> |
| EIGEN_DEVICE_FUNC ScaledPermutationMatrix(const MatrixBase<IndicesDerived>& indices, |
| const MatrixBase<ScalesDerived>& scales) |
| : m_permutation(indices), m_scales(scales) { |
| eigen_assert(indices.size() == scales.size()); |
| } |
| |
| /** Converts the permutation \a permutation, all scales being one. */ |
| template <typename OtherDerived> |
| EIGEN_DEVICE_FUNC explicit ScaledPermutationMatrix(const PermutationBase<OtherDerived>& permutation) |
| : m_permutation(permutation), m_scales(ScalesType::Ones(permutation.rows())) {} |
| |
| /** Converts the diagonal matrix \a diagonal, the permutation being the identity. */ |
| template <typename OtherDerived> |
| EIGEN_DEVICE_FUNC explicit ScaledPermutationMatrix(const DiagonalBase<OtherDerived>& diagonal) |
| : m_permutation(diagonal.rows()), m_scales(diagonal.diagonal()) { |
| m_permutation.setIdentity(); |
| } |
| |
| /** Copies the scaled permutation \a other. */ |
| template <typename OtherDerived> |
| EIGEN_DEVICE_FUNC ScaledPermutationMatrix(const ScaledPermutationBase<OtherDerived>& other) |
| : m_permutation(other.permutation()), m_scales(other.scales()) {} |
| |
| /** Copies the scaled permutation \a other. */ |
| template <typename OtherDerived> |
| EIGEN_DEVICE_FUNC ScaledPermutationMatrix& operator=(const ScaledPermutationBase<OtherDerived>& other) { |
| m_permutation = other.permutation(); |
| m_scales = other.scales(); |
| return *this; |
| } |
| |
| /** \returns the permutation factor */ |
| EIGEN_DEVICE_FUNC const PermutationType& permutation() const { return m_permutation; } |
| /** \returns a reference to the permutation factor */ |
| EIGEN_DEVICE_FUNC PermutationType& permutation() { return m_permutation; } |
| /** \returns the permutation's indices */ |
| EIGEN_DEVICE_FUNC constexpr const IndicesType& indices() const { return m_permutation.indices(); } |
| /** \returns a reference to the permutation's indices */ |
| EIGEN_DEVICE_FUNC constexpr IndicesType& indices() { return m_permutation.indices(); } |
| /** \returns the scales */ |
| EIGEN_DEVICE_FUNC const ScalesType& scales() const { return m_scales; } |
| /** \returns a reference to the scales */ |
| EIGEN_DEVICE_FUNC ScalesType& scales() { return m_scales; } |
| |
| /** Resizes to the given size, leaving the coefficients uninitialized. */ |
| EIGEN_DEVICE_FUNC void resize(Index size) { |
| m_permutation.resize(size); |
| m_scales.resize(size); |
| } |
| |
| /** Sets \c *this to the identity matrix. */ |
| EIGEN_DEVICE_FUNC void setIdentity() { |
| m_permutation.setIdentity(); |
| m_scales.setOnes(); |
| } |
| |
| /** Sets \c *this to the identity matrix of the given size. */ |
| EIGEN_DEVICE_FUNC void setIdentity(Index size) { |
| resize(size); |
| setIdentity(); |
| } |
| |
| protected: |
| PermutationType m_permutation; |
| ScalesType m_scales; |
| }; |
| |
| // The products of a permutation (or its inverse) and a diagonal matrix. With P e_c = e_{sigma(c)}: |
| // P D: (sigma(c), d_c) D P: (sigma(c), d_{sigma(c)}) |
| // P^-1 D: (sigma^-1(c), d_c) D P^-1: (sigma^-1(c), d_{sigma^-1(c)}) |
| |
| /** \returns the scaled permutation \a permutation times \a diagonal |
| * \relates ScaledPermutationMatrix */ |
| template <typename PermutationDerived, typename DiagonalDerived> |
| typename internal::scaled_permutation_result<typename DiagonalDerived::Scalar, PermutationDerived, DiagonalDerived, |
| typename PermutationDerived::StorageIndex>::type |
| operator*(const PermutationBase<PermutationDerived>& permutation, const DiagonalBase<DiagonalDerived>& diagonal) { |
| using Result = |
| typename internal::scaled_permutation_result<typename DiagonalDerived::Scalar, PermutationDerived, |
| DiagonalDerived, typename PermutationDerived::StorageIndex>::type; |
| eigen_assert(permutation.rows() == diagonal.rows()); |
| return Result(permutation.indices(), diagonal.diagonal()); |
| } |
| |
| /** \returns the scaled permutation \a diagonal times \a permutation |
| * \relates ScaledPermutationMatrix */ |
| template <typename DiagonalDerived, typename PermutationDerived> |
| typename internal::scaled_permutation_result<typename DiagonalDerived::Scalar, PermutationDerived, DiagonalDerived, |
| typename PermutationDerived::StorageIndex>::type |
| operator*(const DiagonalBase<DiagonalDerived>& diagonal, const PermutationBase<PermutationDerived>& permutation) { |
| using Result = |
| typename internal::scaled_permutation_result<typename DiagonalDerived::Scalar, PermutationDerived, |
| DiagonalDerived, typename PermutationDerived::StorageIndex>::type; |
| eigen_assert(permutation.rows() == diagonal.rows()); |
| Result result(permutation.rows()); |
| result.indices() = permutation.indices(); |
| for (Index k = 0; k < permutation.rows(); ++k) |
| result.scales().coeffRef(k) = diagonal.diagonal().coeff(permutation.indices().coeff(k)); |
| return result; |
| } |
| |
| /** \returns the scaled permutation \a inverse (an inverse permutation) times \a diagonal |
| * \relates ScaledPermutationMatrix */ |
| template <typename PermutationType, typename DiagonalDerived> |
| typename internal::scaled_permutation_result<typename DiagonalDerived::Scalar, PermutationType, DiagonalDerived, |
| typename PermutationType::StorageIndex>::type |
| operator*(const InverseImpl<PermutationType, PermutationStorage>& inverse, |
| const DiagonalBase<DiagonalDerived>& diagonal) { |
| using Result = |
| typename internal::scaled_permutation_result<typename DiagonalDerived::Scalar, PermutationType, DiagonalDerived, |
| typename PermutationType::StorageIndex>::type; |
| eigen_assert(inverse.rows() == diagonal.rows()); |
| Result result(inverse.rows()); |
| internal::invert_permutation_indices(inverse.derived().nestedExpression().indices(), result.indices()); |
| result.scales() = diagonal.diagonal(); |
| return result; |
| } |
| |
| /** \returns the scaled permutation \a diagonal times \a inverse (an inverse permutation) |
| * \relates ScaledPermutationMatrix */ |
| template <typename DiagonalDerived, typename PermutationType> |
| typename internal::scaled_permutation_result<typename DiagonalDerived::Scalar, PermutationType, DiagonalDerived, |
| typename PermutationType::StorageIndex>::type |
| operator*(const DiagonalBase<DiagonalDerived>& diagonal, |
| const InverseImpl<PermutationType, PermutationStorage>& inverse) { |
| using Result = |
| typename internal::scaled_permutation_result<typename DiagonalDerived::Scalar, PermutationType, DiagonalDerived, |
| typename PermutationType::StorageIndex>::type; |
| eigen_assert(inverse.rows() == diagonal.rows()); |
| Result result(inverse.rows()); |
| internal::invert_permutation_indices(inverse.derived().nestedExpression().indices(), result.indices()); |
| for (Index k = 0; k < inverse.rows(); ++k) |
| result.scales().coeffRef(k) = diagonal.diagonal().coeff(result.indices().coeff(k)); |
| return result; |
| } |
| |
| namespace internal { |
| |
| template <typename Scalar_, int SizeAtCompileTime, int MaxSizeAtCompileTime, typename StorageIndex_> |
| struct evaluator_traits<ScaledPermutationMatrix<Scalar_, SizeAtCompileTime, MaxSizeAtCompileTime, StorageIndex_>> { |
| using Kind = IndexBased; |
| using Shape = ScaledPermutationShape; |
| }; |
| |
| /** \internal Index-based evaluator, for the lazy sums with a dense matrix. Every coefficient is synthesized, so there |
| * is no linear, packet or direct access. */ |
| template <typename Scalar_, int SizeAtCompileTime, int MaxSizeAtCompileTime, typename StorageIndex_> |
| struct evaluator<ScaledPermutationMatrix<Scalar_, SizeAtCompileTime, MaxSizeAtCompileTime, StorageIndex_>> |
| : evaluator_base<ScaledPermutationMatrix<Scalar_, SizeAtCompileTime, MaxSizeAtCompileTime, StorageIndex_>> { |
| using XprType = ScaledPermutationMatrix<Scalar_, SizeAtCompileTime, MaxSizeAtCompileTime, StorageIndex_>; |
| using Scalar = Scalar_; |
| using CoeffReturnType = Scalar; |
| |
| static constexpr int CoeffReadCost = |
| int(NumTraits<StorageIndex_>::ReadCost) + int(NumTraits<Scalar>::ReadCost) + int(NumTraits<Scalar>::AddCost); |
| static constexpr unsigned int Flags = 0; |
| static constexpr int Alignment = 0; |
| |
| EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) : m_indices(xpr.indices()), m_scales(xpr.scales()) {} |
| |
| EIGEN_DEVICE_FUNC Scalar coeff(Index row, Index col) const { |
| return Index(m_indices.coeff(col)) == row ? m_scales.coeff(col) : Scalar(0); |
| } |
| |
| // Linear access is requested only for vector-shaped operands (inner products), i.e. a 1x1 matrix. |
| EIGEN_DEVICE_FUNC Scalar coeff(Index index) const { |
| eigen_assert(index == 0); |
| return m_scales.coeff(index); |
| } |
| |
| protected: |
| evaluator<typename XprType::IndicesType> m_indices; |
| evaluator<typename XprType::ScalesType> m_scales; |
| }; |
| |
| struct ScaledPermutation2Dense {}; |
| |
| template <> |
| struct AssignmentKind<DenseShape, ScaledPermutationShape> { |
| using Kind = ScaledPermutation2Dense; |
| }; |
| |
| // Scaled permutation to dense assignment: zero fill plus one scatter of n coefficients. |
| template <typename DstXprType, typename SrcXprType, typename Functor> |
| struct Assignment<DstXprType, SrcXprType, Functor, ScaledPermutation2Dense> { |
| static EIGEN_DEVICE_FUNC void run( |
| DstXprType& dst, const SrcXprType& src, |
| const internal::assign_op<typename DstXprType::Scalar, typename SrcXprType::Scalar>&) { |
| if (dst.rows() != src.rows() || dst.cols() != src.cols()) dst.resize(src.rows(), src.cols()); |
| dst.setZero(); |
| for (Index k = 0; k < src.rows(); ++k) dst.coeffRef(src.indices().coeff(k), k) = src.scales().coeff(k); |
| } |
| |
| static EIGEN_DEVICE_FUNC void run( |
| DstXprType& dst, const SrcXprType& src, |
| const internal::add_assign_op<typename DstXprType::Scalar, typename SrcXprType::Scalar>&) { |
| eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); |
| for (Index k = 0; k < src.rows(); ++k) dst.coeffRef(src.indices().coeff(k), k) += src.scales().coeff(k); |
| } |
| |
| static EIGEN_DEVICE_FUNC void run( |
| DstXprType& dst, const SrcXprType& src, |
| const internal::sub_assign_op<typename DstXprType::Scalar, typename SrcXprType::Scalar>&) { |
| eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); |
| for (Index k = 0; k < src.rows(); ++k) dst.coeffRef(src.indices().coeff(k), k) -= src.scales().coeff(k); |
| } |
| }; |
| |
| /*************************************************************************** |
| * Products with a dense matrix: rows (S * X) or columns (X * S) are scaled and permuted, O(n m). |
| * evalTo reuses the dense permutation kernel, which handles X aliasing dst, and scales in place afterwards; |
| * the accumulating form works on the nested (evaluated once) operand. |
| * scaleAndAddTo evaluates dst += alpha * (lhs * rhs) with alpha a left factor of the product. Scalar |
| * multiplication need not commute, so both kernels keep that operand order: S * X regroups it as |
| * (alpha * v_c) * X(c, j) by associativity; X * S keeps alpha * (X(i, tau(c)) * v_c), as folding alpha into |
| * v_c would move it past the dense coefficient. |
| ***************************************************************************/ |
| |
| template <typename Lhs, typename Rhs, int ProductTag> |
| struct generic_product_impl<Lhs, Rhs, ScaledPermutationShape, DenseShape, ProductTag> |
| : generic_product_impl_base<Lhs, Rhs, |
| generic_product_impl<Lhs, Rhs, ScaledPermutationShape, DenseShape, ProductTag>> { |
| using Scalar = typename Product<Lhs, Rhs>::Scalar; |
| |
| template <typename Dest> |
| static EIGEN_DEVICE_FUNC void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs) { |
| permutation_matrix_product<Rhs, OnTheLeft, false, DenseShape>::run(dst, lhs.permutation(), rhs); |
| for (Index k = 0; k < lhs.rows(); ++k) { |
| auto row = dst.row(lhs.indices().coeff(k)); |
| row = lhs.scales().coeff(k) * row; |
| } |
| } |
| |
| template <typename Dest> |
| static EIGEN_DEVICE_FUNC void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) { |
| typename nested_eval<Rhs, 1>::type rhsNested(rhs); |
| for (Index k = 0; k < lhs.rows(); ++k) |
| dst.row(lhs.indices().coeff(k)) += (alpha * lhs.scales().coeff(k)) * rhsNested.row(k); |
| } |
| }; |
| |
| template <typename Lhs, typename Rhs, int ProductTag> |
| struct generic_product_impl<Lhs, Rhs, DenseShape, ScaledPermutationShape, ProductTag> |
| : generic_product_impl_base<Lhs, Rhs, |
| generic_product_impl<Lhs, Rhs, DenseShape, ScaledPermutationShape, ProductTag>> { |
| using Scalar = typename Product<Lhs, Rhs>::Scalar; |
| |
| template <typename Dest> |
| static EIGEN_DEVICE_FUNC void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs) { |
| permutation_matrix_product<Lhs, OnTheRight, false, DenseShape>::run(dst, rhs.permutation(), lhs); |
| for (Index k = 0; k < rhs.rows(); ++k) dst.col(k) *= rhs.scales().coeff(k); |
| } |
| |
| template <typename Dest> |
| static EIGEN_DEVICE_FUNC void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) { |
| typename nested_eval<Lhs, 1>::type lhsNested(lhs); |
| for (Index k = 0; k < rhs.rows(); ++k) |
| dst.col(k) += alpha * (lhsNested.col(rhs.indices().coeff(k)) * rhs.scales().coeff(k)); |
| } |
| }; |
| |
| // A triangular or self-adjoint operand is evaluated into a plain matrix first, as toDenseMatrix() does. |
| template <typename Lhs, typename Rhs, int ProductTag, bool ViewOnTheRight> |
| struct scaled_permutation_view_product_impl; |
| |
| template <typename Lhs, typename Rhs, int ProductTag> |
| struct scaled_permutation_view_product_impl<Lhs, Rhs, ProductTag, true> |
| : generic_product_impl_base<Lhs, Rhs, scaled_permutation_view_product_impl<Lhs, Rhs, ProductTag, true>> { |
| using Scalar = typename Product<Lhs, Rhs>::Scalar; |
| using DenseType = typename Rhs::DenseMatrixType; |
| using DenseImpl = generic_product_impl<Lhs, DenseType, ScaledPermutationShape, DenseShape, ProductTag>; |
| |
| template <typename Dest> |
| static EIGEN_DEVICE_FUNC void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs) { |
| const DenseType dense(rhs); |
| DenseImpl::evalTo(dst, lhs, dense); |
| } |
| template <typename Dest> |
| static EIGEN_DEVICE_FUNC void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) { |
| const DenseType dense(rhs); |
| DenseImpl::scaleAndAddTo(dst, lhs, dense, alpha); |
| } |
| }; |
| |
| template <typename Lhs, typename Rhs, int ProductTag> |
| struct scaled_permutation_view_product_impl<Lhs, Rhs, ProductTag, false> |
| : generic_product_impl_base<Lhs, Rhs, scaled_permutation_view_product_impl<Lhs, Rhs, ProductTag, false>> { |
| using Scalar = typename Product<Lhs, Rhs>::Scalar; |
| using DenseType = typename Lhs::DenseMatrixType; |
| using DenseImpl = generic_product_impl<DenseType, Rhs, DenseShape, ScaledPermutationShape, ProductTag>; |
| |
| template <typename Dest> |
| static EIGEN_DEVICE_FUNC void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs) { |
| const DenseType dense(lhs); |
| DenseImpl::evalTo(dst, dense, rhs); |
| } |
| template <typename Dest> |
| static EIGEN_DEVICE_FUNC void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) { |
| const DenseType dense(lhs); |
| DenseImpl::scaleAndAddTo(dst, dense, rhs, alpha); |
| } |
| }; |
| |
| template <typename Lhs, typename Rhs, int ProductTag> |
| struct generic_product_impl<Lhs, Rhs, ScaledPermutationShape, TriangularShape, ProductTag> |
| : scaled_permutation_view_product_impl<Lhs, Rhs, ProductTag, true> {}; |
| template <typename Lhs, typename Rhs, int ProductTag> |
| struct generic_product_impl<Lhs, Rhs, ScaledPermutationShape, SelfAdjointShape, ProductTag> |
| : scaled_permutation_view_product_impl<Lhs, Rhs, ProductTag, true> {}; |
| template <typename Lhs, typename Rhs, int ProductTag> |
| struct generic_product_impl<Lhs, Rhs, TriangularShape, ScaledPermutationShape, ProductTag> |
| : scaled_permutation_view_product_impl<Lhs, Rhs, ProductTag, false> {}; |
| template <typename Lhs, typename Rhs, int ProductTag> |
| struct generic_product_impl<Lhs, Rhs, SelfAdjointShape, ScaledPermutationShape, ProductTag> |
| : scaled_permutation_view_product_impl<Lhs, Rhs, ProductTag, false> {}; |
| |
| } // namespace internal |
| |
| } // namespace Eigen |
| |
| #endif // EIGEN_SCALEDPERMUTATIONMATRIX_H |