# HG changeset patch # Parent 437cf67061229cc2869c4b7c8e390891a1ae8b1f diff --git a/Eigen/src/Core/Block.h b/Eigen/src/Core/Block.h --- a/Eigen/src/Core/Block.h +++ b/Eigen/src/Core/Block.h @@ -1,12 +1,12 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2008-2016 Gael Guennebaud // Copyright (C) 2006-2010 Benoit Jacob // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_BLOCK_H #define EIGEN_BLOCK_H @@ -49,17 +49,17 @@ struct traits::value ? LvalueBit : 0, FlagsRowMajorBit = IsRowMajor ? RowMajorBit : 0, 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 + // We can safely set it to false here. Internal alignment errors will be detected by an eigen_internal_assert in the respective evaluator Alignment = 0 }; }; template::ret> class BlockImpl_dense; } // end namespace internal @@ -141,19 +141,129 @@ template= 0 && blockRows >= 0 && startRow <= xpr.rows() - blockRows && startCol >= 0 && blockCols >= 0 && startCol <= xpr.cols() - blockCols); } + }; - -// The generic default implementation for dense block simplu forward to the internal::BlockImpl_dense + +// Fuse any Block> expressions as a Block expression +// This is the non-const specialization +template +class Block, BlockRows, BlockCols, InnerPanel> + : public Block +{ + typedef Block ArgType; + typedef Block Base; +public: + using Base::operator=; + + /** Column or Row constructor + */ + EIGEN_DEVICE_FUNC + template + inline Block(OtherBlock &blk, Index i) + : Base(blk.nestedExpression(), + blk.startRow() + ((BlockRows==1) && (BlockCols==ArgType::ColsAtCompileTime) ? i : 0), + blk.startCol() + ((BlockRows==ArgType::RowsAtCompileTime) && (BlockCols==1) ? i : 0), + BlockRows==1 ? 1 : blk.rows(), + BlockCols==1 ? 1 : blk.cols() + ) + { + eigen_assert( (i>=0) && ( + ((BlockRows==1) && (BlockCols==ArgType::ColsAtCompileTime) && i + inline Block(OtherBlock &blk, Index startRow, Index startCol) + : Base(blk.nestedExpression(), + blk.startRow() + startRow, + blk.startCol() + startCol) + { + EIGEN_STATIC_ASSERT(Base::RowsAtCompileTime!=Dynamic && Base::ColsAtCompileTime!=Dynamic,THIS_METHOD_IS_ONLY_FOR_FIXED_SIZE) + eigen_assert(startRow >= 0 && BlockRows >= 0 && startRow + BlockRows <= blk.rows() + && startCol >= 0 && BlockCols >= 0 && startCol + BlockCols <= blk.cols()); + } + + /** Dynamic-size constructor + */ + EIGEN_DEVICE_FUNC + template + inline Block(OtherBlock &blk, Index startRow, Index startCol, Index blockRows, Index blockCols) + : Base(blk.nestedExpression(), blk.startRow() + startRow, blk.startCol() + startCol, blockRows, blockCols) + { + eigen_assert((Base::RowsAtCompileTime==Dynamic || Base::RowsAtCompileTime==blockRows) + && (Base::ColsAtCompileTime==Dynamic || Base::ColsAtCompileTime==blockCols)); + eigen_assert(startRow >= 0 && blockRows >= 0 && startRow <= blk.rows() - blockRows + && startCol >= 0 && blockCols >= 0 && startCol <= blk.cols() - blockCols); + } +}; + +// Fuse any Block> expressions as a Block expression +// This is the const specialization +template +class Block, BlockRows, BlockCols, InnerPanel> + : public Block +{ + typedef Block ArgType; + typedef Block Base; +public: + using Base::operator=; + + /** Column or Row constructor + */ + EIGEN_DEVICE_FUNC + inline Block(const ArgType &blk, Index i) + : Base(blk.nestedExpression(), + blk.startRow() + ((BlockRows==1) && (BlockCols==ArgType::ColsAtCompileTime) ? i : 0), + blk.startCol() + ((BlockRows==ArgType::RowsAtCompileTime) && (BlockCols==1) ? i : 0), + BlockRows==1 ? 1 : blk.rows(), + BlockCols==1 ? 1 : blk.cols() + ) + { + eigen_assert( (i>=0) && ( + ((BlockRows==1) && (BlockCols==ArgType::ColsAtCompileTime) && i= 0 && BlockRows >= 0 && startRow + BlockRows <= blk.rows() + && startCol >= 0 && BlockCols >= 0 && startCol + BlockCols <= blk.cols()); + } + + /** Dynamic-size constructor + */ + EIGEN_DEVICE_FUNC + inline Block(const ArgType &blk, Index startRow, Index startCol, Index blockRows, Index blockCols) + : Base(blk.nestedExpression(), blk.startRow() + startRow, blk.startCol() + startCol, blockRows, blockCols) + { + eigen_assert((Base::RowsAtCompileTime==Dynamic || Base::RowsAtCompileTime==blockRows) + && (Base::ColsAtCompileTime==Dynamic || Base::ColsAtCompileTime==blockCols)); + eigen_assert(startRow >= 0 && blockRows >= 0 && startRow <= blk.rows() - blockRows + && startCol >= 0 && blockCols >= 0 && startCol <= blk.cols() - blockCols); + } +}; + +// The generic default implementation for dense block simply forward to the internal::BlockImpl_dense // that must be specialized for direct and non-direct access... template class BlockImpl : public internal::BlockImpl_dense { typedef internal::BlockImpl_dense Impl; typedef typename XprType::StorageIndex StorageIndex; public: diff --git a/test/block.cpp b/test/block.cpp --- a/test/block.cpp +++ b/test/block.cpp @@ -178,16 +178,118 @@ template void block VERIFY_IS_EQUAL(dv, dm); dm.setZero(); dv.setZero(); dm = m1.row(r1).segment(c1,c2-c1+1).transpose(); dv = m1.transpose().block(c1,r1,c2-c1+1,r2-r1+1).col(0); VERIFY_IS_EQUAL(dv, dm); } +template +bool same_type(const T&, const T&) { return true; } + +template +void checkbb(const DenseBase &a_xpr, const DenseBase &a_ref, const DenseBase &a_xprfused) +{ + const Expr& xpr(a_xpr.derived()); + const Ref& ref(a_ref.derived()); + const ExprFused& xprfused(a_xprfused.derived()); + + VERIFY_IS_APPROX(xprfused, ref); + + VERIFY(same_type(xpr, xprfused)); + + VERIFY_IS_EQUAL(ExprFused::Flags, Expr::Flags); + VERIFY_IS_EQUAL(ExprFused::RowsAtCompileTime, Expr::RowsAtCompileTime); + VERIFY_IS_EQUAL(ExprFused::ColsAtCompileTime, Expr::ColsAtCompileTime); + + typedef internal::evaluator EvalFused; + typedef internal::evaluator EvalExpr; + VERIFY_IS_EQUAL(EvalFused::Flags, EvalExpr::Flags); + VERIFY_IS_EQUAL(EvalFused::Alignment, EvalExpr::Alignment); + + VERIFY_IS_APPROX(xpr.derived(), ref); + VERIFY_IS_APPROX(xpr, ref); +} + +template +void check_block_block_fusion(const MatrixType &m) +{ + Index rows = m.rows(); + Index cols = m.cols(); + + MatrixType m1 = MatrixType::Random(rows, cols), + m2 = MatrixType::Random(rows, cols); + + Index r1 = internal::random(0,rows-1); + Index c1 = internal::random(0,cols-1); + Index nr1 = internal::random(1,rows-r1); + Index nc1 = internal::random(1,cols-c1); + + Index r2 = internal::random(0,nr1-1); + Index c2 = internal::random(0,nc1-1); + Index nr2 = internal::random(1,nr1-r2); + Index nc2 = internal::random(1,nc1-c2); + + CALL_SUBTEST( checkbb(m1.block(r1,c1, nr1,nc1).block(r2,c2,nr2,nc2), + m1.block(r1,c1, nr1,nc1).eval().block(r2,c2,nr2,nc2).eval(), + m1.block(r1+r2, c1+c2, nr2, nc2)) ); + CALL_SUBTEST( checkbb((m1+m2).block(r1,c1, nr1,nc1).block(r2,c2,nr2,nc2), + (m1+m2).block(r1,c1, nr1,nc1).eval().block(r2,c2,nr2,nc2).eval(), + (m1+m2).block(r1+r2, c1+c2, nr2, nc2)) ); + + CALL_SUBTEST( checkbb(m1.block(r1,c1, nr1,nc1).row(r2), + m1.block(r1,c1, nr1,nc1).eval().row(r2).eval(), + m1.template block<1,Dynamic>(r1+r2, c1, 1, nc1)) ); + CALL_SUBTEST( checkbb((m1+m2).block(r1,c1, nr1,nc1).row(r2), + (m1+m2).block(r1,c1, nr1,nc1).eval().row(r2).eval(), + (m1+m2).template block<1,Dynamic>(r1+r2, c1, 1, nc1)) ); + + CALL_SUBTEST( checkbb(m1.block(r1,c1, nr1,nc1).col(c2), + m1.block(r1,c1, nr1,nc1).eval().col(c2).eval(), + m1.template block(r1, c1+c2, nr1, 1)) ); + CALL_SUBTEST( checkbb((m1+m2).block(r1,c1, nr1,nc1).col(c2), + (m1+m2).block(r1,c1, nr1,nc1).eval().col(c2).eval(), + (m1+m2).template block(r1, c1+c2, nr1, 1)) ); + + CALL_SUBTEST( checkbb(m1.row(r1).segment(c1,nc1), + m1.row(r1).eval().segment(c1,nc1).eval(), + m1.template block<1,Dynamic>(r1, c1, 1, nc1)) ); + CALL_SUBTEST( checkbb((m1+m2).row(r1).segment(c1,nc1), + (m1+m2).row(r1).eval().segment(c1,nc1).eval(), + (m1+m2).template block<1,Dynamic>(r1, c1, 1, nc1)) ); + + CALL_SUBTEST( checkbb(m1.col(c1).segment(r1,nr1), + m1.col(c1).eval().segment(r1,nr1).eval(), + m1.template block(r1, c1, nr1, 1)) ); + CALL_SUBTEST( checkbb((m1+m2).col(c1).segment(r1,nr1), + (m1+m2).col(c1).eval().segment(r1,nr1).eval(), + (m1+m2).template block(r1, c1, nr1, 1)) ); + + CALL_SUBTEST( checkbb(m1.middleCols(c1,nc1).col(c2).segment(r1,nr1), + m1.middleCols(c1,nc1).eval().col(c2).eval().segment(r1,nr1).eval(), + m1.template block(r1, c1+c2, nr1, 1)) ); + CALL_SUBTEST( checkbb((m1+m2).middleCols(c1,nc1).col(c2).segment(r1,nr1), + (m1+m2).middleCols(c1,nc1).eval().col(c2).eval().segment(r1,nr1).eval(), + (m1+m2).template block(r1, c1+c2, nr1, 1)) ); + + CALL_SUBTEST( checkbb(m1.row(r1).col(c1), + m1.row(r1).eval().col(c1).eval(), + m1.template block<1,1>(r1, c1)) ); + CALL_SUBTEST( checkbb((m1+m2).row(r1).col(c1), + (m1+m2).row(r1).eval().col(c1).eval(), + (m1+m2).template block<1,1>(r1, c1)) ); + + CALL_SUBTEST( checkbb(m1.row(r1).col(c1).segment(0,1), + m1.row(r1).eval().col(c1).eval().segment(0,1).eval(), + m1.template block(r1, c1, 1,1)) ); + CALL_SUBTEST( checkbb((m1+m2).row(r1).col(c1).segment(0,1), + (m1+m2).row(r1).eval().col(c1).eval().segment(0,1).eval(), + (m1+m2).template block(r1, c1, 1,1)) ); +} template void compare_using_data_and_stride(const MatrixType& m) { typedef typename MatrixType::Index Index; Index rows = m.rows(); Index cols = m.cols(); Index size = m.size(); @@ -246,14 +348,23 @@ void test_block() CALL_SUBTEST_2( block(Matrix4d()) ); CALL_SUBTEST_3( block(MatrixXcf(3, 3)) ); CALL_SUBTEST_4( block(MatrixXi(8, 12)) ); CALL_SUBTEST_5( block(MatrixXcd(20, 20)) ); CALL_SUBTEST_6( block(MatrixXf(20, 20)) ); CALL_SUBTEST_8( block(Matrix(3, 4)) ); + CALL_SUBTEST_9( check_block_block_fusion(MatrixXi(internal::random(1,50), internal::random(1,50))) ); + CALL_SUBTEST_9( check_block_block_fusion(Matrix4i()) ); + CALL_SUBTEST_9( check_block_block_fusion(Matrix3i()) ); + + CALL_SUBTEST_9( check_block_block_fusion(MatrixXd(internal::random(1,50), internal::random(1,50))) ); + CALL_SUBTEST_9( check_block_block_fusion(Matrix4d()) ); + CALL_SUBTEST_9( check_block_block_fusion(Matrix3d()) ); + CALL_SUBTEST_9( check_block_block_fusion(Matrix2d()) ); + #ifndef EIGEN_DEFAULT_TO_ROW_MAJOR CALL_SUBTEST_6( data_and_stride(MatrixXf(internal::random(5,50), internal::random(5,50))) ); CALL_SUBTEST_7( data_and_stride(Matrix(internal::random(5,50), internal::random(5,50))) ); #endif } }