| // This file is part of Eigen, a lightweight C++ template library | |
| // for linear algebra. | |
| // | |
| // Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com> | |
| // Copyright (C) 2008-2009 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/. | |
| // SPDX-License-Identifier: MPL-2.0 | |
| #ifndef EIGEN_TRIANGULARMATRIX_H | |
| #define EIGEN_TRIANGULARMATRIX_H | |
| // IWYU pragma: private | |
| #include "./InternalHeaderCheck.h" | |
| namespace Eigen { | |
| namespace internal { | |
| template <int Side, typename TriangularType, typename Rhs> | |
| struct triangular_solve_retval; | |
| template <typename MatrixType, unsigned int Mode, bool IsSelfAdjoint = (int(Mode) & int(SelfAdjoint)) != 0> | |
| struct triangular_base_return_types { | |
| using MatrixConjugateReturnType = internal::remove_all_t<typename MatrixType::ConjugateReturnType>; | |
| enum { | |
| TransposeMode = (int(Mode) & int(Upper) ? Lower : 0) | (int(Mode) & int(Lower) ? Upper : 0) | | |
| (int(Mode) & int(UnitDiag)) | (int(Mode) & int(ZeroDiag)) | |
| }; | |
| using ConstView = TriangularView<std::add_const_t<MatrixType>, Mode>; | |
| using ConjugateReturnType = TriangularView<const MatrixConjugateReturnType, Mode>; | |
| using AdjointReturnType = TriangularView<const typename MatrixType::AdjointReturnType, TransposeMode>; | |
| using TransposeReturnType = TriangularView<typename MatrixType::TransposeReturnType, TransposeMode>; | |
| using ConstTransposeReturnType = TriangularView<const typename MatrixType::ConstTransposeReturnType, TransposeMode>; | |
| }; | |
| template <typename MatrixType, unsigned int Mode> | |
| struct triangular_base_return_types<MatrixType, Mode, true> { | |
| using MatrixConjugateReturnType = internal::remove_all_t<typename MatrixType::ConjugateReturnType>; | |
| enum { | |
| TriangularPart = int(Mode) & int(Upper | Lower), | |
| TransposeMode = (int(Mode) & int(Upper) ? Lower : 0) | (int(Mode) & int(Lower) ? Upper : 0) | |
| }; | |
| using ConstView = SelfAdjointView<std::add_const_t<MatrixType>, TriangularPart>; | |
| using ConjugateReturnType = SelfAdjointView<const MatrixConjugateReturnType, TriangularPart>; | |
| using AdjointReturnType = SelfAdjointView<const typename MatrixType::AdjointReturnType, TransposeMode>; | |
| using TransposeReturnType = SelfAdjointView<typename MatrixType::TransposeReturnType, TransposeMode>; | |
| using ConstTransposeReturnType = SelfAdjointView<const typename MatrixType::ConstTransposeReturnType, TransposeMode>; | |
| }; | |
| template <unsigned int Mode, typename Expression> | |
| EIGEN_DEVICE_FUNC inline typename triangular_base_return_types<Expression, Mode>::ConstView | |
| make_triangular_base_cwise_view(const Expression& expression) { | |
| using ReturnType = typename triangular_base_return_types<Expression, Mode>::ConstView; | |
| return ReturnType(expression); | |
| } | |
| } // namespace internal | |
| /** \class TriangularBase | |
| * \ingroup Core_Module | |
| * | |
| * \brief Base class for triangular part in a matrix | |
| */ | |
| template <typename Derived> | |
| class TriangularBase : public EigenBase<Derived> { | |
| public: | |
| enum { | |
| Mode = internal::traits<Derived>::Mode, | |
| TransposeMode = (int(Mode) & int(Upper) ? Lower : 0) | (int(Mode) & int(Lower) ? Upper : 0) | | |
| (int(Mode) & int(UnitDiag)) | (int(Mode) & int(ZeroDiag)), | |
| RowsAtCompileTime = internal::traits<Derived>::RowsAtCompileTime, | |
| ColsAtCompileTime = internal::traits<Derived>::ColsAtCompileTime, | |
| MaxRowsAtCompileTime = internal::traits<Derived>::MaxRowsAtCompileTime, | |
| MaxColsAtCompileTime = internal::traits<Derived>::MaxColsAtCompileTime, | |
| SizeAtCompileTime = (internal::size_of_xpr_at_compile_time<Derived>::value), | |
| /**< This is equal to the number of coefficients, i.e. the number of | |
| * rows times the number of columns, or to \a Dynamic if this is not | |
| * known at compile-time. \sa RowsAtCompileTime, ColsAtCompileTime */ | |
| MaxSizeAtCompileTime = internal::size_at_compile_time(internal::traits<Derived>::MaxRowsAtCompileTime, | |
| internal::traits<Derived>::MaxColsAtCompileTime) | |
| }; | |
| using Scalar = typename internal::traits<Derived>::Scalar; | |
| using StorageKind = typename internal::traits<Derived>::StorageKind; | |
| using StorageIndex = typename internal::traits<Derived>::StorageIndex; | |
| using DenseMatrixType = typename internal::traits<Derived>::FullMatrixType; | |
| using ExpressionType = typename internal::traits<Derived>::ExpressionType; | |
| using DenseType = DenseMatrixType; | |
| using Nested = const Derived&; | |
| using ReturnTypes = internal::triangular_base_return_types<ExpressionType, Mode>; | |
| using ConstView = typename ReturnTypes::ConstView; | |
| using ConjugateReturnType = typename ReturnTypes::ConjugateReturnType; | |
| using AdjointReturnType = typename ReturnTypes::AdjointReturnType; | |
| using TransposeReturnType = typename ReturnTypes::TransposeReturnType; | |
| using ConstTransposeReturnType = typename ReturnTypes::ConstTransposeReturnType; | |
| EIGEN_DEVICE_FUNC inline TriangularBase() { | |
| eigen_assert(!((int(Mode) & int(UnitDiag)) && (int(Mode) & int(ZeroDiag)))); | |
| } | |
| EIGEN_DEVICE_FUNC constexpr Index rows() const noexcept { return derived().nestedExpression().rows(); } | |
| EIGEN_DEVICE_FUNC constexpr Index cols() const noexcept { return derived().nestedExpression().cols(); } | |
| EIGEN_DEVICE_FUNC constexpr Index size() const noexcept { return rows() * cols(); } | |
| EIGEN_DEVICE_FUNC constexpr Index outerStride() const noexcept { return derived().nestedExpression().outerStride(); } | |
| EIGEN_DEVICE_FUNC constexpr Index innerStride() const noexcept { return derived().nestedExpression().innerStride(); } | |
| // dummy resize function | |
| EIGEN_DEVICE_FUNC void resize(Index rows, Index cols) { | |
| EIGEN_UNUSED_VARIABLE(rows); | |
| EIGEN_UNUSED_VARIABLE(cols); | |
| eigen_assert(rows == this->rows() && cols == this->cols()); | |
| } | |
| /** \sa MatrixBase::fill() */ | |
| EIGEN_DEVICE_FUNC void fill(const Scalar& value) { setConstant(value); } | |
| /** \sa MatrixBase::setConstant() */ | |
| EIGEN_DEVICE_FUNC Derived& setConstant(const Scalar& value) { | |
| EIGEN_STATIC_ASSERT_LVALUE(Derived); | |
| return derived() = DenseMatrixType::Constant(rows(), cols(), value); | |
| } | |
| /** \sa MatrixBase::setZero() */ | |
| EIGEN_DEVICE_FUNC Derived& setZero() { return setConstant(Scalar(0)); } | |
| /** \sa MatrixBase::setOnes() */ | |
| EIGEN_DEVICE_FUNC Derived& setOnes() { return setConstant(Scalar(1)); } | |
| /** \sa MatrixBase::setRandom() */ | |
| EIGEN_DEVICE_FUNC Derived& setRandom() { | |
| EIGEN_STATIC_ASSERT_LVALUE(Derived); | |
| return derived() = DenseMatrixType::Random(rows(), cols()); | |
| } | |
| /** \sa MatrixBase::setIdentity() */ | |
| EIGEN_DEVICE_FUNC Derived& setIdentity() { | |
| EIGEN_STATIC_ASSERT_LVALUE(Derived); | |
| return derived() = DenseMatrixType::Identity(rows(), cols()); | |
| } | |
| /** \returns the coefficient of the \em underlying expression at position (\a row, \a col). | |
| * | |
| * \warning This is raw storage access: the unit diagonal of \c UnitLower / \c UnitUpper and the | |
| * structural zeros of the view are \em not synthesized, so for coordinates outside the part | |
| * referenced by \c Mode the stored value is returned as-is. Only evaluation of the view — for | |
| * example assigning it to a dense matrix or calling toDenseMatrix() — produces the mathematical | |
| * coefficients implied by \c Mode. | |
| */ | |
| EIGEN_DEVICE_FUNC inline Scalar coeff(Index row, Index col) const { | |
| check_coordinates_internal(row, col); | |
| return derived().nestedExpression().coeff(row, col); | |
| } | |
| /** \returns a reference to the coefficient of the underlying expression at position (\a row, \a col). | |
| * | |
| * \warning See the warning of coeff(Index,Index): the unit diagonal and structural zeros of the | |
| * view are not represented in storage and cannot be referenced. | |
| */ | |
| EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index row, Index col) { | |
| EIGEN_STATIC_ASSERT_LVALUE(Derived); | |
| check_coordinates_internal(row, col); | |
| return derived().nestedExpression().coeffRef(row, col); | |
| } | |
| /** \see MatrixBase::copyCoeff(row,col) | |
| */ | |
| template <typename Other> | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void copyCoeff(Index row, Index col, Other& other) { | |
| coeffRef(row, col) = other.coeff(row, col); | |
| } | |
| /** Like coeff(Index,Index), but asserts (in debug builds) that (\a row, \a col) lies inside the | |
| * part referenced by \c Mode; for \c UnitLower / \c UnitUpper and the strictly triangular modes | |
| * that excludes the diagonal, whose implicit values are not stored. */ | |
| EIGEN_DEVICE_FUNC inline Scalar operator()(Index row, Index col) const { | |
| check_coordinates(row, col); | |
| return coeff(row, col); | |
| } | |
| /** Like coeffRef(Index,Index), but asserts (in debug builds) that (\a row, \a col) lies inside | |
| * the part referenced by \c Mode. */ | |
| EIGEN_DEVICE_FUNC inline Scalar& operator()(Index row, Index col) { | |
| check_coordinates(row, col); | |
| return coeffRef(row, col); | |
| } | |
| #ifdef EIGEN_MULTIDIMENSIONAL_SUBSCRIPT | |
| EIGEN_DEVICE_FUNC inline Scalar operator[](Index row, Index col) const { return operator()(row, col); } | |
| EIGEN_DEVICE_FUNC inline Scalar& operator[](Index row, Index col) { return operator()(row, col); } | |
| #endif | |
| #ifndef EIGEN_PARSED_BY_DOXYGEN | |
| EIGEN_DEVICE_FUNC constexpr inline const Derived& derived() const noexcept { | |
| return *static_cast<const Derived*>(this); | |
| } | |
| EIGEN_DEVICE_FUNC constexpr inline Derived& derived() noexcept { return *static_cast<Derived*>(this); } | |
| #endif // not EIGEN_PARSED_BY_DOXYGEN | |
| template <typename DenseDerived> | |
| EIGEN_DEVICE_FUNC void evalTo(MatrixBase<DenseDerived>& other) const; | |
| template <typename DenseDerived> | |
| EIGEN_DEVICE_FUNC void evalToLazy(MatrixBase<DenseDerived>& other) const; | |
| template <typename OtherDerived> | |
| EIGEN_DEVICE_FUNC const Product<Derived, OtherDerived> operator*(const MatrixBase<OtherDerived>& rhs) const { | |
| return Product<Derived, OtherDerived>(derived(), rhs.derived()); | |
| } | |
| template <typename OtherDerived> | |
| EIGEN_DEVICE_FUNC const Product<Derived, OtherDerived> operator*(const DiagonalBase<OtherDerived>& rhs) const { | |
| return Product<Derived, OtherDerived>(derived(), rhs.derived()); | |
| } | |
| /** \returns the dense matrix product of \c *this by the triangular or self-adjoint view \a rhs. | |
| * | |
| * The right factor is evaluated into a dense temporary and the product runs the kernel of \c *this times a | |
| * dense matrix. The result is a plain dense expression even when the structure would be preserved, as for | |
| * two upper triangular factors. | |
| */ | |
| template <typename OtherDerived> | |
| EIGEN_DEVICE_FUNC const Product<Derived, OtherDerived> operator*(const TriangularBase<OtherDerived>& rhs) const { | |
| return Product<Derived, OtherDerived>(derived(), rhs.derived()); | |
| } | |
| template <typename OtherDerived, | |
| std::enable_if_t<int(Mode) == int(OtherDerived::Mode) && (int(Mode) & int(UnitDiag)) == 0, int> = 0> | |
| EIGEN_DEVICE_FUNC inline auto operator+(const TriangularBase<OtherDerived>& other) const { | |
| return internal::make_triangular_base_cwise_view<Mode>(derived().nestedExpression() + | |
| other.derived().nestedExpression()); | |
| } | |
| template <typename OtherDerived, | |
| std::enable_if_t<int(Mode) == int(OtherDerived::Mode) && (int(Mode) & int(UnitDiag)) == 0, int> = 0> | |
| EIGEN_DEVICE_FUNC inline auto operator-(const TriangularBase<OtherDerived>& other) const { | |
| return internal::make_triangular_base_cwise_view<Mode>(derived().nestedExpression() - | |
| other.derived().nestedExpression()); | |
| } | |
| // Sums with a diagonal matrix keep the view's structure: the result is the same view of the lazy dense sum. | |
| // A unit or zero diagonal is implicit in the view and would swallow the diagonal term, so those modes have | |
| // no such operator; a self-adjoint view needs a real diagonal to stay self-adjoint. | |
| // The Mode_ = Mode parameter makes the condition depend on the operator's own template parameters, so an | |
| // excluded mode removes the overload instead of failing the class instantiation. | |
| /** \returns the view of mode \c Mode of the sum of the nested expression and the diagonal matrix \a other */ | |
| template <typename OtherDerived, unsigned int Mode_ = Mode, | |
| std::enable_if_t<(int(Mode_) & (int(UnitDiag) | int(ZeroDiag))) == 0, int> = 0> | |
| EIGEN_DEVICE_FUNC inline auto operator+(const DiagonalBase<OtherDerived>& other) const { | |
| return internal::make_triangular_base_cwise_view<Mode>(derived().nestedExpression() + other.derived()); | |
| } | |
| /** \returns the view of mode \c Mode of the difference of the nested expression and the diagonal matrix \a other | |
| */ | |
| template <typename OtherDerived, unsigned int Mode_ = Mode, | |
| std::enable_if_t<(int(Mode_) & (int(UnitDiag) | int(ZeroDiag))) == 0, int> = 0> | |
| EIGEN_DEVICE_FUNC inline auto operator-(const DiagonalBase<OtherDerived>& other) const { | |
| return internal::make_triangular_base_cwise_view<Mode>(derived().nestedExpression() - other.derived()); | |
| } | |
| /** \returns the view of mode \c Mode of the sum of the diagonal matrix \a lhs and the nested expression of \a rhs | |
| */ | |
| template <typename OtherDerived, unsigned int Mode_ = Mode, | |
| std::enable_if_t<(int(Mode_) & (int(UnitDiag) | int(ZeroDiag))) == 0, int> = 0> | |
| friend EIGEN_DEVICE_FUNC inline auto operator+(const DiagonalBase<OtherDerived>& lhs, const Derived& rhs) { | |
| return internal::make_triangular_base_cwise_view<Mode>(lhs.derived() + rhs.nestedExpression()); | |
| } | |
| /** \returns the view of mode \c Mode of the difference of the diagonal matrix \a lhs and the nested expression of | |
| * \a rhs */ | |
| template <typename OtherDerived, unsigned int Mode_ = Mode, | |
| std::enable_if_t<(int(Mode_) & (int(UnitDiag) | int(ZeroDiag))) == 0, int> = 0> | |
| friend EIGEN_DEVICE_FUNC inline auto operator-(const DiagonalBase<OtherDerived>& lhs, const Derived& rhs) { | |
| return internal::make_triangular_base_cwise_view<Mode>(lhs.derived() - rhs.nestedExpression()); | |
| } | |
| template <typename OtherDerived> | |
| friend EIGEN_DEVICE_FUNC const Product<OtherDerived, Derived> operator*(const MatrixBase<OtherDerived>& lhs, | |
| const Derived& rhs) { | |
| return Product<OtherDerived, Derived>(lhs.derived(), rhs); | |
| } | |
| template <typename OtherDerived> | |
| friend EIGEN_DEVICE_FUNC const Product<OtherDerived, Derived> operator*(const DiagonalBase<OtherDerived>& lhs, | |
| const Derived& rhs) { | |
| return Product<OtherDerived, Derived>(lhs.derived(), rhs); | |
| } | |
| // Products with permutations (and their inverses) evaluate to a dense matrix: the permuted view has no | |
| // triangular or self-adjoint structure Eigen could represent. They live here rather than next to the | |
| // MatrixBase permutation operators so that every operator* a TriangularBase takes part in is in one place. | |
| /** \returns the dense matrix expression of \c *this with the permutation \a rhs applied to its columns. */ | |
| template <typename OtherDerived> | |
| EIGEN_DEVICE_FUNC const Product<Derived, OtherDerived> operator*(const PermutationBase<OtherDerived>& rhs) const { | |
| return Product<Derived, OtherDerived>(derived(), rhs.derived()); | |
| } | |
| /** \returns the dense matrix expression of \c *this with the inverse permutation \a rhs applied to its columns. */ | |
| template <typename OtherDerived> | |
| EIGEN_DEVICE_FUNC const Product<Derived, Inverse<OtherDerived>> operator*( | |
| const InverseImpl<OtherDerived, PermutationStorage>& rhs) const { | |
| return Product<Derived, Inverse<OtherDerived>>(derived(), rhs.derived()); | |
| } | |
| /** \returns the dense matrix expression of \a rhs with the permutation \a lhs applied to its rows. */ | |
| template <typename OtherDerived> | |
| friend EIGEN_DEVICE_FUNC const Product<OtherDerived, Derived> operator*(const PermutationBase<OtherDerived>& lhs, | |
| const Derived& rhs) { | |
| return Product<OtherDerived, Derived>(lhs.derived(), rhs); | |
| } | |
| /** \returns the dense matrix expression of \a rhs with the inverse permutation \a lhs applied to its rows. */ | |
| template <typename OtherDerived> | |
| friend EIGEN_DEVICE_FUNC const Product<Inverse<OtherDerived>, Derived> operator*( | |
| const InverseImpl<OtherDerived, PermutationStorage>& lhs, const Derived& rhs) { | |
| return Product<Inverse<OtherDerived>, Derived>(lhs.derived(), rhs); | |
| } | |
| /** \sa MatrixBase::conjugate() const */ | |
| EIGEN_DEVICE_FUNC inline const ConjugateReturnType conjugate() const { | |
| return ConjugateReturnType(derived().nestedExpression().conjugate()); | |
| } | |
| /** \returns an expression of the complex conjugate of \c *this if Cond==true, | |
| * returns \c *this otherwise. | |
| */ | |
| template <bool Cond> | |
| EIGEN_DEVICE_FUNC inline std::conditional_t<Cond, ConjugateReturnType, ConstView> conjugateIf() const { | |
| using ReturnType = std::conditional_t<Cond, ConjugateReturnType, ConstView>; | |
| return ReturnType(derived().nestedExpression().template conjugateIf<Cond>()); | |
| } | |
| /** \sa MatrixBase::adjoint() const */ | |
| EIGEN_DEVICE_FUNC inline const AdjointReturnType adjoint() const { | |
| return AdjointReturnType(derived().nestedExpression().adjoint()); | |
| } | |
| /** \sa MatrixBase::transpose() */ | |
| template <class Dummy = int, std::enable_if_t<Eigen::internal::is_lvalue<ExpressionType>::value, Dummy*> = nullptr> | |
| EIGEN_DEVICE_FUNC inline TransposeReturnType transpose() { | |
| typename ExpressionType::TransposeReturnType tmp(derived().nestedExpression()); | |
| return TransposeReturnType(tmp); | |
| } | |
| template <class Dummy = int> | |
| EIGEN_DEPRECATED_WITH_REASON("Omit the implementation-only argument.") | |
| EIGEN_DEVICE_FUNC inline TransposeReturnType | |
| transpose(std::enable_if_t<Eigen::internal::is_lvalue<ExpressionType>::value, Dummy*>) { | |
| return transpose<Dummy>(); | |
| } | |
| /** \sa MatrixBase::transpose() const */ | |
| EIGEN_DEVICE_FUNC inline const ConstTransposeReturnType transpose() const { | |
| return ConstTransposeReturnType(derived().nestedExpression().transpose()); | |
| } | |
| EIGEN_DEVICE_FUNC DenseMatrixType toDenseMatrix() const { | |
| DenseMatrixType res(rows(), cols()); | |
| evalToLazy(res); | |
| return res; | |
| } | |
| protected: | |
| void check_coordinates(Index row, Index col) const { | |
| EIGEN_ONLY_USED_FOR_DEBUG(row); | |
| EIGEN_ONLY_USED_FOR_DEBUG(col); | |
| eigen_assert(col >= 0 && col < cols() && row >= 0 && row < rows()); | |
| const int mode = int(Mode) & ~SelfAdjoint; | |
| EIGEN_ONLY_USED_FOR_DEBUG(mode); | |
| eigen_assert((mode == Upper && col >= row) || (mode == Lower && col <= row) || | |
| ((mode == StrictlyUpper || mode == UnitUpper) && col > row) || | |
| ((mode == StrictlyLower || mode == UnitLower) && col < row)); | |
| } | |
| #ifdef EIGEN_INTERNAL_DEBUGGING | |
| void check_coordinates_internal(Index row, Index col) const { check_coordinates(row, col); } | |
| #else | |
| void check_coordinates_internal(Index, Index) const {} | |
| #endif | |
| }; | |
| /** \class TriangularView | |
| * \ingroup Core_Module | |
| * | |
| * \brief Expression of a triangular part in a matrix | |
| * | |
| * \tparam MatrixType the type of the object in which we are taking the triangular part | |
| * \tparam Mode the kind of triangular matrix expression to construct. Can be #Upper, | |
| * #Lower, #UnitUpper, #UnitLower, #StrictlyUpper, or #StrictlyLower. | |
| * This is in fact a bit field; it must have either #Upper or #Lower, | |
| * and additionally it may have #UnitDiag or #ZeroDiag or neither. | |
| * | |
| * This class represents a triangular part of a matrix, not necessarily square. Strictly speaking, for rectangular | |
| * matrices one should speak of "trapezoid" parts. This class is the return type | |
| * of MatrixBase::triangularView() and SparseMatrixBase::triangularView(), and most of the time this is the only way it | |
| * is used. | |
| * | |
| * \sa MatrixBase::triangularView() | |
| */ | |
| namespace internal { | |
| template <typename MatrixType, unsigned int Mode_> | |
| struct traits<TriangularView<MatrixType, Mode_>> : traits<MatrixType> { | |
| using MatrixTypeNested = typename ref_selector<MatrixType>::non_const_type; | |
| using MatrixTypeNestedNonRef = std::remove_reference_t<MatrixTypeNested>; | |
| using MatrixTypeNestedCleaned = remove_all_t<MatrixTypeNested>; | |
| using FullMatrixType = typename MatrixType::PlainObject; | |
| using ExpressionType = MatrixType; | |
| enum { | |
| Mode = Mode_, | |
| FlagsLvalueBit = is_lvalue<MatrixType>::value ? LvalueBit : 0, | |
| Flags = (MatrixTypeNestedCleaned::Flags & (HereditaryBits | FlagsLvalueBit) & | |
| (~(PacketAccessBit | DirectAccessBit | LinearAccessBit))) | |
| }; | |
| }; | |
| } // namespace internal | |
| template <typename MatrixType_, unsigned int Mode_, typename StorageKind> | |
| class TriangularViewImpl; | |
| template <typename MatrixType_, unsigned int Mode_> | |
| class TriangularView | |
| : public TriangularViewImpl<MatrixType_, Mode_, typename internal::traits<MatrixType_>::StorageKind> { | |
| public: | |
| using Base = TriangularViewImpl<MatrixType_, Mode_, typename internal::traits<MatrixType_>::StorageKind>; | |
| using Scalar = typename internal::traits<TriangularView>::Scalar; | |
| using MatrixType = MatrixType_; | |
| protected: | |
| using MatrixTypeNested = typename internal::traits<TriangularView>::MatrixTypeNested; | |
| using MatrixTypeNestedNonRef = typename internal::traits<TriangularView>::MatrixTypeNestedNonRef; | |
| public: | |
| using StorageKind = typename internal::traits<TriangularView>::StorageKind; | |
| using NestedExpression = typename internal::traits<TriangularView>::MatrixTypeNestedCleaned; | |
| enum { | |
| Mode = Mode_, | |
| Flags = internal::traits<TriangularView>::Flags, | |
| TransposeMode = (int(Mode) & int(Upper) ? Lower : 0) | (int(Mode) & int(Lower) ? Upper : 0) | | |
| (int(Mode) & int(UnitDiag)) | (int(Mode) & int(ZeroDiag)), | |
| IsVectorAtCompileTime = false | |
| }; | |
| EIGEN_DEVICE_FUNC explicit inline TriangularView(MatrixType& matrix) : m_matrix(matrix) {} | |
| EIGEN_INHERIT_ASSIGNMENT_OPERATORS(TriangularView) | |
| /** \returns a const reference to the nested expression */ | |
| EIGEN_DEVICE_FUNC constexpr const NestedExpression& nestedExpression() const noexcept { return m_matrix; } | |
| /** \returns a reference to the nested expression */ | |
| EIGEN_DEVICE_FUNC constexpr MatrixTypeNestedNonRef& nestedExpression() noexcept { return m_matrix; } | |
| template <typename Other> | |
| EIGEN_DEVICE_FUNC inline Solve<TriangularView, Other> solve(const MatrixBase<Other>& other) const { | |
| return Solve<TriangularView, Other>(*this, other.derived()); | |
| } | |
| using Base::solve; | |
| /** \returns a selfadjoint view of the referenced triangular part which must be either \c #Upper or \c #Lower. | |
| * | |
| * This is a shortcut for \code this->nestedExpression().selfadjointView<(*this)::Mode>() \endcode | |
| * \sa MatrixBase::selfadjointView() */ | |
| EIGEN_DEVICE_FUNC SelfAdjointView<MatrixTypeNestedNonRef, Mode> selfadjointView() { | |
| EIGEN_STATIC_ASSERT((Mode & (UnitDiag | ZeroDiag)) == 0, PROGRAMMING_ERROR); | |
| return SelfAdjointView<MatrixTypeNestedNonRef, Mode>(m_matrix); | |
| } | |
| /** This is the const version of selfadjointView() */ | |
| EIGEN_DEVICE_FUNC const SelfAdjointView<MatrixTypeNestedNonRef, Mode> selfadjointView() const { | |
| EIGEN_STATIC_ASSERT((Mode & (UnitDiag | ZeroDiag)) == 0, PROGRAMMING_ERROR); | |
| return SelfAdjointView<MatrixTypeNestedNonRef, Mode>(m_matrix); | |
| } | |
| /** \returns the determinant of the triangular matrix | |
| * \sa MatrixBase::determinant() */ | |
| EIGEN_DEVICE_FUNC Scalar determinant() const { | |
| EIGEN_IF_CONSTEXPR (int(Mode) & int(UnitDiag)) { | |
| return 1; | |
| } else EIGEN_IF_CONSTEXPR (int(Mode) & int(ZeroDiag)) { | |
| // A zero diagonal makes the product vanish unless it is empty. | |
| return m_matrix.rows() == 0 ? 1 : 0; | |
| } else { | |
| return m_matrix.diagonal().prod(); | |
| } | |
| } | |
| protected: | |
| MatrixTypeNested m_matrix; | |
| }; | |
| /** \ingroup Core_Module | |
| * | |
| * \brief Base class for a triangular part in a \b dense matrix | |
| * | |
| * This class is an abstract base class of class TriangularView, and objects of type TriangularViewImpl cannot be | |
| * instantiated. It extends class TriangularView with additional methods which are available for dense expressions only. | |
| * | |
| * \sa class TriangularView, MatrixBase::triangularView() | |
| */ | |
| template <typename MatrixType_, unsigned int Mode_> | |
| class TriangularViewImpl<MatrixType_, Mode_, Dense> : public TriangularBase<TriangularView<MatrixType_, Mode_>> { | |
| public: | |
| using TriangularViewType = TriangularView<MatrixType_, Mode_>; | |
| using Base = TriangularBase<TriangularViewType>; | |
| using Scalar = typename internal::traits<TriangularViewType>::Scalar; | |
| using MatrixType = MatrixType_; | |
| using DenseMatrixType = typename MatrixType::PlainObject; | |
| using PlainObject = DenseMatrixType; | |
| public: | |
| using Base::derived; | |
| using Base::evalToLazy; | |
| using Base::operator*; | |
| using StorageKind = typename internal::traits<TriangularViewType>::StorageKind; | |
| enum { Mode = Mode_, Flags = internal::traits<TriangularViewType>::Flags }; | |
| /** \sa MatrixBase::operator+=() */ | |
| template <typename Other> | |
| EIGEN_DEVICE_FUNC TriangularViewType& operator+=(const DenseBase<Other>& other) { | |
| internal::call_assignment_no_alias(derived(), other.derived(), | |
| internal::add_assign_op<Scalar, typename Other::Scalar>()); | |
| return derived(); | |
| } | |
| /** \sa MatrixBase::operator-=() */ | |
| template <typename Other> | |
| EIGEN_DEVICE_FUNC TriangularViewType& operator-=(const DenseBase<Other>& other) { | |
| internal::call_assignment_no_alias(derived(), other.derived(), | |
| internal::sub_assign_op<Scalar, typename Other::Scalar>()); | |
| return derived(); | |
| } | |
| /** \sa MatrixBase::operator*=() */ | |
| EIGEN_DEVICE_FUNC TriangularViewType& operator*=(const typename internal::traits<MatrixType>::Scalar& other) { | |
| return *this = derived().nestedExpression() * other; | |
| } | |
| /** \sa DenseBase::operator/=() */ | |
| EIGEN_DEVICE_FUNC TriangularViewType& operator/=(const typename internal::traits<MatrixType>::Scalar& other) { | |
| return *this = derived().nestedExpression() / other; | |
| } | |
| /** Assigns a triangular matrix to a triangular part of a dense matrix */ | |
| template <typename OtherDerived> | |
| EIGEN_DEVICE_FUNC TriangularViewType& operator=(const TriangularBase<OtherDerived>& other); | |
| /** Shortcut for \code *this = other.triangularView<(*this)::Mode>() \endcode */ | |
| template <typename OtherDerived> | |
| EIGEN_DEVICE_FUNC TriangularViewType& operator=(const MatrixBase<OtherDerived>& other); | |
| #ifndef EIGEN_PARSED_BY_DOXYGEN | |
| EIGEN_DEVICE_FUNC TriangularViewType& operator=(const TriangularViewImpl& other) { | |
| return *this = other.derived().nestedExpression(); | |
| } | |
| template <typename OtherDerived> | |
| /** \deprecated */ | |
| EIGEN_DEPRECATED EIGEN_DEVICE_FUNC void lazyAssign(const TriangularBase<OtherDerived>& other); | |
| template <typename OtherDerived> | |
| /** \deprecated */ | |
| EIGEN_DEPRECATED EIGEN_DEVICE_FUNC void lazyAssign(const MatrixBase<OtherDerived>& other); | |
| #endif | |
| // Scaling a unit triangular view would break its implicit unit diagonal, so only non-unit modes participate. | |
| template <unsigned int M = Mode, std::enable_if_t<(M & UnitDiag) == 0, int> = 0> | |
| EIGEN_DEVICE_FUNC const TriangularView< | |
| const EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(MatrixType, Scalar, internal::scalar_product_op), Mode> | |
| operator*(const Scalar& s) const { | |
| return (derived().nestedExpression() * s).template triangularView<Mode>(); | |
| } | |
| template <unsigned int M = Mode, std::enable_if_t<(M & UnitDiag) == 0, int> = 0> | |
| friend EIGEN_DEVICE_FUNC const TriangularView< | |
| const EIGEN_SCALAR_BINARYOP_EXPR_RETURN_TYPE(Scalar, MatrixType, internal::scalar_product_op), Mode> | |
| operator*(const Scalar& s, const TriangularViewImpl& mat) { | |
| return (s * mat.derived().nestedExpression()).template triangularView<Mode>(); | |
| } | |
| /** \returns the product of the inverse of \c *this with \a other, \a *this being triangular. | |
| * | |
| * This function computes the inverse-matrix matrix product inverse(\c *this) * \a other if | |
| * \a Side==OnTheLeft (the default), or the right-inverse-multiply \a other * inverse(\c *this) if | |
| * \a Side==OnTheRight. | |
| * | |
| * Note that the template parameter \c Side can be omitted, in which case \c Side==OnTheLeft | |
| * | |
| * The matrix \c *this must be triangular and invertible (i.e., all the coefficients of the | |
| * diagonal must be non zero). It works as a forward (resp. backward) substitution if \c *this | |
| * is a lower (resp. upper) triangular matrix. | |
| * | |
| * Example: \include Triangular_solve.cpp | |
| * Output: \verbinclude Triangular_solve.out | |
| * | |
| * This function returns an expression of the inverse-multiply and can works in-place if it is assigned | |
| * to the same matrix or vector \a other. | |
| * | |
| * For users coming from BLAS, this function (and more specifically solveInPlace()) offer | |
| * all the operations supported by the \c *TRSV and \c *TRSM BLAS routines. | |
| * | |
| * \sa TriangularView::solveInPlace() | |
| */ | |
| template <int Side, typename Other> | |
| inline const internal::triangular_solve_retval<Side, TriangularViewType, Other> solve( | |
| const MatrixBase<Other>& other) const; | |
| /** "in-place" version of TriangularView::solve() where the result is written in \a other | |
| * | |
| * \warning The parameter is only marked 'const' to make the C++ compiler accept a temporary expression here. | |
| * This function will const_cast it, so constness isn't honored here. | |
| * | |
| * Note that the template parameter \c Side can be omitted, in which case \c Side==OnTheLeft | |
| * | |
| * See TriangularView:solve() for the details. | |
| */ | |
| template <int Side, typename OtherDerived> | |
| EIGEN_DEVICE_FUNC void solveInPlace(const MatrixBase<OtherDerived>& other) const; | |
| template <typename OtherDerived> | |
| EIGEN_DEVICE_FUNC void solveInPlace(const MatrixBase<OtherDerived>& other) const { | |
| return solveInPlace<OnTheLeft>(other); | |
| } | |
| /** Replaces the referenced triangular part by its inverse. | |
| * | |
| * \c *this must be square and invertible; as with solveInPlace(), no check is made and a zero on the | |
| * diagonal yields a non-finite result. The opposite triangle is neither read nor written, and with a | |
| * \c #UnitDiag mode the diagonal itself is left alone as well. | |
| * | |
| * This is the operation of the \c *TRTRI LAPACK routines. It costs n^3/3 flops, where solving against an | |
| * explicit identity right hand side costs n^3, and its only scratch is one block-sized panel of at most | |
| * 128x128 coefficients, independent of the matrix size. | |
| * | |
| * \sa TriangularView::solveInPlace(), MatrixBase::inverse() | |
| */ | |
| EIGEN_DEVICE_FUNC void inverseInPlace(); | |
| /** Swaps the coefficients of the common triangular parts of two matrices */ | |
| template <typename OtherDerived> | |
| EIGEN_DEVICE_FUNC | |
| #ifdef EIGEN_PARSED_BY_DOXYGEN | |
| void | |
| swap(TriangularBase<OtherDerived>& other) | |
| #else | |
| void | |
| swap(TriangularBase<OtherDerived> const& other) | |
| #endif | |
| { | |
| EIGEN_STATIC_ASSERT_LVALUE(OtherDerived); | |
| call_assignment(derived(), other.const_cast_derived(), internal::swap_assign_op<Scalar>()); | |
| } | |
| /** Shortcut for \code (*this).swap(other.triangularView<(*this)::Mode>()) \endcode */ | |
| template <typename OtherDerived> | |
| /** \deprecated */ | |
| EIGEN_DEPRECATED EIGEN_DEVICE_FUNC void swap(MatrixBase<OtherDerived> const& other) { | |
| EIGEN_STATIC_ASSERT_LVALUE(OtherDerived); | |
| call_assignment(derived(), other.const_cast_derived(), internal::swap_assign_op<Scalar>()); | |
| } | |
| template <typename RhsType, typename DstType> | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void _solve_impl(const RhsType& rhs, DstType& dst) const { | |
| if (!internal::is_same_dense(dst, rhs)) dst = rhs; | |
| this->solveInPlace(dst); | |
| } | |
| template <typename ProductType> | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TriangularViewType& _assignProduct(const ProductType& prod, const Scalar& alpha, | |
| bool beta); | |
| protected: | |
| EIGEN_DEFAULT_COPY_CONSTRUCTOR(TriangularViewImpl) | |
| EIGEN_DEFAULT_EMPTY_CONSTRUCTOR_AND_DESTRUCTOR(TriangularViewImpl) | |
| }; | |
| /*************************************************************************** | |
| * Implementation of triangular evaluation/assignment | |
| ***************************************************************************/ | |
| #ifndef EIGEN_PARSED_BY_DOXYGEN | |
| // FIXME should we keep that possibility | |
| template <typename MatrixType, unsigned int Mode> | |
| template <typename OtherDerived> | |
| EIGEN_DEVICE_FUNC inline TriangularView<MatrixType, Mode>& TriangularViewImpl<MatrixType, Mode, Dense>::operator=( | |
| const MatrixBase<OtherDerived>& other) { | |
| internal::call_assignment_no_alias(derived(), other.derived(), | |
| internal::assign_op<Scalar, typename OtherDerived::Scalar>()); | |
| return derived(); | |
| } | |
| // FIXME should we keep that possibility | |
| template <typename MatrixType, unsigned int Mode> | |
| template <typename OtherDerived> | |
| EIGEN_DEVICE_FUNC void TriangularViewImpl<MatrixType, Mode, Dense>::lazyAssign(const MatrixBase<OtherDerived>& other) { | |
| internal::call_assignment_no_alias(derived(), other.template triangularView<Mode>()); | |
| } | |
| template <typename MatrixType, unsigned int Mode> | |
| template <typename OtherDerived> | |
| EIGEN_DEVICE_FUNC inline TriangularView<MatrixType, Mode>& TriangularViewImpl<MatrixType, Mode, Dense>::operator=( | |
| const TriangularBase<OtherDerived>& other) { | |
| eigen_assert(Mode == int(OtherDerived::Mode)); | |
| internal::call_assignment(derived(), other.derived()); | |
| return derived(); | |
| } | |
| template <typename MatrixType, unsigned int Mode> | |
| template <typename OtherDerived> | |
| EIGEN_DEVICE_FUNC void TriangularViewImpl<MatrixType, Mode, Dense>::lazyAssign( | |
| const TriangularBase<OtherDerived>& other) { | |
| eigen_assert(Mode == int(OtherDerived::Mode)); | |
| internal::call_assignment_no_alias(derived(), other.derived()); | |
| } | |
| #endif | |
| /*************************************************************************** | |
| * Implementation of TriangularBase methods | |
| ***************************************************************************/ | |
| /** Assigns a triangular or selfadjoint matrix to a dense matrix. | |
| * If the matrix is triangular, the opposite part is set to zero. */ | |
| template <typename Derived> | |
| template <typename DenseDerived> | |
| EIGEN_DEVICE_FUNC void TriangularBase<Derived>::evalTo(MatrixBase<DenseDerived>& other) const { | |
| evalToLazy(other.derived()); | |
| } | |
| /*************************************************************************** | |
| * Implementation of TriangularView methods | |
| ***************************************************************************/ | |
| /*************************************************************************** | |
| * Implementation of MatrixBase methods | |
| ***************************************************************************/ | |
| /** | |
| * \returns an expression of a triangular view extracted from the current matrix | |
| * | |
| * The parameter \a Mode can have the following values: \c #Upper, \c #StrictlyUpper, \c #UnitUpper, | |
| * \c #Lower, \c #StrictlyLower, \c #UnitLower. | |
| * | |
| * Example: \include MatrixBase_triangularView.cpp | |
| * Output: \verbinclude MatrixBase_triangularView.out | |
| * | |
| * \sa class TriangularView | |
| */ | |
| template <typename Derived> | |
| template <unsigned int Mode> | |
| EIGEN_DEVICE_FUNC constexpr typename MatrixBase<Derived>::template TriangularViewReturnType<Mode>::Type | |
| MatrixBase<Derived>::triangularView() { | |
| return typename TriangularViewReturnType<Mode>::Type(derived()); | |
| } | |
| /** This is the const version of MatrixBase::triangularView() */ | |
| template <typename Derived> | |
| template <unsigned int Mode> | |
| EIGEN_DEVICE_FUNC constexpr typename MatrixBase<Derived>::template ConstTriangularViewReturnType<Mode>::Type | |
| MatrixBase<Derived>::triangularView() const { | |
| return typename ConstTriangularViewReturnType<Mode>::Type(derived()); | |
| } | |
| /** \returns true if *this is approximately equal to an upper triangular matrix, | |
| * within the precision given by \a prec. | |
| * | |
| * \sa isLowerTriangular() | |
| */ | |
| template <typename Derived> | |
| bool MatrixBase<Derived>::isUpperTriangular(const RealScalar& prec) const { | |
| RealScalar maxAbsOnUpperPart = static_cast<RealScalar>(-1); | |
| for (Index j = 0; j < cols(); ++j) { | |
| Index maxi = numext::mini(j, rows() - 1); | |
| for (Index i = 0; i <= maxi; ++i) { | |
| RealScalar absValue = numext::abs(coeff(i, j)); | |
| if (absValue > maxAbsOnUpperPart) maxAbsOnUpperPart = absValue; | |
| } | |
| } | |
| RealScalar threshold = maxAbsOnUpperPart * prec; | |
| for (Index j = 0; j < cols(); ++j) | |
| for (Index i = j + 1; i < rows(); ++i) | |
| if (numext::abs(coeff(i, j)) > threshold) return false; | |
| return true; | |
| } | |
| /** \returns true if *this is approximately equal to a lower triangular matrix, | |
| * within the precision given by \a prec. | |
| * | |
| * \sa isUpperTriangular() | |
| */ | |
| template <typename Derived> | |
| bool MatrixBase<Derived>::isLowerTriangular(const RealScalar& prec) const { | |
| RealScalar maxAbsOnLowerPart = static_cast<RealScalar>(-1); | |
| for (Index j = 0; j < cols(); ++j) | |
| for (Index i = j; i < rows(); ++i) { | |
| RealScalar absValue = numext::abs(coeff(i, j)); | |
| if (absValue > maxAbsOnLowerPart) maxAbsOnLowerPart = absValue; | |
| } | |
| RealScalar threshold = maxAbsOnLowerPart * prec; | |
| for (Index j = 1; j < cols(); ++j) { | |
| // Rows [0, min(j, rows())) of column j lie strictly above the diagonal. For a column past the diagonal block of a | |
| // wide matrix that is the whole column, so the bound is rows(), not rows() - 1. | |
| Index maxi = numext::mini(j, rows()); | |
| for (Index i = 0; i < maxi; ++i) | |
| if (numext::abs(coeff(i, j)) > threshold) return false; | |
| } | |
| return true; | |
| } | |
| /*************************************************************************** | |
| **************************************************************************** | |
| * Evaluators and Assignment of triangular expressions | |
| *************************************************************************** | |
| ***************************************************************************/ | |
| namespace internal { | |
| // TODO: currently a triangular expression has the form TriangularView<.,.> | |
| // in the future triangular-ness should be defined by the expression traits | |
| // such that Transpose<TriangularView<.,.> > is valid. (currently TriangularBase::transpose() is overloaded to make | |
| // it work) | |
| template <typename MatrixType, unsigned int Mode> | |
| struct evaluator_traits<TriangularView<MatrixType, Mode>> { | |
| using Kind = typename storage_kind_to_evaluator_kind<typename MatrixType::StorageKind>::Kind; | |
| using Shape = typename glue_shapes<typename evaluator_traits<MatrixType>::Shape, TriangularShape>::type; | |
| }; | |
| template <typename MatrixType, unsigned int Mode> | |
| struct unary_evaluator<TriangularView<MatrixType, Mode>, IndexBased> : evaluator<internal::remove_all_t<MatrixType>> { | |
| using XprType = TriangularView<MatrixType, Mode>; | |
| using Base = evaluator<internal::remove_all_t<MatrixType>>; | |
| EIGEN_DEVICE_FUNC unary_evaluator(const XprType& xpr) : Base(xpr.nestedExpression()) {} | |
| }; | |
| // Additional assignment kinds: | |
| struct Triangular2Triangular {}; | |
| struct Triangular2Dense {}; | |
| struct Dense2Triangular {}; | |
| template <typename Kernel, unsigned int Mode, int UnrollCount, bool SetOpposite> | |
| struct triangular_assignment_loop; | |
| // Whether call_triangular_assignment_loop fully unrolls the assignment. | |
| template <typename DstEvaluatorType, typename SrcEvaluatorType> | |
| struct triangular_assignment_unrolls { | |
| static constexpr int Size = DstEvaluatorType::XprType::SizeAtCompileTime; | |
| static constexpr bool value = | |
| Size != Dynamic && SrcEvaluatorType::CoeffReadCost < HugeCost && | |
| Size * (int(DstEvaluatorType::CoeffReadCost) + int(SrcEvaluatorType::CoeffReadCost)) / 2 <= EIGEN_UNROLLING_LIMIT; | |
| }; | |
| /** \internal Specialization of the dense assignment kernel for triangular matrices. | |
| * The main difference is that the triangular, diagonal, and opposite parts are processed through three different | |
| * functions. \tparam UpLo must be either Lower or Upper \tparam Mode must be either 0, UnitDiag, ZeroDiag, or | |
| * SelfAdjoint | |
| */ | |
| template <int UpLo, int Mode, int SetOpposite, typename DstEvaluatorTypeT, typename SrcEvaluatorTypeT, typename Functor, | |
| int Version = Specialized> | |
| class triangular_dense_assignment_kernel | |
| : public generic_dense_assignment_kernel<DstEvaluatorTypeT, SrcEvaluatorTypeT, Functor, Version> { | |
| protected: | |
| using Base = generic_dense_assignment_kernel<DstEvaluatorTypeT, SrcEvaluatorTypeT, Functor, Version>; | |
| using DstXprType = typename Base::DstXprType; | |
| using SrcXprType = typename Base::SrcXprType; | |
| using Base::m_dst; | |
| using Base::m_functor; | |
| using Base::m_src; | |
| public: | |
| using DstEvaluatorType = typename Base::DstEvaluatorType; | |
| using SrcEvaluatorType = typename Base::SrcEvaluatorType; | |
| using Scalar = typename Base::Scalar; | |
| using AssignmentTraits = typename Base::AssignmentTraits; | |
| EIGEN_DEVICE_FUNC triangular_dense_assignment_kernel(DstEvaluatorType& dst, const SrcEvaluatorType& src, | |
| const Functor& func, DstXprType& dstExpr) | |
| : Base(dst, src, func, dstExpr) {} | |
| #ifdef EIGEN_INTERNAL_DEBUGGING | |
| EIGEN_DEVICE_FUNC void assignCoeff(Index row, Index col) { | |
| eigen_internal_assert(row != col); | |
| Base::assignCoeff(row, col); | |
| } | |
| #else | |
| using Base::assignCoeff; | |
| #endif | |
| EIGEN_DEVICE_FUNC void assignDiagonalCoeff(Index id) { | |
| EIGEN_IF_CONSTEXPR (Mode == UnitDiag && SetOpposite) { | |
| m_functor.assignCoeff(m_dst.coeffRef(id, id), Scalar(1)); | |
| } else EIGEN_IF_CONSTEXPR (Mode == ZeroDiag && SetOpposite) { | |
| m_functor.assignCoeff(m_dst.coeffRef(id, id), Scalar(0)); | |
| } else EIGEN_IF_CONSTEXPR (Mode == 0) { | |
| Base::assignCoeff(id, id); | |
| } | |
| } | |
| EIGEN_DEVICE_FUNC void assignOppositeCoeff(Index row, Index col) { | |
| eigen_internal_assert(row != col); | |
| EIGEN_IF_CONSTEXPR (SetOpposite) { | |
| m_functor.assignCoeff(m_dst.coeffRef(row, col), Scalar(0)); | |
| } | |
| } | |
| }; | |
| template <int Mode, bool SetOpposite, typename DstXprType, typename SrcXprType, typename Functor> | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void call_triangular_assignment_loop(DstXprType& dst, const SrcXprType& src, | |
| const Functor& func) { | |
| using DstEvaluatorType = evaluator<DstXprType>; | |
| using SrcEvaluatorType = evaluator<SrcXprType>; | |
| SrcEvaluatorType srcEvaluator(src); | |
| Index dstRows = src.rows(); | |
| Index dstCols = src.cols(); | |
| if ((dst.rows() != dstRows) || (dst.cols() != dstCols)) dst.resize(dstRows, dstCols); | |
| DstEvaluatorType dstEvaluator(dst); | |
| using Kernel = triangular_dense_assignment_kernel<Mode&(Lower | Upper), Mode&(UnitDiag | ZeroDiag | SelfAdjoint), | |
| SetOpposite, DstEvaluatorType, SrcEvaluatorType, Functor>; | |
| Kernel kernel(dstEvaluator, srcEvaluator, func, dst.const_cast_derived()); | |
| constexpr bool unroll = triangular_assignment_unrolls<DstEvaluatorType, SrcEvaluatorType>::value; | |
| triangular_assignment_loop<Kernel, Mode, unroll ? int(DstXprType::SizeAtCompileTime) : Dynamic, SetOpposite>::run( | |
| kernel); | |
| } | |
| template <int Mode, bool SetOpposite, typename DstXprType, typename SrcXprType> | |
| EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void call_triangular_assignment_loop(DstXprType& dst, const SrcXprType& src) { | |
| call_triangular_assignment_loop<Mode, SetOpposite>( | |
| dst, src, internal::assign_op<typename DstXprType::Scalar, typename SrcXprType::Scalar>()); | |
| } | |
| template <> | |
| struct AssignmentKind<TriangularShape, TriangularShape> { | |
| using Kind = Triangular2Triangular; | |
| }; | |
| template <> | |
| struct AssignmentKind<DenseShape, TriangularShape> { | |
| using Kind = Triangular2Dense; | |
| }; | |
| template <> | |
| struct AssignmentKind<TriangularShape, DenseShape> { | |
| using Kind = Dense2Triangular; | |
| }; | |
| template <typename Shape> | |
| struct is_dense_structured_shape | |
| : bool_constant<std::is_same<Shape, TriangularShape>::value || std::is_same<Shape, SelfAdjointShape>::value> {}; | |
| template <typename Lhs, typename Rhs> | |
| struct is_dense_structured_diagonal_product | |
| : bool_constant<(is_dense_structured_shape<typename evaluator_traits<Lhs>::Shape>::value && | |
| std::is_same<typename evaluator_traits<Rhs>::Shape, DiagonalShape>::value) || | |
| (std::is_same<typename evaluator_traits<Lhs>::Shape, DiagonalShape>::value && | |
| is_dense_structured_shape<typename evaluator_traits<Rhs>::Shape>::value)> {}; | |
| template <typename DstXprType, typename SrcXprType, typename Functor> | |
| struct Assignment<DstXprType, SrcXprType, Functor, Triangular2Triangular> { | |
| EIGEN_DEVICE_FUNC static void run(DstXprType& dst, const SrcXprType& src, const Functor& func) { | |
| eigen_assert(int(DstXprType::Mode) == int(SrcXprType::Mode)); | |
| call_triangular_assignment_loop<DstXprType::Mode, false>(dst, src, func); | |
| } | |
| }; | |
| template <typename DstXprType, typename SrcXprType, typename Functor> | |
| struct Assignment<DstXprType, SrcXprType, Functor, Triangular2Dense> { | |
| EIGEN_DEVICE_FUNC static void run(DstXprType& dst, const SrcXprType& src, const Functor& func) { | |
| call_triangular_assignment_loop<SrcXprType::Mode, (int(SrcXprType::Mode) & int(SelfAdjoint)) == 0>(dst, src, func); | |
| } | |
| }; | |
| template <typename DstXprType, typename SrcXprType, typename Functor> | |
| struct Assignment<DstXprType, SrcXprType, Functor, Dense2Triangular> { | |
| EIGEN_DEVICE_FUNC static void run(DstXprType& dst, const SrcXprType& src, const Functor& func) { | |
| call_triangular_assignment_loop<DstXprType::Mode, false>(dst, src, func); | |
| } | |
| }; | |
| template <typename Kernel, unsigned int Mode, int UnrollCount, bool SetOpposite> | |
| struct triangular_assignment_loop { | |
| // FIXME: this is not very clean, perhaps this information should be provided by the kernel? | |
| using DstEvaluatorType = typename Kernel::DstEvaluatorType; | |
| using DstXprType = typename DstEvaluatorType::XprType; | |
| enum { | |
| col = (UnrollCount - 1) / DstXprType::RowsAtCompileTime, | |
| row = (UnrollCount - 1) % DstXprType::RowsAtCompileTime | |
| }; | |
| using Scalar = typename Kernel::Scalar; | |
| EIGEN_DEVICE_FUNC static inline void run(Kernel& kernel) { | |
| triangular_assignment_loop<Kernel, Mode, UnrollCount - 1, SetOpposite>::run(kernel); | |
| if (row == col) | |
| kernel.assignDiagonalCoeff(row); | |
| else if (((Mode & Lower) && row > col) || ((Mode & Upper) && row < col)) | |
| kernel.assignCoeff(row, col); | |
| else EIGEN_IF_CONSTEXPR (SetOpposite) { | |
| kernel.assignOppositeCoeff(row, col); | |
| } | |
| } | |
| }; | |
| // prevent buggy user code from causing an infinite recursion | |
| template <typename Kernel, unsigned int Mode, bool SetOpposite> | |
| struct triangular_assignment_loop<Kernel, Mode, 0, SetOpposite> { | |
| EIGEN_DEVICE_FUNC static inline void run(Kernel&) {} | |
| }; | |
| // TODO: experiment with a recursive assignment procedure splitting the current | |
| // triangular part into one rectangular and two triangular parts. | |
| template <typename Kernel, unsigned int Mode, bool SetOpposite> | |
| struct triangular_assignment_loop<Kernel, Mode, Dynamic, SetOpposite> { | |
| using Scalar = typename Kernel::Scalar; | |
| using DstEvaluatorType = typename Kernel::DstEvaluatorType; | |
| using AssignmentTraits = typename Kernel::AssignmentTraits; | |
| enum { | |
| IsRowMajor = (int(DstEvaluatorType::Flags) & RowMajorBit) != 0, | |
| // In col-major: inner=row, outer=col. Upper means row<col i.e. inner<outer -> active before diagonal. | |
| // In row-major: inner=col, outer=row. Upper means row<col i.e. inner>outer -> active after diagonal. | |
| // So ActiveBeforeDiag = (Upper XOR IsRowMajor). | |
| ActiveBeforeDiag = (bool(Mode & Upper) != bool(IsRowMajor)) | |
| }; | |
| // Compile-time outer/inner to row/col mapping. These constant-fold away entirely: | |
| // ColMajor: row(outer,i) -> i, col(outer,i) -> outer | |
| // RowMajor: row(outer,i) -> outer, col(outer,i) -> i | |
| static constexpr Index row(Index outer, Index inner) { return IsRowMajor ? outer : inner; } | |
| static constexpr Index col(Index outer, Index inner) { return IsRowMajor ? inner : outer; } | |
| // Iterates in outer/inner order matching the storage layout for cache friendliness. | |
| // Unlike the old code (which always iterated outer=col, inner=row), this gives | |
| // contiguous memory access for both ColMajor and RowMajor storage. | |
| // Simple scalar loops allow GCC to recognize memcpy/memset idioms and Clang to auto-vectorize. | |
| // Uses a single running index 'i' per column (not separate loop variables) so the compiler | |
| // can track the continuous progression and optimize register allocation. | |
| EIGEN_DEVICE_FUNC static inline void run(Kernel& kernel) { | |
| const Index outerSize = IsRowMajor ? kernel.rows() : kernel.cols(); | |
| const Index innerSize = IsRowMajor ? kernel.cols() : kernel.rows(); | |
| for (Index outer = 0; outer < outerSize; ++outer) { | |
| const Index maxi = numext::mini(outer, innerSize); | |
| Index i = 0; | |
| EIGEN_IF_CONSTEXPR (ActiveBeforeDiag) { | |
| for (; i < maxi; ++i) kernel.assignCoeff(row(outer, i), col(outer, i)); | |
| } else EIGEN_IF_CONSTEXPR (SetOpposite) { | |
| for (; i < maxi; ++i) kernel.assignOppositeCoeff(row(outer, i), col(outer, i)); | |
| } else { | |
| i = maxi; | |
| } | |
| if (i < innerSize) kernel.assignDiagonalCoeff(i++); | |
| EIGEN_IF_CONSTEXPR (!ActiveBeforeDiag) { | |
| for (; i < innerSize; ++i) kernel.assignCoeff(row(outer, i), col(outer, i)); | |
| } else EIGEN_IF_CONSTEXPR (SetOpposite) { | |
| for (; i < innerSize; ++i) kernel.assignOppositeCoeff(row(outer, i), col(outer, i)); | |
| } | |
| } | |
| } | |
| }; | |
| } // end namespace internal | |
| /** Assigns a triangular or selfadjoint matrix to a dense matrix. | |
| * If the matrix is triangular, the opposite part is set to zero. */ | |
| template <typename Derived> | |
| template <typename DenseDerived> | |
| EIGEN_DEVICE_FUNC void TriangularBase<Derived>::evalToLazy(MatrixBase<DenseDerived>& other) const { | |
| other.derived().resize(this->rows(), this->cols()); | |
| internal::call_triangular_assignment_loop<Derived::Mode, | |
| (int(Derived::Mode) & int(SelfAdjoint)) == 0 /* SetOpposite */>( | |
| other.derived(), derived().nestedExpression()); | |
| } | |
| namespace internal { | |
| template <bool UseTriangularAssignmentLoop> | |
| struct triangular_product_assignment_dispatcher { | |
| template <typename DstXprType, typename SrcXprType, typename Functor, typename Scalar> | |
| static void run(DstXprType& dst, const SrcXprType& src, const Functor&, const Scalar& alpha, bool beta) { | |
| if (!beta) { | |
| Index dstRows = src.rows(); | |
| Index dstCols = src.cols(); | |
| if ((dst.rows() != dstRows) || (dst.cols() != dstCols)) dst.resize(dstRows, dstCols); | |
| } | |
| dst._assignProduct(src, alpha, beta); | |
| } | |
| }; | |
| // Underlying-storage data pointer for the diagonal operand of a structured x diagonal | |
| // product, or nullptr for non-diagonal operands. The structured (triangular/selfadjoint) | |
| // operand can safely share storage with dst because the kernel reads each (row, col) cell | |
| // before writing it; only diagonal/dst overlap can corrupt later reads via the diagonal | |
| // entries that have already been written. | |
| template <typename Op> | |
| EIGEN_DEVICE_FUNC inline const void* diagonal_operand_data(const Op& op, DiagonalShape) { | |
| return extract_data(op.diagonal()); | |
| } | |
| template <typename Op, typename Shape> | |
| EIGEN_DEVICE_FUNC inline const void* diagonal_operand_data(const Op& /*op*/, Shape) { | |
| return nullptr; | |
| } | |
| template <typename DstXprType, typename SrcXprType> | |
| EIGEN_DEVICE_FUNC inline bool structured_diagonal_product_aliases(const DstXprType& dst, const SrcXprType& src) { | |
| const void* dst_data = dst.nestedExpression().data(); | |
| if (dst_data == nullptr) return false; | |
| const void* lhs_diag_data = | |
| diagonal_operand_data(src.lhs(), typename evaluator_traits<typename SrcXprType::Lhs>::Shape{}); | |
| const void* rhs_diag_data = | |
| diagonal_operand_data(src.rhs(), typename evaluator_traits<typename SrcXprType::Rhs>::Shape{}); | |
| return (lhs_diag_data != nullptr && lhs_diag_data == dst_data) || | |
| (rhs_diag_data != nullptr && rhs_diag_data == dst_data); | |
| } | |
| template <> | |
| struct triangular_product_assignment_dispatcher<true> { | |
| template <typename DstXprType, typename SrcXprType, typename Functor, typename Scalar> | |
| static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(DstXprType& dst, const SrcXprType& src, const Functor& func, | |
| const Scalar& alpha, bool beta) { | |
| EIGEN_UNUSED_VARIABLE(alpha); | |
| EIGEN_UNUSED_VARIABLE(beta); | |
| EIGEN_STATIC_ASSERT((int(DstXprType::Mode) & int(UnitDiag)) == 0, | |
| WRITING_TO_TRIANGULAR_PART_WITH_UNIT_DIAGONAL_IS_NOT_SUPPORTED); | |
| // The triangular assignment loop reads src.coeff(row, col) lazily while writing | |
| // dst.coeffRef(row, col). When the diagonal operand of the product shares storage with | |
| // dst (e.g. | |
| // A.triangularView<Upper>() = A.diagonal().asDiagonal() * A.triangularView<Upper>()) | |
| // the diagonal entries already written in earlier columns would feed back as modified | |
| // values, corrupting later reads. Materialize the source into a temporary first when | |
| // overlap is detected at run time. The structured (triangular/selfadjoint) operand may | |
| // safely alias dst because the kernel reads each cell before writing it. | |
| if (structured_diagonal_product_aliases(dst, src)) { | |
| typename SrcXprType::PlainObject tmp(src); | |
| call_triangular_assignment_loop<DstXprType::Mode, false>(dst, tmp, func); | |
| } else { | |
| call_triangular_assignment_loop<DstXprType::Mode, false>(dst, src, func); | |
| } | |
| } | |
| }; | |
| // Triangular = Product | |
| template <typename DstXprType, typename Lhs, typename Rhs, typename Scalar> | |
| struct Assignment<DstXprType, Product<Lhs, Rhs, DefaultProduct>, | |
| internal::assign_op<Scalar, typename Product<Lhs, Rhs, DefaultProduct>::Scalar>, Dense2Triangular> { | |
| using SrcXprType = Product<Lhs, Rhs, DefaultProduct>; | |
| static void run(DstXprType& dst, const SrcXprType& src, | |
| const internal::assign_op<Scalar, typename SrcXprType::Scalar>& func) { | |
| enum { UseTriangularAssignmentLoop = is_dense_structured_diagonal_product<Lhs, Rhs>::value }; | |
| triangular_product_assignment_dispatcher<UseTriangularAssignmentLoop>::run(dst, src, func, Scalar(1), false); | |
| } | |
| }; | |
| // Triangular += Product | |
| template <typename DstXprType, typename Lhs, typename Rhs, typename Scalar> | |
| struct Assignment<DstXprType, Product<Lhs, Rhs, DefaultProduct>, | |
| internal::add_assign_op<Scalar, typename Product<Lhs, Rhs, DefaultProduct>::Scalar>, | |
| Dense2Triangular> { | |
| using SrcXprType = Product<Lhs, Rhs, DefaultProduct>; | |
| static void run(DstXprType& dst, const SrcXprType& src, | |
| const internal::add_assign_op<Scalar, typename SrcXprType::Scalar>& func) { | |
| enum { UseTriangularAssignmentLoop = is_dense_structured_diagonal_product<Lhs, Rhs>::value }; | |
| triangular_product_assignment_dispatcher<UseTriangularAssignmentLoop>::run(dst, src, func, Scalar(1), true); | |
| } | |
| }; | |
| // Triangular -= Product | |
| template <typename DstXprType, typename Lhs, typename Rhs, typename Scalar> | |
| struct Assignment<DstXprType, Product<Lhs, Rhs, DefaultProduct>, | |
| internal::sub_assign_op<Scalar, typename Product<Lhs, Rhs, DefaultProduct>::Scalar>, | |
| Dense2Triangular> { | |
| using SrcXprType = Product<Lhs, Rhs, DefaultProduct>; | |
| static void run(DstXprType& dst, const SrcXprType& src, | |
| const internal::sub_assign_op<Scalar, typename SrcXprType::Scalar>& func) { | |
| enum { UseTriangularAssignmentLoop = is_dense_structured_diagonal_product<Lhs, Rhs>::value }; | |
| triangular_product_assignment_dispatcher<UseTriangularAssignmentLoop>::run(dst, src, func, Scalar(-1), true); | |
| } | |
| }; | |
| } // end namespace internal | |
| } // end namespace Eigen | |
| #endif // EIGEN_TRIANGULARMATRIX_H |