From 4989922be2708378b2438db5a843640ec468ce4c Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 16 Jan 2017 22:21:23 +0100 Subject: [PATCH] Add support for symbolic expressions as arguments of operator() --- Eigen/Core | 3 +- Eigen/src/Core/ArithmeticSequence.h | 66 +------------------- Eigen/src/Core/IndexedView.h | 8 ++- Eigen/src/Core/util/IndexedViewHelper.h | 80 ++++++++++++++++++++++++- Eigen/src/plugins/IndexedViewMethods.h | 41 +++++++++---- test/indexed_view.cpp | 8 +++ 6 files changed, 126 insertions(+), 80 deletions(-) diff --git a/Eigen/Core b/Eigen/Core index 38306e11d..2ce2dd6b2 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -354,8 +354,9 @@ using std::ptrdiff_t; #include "src/Core/util/StaticAssert.h" #include "src/Core/util/XprHelper.h" #include "src/Core/util/Memory.h" -#include "src/Core/util/IntegralConstant.h" #include "src/Core/util/SymbolicIndex.h" +#include "src/Core/util/IntegralConstant.h" + #include "src/Core/NumTraits.h" #include "src/Core/MathFunctions.h" diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 79e6bb74e..056ace1f2 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -12,56 +12,6 @@ namespace Eigen { -/** \namespace Eigen::placeholders - * \ingroup Core_Module - * - * Namespace containing symbolic placeholder and identifiers - */ -namespace placeholders { - -namespace internal { -struct symbolic_last_tag {}; -} - -/** \var last - * \ingroup Core_Module - * - * Can be used as a parameter to Eigen::seq and Eigen::seqN functions to symbolically reference the last element/row/columns - * of the underlying vector or matrix once passed to DenseBase::operator()(const RowIndices&, const ColIndices&). - * - * This symbolic placeholder support standard arithmetic operation. - * - * A typical usage example would be: - * \code - * using namespace Eigen; - * using Eigen::placeholders::last; - * VectorXd v(n); - * v(seq(2,last-2)).setOnes(); - * \endcode - * - * \sa end - */ -static const Symbolic::SymbolExpr last; - -/** \var end - * \ingroup Core_Module - * - * Can be used as a parameter to Eigen::seq and Eigen::seqN functions to symbolically reference the last+1 element/row/columns - * of the underlying vector or matrix once passed to DenseBase::operator()(const RowIndices&, const ColIndices&). - * - * This symbolic placeholder support standard arithmetic operation. - * It is essentially an alias to last+1 - * - * \sa last - */ -#ifdef EIGEN_PARSED_BY_DOXYGEN -static const auto end = last+1; -#else -static const Symbolic::AddExpr,Symbolic::ValueExpr> end(last+1); -#endif - -} // end namespace placeholders - //-------------------------------------------------------------------------------- // seq(first,last,incr) and seqN(first,size,incr) //-------------------------------------------------------------------------------- @@ -293,18 +243,6 @@ seq(const Symbolic::BaseExpr &f, const Symbolic::BaseExpr -fix_t eval_expr_given_size(fix_t x, Index /*size*/) { return x; } - -template -Index eval_expr_given_size(const Symbolic::BaseExpr &x, Index size) -{ - return x.derived().eval(placeholders::last=size-1); -} - // Convert a symbolic span into a usable one (i.e., remove last/end "keywords") template struct make_size_type { @@ -318,7 +256,7 @@ struct IndexedViewCompatibleType template ArithmeticSequence::type,IncrType> -makeIndexedViewCompatible(const ArithmeticSequence& ids, Index size) { +makeIndexedViewCompatible(const ArithmeticSequence& ids, Index size,SpecializedType) { return ArithmeticSequence::type,IncrType>( eval_expr_given_size(ids.firstObject(),size),eval_expr_given_size(ids.sizeObject(),size),ids.incrObject()); } @@ -436,7 +374,7 @@ struct IndexedViewCompatibleType legacy::ArithmeticSequenceProxyWithBounds -makeIndexedViewCompatible(const legacy::ArithmeticSequenceProxyWithBounds& ids, Index size) { +makeIndexedViewCompatible(const legacy::ArithmeticSequenceProxyWithBounds& ids, Index size,SpecializedType) { return legacy::ArithmeticSequenceProxyWithBounds( eval_expr_given_size(ids.firstObject(),size),eval_expr_given_size(ids.lastObject(),size),ids.incrObject()); } diff --git a/Eigen/src/Core/IndexedView.h b/Eigen/src/Core/IndexedView.h index 38ee69638..63878428e 100644 --- a/Eigen/src/Core/IndexedView.h +++ b/Eigen/src/Core/IndexedView.h @@ -45,6 +45,10 @@ struct traits > InnerStrideAtCompileTime = InnerIncr<0 || InnerIncr==DynamicIndex || XprInnerStride==Dynamic ? Dynamic : XprInnerStride * InnerIncr, OuterStrideAtCompileTime = OuterIncr<0 || OuterIncr==DynamicIndex || XprOuterstride==Dynamic ? Dynamic : XprOuterstride * OuterIncr, + ReturnAsScalar = is_same::value && is_same::value, + ReturnAsBlock = (!ReturnAsScalar) && IsBlockAlike, + ReturnAsIndexedView = (!ReturnAsScalar) && (!ReturnAsBlock), + // FIXME we deal with compile-time strides if and only if we have DirectAccessBit flag, // but this is too strict regarding negative strides... DirectAccessMask = (InnerIncr!=UndefinedIncr && OuterIncr!=UndefinedIncr && InnerIncr>=0 && OuterIncr>=0) ? DirectAccessBit : 0, @@ -91,8 +95,8 @@ class IndexedViewImpl; * - decltype(ArrayXi::LinSpaced(...)) * - Any view/expressions of the previous types * - Eigen::ArithmeticSequence - * - Eigen::AllRange (helper for Eigen::all) - * - Eigen::IntAsArray (helper for single index) + * - Eigen::internal::AllRange (helper for Eigen::all) + * - Eigen::internal::SingleRange (helper for single index) * - etc. * * In typical usages of %Eigen, this class should never be used directly. It is the return type of diff --git a/Eigen/src/Core/util/IndexedViewHelper.h b/Eigen/src/Core/util/IndexedViewHelper.h index 4f6dd065e..09637a157 100644 --- a/Eigen/src/Core/util/IndexedViewHelper.h +++ b/Eigen/src/Core/util/IndexedViewHelper.h @@ -13,7 +13,69 @@ namespace Eigen { +/** \namespace Eigen::placeholders + * \ingroup Core_Module + * + * Namespace containing symbolic placeholder and identifiers + */ +namespace placeholders { + namespace internal { +struct symbolic_last_tag {}; +} + +/** \var last + * \ingroup Core_Module + * + * Can be used as a parameter to Eigen::seq and Eigen::seqN functions to symbolically reference the last element/row/columns + * of the underlying vector or matrix once passed to DenseBase::operator()(const RowIndices&, const ColIndices&). + * + * This symbolic placeholder support standard arithmetic operation. + * + * A typical usage example would be: + * \code + * using namespace Eigen; + * using Eigen::placeholders::last; + * VectorXd v(n); + * v(seq(2,last-2)).setOnes(); + * \endcode + * + * \sa end + */ +static const Symbolic::SymbolExpr last; + +/** \var end + * \ingroup Core_Module + * + * Can be used as a parameter to Eigen::seq and Eigen::seqN functions to symbolically reference the last+1 element/row/columns + * of the underlying vector or matrix once passed to DenseBase::operator()(const RowIndices&, const ColIndices&). + * + * This symbolic placeholder support standard arithmetic operation. + * It is essentially an alias to last+1 + * + * \sa last + */ +#ifdef EIGEN_PARSED_BY_DOXYGEN +static const auto end = last+1; +#else +static const Symbolic::AddExpr,Symbolic::ValueExpr> end(last+1); +#endif + +} // end namespace placeholders + +namespace internal { + + // Replace symbolic last/end "keywords" by their true runtime value +inline Index eval_expr_given_size(Index x, Index /* size */) { return x; } + +template +fix_t eval_expr_given_size(fix_t x, Index /*size*/) { return x; } + +template +Index eval_expr_given_size(const Symbolic::BaseExpr &x, Index size) +{ + return x.derived().eval(placeholders::last=size-1); +} // Extract increment/step at compile time template struct get_compile_time_incr { @@ -31,8 +93,8 @@ struct IndexedViewCompatibleType { typedef T type; }; -template -const T& makeIndexedViewCompatible(const T& x, Index /*size*/) { return x; } +template +const T& makeIndexedViewCompatible(const T& x, Index /*size*/, Q) { return x; } //-------------------------------------------------------------------------------- // Handling of a single Index @@ -62,6 +124,18 @@ struct IndexedViewCompatibleType +struct IndexedViewCompatibleType::value>::type> { + typedef SingleRange type; +}; + + +template +typename enable_if::value,SingleRange>::type +makeIndexedViewCompatible(const T& id, Index size, SpecializedType) { + return eval_expr_given_size(id,size); +} + //-------------------------------------------------------------------------------- // Handling of all //-------------------------------------------------------------------------------- @@ -85,7 +159,7 @@ struct IndexedViewCompatibleType { }; template -inline AllRange::value> makeIndexedViewCompatible(all_t , XprSizeType size) { +inline AllRange::value> makeIndexedViewCompatible(all_t , XprSizeType size, SpecializedType) { return AllRange::value>(size); } diff --git a/Eigen/src/plugins/IndexedViewMethods.h b/Eigen/src/plugins/IndexedViewMethods.h index 0584a5926..90ade05ed 100644 --- a/Eigen/src/plugins/IndexedViewMethods.h +++ b/Eigen/src/plugins/IndexedViewMethods.h @@ -38,19 +38,24 @@ typedef typename internal::IndexedViewCompatibleType::type IvcIndex; template typename IvcRowType::type ivcRow(const Indices& indices) const { - return internal::makeIndexedViewCompatible(indices, internal::variable_if_dynamic(derived().rows())); + return internal::makeIndexedViewCompatible(indices, internal::variable_if_dynamic(derived().rows()),Specialized); }; template typename IvcColType::type ivcCol(const Indices& indices) const { - return internal::makeIndexedViewCompatible(indices, internal::variable_if_dynamic(derived().cols())); + return internal::makeIndexedViewCompatible(indices, internal::variable_if_dynamic(derived().cols()),Specialized); }; template typename IvcColType::type ivcSize(const Indices& indices) const { - return internal::makeIndexedViewCompatible(indices, internal::variable_if_dynamic(derived().size())); + return internal::makeIndexedViewCompatible(indices, internal::variable_if_dynamic(derived().size()),Specialized); +}; + +template +struct valid_indexed_view_overload { + enum { value = !(internal::is_integral::value && internal::is_integral::value) }; }; public: @@ -67,9 +72,8 @@ struct EIGEN_INDEXED_VIEW_METHOD_TYPE { // This is the generic version template -typename internal::enable_if< - ! (internal::traits::type>::IsBlockAlike - || (internal::is_integral::value && internal::is_integral::value)), +typename internal::enable_if::value + && internal::traits::type>::ReturnAsIndexedView, typename EIGEN_INDEXED_VIEW_METHOD_TYPE::type >::type operator()(const RowIndices& rowIndices, const ColIndices& colIndices) EIGEN_INDEXED_VIEW_METHOD_CONST { @@ -80,9 +84,8 @@ operator()(const RowIndices& rowIndices, const ColIndices& colIndices) EIGEN_IND // The folowing overload returns a Block<> object template -typename internal::enable_if< - internal::traits::type>::IsBlockAlike - && !(internal::is_integral::value && internal::is_integral::value), +typename internal::enable_if::value + && internal::traits::type>::ReturnAsBlock, typename internal::traits::type>::BlockType>::type operator()(const RowIndices& rowIndices, const ColIndices& colIndices) EIGEN_INDEXED_VIEW_METHOD_CONST { @@ -96,6 +99,17 @@ operator()(const RowIndices& rowIndices, const ColIndices& colIndices) EIGEN_IND internal::size(actualColIndices)); } +// The following overload returns a Scalar + +template +typename internal::enable_if::value + && internal::traits::type>::ReturnAsScalar, + CoeffReturnType >::type +operator()(const RowIndices& rowIndices, const ColIndices& colIndices) EIGEN_INDEXED_VIEW_METHOD_CONST +{ + return Base::operator()(internal::eval_expr_given_size(rowIndices,rows()),internal::eval_expr_given_size(colIndices,cols())); +} + // The folowing three overloads are needed to handle raw Index[N] arrays. template @@ -148,7 +162,7 @@ operator()(const Indices& indices) EIGEN_INDEXED_VIEW_METHOD_CONST template typename internal::enable_if< - (internal::get_compile_time_incr::type>::value==1) && (!internal::is_integral::value), + (internal::get_compile_time_incr::type>::value==1) && (!internal::is_integral::value) && (!Symbolic::is_symbolic::value), VectorBlock::value> >::type operator()(const Indices& indices) EIGEN_INDEXED_VIEW_METHOD_CONST { @@ -158,6 +172,13 @@ operator()(const Indices& indices) EIGEN_INDEXED_VIEW_METHOD_CONST (derived(), internal::first(actualIndices), internal::size(actualIndices)); } +template +typename internal::enable_if::value, CoeffReturnType >::type +operator()(const IndexType& id) EIGEN_INDEXED_VIEW_METHOD_CONST +{ + return Base::operator()(internal::eval_expr_given_size(id,size())); +} + template typename internal::enable_if >::type diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index 472268010..88211f05e 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -211,6 +211,12 @@ void check_indexed_view() VERIFY_IS_APPROX( A(seq(1,n-1-2), seq(n-1-5,7)), A(seq(1,last-2), seq(last-5,7)) ); VERIFY_IS_APPROX( A(seq(n-1-5,n-1-2), seq(n-1-5,n-1-2)), A(seq(last-5,last-2), seq(last-5,last-2)) ); + VERIFY_IS_APPROX( A.col(A.cols()-1), A(all,last) ); + VERIFY_IS_APPROX( A(A.rows()-2, A.cols()/2), A(last-1, end/2) ); + VERIFY_IS_APPROX( a(a.size()-2), a(last-1) ); + VERIFY_IS_APPROX( a(a.size()/2), a((last+1)/2) ); + + // Check fall-back to Block { VERIFY( is_same_type(A.col(0), A(all,0)) ); @@ -219,6 +225,8 @@ void check_indexed_view() VERIFY( is_same_type(A.middleRows(2,4), A(seqN(2,4),all)) ); VERIFY( is_same_type(A.middleCols(2,4), A(all,seqN(2,4))) ); + VERIFY( is_same_type(A.col(A.cols()-1), A(all,last)) ); + const ArrayXXi& cA(A); VERIFY( is_same_type(cA.col(0), cA(all,0)) ); VERIFY( is_same_type(cA.row(0), cA(0,all)) );