From 36a0db93f724f49a372aa2e8b14bedc4aec06909 Mon Sep 17 00:00:00 2001 From: Antonio Sanchez Date: Tue, 11 Apr 2023 10:18:58 -0700 Subject: [PATCH 1/5] Avoid resursive block definitions. In algorithms that require recursive calls on blocks (e.g. as required by tlapack), recursive block class definitions can lead to endless compile loops, causing the compiler to crash. Since blocks are contiguous sections of an underlying expression, we are ble to avoid this by referring to the original undelrying expression when taking a block of a block. This should also end up being more efficient. Note that this is a breaking change, in that existing code that explicitly stores block-of-block types will now have a type mismatch. There were only a small handful of such cases encountered in the tests. --- Eigen/src/Core/Block.h | 10 +- Eigen/src/Core/util/XprHelper.h | 42 + Eigen/src/Geometry/Quaternion.h | 10 +- Eigen/src/Geometry/Transform.h | 24 +- Eigen/src/Householder/HouseholderSequence.h | 23 +- .../IterativeSolverBase.h | 4 +- Eigen/src/plugins/BlockMethods.h | 790 +++++++++--------- Eigen/src/plugins/IndexedViewMethods.h | 32 +- test/block.cpp | 13 + 9 files changed, 537 insertions(+), 411 deletions(-) diff --git a/Eigen/src/Core/Block.h b/Eigen/src/Core/Block.h index 58057633e..9141f680d 100644 --- a/Eigen/src/Core/Block.h +++ b/Eigen/src/Core/Block.h @@ -16,9 +16,10 @@ namespace Eigen { namespace internal { -template -struct traits > : traits +template +struct traits > : traits { + typedef XprType_ XprType; typedef typename traits::Scalar Scalar; typedef typename traits::StorageKind StorageKind; typedef typename traits::XprKind XprKind; @@ -52,12 +53,13 @@ struct traits > : traits::value ? LvalueBit : 0, FlagsRowMajorBit = IsRowMajor ? RowMajorBit : 0, - Flags = (traits::Flags & (DirectAccessBit | (InnerPanel?CompressedAccessBit:0))) | FlagsLvalueBit | FlagsRowMajorBit, + Flags = (traits::Flags & (DirectAccessBit | (InnerPanel_?CompressedAccessBit:0))) | FlagsLvalueBit | FlagsRowMajorBit, // FIXME DirectAccessBit should not be handled by expressions // // Alignment is needed by MapBase's assertions // We can sefely set it to false here. Internal alignment errors will be detected by an eigen_internal_assert in the respective evaluator - Alignment = 0 + Alignment = 0, + InnerPanel = InnerPanel_ ? 1 : 0 }; }; diff --git a/Eigen/src/Core/util/XprHelper.h b/Eigen/src/Core/util/XprHelper.h index b5f91bf75..34809a951 100644 --- a/Eigen/src/Core/util/XprHelper.h +++ b/Eigen/src/Core/util/XprHelper.h @@ -742,6 +742,48 @@ std::string demangle_flags(int f) } #endif +template +struct is_block_xpr : std::false_type {}; + +template +struct is_block_xpr> : std::true_type {}; + +// Helper utility for constructing non-recursive block expressions. +template +struct block_xpr_helper { + using BaseType = XprType; + + // For regular block expressions, simply forward along the InnerPanel argument, + // which is set when calling row/column expressions. + static constexpr bool is_inner_panel(bool inner_panel) { return inner_panel; }; + + // Only enable non-const base function if XprType is not const (otherwise we get a duplicate definition). + template::value>> + static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE BaseType& base(XprType& xpr) { return xpr; } + static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE const BaseType& base(const XprType& xpr) { return xpr; } + static constexpr EIGEN_ALWAYS_INLINE Index row(const XprType& /*xpr*/, Index r) { return r; } + static constexpr EIGEN_ALWAYS_INLINE Index col(const XprType& /*xpr*/, Index c) { return c; } +}; + +template +struct block_xpr_helper> { + using BlockXprType = Block; + // Recursive helper in case of explicit block-of-block expression. + using NestedXprHelper = block_xpr_helper; + using BaseType = typename NestedXprHelper::BaseType; + + // For block-of-block expressions, we need to combine the InnerPannel trait + // with that of the block subexpression. + static constexpr bool is_inner_panel(bool inner_panel) { return InnerPanel && inner_panel; } + + // Only enable non-const base function if XprType is not const (otherwise we get a duplicates definition). + template::value>> + static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE BaseType& base(BlockXprType& xpr) { return NestedXprHelper::base(xpr.nestedExpression()); } + static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE const BaseType& base(const BlockXprType& xpr) { return NestedXprHelper::base(xpr.nestedExpression()); } + static constexpr EIGEN_ALWAYS_INLINE Index row(const BlockXprType& xpr, Index r) { return xpr.startRow() + NestedXprHelper::row(xpr.nestedExpression(), r); } + static constexpr EIGEN_ALWAYS_INLINE Index col(const BlockXprType& xpr, Index c) { return xpr.startCol() + NestedXprHelper::col(xpr.nestedExpression(), c); } +}; + } // end namespace internal diff --git a/Eigen/src/Geometry/Quaternion.h b/Eigen/src/Geometry/Quaternion.h index 0aca4c471..d6e6c21f0 100644 --- a/Eigen/src/Geometry/Quaternion.h +++ b/Eigen/src/Geometry/Quaternion.h @@ -48,6 +48,8 @@ class QuaternionBase : public RotationBase typedef typename Coefficients::CoeffReturnType CoeffReturnType; typedef std::conditional_t::Flags&LvalueBit), Scalar&, CoeffReturnType> NonConstCoeffReturnType; + typedef typename Coefficients::template FixedSegmentReturnType<3>::Type CoefficientsVec; + typedef typename Coefficients::template ConstFixedSegmentReturnType<3>::Type ConstCoefficientsVec; enum { @@ -83,16 +85,16 @@ class QuaternionBase : public RotationBase EIGEN_DEVICE_FUNC inline NonConstCoeffReturnType w() { return this->derived().coeffs().w(); } /** \returns a read-only vector expression of the imaginary part (x,y,z) */ - EIGEN_DEVICE_FUNC inline const VectorBlock vec() const { return coeffs().template head<3>(); } + EIGEN_DEVICE_FUNC inline ConstCoefficientsVec vec() const { return coeffs().template head<3>(); } /** \returns a vector expression of the imaginary part (x,y,z) */ - EIGEN_DEVICE_FUNC inline VectorBlock vec() { return coeffs().template head<3>(); } + EIGEN_DEVICE_FUNC inline CoefficientsVec vec() { return coeffs().template head<3>(); } /** \returns a read-only vector expression of the coefficients (x,y,z,w) */ - EIGEN_DEVICE_FUNC inline const typename internal::traits::Coefficients& coeffs() const { return derived().coeffs(); } + EIGEN_DEVICE_FUNC inline const Coefficients& coeffs() const { return derived().coeffs(); } /** \returns a vector expression of the coefficients (x,y,z,w) */ - EIGEN_DEVICE_FUNC inline typename internal::traits::Coefficients& coeffs() { return derived().coeffs(); } + EIGEN_DEVICE_FUNC inline Coefficients& coeffs() { return derived().coeffs(); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE QuaternionBase& operator=(const QuaternionBase& other); template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator=(const QuaternionBase& other); diff --git a/Eigen/src/Geometry/Transform.h b/Eigen/src/Geometry/Transform.h index fd0ae7e6c..ddf7c2a93 100644 --- a/Eigen/src/Geometry/Transform.h +++ b/Eigen/src/Geometry/Transform.h @@ -225,23 +225,23 @@ public: /** type of the matrix used to represent the linear part of the transformation */ typedef Matrix LinearMatrixType; /** type of read/write reference to the linear part of the transformation */ - typedef Block LinearPart; + typedef typename MatrixType::template FixedBlockXpr::Type LinearPart; /** type of read reference to the linear part of the transformation */ - typedef const Block ConstLinearPart; + typedef typename MatrixType::template ConstFixedBlockXpr::Type ConstLinearPart; /** type of read/write reference to the affine part of the transformation */ typedef std::conditional_t > AffinePart; + typename MatrixType::template FixedBlockXpr::Type > AffinePart; /** type of read reference to the affine part of the transformation */ typedef std::conditional_t > ConstAffinePart; + typename MatrixType::template ConstFixedBlockXpr::Type > ConstAffinePart; /** type of a vector */ typedef Matrix VectorType; /** type of a read/write reference to the translation part of the rotation */ - typedef Block::Flags & RowMajorBit)> TranslationPart; + typedef typename MatrixType::template FixedBlockXpr::Flags & RowMajorBit)>::Type TranslationPart; /** type of a read reference to the translation part of the rotation */ - typedef const Block::Flags & RowMajorBit)> ConstTranslationPart; + typedef typename MatrixType::template ConstFixedBlockXpr::Flags & RowMajorBit)>::Type ConstTranslationPart; /** corresponding translation type */ typedef Translation TranslationType; @@ -658,26 +658,26 @@ public: * \returns the Dim x Dim linear part if the transformation is affine, * and the HDim x Dim part for projective transformations. */ - EIGEN_DEVICE_FUNC inline Block linearExt() + EIGEN_DEVICE_FUNC inline typename MatrixType::template FixedBlockXpr::Type linearExt() { return m_matrix.template block(0,0); } /** \internal * \returns the Dim x Dim linear part if the transformation is affine, * and the HDim x Dim part for projective transformations. */ - EIGEN_DEVICE_FUNC inline const Block linearExt() const + EIGEN_DEVICE_FUNC inline typename MatrixType::template ConstFixedBlockXpr::Type linearExt() const { return m_matrix.template block(0,0); } /** \internal * \returns the translation part if the transformation is affine, * and the last column for projective transformations. */ - EIGEN_DEVICE_FUNC inline Block translationExt() + EIGEN_DEVICE_FUNC inline typename MatrixType::template FixedBlockXpr::Type translationExt() { return m_matrix.template block(0,Dim); } /** \internal * \returns the translation part if the transformation is affine, * and the last column for projective transformations. */ - EIGEN_DEVICE_FUNC inline const Block translationExt() const + EIGEN_DEVICE_FUNC inline typename MatrixType::template ConstFixedBlockXpr::Type translationExt() const { return m_matrix.template block(0,Dim); } @@ -1362,7 +1362,7 @@ struct transform_right_product_impl< TransformType, MatrixType, 1, RhsCols> { EIGEN_STATIC_ASSERT(OtherRows==HDim, YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES); - typedef Block TopLeftLhs; + typedef typename ResultType::template FixedBlockXpr::Type TopLeftLhs; ResultType res(other.rows(),other.cols()); TopLeftLhs(res, 0, 0, Dim, other.cols()).noalias() = T.affine() * other; @@ -1388,7 +1388,7 @@ struct transform_right_product_impl< TransformType, MatrixType, 2, RhsCols> { EIGEN_STATIC_ASSERT(OtherRows==Dim, YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES); - typedef Block TopLeftLhs; + typedef typename ResultType::template FixedBlockXpr::Type TopLeftLhs; ResultType res(Replicate(T.translation(),1,other.cols())); TopLeftLhs(res, 0, 0, Dim, other.cols()).noalias() += T.linear() * other; diff --git a/Eigen/src/Householder/HouseholderSequence.h b/Eigen/src/Householder/HouseholderSequence.h index 41fef641d..4cdc1c11f 100644 --- a/Eigen/src/Householder/HouseholderSequence.h +++ b/Eigen/src/Householder/HouseholderSequence.h @@ -87,24 +87,24 @@ struct evaluator_traits > template struct hseq_side_dependent_impl { - typedef Block EssentialVectorType; + typedef typename VectorsType::template ConstFixedBlockXpr::Type EssentialVectorType; typedef HouseholderSequence HouseholderSequenceType; static EIGEN_DEVICE_FUNC inline const EssentialVectorType essentialVector(const HouseholderSequenceType& h, Index k) { Index start = k+1+h.m_shift; - return Block(h.m_vectors, start, k, h.rows()-start, 1); + return h.m_vectors.template block(start, k, h.rows()-start, 1); } }; template struct hseq_side_dependent_impl { - typedef Transpose > EssentialVectorType; + typedef Transpose::Type > EssentialVectorType; typedef HouseholderSequence HouseholderSequenceType; static inline const EssentialVectorType essentialVector(const HouseholderSequenceType& h, Index k) { Index start = k+1+h.m_shift; - return Block(h.m_vectors, k, start, 1, h.rows()-start).transpose(); + return h.m_vectors.template block<1, Dynamic>(k, start, 1, h.rows()-start).transpose(); } }; @@ -384,18 +384,19 @@ template class HouseholderS Index bs = end-k; Index start = k + m_shift; - typedef Block,Dynamic,Dynamic> SubVectorsType; - SubVectorsType sub_vecs1(m_vectors.const_cast_derived(), Side==OnTheRight ? k : start, - Side==OnTheRight ? start : k, - Side==OnTheRight ? bs : m_vectors.rows()-start, - Side==OnTheRight ? m_vectors.cols()-start : bs); + typedef typename internal::remove_all_t::BlockXpr SubVectorsType; + SubVectorsType sub_vecs1 = m_vectors.const_cast_derived().block( + Side==OnTheRight ? k : start, + Side==OnTheRight ? start : k, + Side==OnTheRight ? bs : m_vectors.rows()-start, + Side==OnTheRight ? m_vectors.cols()-start : bs); std::conditional_t, SubVectorsType&> sub_vecs(sub_vecs1); Index dstRows = rows()-m_shift-k; if (inputIsIdentity) { - Block sub_dst = dst.bottomRightCorner(dstRows, dstRows); + auto sub_dst = dst.bottomRightCorner(dstRows, dstRows); apply_block_householder_on_the_left(sub_dst, sub_vecs, m_coeffs.segment(k, bs), !m_reverse); } else @@ -415,7 +416,7 @@ template class HouseholderS if (inputIsIdentity) { - Block sub_dst = dst.bottomRightCorner(dstRows, dstRows); + auto sub_dst = dst.bottomRightCorner(dstRows, dstRows); sub_dst.applyHouseholderOnTheLeft(essentialVector(actual_k), m_coeffs.coeff(actual_k), workspace.data()); } else diff --git a/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h b/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h index 49829d018..81c176c4e 100644 --- a/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h +++ b/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h @@ -379,8 +379,8 @@ public: ComputationInfo global_info = Success; for(Index k=0; k; +using BlockXprBase = typename BlockXprHelper::BaseType; + /// \internal expression type of a column */ -typedef Block::RowsAtCompileTime, 1, !IsRowMajor> ColXpr; -typedef const Block::RowsAtCompileTime, 1, !IsRowMajor> ConstColXpr; +typedef Block::RowsAtCompileTime, 1, BlockXprHelper::is_inner_panel(!IsRowMajor)> ColXpr; +typedef const Block::RowsAtCompileTime, 1, BlockXprHelper::is_inner_panel(!IsRowMajor)> ConstColXpr; /// \internal expression type of a row */ -typedef Block::ColsAtCompileTime, IsRowMajor> RowXpr; -typedef const Block::ColsAtCompileTime, IsRowMajor> ConstRowXpr; +typedef Block::ColsAtCompileTime, BlockXprHelper::is_inner_panel(IsRowMajor)> RowXpr; +typedef const Block::ColsAtCompileTime, BlockXprHelper::is_inner_panel(IsRowMajor)> ConstRowXpr; /// \internal expression type of a block of whole columns */ -typedef Block::RowsAtCompileTime, Dynamic, !IsRowMajor> ColsBlockXpr; -typedef const Block::RowsAtCompileTime, Dynamic, !IsRowMajor> ConstColsBlockXpr; +typedef Block::RowsAtCompileTime, Dynamic, BlockXprHelper::is_inner_panel(!IsRowMajor)> ColsBlockXpr; +typedef const Block::RowsAtCompileTime, Dynamic, BlockXprHelper::is_inner_panel(!IsRowMajor)> ConstColsBlockXpr; /// \internal expression type of a block of whole rows */ -typedef Block::ColsAtCompileTime, IsRowMajor> RowsBlockXpr; -typedef const Block::ColsAtCompileTime, IsRowMajor> ConstRowsBlockXpr; +typedef Block::ColsAtCompileTime, BlockXprHelper::is_inner_panel(IsRowMajor)> RowsBlockXpr; +typedef const Block::ColsAtCompileTime, BlockXprHelper::is_inner_panel(IsRowMajor)> ConstRowsBlockXpr; /// \internal expression type of a block of whole columns */ -template struct NColsBlockXpr { typedef Block::RowsAtCompileTime, N, !IsRowMajor> Type; }; -template struct ConstNColsBlockXpr { typedef const Block::RowsAtCompileTime, N, !IsRowMajor> Type; }; +template struct NColsBlockXpr { typedef Block::RowsAtCompileTime, N, BlockXprHelper::is_inner_panel(!IsRowMajor)> Type; }; +template struct ConstNColsBlockXpr { typedef const Block::RowsAtCompileTime, N, BlockXprHelper::is_inner_panel(!IsRowMajor)> Type; }; /// \internal expression type of a block of whole rows */ -template struct NRowsBlockXpr { typedef Block::ColsAtCompileTime, IsRowMajor> Type; }; -template struct ConstNRowsBlockXpr { typedef const Block::ColsAtCompileTime, IsRowMajor> Type; }; +template struct NRowsBlockXpr { typedef Block::ColsAtCompileTime, BlockXprHelper::is_inner_panel(IsRowMajor)> Type; }; +template struct ConstNRowsBlockXpr { typedef const Block::ColsAtCompileTime, BlockXprHelper::is_inner_panel(IsRowMajor)> Type; }; /// \internal expression of a block */ -typedef Block BlockXpr; -typedef const Block ConstBlockXpr; +typedef Block BlockXpr; +typedef const Block ConstBlockXpr; /// \internal expression of a block of fixed sizes */ -template struct FixedBlockXpr { typedef Block Type; }; -template struct ConstFixedBlockXpr { typedef Block Type; }; - -typedef VectorBlock SegmentReturnType; -typedef const VectorBlock ConstSegmentReturnType; -template struct FixedSegmentReturnType { typedef VectorBlock Type; }; -template struct ConstFixedSegmentReturnType { typedef const VectorBlock Type; }; +template +struct FixedBlockXpr { + typedef Block::Flags & RowMajorBit) + ? Cols != Dynamic && Cols == internal::traits::ColsAtCompileTime + : Rows != Dynamic && Rows == internal::traits::RowsAtCompileTime > Type; +}; +template +struct ConstFixedBlockXpr { + typedef const Block::Flags & RowMajorBit) + ? Cols != Dynamic && Cols == internal::traits::ColsAtCompileTime + : Rows != Dynamic && Rows == internal::traits::RowsAtCompileTime > Type; +}; + +template struct FixedSegmentReturnType { + typedef Block Type; +}; +template struct ConstFixedSegmentReturnType { + typedef const Block Type; +}; +using SegmentReturnType = typename FixedSegmentReturnType::Type; +using ConstSegmentReturnType = typename ConstFixedSegmentReturnType::Type; /// \internal inner-vector -typedef Block InnerVectorReturnType; -typedef Block ConstInnerVectorReturnType; +typedef Block InnerVectorReturnType; +typedef Block ConstInnerVectorReturnType; /// \internal set of inner-vectors -typedef Block InnerVectorsReturnType; -typedef Block ConstInnerVectorsReturnType; +typedef Block InnerVectorsReturnType; +typedef Block ConstInnerVectorsReturnType; #endif // not EIGEN_PARSED_BY_DOXYGEN @@ -96,7 +117,7 @@ typename FixedBlockXpr<...,...>::Type block(Index startRow, Index startCol, NRowsType blockRows, NColsType blockCols) { return typename FixedBlockXpr::value,internal::get_fixed_value::value>::Type( - derived(), startRow, startCol, internal::get_runtime_value(blockRows), internal::get_runtime_value(blockCols)); + BlockXprHelper::base(derived()), BlockXprHelper::row(derived(), startRow), BlockXprHelper::col(derived(), startCol), internal::get_runtime_value(blockRows), internal::get_runtime_value(blockCols)); } /// This is the const version of block(Index,Index,NRowsType,NColsType) @@ -110,10 +131,95 @@ const typename ConstFixedBlockXpr<...,...>::Type block(Index startRow, Index startCol, NRowsType blockRows, NColsType blockCols) const { return typename ConstFixedBlockXpr::value,internal::get_fixed_value::value>::Type( - derived(), startRow, startCol, internal::get_runtime_value(blockRows), internal::get_runtime_value(blockCols)); + BlockXprHelper::base(derived()), BlockXprHelper::row(derived(), startRow), BlockXprHelper::col(derived(), startCol), internal::get_runtime_value(blockRows), internal::get_runtime_value(blockCols)); } +/// \returns a fixed-size expression of a block of \c *this. +/// +/// The template parameters \a NRows and \a NCols are the number of +/// rows and columns in the block. +/// +/// \param startRow the first row in the block +/// \param startCol the first column in the block +/// +/// Example: \include MatrixBase_block_int_int.cpp +/// Output: \verbinclude MatrixBase_block_int_int.out +/// +/// \note The usage of of this overload is discouraged from %Eigen 3.4, better used the generic +/// block(Index,Index,NRowsType,NColsType), here is the one-to-one equivalence: +/// \code +/// mat.template block(i,j) <--> mat.block(i,j,fix,fix) +/// \endcode +/// +/// \note since block is a templated member, the keyword template has to be used +/// if the matrix type is also a template parameter: \code m.template block<3,3>(1,1); \endcode +/// +EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL +/// +/// \sa block(Index,Index,NRowsType,NColsType), class Block +/// +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +typename FixedBlockXpr::Type block(Index startRow, Index startCol) +{ + return typename FixedBlockXpr::Type(BlockXprHelper::base(derived()), BlockXprHelper::row(derived(), startRow), BlockXprHelper::col(derived(), startCol)); +} + +/// This is the const version of block<>(Index, Index). */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +const typename ConstFixedBlockXpr::Type block(Index startRow, Index startCol) const +{ + return typename ConstFixedBlockXpr::Type(BlockXprHelper::base(derived()), BlockXprHelper::row(derived(), startRow), BlockXprHelper::col(derived(), startCol)); +} + +/// \returns an expression of a block of \c *this. +/// +/// \tparam NRows number of rows in block as specified at compile-time +/// \tparam NCols number of columns in block as specified at compile-time +/// \param startRow the first row in the block +/// \param startCol the first column in the block +/// \param blockRows number of rows in block as specified at run-time +/// \param blockCols number of columns in block as specified at run-time +/// +/// This function is mainly useful for blocks where the number of rows is specified at compile-time +/// and the number of columns is specified at run-time, or vice versa. The compile-time and run-time +/// information should not contradict. In other words, \a blockRows should equal \a NRows unless +/// \a NRows is \a Dynamic, and the same for the number of columns. +/// +/// Example: \include MatrixBase_template_int_int_block_int_int_int_int.cpp +/// Output: \verbinclude MatrixBase_template_int_int_block_int_int_int_int.out +/// +/// \note The usage of of this overload is discouraged from %Eigen 3.4, better used the generic +/// block(Index,Index,NRowsType,NColsType), here is the one-to-one complete equivalence: +/// \code +/// mat.template block(i,j,rows,cols) <--> mat.block(i,j,fix(rows),fix(cols)) +/// \endcode +/// If we known that, e.g., NRows==Dynamic and NCols!=Dynamic, then the equivalence becomes: +/// \code +/// mat.template block(i,j,rows,NCols) <--> mat.block(i,j,rows,fix) +/// \endcode +/// +EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL +/// +/// \sa block(Index,Index,NRowsType,NColsType), class Block +/// +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +typename FixedBlockXpr::Type block(Index startRow, Index startCol, + Index blockRows, Index blockCols) +{ + return typename FixedBlockXpr::Type(BlockXprHelper::base(derived()), BlockXprHelper::row(derived(), startRow), BlockXprHelper::col(derived(), startCol), blockRows, blockCols); +} +/// This is the const version of block<>(Index, Index, Index, Index). +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +const typename ConstFixedBlockXpr::Type block(Index startRow, Index startCol, + Index blockRows, Index blockCols) const +{ + return typename ConstFixedBlockXpr::Type(BlockXprHelper::base(derived()), BlockXprHelper::row(derived(), startRow), BlockXprHelper::col(derived(), startCol), blockRows, blockCols); +} /// \returns a expression of a top-right corner of \c *this with either dynamic or fixed sizes. /// @@ -141,8 +247,7 @@ typename FixedBlockXpr<...,...>::Type #endif topRightCorner(NRowsType cRows, NColsType cCols) { - return typename FixedBlockXpr::value,internal::get_fixed_value::value>::Type - (derived(), 0, cols() - internal::get_runtime_value(cCols), internal::get_runtime_value(cRows), internal::get_runtime_value(cCols)); + return block(0, cols() - internal::get_runtime_value(cCols), cRows, cCols); } /// This is the const version of topRightCorner(NRowsType, NColsType). @@ -155,8 +260,7 @@ const typename ConstFixedBlockXpr<...,...>::Type #endif topRightCorner(NRowsType cRows, NColsType cCols) const { - return typename ConstFixedBlockXpr::value,internal::get_fixed_value::value>::Type - (derived(), 0, cols() - internal::get_runtime_value(cCols), internal::get_runtime_value(cRows), internal::get_runtime_value(cCols)); + return block(0, cols() - internal::get_runtime_value(cCols), cRows, cCols); } /// \returns an expression of a fixed-size top-right corner of \c *this. @@ -175,7 +279,7 @@ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename FixedBlockXpr::Type topRightCorner() { - return typename FixedBlockXpr::Type(derived(), 0, cols() - CCols); + return block(0, cols() - CCols); } /// This is the const version of topRightCorner(). @@ -183,7 +287,7 @@ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename ConstFixedBlockXpr::Type topRightCorner() const { - return typename ConstFixedBlockXpr::Type(derived(), 0, cols() - CCols); + return block(0, cols() - CCols); } /// \returns an expression of a top-right corner of \c *this. @@ -209,7 +313,7 @@ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename FixedBlockXpr::Type topRightCorner(Index cRows, Index cCols) { - return typename FixedBlockXpr::Type(derived(), 0, cols() - cCols, cRows, cCols); + return block(0, cols() - cCols, cRows, cCols); } /// This is the const version of topRightCorner(Index, Index). @@ -217,7 +321,7 @@ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename ConstFixedBlockXpr::Type topRightCorner(Index cRows, Index cCols) const { - return typename ConstFixedBlockXpr::Type(derived(), 0, cols() - cCols, cRows, cCols); + return block(0, cols() - cCols, cRows, cCols); } @@ -248,8 +352,7 @@ typename FixedBlockXpr<...,...>::Type #endif topLeftCorner(NRowsType cRows, NColsType cCols) { - return typename FixedBlockXpr::value,internal::get_fixed_value::value>::Type - (derived(), 0, 0, internal::get_runtime_value(cRows), internal::get_runtime_value(cCols)); + return block(0, 0, cRows, cCols); } /// This is the const version of topLeftCorner(Index, Index). @@ -262,8 +365,7 @@ const typename ConstFixedBlockXpr<...,...>::Type #endif topLeftCorner(NRowsType cRows, NColsType cCols) const { - return typename ConstFixedBlockXpr::value,internal::get_fixed_value::value>::Type - (derived(), 0, 0, internal::get_runtime_value(cRows), internal::get_runtime_value(cCols)); + return block(0, 0, cRows, cCols); } /// \returns an expression of a fixed-size top-left corner of \c *this. @@ -281,7 +383,7 @@ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename FixedBlockXpr::Type topLeftCorner() { - return typename FixedBlockXpr::Type(derived(), 0, 0); + return block(0, 0); } /// This is the const version of topLeftCorner(). @@ -289,7 +391,7 @@ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename ConstFixedBlockXpr::Type topLeftCorner() const { - return typename ConstFixedBlockXpr::Type(derived(), 0, 0); + return block(0, 0); } /// \returns an expression of a top-left corner of \c *this. @@ -315,7 +417,7 @@ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename FixedBlockXpr::Type topLeftCorner(Index cRows, Index cCols) { - return typename FixedBlockXpr::Type(derived(), 0, 0, cRows, cCols); + return block(0, 0, cRows, cCols); } /// This is the const version of topLeftCorner(Index, Index). @@ -323,7 +425,7 @@ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename ConstFixedBlockXpr::Type topLeftCorner(Index cRows, Index cCols) const { - return typename ConstFixedBlockXpr::Type(derived(), 0, 0, cRows, cCols); + return block(0, 0, cRows, cCols); } @@ -354,9 +456,9 @@ typename FixedBlockXpr<...,...>::Type #endif bottomRightCorner(NRowsType cRows, NColsType cCols) { - return typename FixedBlockXpr::value,internal::get_fixed_value::value>::Type - (derived(), rows() - internal::get_runtime_value(cRows), cols() - internal::get_runtime_value(cCols), - internal::get_runtime_value(cRows), internal::get_runtime_value(cCols)); + return block(rows() - internal::get_runtime_value(cRows), + cols() - internal::get_runtime_value(cCols), + cRows, cCols); } /// This is the const version of bottomRightCorner(NRowsType, NColsType). @@ -369,9 +471,9 @@ const typename ConstFixedBlockXpr<...,...>::Type #endif bottomRightCorner(NRowsType cRows, NColsType cCols) const { - return typename ConstFixedBlockXpr::value,internal::get_fixed_value::value>::Type - (derived(), rows() - internal::get_runtime_value(cRows), cols() - internal::get_runtime_value(cCols), - internal::get_runtime_value(cRows), internal::get_runtime_value(cCols)); + return block(rows() - internal::get_runtime_value(cRows), + cols() - internal::get_runtime_value(cCols), + cRows, cCols); } /// \returns an expression of a fixed-size bottom-right corner of \c *this. @@ -389,7 +491,7 @@ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename FixedBlockXpr::Type bottomRightCorner() { - return typename FixedBlockXpr::Type(derived(), rows() - CRows, cols() - CCols); + return block(rows() - CRows, cols() - CCols); } /// This is the const version of bottomRightCorner(). @@ -397,7 +499,7 @@ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename ConstFixedBlockXpr::Type bottomRightCorner() const { - return typename ConstFixedBlockXpr::Type(derived(), rows() - CRows, cols() - CCols); + return block(rows() - CRows, cols() - CCols); } /// \returns an expression of a bottom-right corner of \c *this. @@ -423,7 +525,7 @@ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename FixedBlockXpr::Type bottomRightCorner(Index cRows, Index cCols) { - return typename FixedBlockXpr::Type(derived(), rows() - cRows, cols() - cCols, cRows, cCols); + return block(rows() - cRows, cols() - cCols, cRows, cCols); } /// This is the const version of bottomRightCorner(Index, Index). @@ -431,7 +533,7 @@ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename ConstFixedBlockXpr::Type bottomRightCorner(Index cRows, Index cCols) const { - return typename ConstFixedBlockXpr::Type(derived(), rows() - cRows, cols() - cCols, cRows, cCols); + return block(rows() - cRows, cols() - cCols, cRows, cCols); } @@ -462,9 +564,7 @@ typename FixedBlockXpr<...,...>::Type #endif bottomLeftCorner(NRowsType cRows, NColsType cCols) { - return typename FixedBlockXpr::value,internal::get_fixed_value::value>::Type - (derived(), rows() - internal::get_runtime_value(cRows), 0, - internal::get_runtime_value(cRows), internal::get_runtime_value(cCols)); + return block(rows() - internal::get_runtime_value(cRows), 0, cRows, cCols); } /// This is the const version of bottomLeftCorner(NRowsType, NColsType). @@ -477,9 +577,7 @@ typename ConstFixedBlockXpr<...,...>::Type #endif bottomLeftCorner(NRowsType cRows, NColsType cCols) const { - return typename ConstFixedBlockXpr::value,internal::get_fixed_value::value>::Type - (derived(), rows() - internal::get_runtime_value(cRows), 0, - internal::get_runtime_value(cRows), internal::get_runtime_value(cCols)); + return block(rows() - internal::get_runtime_value(cRows), 0, cRows, cCols); } /// \returns an expression of a fixed-size bottom-left corner of \c *this. @@ -497,7 +595,7 @@ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename FixedBlockXpr::Type bottomLeftCorner() { - return typename FixedBlockXpr::Type(derived(), rows() - CRows, 0); + return block(rows() - CRows, 0); } /// This is the const version of bottomLeftCorner(). @@ -505,7 +603,7 @@ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename ConstFixedBlockXpr::Type bottomLeftCorner() const { - return typename ConstFixedBlockXpr::Type(derived(), rows() - CRows, 0); + return block(rows() - CRows, 0); } /// \returns an expression of a bottom-left corner of \c *this. @@ -531,7 +629,7 @@ template EIGEN_STRONG_INLINE typename FixedBlockXpr::Type bottomLeftCorner(Index cRows, Index cCols) { - return typename FixedBlockXpr::Type(derived(), rows() - cRows, 0, cRows, cCols); + return block(rows() - cRows, 0, cRows, cCols); } /// This is the const version of bottomLeftCorner(Index, Index). @@ -539,18 +637,17 @@ template EIGEN_STRONG_INLINE const typename ConstFixedBlockXpr::Type bottomLeftCorner(Index cRows, Index cCols) const { - return typename ConstFixedBlockXpr::Type(derived(), rows() - cRows, 0, cRows, cCols); + return block(rows() - cRows, 0, cRows, cCols); } - - -/// \returns a block consisting of the top rows of \c *this. +/// \returns a block consisting of a range of rows of \c *this. /// +/// \param startRow the index of the first row in the block /// \param n the number of rows in the block /// \tparam NRowsType the type of the value handling the number of rows in the block, typically Index. /// -/// Example: \include MatrixBase_topRows_int.cpp -/// Output: \verbinclude MatrixBase_topRows_int.out +/// Example: \include DenseBase_middleRows_int.cpp +/// Output: \verbinclude DenseBase_middleRows_int.out /// /// The number of rows \a n can also be specified at compile-time by passing Eigen::fix, /// or Eigen::fix(n) as arguments. @@ -567,13 +664,15 @@ typename NRowsBlockXpr::value>::Type #else typename NRowsBlockXpr<...>::Type #endif -topRows(NRowsType n) +middleRows(Index startRow, NRowsType n) { return typename NRowsBlockXpr::value>::Type - (derived(), 0, 0, internal::get_runtime_value(n), cols()); + (BlockXprHelper::base(derived()), + BlockXprHelper::row(derived(), startRow), BlockXprHelper::col(derived(), 0), + internal::get_runtime_value(n), cols()); } -/// This is the const version of topRows(NRowsType). +/// This is the const version of middleRows(Index,NRowsType). template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE #ifndef EIGEN_PARSED_BY_DOXYGEN @@ -581,22 +680,25 @@ const typename ConstNRowsBlockXpr::value>:: #else const typename ConstNRowsBlockXpr<...>::Type #endif -topRows(NRowsType n) const +middleRows(Index startRow, NRowsType n) const { return typename ConstNRowsBlockXpr::value>::Type - (derived(), 0, 0, internal::get_runtime_value(n), cols()); + (BlockXprHelper::base(derived()), + BlockXprHelper::row(derived(), startRow), BlockXprHelper::col(derived(), 0), + internal::get_runtime_value(n), cols()); } -/// \returns a block consisting of the top rows of \c *this. +/// \returns a block consisting of a range of rows of \c *this. /// /// \tparam N the number of rows in the block as specified at compile-time +/// \param startRow the index of the first row in the block /// \param n the number of rows in the block as specified at run-time /// /// The compile-time and run-time information should not contradict. In other words, /// \a n should equal \a N unless \a N is \a Dynamic. /// -/// Example: \include MatrixBase_template_int_topRows.cpp -/// Output: \verbinclude MatrixBase_template_int_topRows.out +/// Example: \include DenseBase_template_int_middleRows.cpp +/// Output: \verbinclude DenseBase_template_int_middleRows.out /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) /// @@ -604,28 +706,33 @@ EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) /// template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE -typename NRowsBlockXpr::Type topRows(Index n = N) +typename NRowsBlockXpr::Type middleRows(Index startRow, Index n = N) { - return typename NRowsBlockXpr::Type(derived(), 0, 0, n, cols()); + return typename NRowsBlockXpr::Type + (BlockXprHelper::base(derived()), + BlockXprHelper::row(derived(), startRow), BlockXprHelper::col(derived(), 0), + n, cols()); } -/// This is the const version of topRows(). +/// This is the const version of middleRows(). template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE -typename ConstNRowsBlockXpr::Type topRows(Index n = N) const +typename ConstNRowsBlockXpr::Type middleRows(Index startRow, Index n = N) const { - return typename ConstNRowsBlockXpr::Type(derived(), 0, 0, n, cols()); + return typename ConstNRowsBlockXpr::Type + (BlockXprHelper::base(derived()), + BlockXprHelper::row(derived(), startRow), BlockXprHelper::col(derived(), 0), + n, cols()); } - -/// \returns a block consisting of the bottom rows of \c *this. +/// \returns a block consisting of the top rows of \c *this. /// /// \param n the number of rows in the block /// \tparam NRowsType the type of the value handling the number of rows in the block, typically Index. /// -/// Example: \include MatrixBase_bottomRows_int.cpp -/// Output: \verbinclude MatrixBase_bottomRows_int.out +/// Example: \include MatrixBase_topRows_int.cpp +/// Output: \verbinclude MatrixBase_topRows_int.out /// /// The number of rows \a n can also be specified at compile-time by passing Eigen::fix, /// or Eigen::fix(n) as arguments. @@ -642,13 +749,12 @@ typename NRowsBlockXpr::value>::Type #else typename NRowsBlockXpr<...>::Type #endif -bottomRows(NRowsType n) +topRows(NRowsType n) { - return typename NRowsBlockXpr::value>::Type - (derived(), rows() - internal::get_runtime_value(n), 0, internal::get_runtime_value(n), cols()); + return middleRows(0, n); } -/// This is the const version of bottomRows(NRowsType). +/// This is the const version of topRows(NRowsType). template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE #ifndef EIGEN_PARSED_BY_DOXYGEN @@ -656,13 +762,12 @@ const typename ConstNRowsBlockXpr::value>:: #else const typename ConstNRowsBlockXpr<...>::Type #endif -bottomRows(NRowsType n) const +topRows(NRowsType n) const { - return typename ConstNRowsBlockXpr::value>::Type - (derived(), rows() - internal::get_runtime_value(n), 0, internal::get_runtime_value(n), cols()); + return middleRows(0, n); } -/// \returns a block consisting of the bottom rows of \c *this. +/// \returns a block consisting of the top rows of \c *this. /// /// \tparam N the number of rows in the block as specified at compile-time /// \param n the number of rows in the block as specified at run-time @@ -670,8 +775,8 @@ bottomRows(NRowsType n) const /// The compile-time and run-time information should not contradict. In other words, /// \a n should equal \a N unless \a N is \a Dynamic. /// -/// Example: \include MatrixBase_template_int_bottomRows.cpp -/// Output: \verbinclude MatrixBase_template_int_bottomRows.out +/// Example: \include MatrixBase_template_int_topRows.cpp +/// Output: \verbinclude MatrixBase_template_int_topRows.out /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) /// @@ -679,29 +784,28 @@ EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) /// template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE -typename NRowsBlockXpr::Type bottomRows(Index n = N) +typename NRowsBlockXpr::Type topRows(Index n = N) { - return typename NRowsBlockXpr::Type(derived(), rows() - n, 0, n, cols()); + return middleRows(0, n); } -/// This is the const version of bottomRows(). +/// This is the const version of topRows(). template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE -typename ConstNRowsBlockXpr::Type bottomRows(Index n = N) const +typename ConstNRowsBlockXpr::Type topRows(Index n = N) const { - return typename ConstNRowsBlockXpr::Type(derived(), rows() - n, 0, n, cols()); + return middleRows(0, n); } -/// \returns a block consisting of a range of rows of \c *this. +/// \returns a block consisting of the bottom rows of \c *this. /// -/// \param startRow the index of the first row in the block /// \param n the number of rows in the block /// \tparam NRowsType the type of the value handling the number of rows in the block, typically Index. /// -/// Example: \include DenseBase_middleRows_int.cpp -/// Output: \verbinclude DenseBase_middleRows_int.out +/// Example: \include MatrixBase_bottomRows_int.cpp +/// Output: \verbinclude MatrixBase_bottomRows_int.out /// /// The number of rows \a n can also be specified at compile-time by passing Eigen::fix, /// or Eigen::fix(n) as arguments. @@ -718,13 +822,12 @@ typename NRowsBlockXpr::value>::Type #else typename NRowsBlockXpr<...>::Type #endif -middleRows(Index startRow, NRowsType n) +bottomRows(NRowsType n) { - return typename NRowsBlockXpr::value>::Type - (derived(), startRow, 0, internal::get_runtime_value(n), cols()); + return middleRows(rows() - internal::get_runtime_value(n), n); } -/// This is the const version of middleRows(Index,NRowsType). +/// This is the const version of bottomRows(NRowsType). template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE #ifndef EIGEN_PARSED_BY_DOXYGEN @@ -732,23 +835,21 @@ const typename ConstNRowsBlockXpr::value>:: #else const typename ConstNRowsBlockXpr<...>::Type #endif -middleRows(Index startRow, NRowsType n) const +bottomRows(NRowsType n) const { - return typename ConstNRowsBlockXpr::value>::Type - (derived(), startRow, 0, internal::get_runtime_value(n), cols()); + return middleRows(rows() - internal::get_runtime_value(n), n); } -/// \returns a block consisting of a range of rows of \c *this. +/// \returns a block consisting of the bottom rows of \c *this. /// /// \tparam N the number of rows in the block as specified at compile-time -/// \param startRow the index of the first row in the block /// \param n the number of rows in the block as specified at run-time /// /// The compile-time and run-time information should not contradict. In other words, /// \a n should equal \a N unless \a N is \a Dynamic. /// -/// Example: \include DenseBase_template_int_middleRows.cpp -/// Output: \verbinclude DenseBase_template_int_middleRows.out +/// Example: \include MatrixBase_template_int_bottomRows.cpp +/// Output: \verbinclude MatrixBase_template_int_bottomRows.out /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) /// @@ -756,28 +857,27 @@ EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) /// template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE -typename NRowsBlockXpr::Type middleRows(Index startRow, Index n = N) +typename NRowsBlockXpr::Type bottomRows(Index n = N) { - return typename NRowsBlockXpr::Type(derived(), startRow, 0, n, cols()); + return middleRows(rows() - n, n); } -/// This is the const version of middleRows(). +/// This is the const version of bottomRows(). template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE -typename ConstNRowsBlockXpr::Type middleRows(Index startRow, Index n = N) const +typename ConstNRowsBlockXpr::Type bottomRows(Index n = N) const { - return typename ConstNRowsBlockXpr::Type(derived(), startRow, 0, n, cols()); + return middleRows(rows() - n, n); } - - -/// \returns a block consisting of the left columns of \c *this. +/// \returns a block consisting of a range of columns of \c *this. /// -/// \param n the number of columns in the block +/// \param startCol the index of the first column in the block +/// \param numCols the number of columns in the block /// \tparam NColsType the type of the value handling the number of columns in the block, typically Index. /// -/// Example: \include MatrixBase_leftCols_int.cpp -/// Output: \verbinclude MatrixBase_leftCols_int.out +/// Example: \include DenseBase_middleCols_int.cpp +/// Output: \verbinclude DenseBase_middleCols_int.out /// /// The number of columns \a n can also be specified at compile-time by passing Eigen::fix, /// or Eigen::fix(n) as arguments. @@ -794,13 +894,15 @@ typename NColsBlockXpr::value>::Type #else typename NColsBlockXpr<...>::Type #endif -leftCols(NColsType n) +middleCols(Index startCol, NColsType numCols) { return typename NColsBlockXpr::value>::Type - (derived(), 0, 0, rows(), internal::get_runtime_value(n)); + (BlockXprHelper::base(derived()), + BlockXprHelper::row(derived(), 0), BlockXprHelper::col(derived(), startCol), + rows(), internal::get_runtime_value(numCols)); } -/// This is the const version of leftCols(NColsType). +/// This is the const version of middleCols(Index,NColsType). template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE #ifndef EIGEN_PARSED_BY_DOXYGEN @@ -808,22 +910,25 @@ const typename ConstNColsBlockXpr::value>:: #else const typename ConstNColsBlockXpr<...>::Type #endif -leftCols(NColsType n) const +middleCols(Index startCol, NColsType numCols) const { return typename ConstNColsBlockXpr::value>::Type - (derived(), 0, 0, rows(), internal::get_runtime_value(n)); + (BlockXprHelper::base(derived()), + BlockXprHelper::row(derived(), 0), BlockXprHelper::col(derived(), startCol), + rows(), internal::get_runtime_value(numCols)); } -/// \returns a block consisting of the left columns of \c *this. +/// \returns a block consisting of a range of columns of \c *this. /// /// \tparam N the number of columns in the block as specified at compile-time +/// \param startCol the index of the first column in the block /// \param n the number of columns in the block as specified at run-time /// /// The compile-time and run-time information should not contradict. In other words, /// \a n should equal \a N unless \a N is \a Dynamic. /// -/// Example: \include MatrixBase_template_int_leftCols.cpp -/// Output: \verbinclude MatrixBase_template_int_leftCols.out +/// Example: \include DenseBase_template_int_middleCols.cpp +/// Output: \verbinclude DenseBase_template_int_middleCols.out /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) /// @@ -831,28 +936,32 @@ EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) /// template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE -typename NColsBlockXpr::Type leftCols(Index n = N) +typename NColsBlockXpr::Type middleCols(Index startCol, Index n = N) { - return typename NColsBlockXpr::Type(derived(), 0, 0, rows(), n); + return typename NColsBlockXpr::Type + (BlockXprHelper::base(derived()), + BlockXprHelper::row(derived(), 0), BlockXprHelper::col(derived(), startCol), + rows(), n); } -/// This is the const version of leftCols(). +/// This is the const version of middleCols(). template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE -typename ConstNColsBlockXpr::Type leftCols(Index n = N) const +typename ConstNColsBlockXpr::Type middleCols(Index startCol, Index n = N) const { - return typename ConstNColsBlockXpr::Type(derived(), 0, 0, rows(), n); + return typename ConstNColsBlockXpr::Type + (BlockXprHelper::base(derived()), + BlockXprHelper::row(derived(), 0), BlockXprHelper::col(derived(), startCol), + rows(), n); } - - -/// \returns a block consisting of the right columns of \c *this. +/// \returns a block consisting of the left columns of \c *this. /// /// \param n the number of columns in the block /// \tparam NColsType the type of the value handling the number of columns in the block, typically Index. /// -/// Example: \include MatrixBase_rightCols_int.cpp -/// Output: \verbinclude MatrixBase_rightCols_int.out +/// Example: \include MatrixBase_leftCols_int.cpp +/// Output: \verbinclude MatrixBase_leftCols_int.out /// /// The number of columns \a n can also be specified at compile-time by passing Eigen::fix, /// or Eigen::fix(n) as arguments. @@ -869,13 +978,12 @@ typename NColsBlockXpr::value>::Type #else typename NColsBlockXpr<...>::Type #endif -rightCols(NColsType n) +leftCols(NColsType n) { - return typename NColsBlockXpr::value>::Type - (derived(), 0, cols() - internal::get_runtime_value(n), rows(), internal::get_runtime_value(n)); + return middleCols(0, n); } -/// This is the const version of rightCols(NColsType). +/// This is the const version of leftCols(NColsType). template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE #ifndef EIGEN_PARSED_BY_DOXYGEN @@ -883,13 +991,12 @@ const typename ConstNColsBlockXpr::value>:: #else const typename ConstNColsBlockXpr<...>::Type #endif -rightCols(NColsType n) const +leftCols(NColsType n) const { - return typename ConstNColsBlockXpr::value>::Type - (derived(), 0, cols() - internal::get_runtime_value(n), rows(), internal::get_runtime_value(n)); + return middleCols(0, n); } -/// \returns a block consisting of the right columns of \c *this. +/// \returns a block consisting of the left columns of \c *this. /// /// \tparam N the number of columns in the block as specified at compile-time /// \param n the number of columns in the block as specified at run-time @@ -897,8 +1004,8 @@ rightCols(NColsType n) const /// The compile-time and run-time information should not contradict. In other words, /// \a n should equal \a N unless \a N is \a Dynamic. /// -/// Example: \include MatrixBase_template_int_rightCols.cpp -/// Output: \verbinclude MatrixBase_template_int_rightCols.out +/// Example: \include MatrixBase_template_int_leftCols.cpp +/// Output: \verbinclude MatrixBase_template_int_leftCols.out /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) /// @@ -906,29 +1013,28 @@ EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) /// template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE -typename NColsBlockXpr::Type rightCols(Index n = N) +typename NColsBlockXpr::Type leftCols(Index n = N) { - return typename NColsBlockXpr::Type(derived(), 0, cols() - n, rows(), n); + return middleCols(0, n); } -/// This is the const version of rightCols(). +/// This is the const version of leftCols(). template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE -typename ConstNColsBlockXpr::Type rightCols(Index n = N) const +typename ConstNColsBlockXpr::Type leftCols(Index n = N) const { - return typename ConstNColsBlockXpr::Type(derived(), 0, cols() - n, rows(), n); + return middleCols(0, n); } -/// \returns a block consisting of a range of columns of \c *this. +/// \returns a block consisting of the right columns of \c *this. /// -/// \param startCol the index of the first column in the block -/// \param numCols the number of columns in the block +/// \param n the number of columns in the block /// \tparam NColsType the type of the value handling the number of columns in the block, typically Index. /// -/// Example: \include DenseBase_middleCols_int.cpp -/// Output: \verbinclude DenseBase_middleCols_int.out +/// Example: \include MatrixBase_rightCols_int.cpp +/// Output: \verbinclude MatrixBase_rightCols_int.out /// /// The number of columns \a n can also be specified at compile-time by passing Eigen::fix, /// or Eigen::fix(n) as arguments. @@ -945,13 +1051,12 @@ typename NColsBlockXpr::value>::Type #else typename NColsBlockXpr<...>::Type #endif -middleCols(Index startCol, NColsType numCols) +rightCols(NColsType n) { - return typename NColsBlockXpr::value>::Type - (derived(), 0, startCol, rows(), internal::get_runtime_value(numCols)); + return middleCols(cols() - internal::get_runtime_value(n), n); } -/// This is the const version of middleCols(Index,NColsType). +/// This is the const version of rightCols(NColsType). template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE #ifndef EIGEN_PARSED_BY_DOXYGEN @@ -959,23 +1064,21 @@ const typename ConstNColsBlockXpr::value>:: #else const typename ConstNColsBlockXpr<...>::Type #endif -middleCols(Index startCol, NColsType numCols) const +rightCols(NColsType n) const { - return typename ConstNColsBlockXpr::value>::Type - (derived(), 0, startCol, rows(), internal::get_runtime_value(numCols)); + return middleCols(cols() - internal::get_runtime_value(n), n); } -/// \returns a block consisting of a range of columns of \c *this. +/// \returns a block consisting of the right columns of \c *this. /// /// \tparam N the number of columns in the block as specified at compile-time -/// \param startCol the index of the first column in the block /// \param n the number of columns in the block as specified at run-time /// /// The compile-time and run-time information should not contradict. In other words, /// \a n should equal \a N unless \a N is \a Dynamic. /// -/// Example: \include DenseBase_template_int_middleCols.cpp -/// Output: \verbinclude DenseBase_template_int_middleCols.out +/// Example: \include MatrixBase_template_int_rightCols.cpp +/// Output: \verbinclude MatrixBase_template_int_rightCols.out /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) /// @@ -983,106 +1086,17 @@ EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) /// template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE -typename NColsBlockXpr::Type middleCols(Index startCol, Index n = N) +typename NColsBlockXpr::Type rightCols(Index n = N) { - return typename NColsBlockXpr::Type(derived(), 0, startCol, rows(), n); + return middleCols(cols() - n, n); } -/// This is the const version of middleCols(). +/// This is the const version of rightCols(). template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE -typename ConstNColsBlockXpr::Type middleCols(Index startCol, Index n = N) const -{ - return typename ConstNColsBlockXpr::Type(derived(), 0, startCol, rows(), n); -} - - - -/// \returns a fixed-size expression of a block of \c *this. -/// -/// The template parameters \a NRows and \a NCols are the number of -/// rows and columns in the block. -/// -/// \param startRow the first row in the block -/// \param startCol the first column in the block -/// -/// Example: \include MatrixBase_block_int_int.cpp -/// Output: \verbinclude MatrixBase_block_int_int.out -/// -/// \note The usage of of this overload is discouraged from %Eigen 3.4, better used the generic -/// block(Index,Index,NRowsType,NColsType), here is the one-to-one equivalence: -/// \code -/// mat.template block(i,j) <--> mat.block(i,j,fix,fix) -/// \endcode -/// -/// \note since block is a templated member, the keyword template has to be used -/// if the matrix type is also a template parameter: \code m.template block<3,3>(1,1); \endcode -/// -EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL -/// -/// \sa block(Index,Index,NRowsType,NColsType), class Block -/// -template -EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE -typename FixedBlockXpr::Type block(Index startRow, Index startCol) -{ - return typename FixedBlockXpr::Type(derived(), startRow, startCol); -} - -/// This is the const version of block<>(Index, Index). */ -template -EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE -const typename ConstFixedBlockXpr::Type block(Index startRow, Index startCol) const -{ - return typename ConstFixedBlockXpr::Type(derived(), startRow, startCol); -} - -/// \returns an expression of a block of \c *this. -/// -/// \tparam NRows number of rows in block as specified at compile-time -/// \tparam NCols number of columns in block as specified at compile-time -/// \param startRow the first row in the block -/// \param startCol the first column in the block -/// \param blockRows number of rows in block as specified at run-time -/// \param blockCols number of columns in block as specified at run-time -/// -/// This function is mainly useful for blocks where the number of rows is specified at compile-time -/// and the number of columns is specified at run-time, or vice versa. The compile-time and run-time -/// information should not contradict. In other words, \a blockRows should equal \a NRows unless -/// \a NRows is \a Dynamic, and the same for the number of columns. -/// -/// Example: \include MatrixBase_template_int_int_block_int_int_int_int.cpp -/// Output: \verbinclude MatrixBase_template_int_int_block_int_int_int_int.out -/// -/// \note The usage of of this overload is discouraged from %Eigen 3.4, better used the generic -/// block(Index,Index,NRowsType,NColsType), here is the one-to-one complete equivalence: -/// \code -/// mat.template block(i,j,rows,cols) <--> mat.block(i,j,fix(rows),fix(cols)) -/// \endcode -/// If we known that, e.g., NRows==Dynamic and NCols!=Dynamic, then the equivalence becomes: -/// \code -/// mat.template block(i,j,rows,NCols) <--> mat.block(i,j,rows,fix) -/// \endcode -/// -EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL -/// -/// \sa block(Index,Index,NRowsType,NColsType), class Block -/// -template -EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE -typename FixedBlockXpr::Type block(Index startRow, Index startCol, - Index blockRows, Index blockCols) -{ - return typename FixedBlockXpr::Type(derived(), startRow, startCol, blockRows, blockCols); -} - -/// This is the const version of block<>(Index, Index, Index, Index). -template -EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE -const typename ConstFixedBlockXpr::Type block(Index startRow, Index startCol, - Index blockRows, Index blockCols) const +typename ConstNColsBlockXpr::Type rightCols(Index n = N) const { - return typename ConstFixedBlockXpr::Type(derived(), startRow, startCol, blockRows, blockCols); + return middleCols(cols() - n, n); } /// \returns an expression of the \a i-th column of \c *this. Note that the numbering starts at 0. @@ -1096,14 +1110,18 @@ EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ColXpr col(Index i) { - return ColXpr(derived(), i); + return ColXpr(BlockXprHelper::base(derived()), + BlockXprHelper::row(derived(), 0), BlockXprHelper::col(derived(), i), + rows(), 1); } /// This is the const version of col(). EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ConstColXpr col(Index i) const { - return ConstColXpr(derived(), i); + return ConstColXpr(BlockXprHelper::base(derived()), + BlockXprHelper::row(derived(), 0), BlockXprHelper::col(derived(), i), + rows(), 1); } /// \returns an expression of the \a i-th row of \c *this. Note that the numbering starts at 0. @@ -1117,14 +1135,18 @@ EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE RowXpr row(Index i) { - return RowXpr(derived(), i); + return RowXpr(BlockXprHelper::base(derived()), + BlockXprHelper::row(derived(), i), BlockXprHelper::col(derived(), 0), + 1, cols()); } /// This is the const version of row(). */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ConstRowXpr row(Index i) const { - return ConstRowXpr(derived(), i); + return ConstRowXpr(BlockXprHelper::base(derived()), + BlockXprHelper::row(derived(), i), BlockXprHelper::col(derived(), 0), + 1, cols()); } /// \returns an expression of a segment (i.e. a vector block) in \c *this with either dynamic or fixed sizes. @@ -1159,10 +1181,13 @@ segment(Index start, NType n) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) return typename FixedSegmentReturnType::value>::Type - (derived(), start, internal::get_runtime_value(n)); + (BlockXprHelper::base(derived()), + BlockXprHelper::row(derived(), IsRowMajor ? 0 : start), + BlockXprHelper::col(derived(), IsRowMajor ? start : 0), + IsRowMajor ? 1 : internal::get_runtime_value(n), + IsRowMajor ? internal::get_runtime_value(n) : 1); } - /// This is the const version of segment(Index,NType). template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE @@ -1175,67 +1200,65 @@ segment(Index start, NType n) const { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) return typename ConstFixedSegmentReturnType::value>::Type - (derived(), start, internal::get_runtime_value(n)); + (BlockXprHelper::base(derived()), + BlockXprHelper::row(derived(), IsRowMajor ? 0 : start), + BlockXprHelper::col(derived(), IsRowMajor ? start : 0), + IsRowMajor ? 1 : internal::get_runtime_value(n), + IsRowMajor ? internal::get_runtime_value(n) : 1); } -/// \returns an expression of the first coefficients of \c *this with either dynamic or fixed sizes. +/// \returns a fixed-size expression of a segment (i.e. a vector block) in \c *this /// /// \only_for_vectors /// -/// \param n the number of coefficients in the segment -/// \tparam NType the type of the value handling the number of coefficients in the segment, typically Index. -/// -/// Example: \include MatrixBase_start_int.cpp -/// Output: \verbinclude MatrixBase_start_int.out +/// \tparam N the number of coefficients in the segment as specified at compile-time +/// \param start the index of the first element in the segment +/// \param n the number of coefficients in the segment as specified at compile-time /// -/// The number of coefficients \a n can also be specified at compile-time by passing Eigen::fix, -/// or Eigen::fix(n) as arguments. -/// See \link block(Index,Index,NRowsType,NColsType) block() \endlink for the details. +/// The compile-time and run-time information should not contradict. In other words, +/// \a n should equal \a N unless \a N is \a Dynamic. /// -/// \note Even in the case that the returned expression has dynamic size, in the case -/// when it is applied to a fixed-size vector, it inherits a fixed maximal size, -/// which means that evaluating it does not cause a dynamic memory allocation. +/// Example: \include MatrixBase_template_int_segment.cpp +/// Output: \verbinclude MatrixBase_template_int_segment.out /// -/// \sa class Block, block(Index,Index) +/// \sa segment(Index,NType), class Block /// -template +template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE -#ifndef EIGEN_PARSED_BY_DOXYGEN -typename FixedSegmentReturnType::value>::Type -#else -typename FixedSegmentReturnType<...>::Type -#endif -head(NType n) +typename FixedSegmentReturnType::Type segment(Index start, Index n = N) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return typename FixedSegmentReturnType::value>::Type - (derived(), 0, internal::get_runtime_value(n)); + return typename FixedSegmentReturnType::Type + (BlockXprHelper::base(derived()), + BlockXprHelper::row(derived(), IsRowMajor ? 0 : start), + BlockXprHelper::col(derived(), IsRowMajor ? start : 0), + IsRowMajor ? 1 : n, + IsRowMajor ? n : 1); } -/// This is the const version of head(NType). -template +/// This is the const version of segment(Index). +template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE -#ifndef EIGEN_PARSED_BY_DOXYGEN -const typename ConstFixedSegmentReturnType::value>::Type -#else -const typename ConstFixedSegmentReturnType<...>::Type -#endif -head(NType n) const +typename ConstFixedSegmentReturnType::Type segment(Index start, Index n = N) const { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return typename ConstFixedSegmentReturnType::value>::Type - (derived(), 0, internal::get_runtime_value(n)); + return typename ConstFixedSegmentReturnType::Type + (BlockXprHelper::base(derived()), + BlockXprHelper::row(derived(), IsRowMajor ? 0 : start), + BlockXprHelper::col(derived(), IsRowMajor ? start : 0), + IsRowMajor ? 1 : n, + IsRowMajor ? n : 1); } -/// \returns an expression of a last coefficients of \c *this with either dynamic or fixed sizes. +/// \returns an expression of the first coefficients of \c *this with either dynamic or fixed sizes. /// /// \only_for_vectors /// /// \param n the number of coefficients in the segment /// \tparam NType the type of the value handling the number of coefficients in the segment, typically Index. /// -/// Example: \include MatrixBase_end_int.cpp -/// Output: \verbinclude MatrixBase_end_int.out +/// Example: \include MatrixBase_start_int.cpp +/// Output: \verbinclude MatrixBase_start_int.out /// /// The number of coefficients \a n can also be specified at compile-time by passing Eigen::fix, /// or Eigen::fix(n) as arguments. @@ -1254,14 +1277,12 @@ typename FixedSegmentReturnType::value>::Type #else typename FixedSegmentReturnType<...>::Type #endif -tail(NType n) +head(NType n) { - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return typename FixedSegmentReturnType::value>::Type - (derived(), this->size() - internal::get_runtime_value(n), internal::get_runtime_value(n)); + return segment(0, n); } -/// This is the const version of tail(Index). +/// This is the const version of head(NType). template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE #ifndef EIGEN_PARSED_BY_DOXYGEN @@ -1269,76 +1290,84 @@ const typename ConstFixedSegmentReturnType::val #else const typename ConstFixedSegmentReturnType<...>::Type #endif -tail(NType n) const +head(NType n) const { - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return typename ConstFixedSegmentReturnType::value>::Type - (derived(), this->size() - internal::get_runtime_value(n), internal::get_runtime_value(n)); + return segment(0, n); } -/// \returns a fixed-size expression of a segment (i.e. a vector block) in \c *this +/// \returns a fixed-size expression of the first coefficients of \c *this. /// /// \only_for_vectors /// /// \tparam N the number of coefficients in the segment as specified at compile-time -/// \param start the index of the first element in the segment -/// \param n the number of coefficients in the segment as specified at compile-time +/// \param n the number of coefficients in the segment as specified at run-time /// /// The compile-time and run-time information should not contradict. In other words, /// \a n should equal \a N unless \a N is \a Dynamic. /// -/// Example: \include MatrixBase_template_int_segment.cpp -/// Output: \verbinclude MatrixBase_template_int_segment.out +/// Example: \include MatrixBase_template_int_start.cpp +/// Output: \verbinclude MatrixBase_template_int_start.out /// -/// \sa segment(Index,NType), class Block +/// \sa head(NType), class Block /// template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE -typename FixedSegmentReturnType::Type segment(Index start, Index n = N) +typename FixedSegmentReturnType::Type head(Index n = N) { - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return typename FixedSegmentReturnType::Type(derived(), start, n); + return segment(0, n); } -/// This is the const version of segment(Index). +/// This is the const version of head(). template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE -typename ConstFixedSegmentReturnType::Type segment(Index start, Index n = N) const +typename ConstFixedSegmentReturnType::Type head(Index n = N) const { - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return typename ConstFixedSegmentReturnType::Type(derived(), start, n); + return segment(0, n); } -/// \returns a fixed-size expression of the first coefficients of \c *this. +/// \returns an expression of a last coefficients of \c *this with either dynamic or fixed sizes. /// /// \only_for_vectors /// -/// \tparam N the number of coefficients in the segment as specified at compile-time -/// \param n the number of coefficients in the segment as specified at run-time +/// \param n the number of coefficients in the segment +/// \tparam NType the type of the value handling the number of coefficients in the segment, typically Index. /// -/// The compile-time and run-time information should not contradict. In other words, -/// \a n should equal \a N unless \a N is \a Dynamic. +/// Example: \include MatrixBase_end_int.cpp +/// Output: \verbinclude MatrixBase_end_int.out /// -/// Example: \include MatrixBase_template_int_start.cpp -/// Output: \verbinclude MatrixBase_template_int_start.out +/// The number of coefficients \a n can also be specified at compile-time by passing Eigen::fix, +/// or Eigen::fix(n) as arguments. +/// See \link block(Index,Index,NRowsType,NColsType) block() \endlink for the details. /// -/// \sa head(NType), class Block +/// \note Even in the case that the returned expression has dynamic size, in the case +/// when it is applied to a fixed-size vector, it inherits a fixed maximal size, +/// which means that evaluating it does not cause a dynamic memory allocation. /// -template +/// \sa class Block, block(Index,Index) +/// +template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE -typename FixedSegmentReturnType::Type head(Index n = N) +#ifndef EIGEN_PARSED_BY_DOXYGEN +typename FixedSegmentReturnType::value>::Type +#else +typename FixedSegmentReturnType<...>::Type +#endif +tail(NType n) { - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return typename FixedSegmentReturnType::Type(derived(), 0, n); + return segment(this->size() - internal::get_runtime_value(n), n); } -/// This is the const version of head(). -template +/// This is the const version of tail(Index). +template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE -typename ConstFixedSegmentReturnType::Type head(Index n = N) const +#ifndef EIGEN_PARSED_BY_DOXYGEN +const typename ConstFixedSegmentReturnType::value>::Type +#else +const typename ConstFixedSegmentReturnType<...>::Type +#endif +tail(NType n) const { - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return typename ConstFixedSegmentReturnType::Type(derived(), 0, n); + return segment(this->size() - internal::get_runtime_value(n), n); } /// \returns a fixed-size expression of the last coefficients of \c *this. @@ -1360,8 +1389,7 @@ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename FixedSegmentReturnType::Type tail(Index n = N) { - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return typename FixedSegmentReturnType::Type(derived(), size() - n); + return segment(size() - n, n); } /// This is the const version of tail. @@ -1369,34 +1397,42 @@ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename ConstFixedSegmentReturnType::Type tail(Index n = N) const { - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return typename ConstFixedSegmentReturnType::Type(derived(), size() - n); + return segment(size() - n, n); } /// \returns the \a outer -th column (resp. row) of the matrix \c *this if \c *this /// is col-major (resp. row-major). /// EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE -InnerVectorReturnType innerVector(Index outer) -{ return InnerVectorReturnType(derived(), outer); } +InnerVectorReturnType innerVector(Index outer) { + return InnerVectorReturnType( + BlockXprHelper::base(derived()), + IsRowMajor ? outer : 0, IsRowMajor ? 0 : outer, + IsRowMajor ? 1 : rows(), IsRowMajor ? cols() : 1); +} /// \returns the \a outer -th column (resp. row) of the matrix \c *this if \c *this /// is col-major (resp. row-major). Read-only. /// EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE -const ConstInnerVectorReturnType innerVector(Index outer) const -{ return ConstInnerVectorReturnType(derived(), outer); } +const ConstInnerVectorReturnType innerVector(Index outer) const { + return ConstInnerVectorReturnType( + BlockXprHelper::base(derived()), + IsRowMajor ? outer : 0, IsRowMajor ? 0 : outer, + IsRowMajor ? 1 : rows(), IsRowMajor ? cols() : 1); +} /// \returns the \a outer -th column (resp. row) of the matrix \c *this if \c *this /// is col-major (resp. row-major). /// EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE InnerVectorsReturnType -innerVectors(Index outerStart, Index outerSize) -{ - return Block(derived(), - IsRowMajor ? outerStart : 0, IsRowMajor ? 0 : outerStart, - IsRowMajor ? outerSize : rows(), IsRowMajor ? cols() : outerSize); +innerVectors(Index outerStart, Index outerSize) { + return InnerVectorsReturnType( + BlockXprHelper::base(derived()), + IsRowMajor ? BlockXprHelper::row(derived(), outerStart) : BlockXprHelper::col(derived(), 0), + IsRowMajor ? BlockXprHelper::row(derived(), 0) : BlockXprHelper::col(derived(), outerStart), + IsRowMajor ? outerSize : rows(), IsRowMajor ? cols() : outerSize); } @@ -1405,12 +1441,12 @@ innerVectors(Index outerStart, Index outerSize) /// EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const ConstInnerVectorsReturnType -innerVectors(Index outerStart, Index outerSize) const -{ - return Block(derived(), - IsRowMajor ? outerStart : 0, IsRowMajor ? 0 : outerStart, - IsRowMajor ? outerSize : rows(), IsRowMajor ? cols() : outerSize); - +innerVectors(Index outerStart, Index outerSize) const { + return ConstInnerVectorsReturnType( + BlockXprHelper::base(derived()), + IsRowMajor ? BlockXprHelper::row(derived(), outerStart) : BlockXprHelper::col(derived(), 0), + IsRowMajor ? BlockXprHelper::row(derived(), 0) : BlockXprHelper::col(derived(), outerStart), + IsRowMajor ? outerSize : rows(), IsRowMajor ? cols() : outerSize); } /** \returns the i-th subvector (column or vector) according to the \c Direction @@ -1421,7 +1457,12 @@ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::conditional_t subVector(Index i) { - return std::conditional_t(derived(),i); + return std::conditional_t( + BlockXprHelper::base(derived()), + Direction==Vertical ? 0 : BlockXprHelper::col(derived(), i), + Direction==Vertical ? BlockXprHelper::row(derived(), i) : 0, + Direction==Vertical ? rows() : 1, + Direction==Vertical ? 1 : cols()); } /** This is the const version of subVector(Index) */ @@ -1430,7 +1471,12 @@ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::conditional_t subVector(Index i) const { - return std::conditional_t(derived(),i); + return std::conditional_t( + BlockXprHelper::base(derived()), + Direction==Vertical ? 0 : BlockXprHelper::col(derived(), i), + Direction==Vertical ? BlockXprHelper::row(derived(), i) : 0, + Direction==Vertical ? rows() : 1, + Direction==Vertical ? 1 : cols()); } /** \returns the number of subvectors (rows or columns) in the direction \c Direction @@ -1439,4 +1485,4 @@ subVector(Index i) const template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EIGEN_CONSTEXPR Index subVectors() const -{ return (Direction==Vertical)?cols():rows(); } +{ return (Direction==Vertical) ? cols() : rows(); } diff --git a/Eigen/src/plugins/IndexedViewMethods.h b/Eigen/src/plugins/IndexedViewMethods.h index 78f12fe05..404480b58 100644 --- a/Eigen/src/plugins/IndexedViewMethods.h +++ b/Eigen/src/plugins/IndexedViewMethods.h @@ -148,17 +148,37 @@ struct VectorIndexedViewSelector { // Block template struct VectorIndexedViewSelector { - - using ReturnType = VectorBlock::value>; - using ConstReturnType = VectorBlock::value>; + using BlockXprHelper = internal::block_xpr_helper; + using BlockXprBase = typename BlockXprHelper::BaseType; + template struct FixedSegmentReturnType { + typedef Block Type; + }; + template struct ConstFixedSegmentReturnType { + typedef const Block Type; + }; + + using ReturnType = typename FixedSegmentReturnType::value>::Type; + using ConstReturnType = typename ConstFixedSegmentReturnType::value>::Type; static inline ReturnType run(Derived& derived, const Indices& indices) { IvcType actualIndices = derived.ivcSize(indices); - return ReturnType(derived, internal::first(actualIndices), internal::index_list_size(actualIndices)); + auto start = internal::first(actualIndices); + auto n = internal::get_runtime_value(internal::index_list_size(actualIndices)); + return ReturnType(BlockXprHelper::base(derived), + BlockXprHelper::row(derived, IsRowMajor ? 0 : start), + BlockXprHelper::col(derived, IsRowMajor ? start : 0), + IsRowMajor ? 1 : n, + IsRowMajor ? n : 1); } static inline ConstReturnType run(const Derived& derived, const Indices& indices) { IvcType actualIndices = derived.ivcSize(indices); - return ConstReturnType(derived, internal::first(actualIndices), internal::index_list_size(actualIndices)); + auto start = internal::first(actualIndices); + auto n = internal::get_runtime_value(internal::index_list_size(actualIndices)); + return ConstReturnType(BlockXprHelper::base(derived), + BlockXprHelper::row(derived, IsRowMajor ? 0 : start), + BlockXprHelper::col(derived, IsRowMajor ? start : 0), + IsRowMajor ? 1 : n, + IsRowMajor ? n : 1); } }; @@ -344,7 +364,7 @@ operator()(const RowIndices& rowIndices, const ColIndices& colIndices); * \only_for_vectors */ template -IndexedView_or_VectorBlock +IndexedView_or_Block operator()(const Indices& indices); #endif // EIGEN_PARSED_BY_DOXYGEN diff --git a/test/block.cpp b/test/block.cpp index f8583c330..13b397265 100644 --- a/test/block.cpp +++ b/test/block.cpp @@ -306,6 +306,18 @@ void data_and_stride(const MatrixType& m) compare_using_data_and_stride(m1.col(c1).transpose()); } +template +void recursive_block_check(const Xpr& xpr) { + // Recursively reduce rows/cols until the result is 1x1. This is just + // to ensure we don't introduce infinite compile-time recursion. + if (xpr.rows() > 1) { + recursive_block_check(xpr.block(0, 0, (xpr.rows() + 1) / 2, xpr.cols())); + } + if (xpr.cols() > 1) { + recursive_block_check(xpr.block(0, 0, xpr.rows(), (xpr.cols() + 1)/2)); + } +} + EIGEN_DECLARE_TEST(block) { for(int i = 0; i < g_repeat; i++) { @@ -320,6 +332,7 @@ EIGEN_DECLARE_TEST(block) CALL_SUBTEST_7( block(Matrix(internal::random(2,50), internal::random(2,50))) ); CALL_SUBTEST_8( block(Matrix(3, 4)) ); + CALL_SUBTEST_9( recursive_block_check(Matrix(3, 4)) ); #ifndef EIGEN_DEFAULT_TO_ROW_MAJOR CALL_SUBTEST_6( data_and_stride(MatrixXf(internal::random(5,50), internal::random(5,50))) ); -- GitLab From 29b8f9e4538d93c664994f1e331ca9cec257848c Mon Sep 17 00:00:00 2001 From: Charlie Schlosser Date: Thu, 10 Aug 2023 18:20:34 -0400 Subject: [PATCH 2/5] add unwind methods --- Eigen/src/Core/Block.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Eigen/src/Core/Block.h b/Eigen/src/Core/Block.h index b3c1ad955..8ddbaf6d6 100644 --- a/Eigen/src/Core/Block.h +++ b/Eigen/src/Core/Block.h @@ -108,6 +108,7 @@ template class : public BlockImpl::StorageKind> { typedef BlockImpl::StorageKind> Impl; + using BlockHelper = internal::block_xpr_helper; public: //typedef typename Impl::Base Base; typedef Impl Base; @@ -150,6 +151,20 @@ template class eigen_assert(startRow >= 0 && blockRows >= 0 && startRow <= xpr.rows() - blockRows && startCol >= 0 && blockCols >= 0 && startCol <= xpr.cols() - blockCols); } + + using ConstUnwindReturnType = Block; + using UnwindReturnType = Block; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ConstUnwindReturnType unwind() const { + return ConstUnwindReturnType(BlockHelper::base(*this), BlockHelper::row(*this, 0), BlockHelper::col(*this, 0), + this->rows(), this->cols()); + } + + template ::value>> + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE UnwindReturnType unwind() { + return UnwindReturnType(BlockHelper::base(*this), BlockHelper::row(*this, 0), BlockHelper::col(*this, 0), + this->rows(), this->cols()); + } }; // The generic default implementation for dense block simplu forward to the internal::BlockImpl_dense -- GitLab From 9b2b4af05be5bbc31dd9447e3470f305c2999042 Mon Sep 17 00:00:00 2001 From: Charlie Schlosser Date: Thu, 10 Aug 2023 20:00:37 -0400 Subject: [PATCH 3/5] add unwind test --- test/block.cpp | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/test/block.cpp b/test/block.cpp index e54f8e030..072b22afb 100644 --- a/test/block.cpp +++ b/test/block.cpp @@ -305,19 +305,33 @@ void data_and_stride(const MatrixType& m) compare_using_data_and_stride(m1.row(r1).transpose()); compare_using_data_and_stride(m1.col(c1).transpose()); } - + template void recursive_block_check(const Xpr& xpr) { // Recursively reduce rows/cols until the result is 1x1. This is just // to ensure we don't introduce infinite compile-time recursion. if (xpr.rows() > 1) { - recursive_block_check(xpr.block(0, 0, (xpr.rows() + 1) / 2, xpr.cols())); + Index rows = (xpr.rows() + 1) / 2; + Index cols = xpr.cols(); + Block nestedBlock(xpr, 0, 0, rows, cols); + VERIFY_IS_CWISE_EQUAL(nestedBlock, nestedBlock.unwind()); + recursive_block_check(xpr.block(0, 0, rows, cols)); } if (xpr.cols() > 1) { - recursive_block_check(xpr.block(0, 0, xpr.rows(), (xpr.cols() + 1)/2)); + Index rows = xpr.rows(); + Index cols = (xpr.cols() + 1) / 2; + Block nestedBlock(xpr, 0, 0, rows, cols); + VERIFY_IS_CWISE_EQUAL(nestedBlock, nestedBlock.unwind()); + recursive_block_check(xpr.block(0, 0, rows, cols)); } } +template +void init_recursive_block_check(const Xpr& xpr) { + Xpr xprTest = Xpr::Random(xpr.rows(), xpr.cols()); + recursive_block_check(xprTest); +} + EIGEN_DECLARE_TEST(block) { for(int i = 0; i < g_repeat; i++) { @@ -332,7 +346,7 @@ EIGEN_DECLARE_TEST(block) CALL_SUBTEST_7( block(Matrix(internal::random(2,50), internal::random(2,50))) ); CALL_SUBTEST_8( block(Matrix(3, 4)) ); - CALL_SUBTEST_9( recursive_block_check(Matrix(3, 4)) ); + CALL_SUBTEST_9( init_recursive_block_check(Matrix(3, 4))); #ifndef EIGEN_DEFAULT_TO_ROW_MAJOR CALL_SUBTEST_6( data_and_stride(MatrixXf(internal::random(5,50), internal::random(5,50))) ); -- GitLab From 0108873de6a2567f99df2029e1e2d309657aebb6 Mon Sep 17 00:00:00 2001 From: Charlie Schlosser Date: Thu, 10 Aug 2023 21:26:40 -0400 Subject: [PATCH 4/5] allow const blocks to benefit from non-recursion --- Eigen/src/Core/util/XprHelper.h | 21 ++++++++++++- test/block.cpp | 52 +++++++++++++++++++++++---------- 2 files changed, 56 insertions(+), 17 deletions(-) diff --git a/Eigen/src/Core/util/XprHelper.h b/Eigen/src/Core/util/XprHelper.h index d9199404e..13ccae8ff 100644 --- a/Eigen/src/Core/util/XprHelper.h +++ b/Eigen/src/Core/util/XprHelper.h @@ -814,11 +814,14 @@ struct is_block_xpr : std::false_type {}; template struct is_block_xpr> : std::true_type {}; +template +struct is_block_xpr> : std::true_type {}; + // Helper utility for constructing non-recursive block expressions. template struct block_xpr_helper { using BaseType = XprType; - + // For regular block expressions, simply forward along the InnerPanel argument, // which is set when calling row/column expressions. static constexpr bool is_inner_panel(bool inner_panel) { return inner_panel; }; @@ -850,6 +853,22 @@ struct block_xpr_helper> { static constexpr EIGEN_ALWAYS_INLINE Index col(const BlockXprType& xpr, Index c) { return xpr.startCol() + NestedXprHelper::col(xpr.nestedExpression(), c); } }; +template +struct block_xpr_helper> { + using BlockXprType = const Block; + // Recursive helper in case of explicit block-of-block expression. + using NestedXprHelper = block_xpr_helper; + using BaseType = typename NestedXprHelper::BaseType; + + // For block-of-block expressions, we need to combine the InnerPannel trait + // with that of the block subexpression. + static constexpr bool is_inner_panel(bool inner_panel) { return InnerPanel && inner_panel; } + + static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE const BaseType& base(const BlockXprType& xpr) { return NestedXprHelper::base(xpr.nestedExpression()); } + static constexpr EIGEN_ALWAYS_INLINE Index row(const BlockXprType& xpr, Index r) { return xpr.startRow() + NestedXprHelper::row(xpr.nestedExpression(), r); } + static constexpr EIGEN_ALWAYS_INLINE Index col(const BlockXprType& xpr, Index c) { return xpr.startCol() + NestedXprHelper::col(xpr.nestedExpression(), c); } +}; + } // end namespace internal diff --git a/test/block.cpp b/test/block.cpp index 072b22afb..4745c0aa4 100644 --- a/test/block.cpp +++ b/test/block.cpp @@ -305,31 +305,50 @@ void data_and_stride(const MatrixType& m) compare_using_data_and_stride(m1.row(r1).transpose()); compare_using_data_and_stride(m1.col(c1).transpose()); } - + template void recursive_block_check(const Xpr& xpr) { // Recursively reduce rows/cols until the result is 1x1. This is just // to ensure we don't introduce infinite compile-time recursion. if (xpr.rows() > 1) { - Index rows = (xpr.rows() + 1) / 2; - Index cols = xpr.cols(); - Block nestedBlock(xpr, 0, 0, rows, cols); - VERIFY_IS_CWISE_EQUAL(nestedBlock, nestedBlock.unwind()); - recursive_block_check(xpr.block(0, 0, rows, cols)); + recursive_block_check(xpr.block(0, 0, (xpr.rows() + 1) / 2, xpr.cols())); } if (xpr.cols() > 1) { - Index rows = xpr.rows(); - Index cols = (xpr.cols() + 1) / 2; - Block nestedBlock(xpr, 0, 0, rows, cols); - VERIFY_IS_CWISE_EQUAL(nestedBlock, nestedBlock.unwind()); - recursive_block_check(xpr.block(0, 0, rows, cols)); + recursive_block_check(xpr.block(0, 0, xpr.rows(), (xpr.cols() + 1)/2)); } } -template -void init_recursive_block_check(const Xpr& xpr) { - Xpr xprTest = Xpr::Random(xpr.rows(), xpr.cols()); - recursive_block_check(xprTest); +template +struct unwind_test_impl { + static void run(Xpr& xpr) { + Index startRow = xpr.rows() / 5; + Index startCol = xpr.cols() / 6; + Index rows = xpr.rows() / 3; + Index cols = xpr.cols() / 2; + // test equivalence of const expressions + const Block constNestedBlock(xpr, startRow, startCol, rows, cols); + const Block constUnwoundBlock = constNestedBlock.unwind(); + VERIFY_IS_CWISE_EQUAL(constNestedBlock, constUnwoundBlock); + // modify a random element and test equivalence of non-const expressions + Block nestedBlock(xpr, startRow, startCol, rows, cols); + Block unwoundBlock = nestedBlock.unwind(); + Index r = internal::random(0, rows - 1); + Index c = internal::random(0, cols - 1); + nestedBlock.coeffRef(r, c) = internal::random::Scalar>(); + VERIFY_IS_CWISE_EQUAL(nestedBlock, unwoundBlock); + unwind_test_impl, Depth + 1>::run(nestedBlock); + } +}; + +template +struct unwind_test_impl { + static void run(const Xpr& xpr) {} +}; + +template +void unwind_test(const BaseXpr&) { + BaseXpr xpr = BaseXpr::Random(100, 100); + unwind_test_impl::run(xpr); } EIGEN_DECLARE_TEST(block) @@ -346,7 +365,8 @@ EIGEN_DECLARE_TEST(block) CALL_SUBTEST_7( block(Matrix(internal::random(2,50), internal::random(2,50))) ); CALL_SUBTEST_8( block(Matrix(3, 4)) ); - CALL_SUBTEST_9( init_recursive_block_check(Matrix(3, 4))); + CALL_SUBTEST_9( recursive_block_check(Matrix(3, 4)) ); + CALL_SUBTEST_10( unwind_test(MatrixXf())); #ifndef EIGEN_DEFAULT_TO_ROW_MAJOR CALL_SUBTEST_6( data_and_stride(MatrixXf(internal::random(5,50), internal::random(5,50))) ); -- GitLab From 4c3dc88d993577c1b82c80f6c8f14bb867d2f13d Mon Sep 17 00:00:00 2001 From: Charlie Schlosser Date: Thu, 10 Aug 2023 21:39:11 -0400 Subject: [PATCH 5/5] remove unused variable --- test/block.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/block.cpp b/test/block.cpp index 4745c0aa4..b7bbfadff 100644 --- a/test/block.cpp +++ b/test/block.cpp @@ -342,7 +342,7 @@ struct unwind_test_impl { template struct unwind_test_impl { - static void run(const Xpr& xpr) {} + static void run(const Xpr&) {} }; template -- GitLab