From ac7e4ac9c071ee879e9da278a9a2cf6cef82f053 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 6 Jan 2017 00:01:44 +0100 Subject: [PATCH 01/65] Initial commit to add a generic indexed-based view of matrices. This version already works as a read-only expression. Numerous refactoring, renaming, extension, tuning passes are expected... --- Eigen/Core | 2 + Eigen/src/Core/ArithmeticSequence.h | 229 ++++++++++++++++++++++ Eigen/src/Core/DenseBase.h | 9 + Eigen/src/Core/IndexedView.h | 137 +++++++++++++ Eigen/src/Core/util/ForwardDeclarations.h | 1 + 5 files changed, 378 insertions(+) create mode 100644 Eigen/src/Core/ArithmeticSequence.h create mode 100644 Eigen/src/Core/IndexedView.h diff --git a/Eigen/Core b/Eigen/Core index 16be82ac2..a93e3ce65 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -418,6 +418,7 @@ using std::ptrdiff_t; // on CUDA devices #include "src/Core/arch/CUDA/Complex.h" +#include "src/Core/ArithmeticSequence.h" #include "src/Core/DenseCoeffsBase.h" #include "src/Core/DenseBase.h" #include "src/Core/MatrixBase.h" @@ -458,6 +459,7 @@ using std::ptrdiff_t; #include "src/Core/Ref.h" #include "src/Core/Block.h" #include "src/Core/VectorBlock.h" +#include "src/Core/IndexedView.h" #include "src/Core/Transpose.h" #include "src/Core/DiagonalMatrix.h" #include "src/Core/Diagonal.h" diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h new file mode 100644 index 000000000..3439a2586 --- /dev/null +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -0,0 +1,229 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2017 Gael Guennebaud +// +// 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_ARITHMETIC_SEQUENCE_H +#define EIGEN_ARITHMETIC_SEQUENCE_H + +namespace Eigen { + + +struct all_t { all_t() {} }; +static const all_t all; + +struct shifted_last { + explicit shifted_last(int o) : offset(o) {} + int offset; + shifted_last operator+ (int x) const { return shifted_last(offset+x); } + shifted_last operator- (int x) const { return shifted_last(offset-x); } + int operator- (shifted_last x) const { return offset-x.offset; } +}; + +struct last_t { + last_t() {} + shifted_last operator- (int offset) const { return shifted_last(-offset); } + shifted_last operator+ (int offset) const { return shifted_last(+offset); } + int operator- (last_t) const { return 0; } + int operator- (shifted_last x) const { return -x.offset; } +}; +static const last_t last; + + +struct shifted_end { + explicit shifted_end(int o) : offset(o) {} + int offset; + shifted_end operator+ (int x) const { return shifted_end(offset+x); } + shifted_end operator- (int x) const { return shifted_end(offset-x); } + int operator- (shifted_end x) const { return offset-x.offset; } +}; + +struct end_t { + end_t() {} + shifted_end operator- (int offset) const { return shifted_end (-offset); } + shifted_end operator+ (int offset) const { return shifted_end ( offset); } + int operator- (end_t) const { return 0; } + int operator- (shifted_end x) const { return -x.offset; } +}; +static const end_t end; + +template struct Index_c { + static const int value = N; + operator int() const { return value; } + Index_c (Index_c (*)() ) {} + Index_c() {} + // Needed in C++14 to allow c(): + Index_c operator() () const { return *this; } +}; + +//-------------------------------------------------------------------------------- +// Range(first,last) and Slice(first,step,last) +//-------------------------------------------------------------------------------- + +template > +struct Range_t { + Range_t(FirstType f, LastType l) : m_first(f), m_last(l) {} + Range_t(FirstType f, LastType l, StepType s) : m_first(f), m_last(l), m_step(s) {} + + FirstType m_first; + LastType m_last; + StepType m_step; + + enum { SizeAtCompileTime = -1 }; + + Index size() const { return (m_last-m_first+m_step)/m_step; } + Index operator[] (Index k) const { return m_first + k*m_step; } +}; + +template struct cleanup_slice_type { typedef Index type; }; +template<> struct cleanup_slice_type { typedef last_t type; }; +template<> struct cleanup_slice_type { typedef shifted_last type; }; +template<> struct cleanup_slice_type { typedef end_t type; }; +template<> struct cleanup_slice_type { typedef shifted_end type; }; +template struct cleanup_slice_type > { typedef Index_c type; }; +template struct cleanup_slice_type (*)() > { typedef Index_c type; }; + +template +Range_t::type,typename cleanup_slice_type::type > +range(FirstType f, LastType l) { + return Range_t::type,typename cleanup_slice_type::type>(f,l); +} + +template +Range_t::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type > +range(FirstType f, LastType l, StepType s) { + return Range_t::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type>(f,l,typename cleanup_slice_type::type(s)); +} + + +template struct get_compile_time { + enum { value = Default }; +}; + +template struct get_compile_time,Default> { + enum { value = N }; +}; + +template struct is_compile_time { enum { value = false }; }; +template struct is_compile_time > { enum { value = true }; }; + +template > +struct Span_t { + Span_t(FirstType first, SizeType size) : m_first(first), m_size(size) {} + Span_t(FirstType first, SizeType size, StepType step) : m_first(first), m_size(size), m_step(step) {} + + FirstType m_first; + SizeType m_size; + StepType m_step; + + enum { SizeAtCompileTime = get_compile_time::value }; + + Index size() const { return m_size; } + Index operator[] (Index k) const { return m_first + k*m_step; } +}; + +template +Span_t::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type > +span(FirstType first, SizeType size, StepType step) { + return Span_t::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type>(first,size,step); +} + +template +Span_t::type,typename cleanup_slice_type::type > +span(FirstType first, SizeType size) { + return Span_t::type,typename cleanup_slice_type::type>(first,size); +} + +#if __cplusplus > 201103L +template +static const Index_c c{}; +#else +template +inline Index_c c() { return Index_c(); } +#endif + +namespace internal { + +// MakeIndexing/make_indexing turn an arbitrary object of type T into something usable by MatrixSlice +template +struct MakeIndexing { + typedef T type; +}; + +template +const T& make_indexing(const T& x, Index size) { return x; } + +struct IntAsArray { + IntAsArray(Index val) : m_value(val) {} + Index operator[](Index) const { return m_value; } + Index size() const { return 1; } + Index m_value; +}; + +// Turn a single index into something that looks like an array (i.e., that exposes a .size(), and operatro[](int) methods) +template +struct MakeIndexing::value>::type> { + // Here we could simply use Array, but maybe it's less work for the compiler to use + // a simpler wrapper as IntAsArray + //typedef Eigen::Array type; + typedef IntAsArray type; +}; + +// Replace symbolic last/end "keywords" by their true runtime value +Index symbolic2value(Index x, Index /* size */) { return x; } +Index symbolic2value(last_t, Index size) { return size-1; } +Index symbolic2value(shifted_last x, Index size) { return size+x.offset-1; } +Index symbolic2value(end_t, Index size) { return size; } +Index symbolic2value(shifted_end x, Index size) { return size+x.offset; } + +// Convert a symbolic range into a usable one (i.e., remove last/end "keywords") +template +struct MakeIndexing > { + typedef Range_t type; +}; + +template +Range_t make_indexing(const Range_t& ids, Index size) { + return Range_t(symbolic2value(ids.m_first,size),symbolic2value(ids.m_last,size),ids.m_step); +} + +// Convert a symbolic span into a usable one (i.e., remove last/end "keywords") +template +struct MakeIndexing > { + typedef Span_t type; +}; + +template +Span_t make_indexing(const Span_t& ids, Index size) { + return Span_t(symbolic2value(ids.m_first,size),ids.m_size,ids.m_step); +} + +// Convert a symbolic 'all' into a usable range +// Implementation-wise, it would be more efficient to not having to store m_size since +// this information is already in the nested expression. To this end, we would need a +// get_size(indices, underlying_size); function returning indices.size() by default. +struct AllRange { + AllRange(Index size) : m_size(size) {} + Index operator[](Index i) const { return i; } + Index size() const { return m_size; } + Index m_size; +}; + +template<> +struct MakeIndexing { + typedef AllRange type; +}; + +AllRange make_indexing(all_t , Index size) { + return AllRange(size); +} + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_ARITHMETIC_SEQUENCE_H diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index 9f3c7c8a9..f8a6b2625 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -557,6 +557,15 @@ template class DenseBase } EIGEN_DEVICE_FUNC void reverseInPlace(); + template + typename internal::enable_if< + !(internal::is_integral::value && internal::is_integral::value), + IndexedView::type,typename internal::MakeIndexing::type> >::type + operator()(const RowIndices& rowIndices, const ColIndices& colIndices) const { + return IndexedView::type,typename internal::MakeIndexing::type>( + derived(), internal::make_indexing(rowIndices,derived().rows()), internal::make_indexing(colIndices,derived().cols())); + } + #define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::DenseBase #define EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL #define EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(COND) diff --git a/Eigen/src/Core/IndexedView.h b/Eigen/src/Core/IndexedView.h new file mode 100644 index 000000000..e11739a99 --- /dev/null +++ b/Eigen/src/Core/IndexedView.h @@ -0,0 +1,137 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2017 Gael Guennebaud +// +// 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_INDEXED_VIEW_H +#define EIGEN_INDEXED_VIEW_H + +namespace Eigen { + +namespace internal { + +template +struct traits > + : traits +{ + enum { + FlagsLvalueBit = is_lvalue::value ? LvalueBit : 0, + Flags = traits::Flags & (RowMajorBit | FlagsLvalueBit /*| DirectAccessBit*/), + //MatrixTypeInnerStride = inner_stride_at_compile_time::ret, + InnerStrideAtCompileTime = int(Dynamic), + OuterStrideAtCompileTime = int(Dynamic) + }; +}; + +} + +template +class IndexedViewImpl; + +// Expression of a generic slice +template +class IndexedView : public IndexedViewImpl::StorageKind> +{ +public: + typedef typename IndexedViewImpl::StorageKind>::Base Base; + EIGEN_GENERIC_PUBLIC_INTERFACE(IndexedView) + + typedef typename internal::ref_selector::non_const_type MatrixTypeNested; + typedef typename internal::remove_all::type NestedExpression; + + template + IndexedView(XprType& xpr, const T0& rowIndices, const T1& colIndices) + : m_xpr(xpr), m_rowIndices(rowIndices), m_colIndices(colIndices) + {} + Index rows() const { return m_rowIndices.size(); } + Index cols() const { return m_colIndices.size(); } + + /** \returns the nested expression */ + const typename internal::remove_all::type& + nestedExpression() const { return m_xpr; } + + /** \returns the nested expression */ + typename internal::remove_reference::type& + nestedExpression() { return m_xpr.const_cast_derived(); } + + const RowIndices& rowIndices() const { return m_rowIndices; } + const ColIndices& colIndices() const { return m_colIndices; } + +// std::pair index(Index i, Index j) const { +// return std::pair(m_rowIndices[i], m_colIndices[j]); +// } +// +// void print() const { +// for(Index i=0; i k = index(i,j); +// std::cout << '(' << k.first << ',' << k.second << ") "; +// } +// std::cout << '\n'; +// } +// } +protected: + MatrixTypeNested m_xpr; + RowIndices m_rowIndices; + ColIndices m_colIndices; +}; + + +// Generic API dispatcher +template +class IndexedViewImpl + : public internal::generic_xpr_base >::type +{ +public: + typedef typename internal::generic_xpr_base >::type Base; +}; + +namespace internal { + + +template +struct unary_evaluator, IndexBased> + : evaluator_base > +{ + typedef IndexedView XprType; + + enum { + CoeffReadCost = evaluator::CoeffReadCost /* + cost of row/col index */, + + Flags = (evaluator::Flags & (HereditaryBits /*| LinearAccessBit | DirectAccessBit*/)), + + Alignment = 0 + }; + + EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& xpr) : m_argImpl(xpr.nestedExpression()), m_xpr(xpr) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + return m_argImpl.coeff(m_xpr.rowIndices()[row], m_xpr.colIndices()[col]); + } + +protected: + + evaluator m_argImpl; + const XprType& m_xpr; + +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_INDEXED_VIEW_H diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h index ea107393a..1a48cff04 100644 --- a/Eigen/src/Core/util/ForwardDeclarations.h +++ b/Eigen/src/Core/util/ForwardDeclarations.h @@ -83,6 +83,7 @@ template class ForceAlignedAccess; template class SwapWrapper; template class Block; +template class IndexedView; template class VectorBlock; template class Transpose; From 60e99ad8d76c167a48dab82d2fc16a87956fd7a4 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 6 Jan 2017 11:59:08 +0100 Subject: [PATCH 02/65] Add unit test for indexed views --- test/CMakeLists.txt | 1 + test/indexed_view.cpp | 107 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 test/indexed_view.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index e17985107..921d9688c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -161,6 +161,7 @@ ei_add_test(redux) ei_add_test(visitor) ei_add_test(block) ei_add_test(corners) +ei_add_test(indexed_view) ei_add_test(swap) ei_add_test(resize) ei_add_test(conservative_resize) diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp new file mode 100644 index 000000000..1bb2b4256 --- /dev/null +++ b/test/indexed_view.cpp @@ -0,0 +1,107 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2017 Gael Guennebaud +// +// 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/. + +#include +#include +#include "main.h" + +typedef std::pair IndexPair; + +Index encode(Index i, Index j) { + return i*100 + j; +} + +IndexPair decode(Index ij) { + return IndexPair(ij / 100, ij % 100); +} + +template +bool match(const T& xpr, std::string ref, std::string str_xpr = "") { + std::cout << str_xpr << "\n" << xpr << "\n\n"; + std::stringstream str; + str << xpr; + return str.str() == ref; +} + +#define MATCH(X,R) match(X, R, #X) + +void check_indexed_view() +{ + Index n = 10; + + ArrayXXi A = ArrayXXi::NullaryExpr(n,n, std::ptr_fun(encode)); + + for(Index i=0; i vala(10); Map(&vala[0],10) = eia; + std::valarray vali(4); Map(&vali[0],4) = eii; + std::vector veci(4); Map(veci.data(),4) = eii; + + VERIFY( MATCH( A(3, range(9,3,-1)), + "309 308 307 306 305 304 303") + ); + + VERIFY( MATCH( A(span(2,5), range(9,3,-1)), + "209 208 207 206 205 204 203\n" + "309 308 307 306 305 304 303\n" + "409 408 407 406 405 404 403\n" + "509 508 507 506 505 504 503\n" + "609 608 607 606 605 604 603") + ); + + VERIFY( MATCH( A(span(2,5), 5), + "205\n" + "305\n" + "405\n" + "505\n" + "605") + ); + + VERIFY( MATCH( A(span(last,5,-1), range(2,last)), + "902 903 904 905 906 907 908 909\n" + "802 803 804 805 806 807 808 809\n" + "702 703 704 705 706 707 708 709\n" + "602 603 604 605 606 607 608 609\n" + "502 503 504 505 506 507 508 509") + ); + + VERIFY( MATCH( A(eii, veci), + "303 301 306 305\n" + "103 101 106 105\n" + "603 601 606 605\n" + "503 501 506 505") + ); + + VERIFY( MATCH( A(eii, all), + "300 301 302 303 304 305 306 307 308 309\n" + "100 101 102 103 104 105 106 107 108 109\n" + "600 601 602 603 604 605 606 607 608 609\n" + "500 501 502 503 504 505 506 507 508 509") + ); + // takes the row numer 3, and repeat it 5 times + VERIFY( MATCH( A(span(3,5,0), all), + "300 301 302 303 304 305 306 307 308 309\n" + "300 301 302 303 304 305 306 307 308 309\n" + "300 301 302 303 304 305 306 307 308 309\n" + "300 301 302 303 304 305 306 307 308 309\n" + "300 301 302 303 304 305 306 307 308 309") + ); + +} + +void test_indexed_view() +{ +// for(int i = 0; i < g_repeat; i++) { + CALL_SUBTEST_1( check_indexed_view() ); +// } +} From 3730e3ca9ec8e256b76c08fb4b1e928c62f37b40 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 6 Jan 2017 13:10:10 +0100 Subject: [PATCH 03/65] Use "fix" for compile-time values, propagate compile-time sizes for span, clean some cleanup. --- Eigen/src/Core/ArithmeticSequence.h | 134 +++++++++++++++++----------- Eigen/src/Core/IndexedView.h | 13 ++- test/indexed_view.cpp | 15 +++- 3 files changed, 106 insertions(+), 56 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 3439a2586..1e7812c8c 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -12,6 +12,9 @@ namespace Eigen { +//-------------------------------------------------------------------------------- +// Pseudo keywords: all, last, end +//-------------------------------------------------------------------------------- struct all_t { all_t() {} }; static const all_t all; @@ -51,32 +54,55 @@ struct end_t { }; static const end_t end; -template struct Index_c { +//-------------------------------------------------------------------------------- +// integral constant +//-------------------------------------------------------------------------------- + +template struct fix_t { static const int value = N; operator int() const { return value; } - Index_c (Index_c (*)() ) {} - Index_c() {} - // Needed in C++14 to allow c(): - Index_c operator() () const { return *this; } + fix_t (fix_t (*)() ) {} + fix_t() {} + // Needed in C++14 to allow fix(): + fix_t operator() () const { return *this; } }; +template struct get_compile_time { + enum { value = Default }; +}; + +template struct get_compile_time,Default> { + enum { value = N }; +}; + +template struct is_compile_time { enum { value = false }; }; +template struct is_compile_time > { enum { value = true }; }; + +#if __cplusplus > 201103L +template +static const fix_t fix{}; +#else +template +inline fix_t fix() { return fix_t(); } +#endif + //-------------------------------------------------------------------------------- -// Range(first,last) and Slice(first,step,last) +// range(first,last,incr) and span(first,size,incr) //-------------------------------------------------------------------------------- -template > +template > struct Range_t { Range_t(FirstType f, LastType l) : m_first(f), m_last(l) {} - Range_t(FirstType f, LastType l, StepType s) : m_first(f), m_last(l), m_step(s) {} + Range_t(FirstType f, LastType l, IncrType s) : m_first(f), m_last(l), m_incr(s) {} FirstType m_first; LastType m_last; - StepType m_step; + IncrType m_incr; enum { SizeAtCompileTime = -1 }; - Index size() const { return (m_last-m_first+m_step)/m_step; } - Index operator[] (Index k) const { return m_first + k*m_step; } + Index size() const { return (m_last-m_first+m_incr)/m_incr; } + Index operator[] (Index k) const { return m_first + k*m_incr; } }; template struct cleanup_slice_type { typedef Index type; }; @@ -84,8 +110,8 @@ template<> struct cleanup_slice_type { typedef last_t type; }; template<> struct cleanup_slice_type { typedef shifted_last type; }; template<> struct cleanup_slice_type { typedef end_t type; }; template<> struct cleanup_slice_type { typedef shifted_end type; }; -template struct cleanup_slice_type > { typedef Index_c type; }; -template struct cleanup_slice_type (*)() > { typedef Index_c type; }; +template struct cleanup_slice_type > { typedef fix_t type; }; +template struct cleanup_slice_type (*)() > { typedef fix_t type; }; template Range_t::type,typename cleanup_slice_type::type > @@ -93,43 +119,34 @@ range(FirstType f, LastType l) { return Range_t::type,typename cleanup_slice_type::type>(f,l); } -template -Range_t::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type > -range(FirstType f, LastType l, StepType s) { - return Range_t::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type>(f,l,typename cleanup_slice_type::type(s)); +template +Range_t::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type > +range(FirstType f, LastType l, IncrType s) { + return Range_t::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type>(f,l,typename cleanup_slice_type::type(s)); } -template struct get_compile_time { - enum { value = Default }; -}; -template struct get_compile_time,Default> { - enum { value = N }; -}; -template struct is_compile_time { enum { value = false }; }; -template struct is_compile_time > { enum { value = true }; }; - -template > +template > struct Span_t { Span_t(FirstType first, SizeType size) : m_first(first), m_size(size) {} - Span_t(FirstType first, SizeType size, StepType step) : m_first(first), m_size(size), m_step(step) {} + Span_t(FirstType first, SizeType size, IncrType incr) : m_first(first), m_size(size), m_incr(incr) {} FirstType m_first; SizeType m_size; - StepType m_step; + IncrType m_incr; enum { SizeAtCompileTime = get_compile_time::value }; Index size() const { return m_size; } - Index operator[] (Index k) const { return m_first + k*m_step; } + Index operator[] (Index k) const { return m_first + k*m_incr; } }; -template -Span_t::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type > -span(FirstType first, SizeType size, StepType step) { - return Span_t::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type>(first,size,step); +template +Span_t::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type > +span(FirstType first, SizeType size, IncrType incr) { + return Span_t::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type>(first,size,incr); } template @@ -138,16 +155,24 @@ span(FirstType first, SizeType size) { return Span_t::type,typename cleanup_slice_type::type>(first,size); } -#if __cplusplus > 201103L -template -static const Index_c c{}; -#else -template -inline Index_c c() { return Index_c(); } -#endif + namespace internal { +template struct get_compile_time_size { + enum { value = -1 }; +}; + +template struct get_compile_time_size::type> { + enum { value = T::SizeAtCompileTime }; +}; + +#ifdef EIGEN_HAS_CXX11 +template struct get_compile_time_size > { + enum { value = N }; +}; +#endif + // MakeIndexing/make_indexing turn an arbitrary object of type T into something usable by MatrixSlice template struct MakeIndexing { @@ -158,6 +183,9 @@ template const T& make_indexing(const T& x, Index size) { return x; } struct IntAsArray { + enum { + SizeAtCompileTime = 1 + }; IntAsArray(Index val) : m_value(val) {} Index operator[](Index) const { return m_value; } Index size() const { return 1; } @@ -181,25 +209,25 @@ Index symbolic2value(end_t, Index size) { return size; } Index symbolic2value(shifted_end x, Index size) { return size+x.offset; } // Convert a symbolic range into a usable one (i.e., remove last/end "keywords") -template -struct MakeIndexing > { - typedef Range_t type; +template +struct MakeIndexing > { + typedef Range_t type; }; -template -Range_t make_indexing(const Range_t& ids, Index size) { - return Range_t(symbolic2value(ids.m_first,size),symbolic2value(ids.m_last,size),ids.m_step); +template +Range_t make_indexing(const Range_t& ids, Index size) { + return Range_t(symbolic2value(ids.m_first,size),symbolic2value(ids.m_last,size),ids.m_incr); } // Convert a symbolic span into a usable one (i.e., remove last/end "keywords") -template -struct MakeIndexing > { - typedef Span_t type; +template +struct MakeIndexing > { + typedef Span_t type; }; -template -Span_t make_indexing(const Span_t& ids, Index size) { - return Span_t(symbolic2value(ids.m_first,size),ids.m_size,ids.m_step); +template +Span_t make_indexing(const Span_t& ids, Index size) { + return Span_t(symbolic2value(ids.m_first,size),ids.m_size,ids.m_incr); } // Convert a symbolic 'all' into a usable range diff --git a/Eigen/src/Core/IndexedView.h b/Eigen/src/Core/IndexedView.h index e11739a99..7fc856feb 100644 --- a/Eigen/src/Core/IndexedView.h +++ b/Eigen/src/Core/IndexedView.h @@ -19,8 +19,19 @@ struct traits > : traits { enum { + RowsAtCompileTime = get_compile_time_size::value, + ColsAtCompileTime = get_compile_time_size::value, + MaxRowsAtCompileTime = RowsAtCompileTime != Dynamic ? int(RowsAtCompileTime) : int(traits::MaxRowsAtCompileTime), + MaxColsAtCompileTime = ColsAtCompileTime != Dynamic ? int(ColsAtCompileTime) : int(traits::MaxColsAtCompileTime), + + XprTypeIsRowMajor = (int(traits::Flags)&RowMajorBit) != 0, + IsRowMajor = (MaxRowsAtCompileTime==1&&MaxColsAtCompileTime!=1) ? 1 + : (MaxColsAtCompileTime==1&&MaxRowsAtCompileTime!=1) ? 0 + : XprTypeIsRowMajor, + + FlagsRowMajorBit = IsRowMajor ? RowMajorBit : 0, FlagsLvalueBit = is_lvalue::value ? LvalueBit : 0, - Flags = traits::Flags & (RowMajorBit | FlagsLvalueBit /*| DirectAccessBit*/), + Flags = (traits::Flags & HereditaryBits) | FlagsLvalueBit | FlagsRowMajorBit, //MatrixTypeInnerStride = inner_stride_at_compile_time::ret, InnerStrideAtCompileTime = int(Dynamic), OuterStrideAtCompileTime = int(Dynamic) diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index 1bb2b4256..0be5e434c 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -13,8 +13,8 @@ typedef std::pair IndexPair; -Index encode(Index i, Index j) { - return i*100 + j; +int encode(Index i, Index j) { + return int(i*100 + j); } IndexPair decode(Index ij) { @@ -97,6 +97,17 @@ void check_indexed_view() "300 301 302 303 304 305 306 307 308 309") ); + Array44i B; + VERIFY( (A(span(2,5), 5)).ColsAtCompileTime == 1); + VERIFY( (A(span(2,5), 5)).RowsAtCompileTime == Dynamic); + VERIFY( (A(span(2,fix<5>), 5)).RowsAtCompileTime == 5); + VERIFY( (A(4, all)).ColsAtCompileTime == Dynamic); + VERIFY( (A(4, all)).RowsAtCompileTime == 1); + VERIFY( (B(1, all)).ColsAtCompileTime == 4); + VERIFY( (B(1, all)).RowsAtCompileTime == 1); + VERIFY( (B(all,1)).ColsAtCompileTime == 1); + VERIFY( (B(all,1)).RowsAtCompileTime == 4); + } void test_indexed_view() From fad1fa75b32ccd3a19fc783a0c660ca512283224 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 6 Jan 2017 13:29:33 +0100 Subject: [PATCH 04/65] Propagate compile-time size with "all" and add c++11 array unit test --- Eigen/src/Core/ArithmeticSequence.h | 10 +++++++--- Eigen/src/Core/IndexedView.h | 4 ++-- test/indexed_view.cpp | 11 +++++++++++ 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 1e7812c8c..06b6b53eb 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -159,16 +159,16 @@ span(FirstType first, SizeType size) { namespace internal { -template struct get_compile_time_size { +template struct get_compile_time_size { enum { value = -1 }; }; -template struct get_compile_time_size::type> { +template struct get_compile_time_size::type> { enum { value = T::SizeAtCompileTime }; }; #ifdef EIGEN_HAS_CXX11 -template struct get_compile_time_size > { +template struct get_compile_time_size,XprSize> { enum { value = N }; }; #endif @@ -250,6 +250,10 @@ AllRange make_indexing(all_t , Index size) { return AllRange(size); } +template struct get_compile_time_size { + enum { value = XprSize }; +}; + } // end namespace internal } // end namespace Eigen diff --git a/Eigen/src/Core/IndexedView.h b/Eigen/src/Core/IndexedView.h index 7fc856feb..bc1eff8f9 100644 --- a/Eigen/src/Core/IndexedView.h +++ b/Eigen/src/Core/IndexedView.h @@ -19,8 +19,8 @@ struct traits > : traits { enum { - RowsAtCompileTime = get_compile_time_size::value, - ColsAtCompileTime = get_compile_time_size::value, + RowsAtCompileTime = get_compile_time_size::RowsAtCompileTime>::value, + ColsAtCompileTime = get_compile_time_size::ColsAtCompileTime>::value, MaxRowsAtCompileTime = RowsAtCompileTime != Dynamic ? int(RowsAtCompileTime) : int(traits::MaxRowsAtCompileTime), MaxColsAtCompileTime = ColsAtCompileTime != Dynamic ? int(ColsAtCompileTime) : int(traits::MaxColsAtCompileTime), diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index 0be5e434c..5d8ce16ee 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -11,6 +11,10 @@ #include #include "main.h" +#if EIGEN_HAS_CXX11 +#include +#endif + typedef std::pair IndexPair; int encode(Index i, Index j) { @@ -108,6 +112,13 @@ void check_indexed_view() VERIFY( (B(all,1)).ColsAtCompileTime == 1); VERIFY( (B(all,1)).RowsAtCompileTime == 4); + VERIFY( (A(all, eii)).ColsAtCompileTime == eii.SizeAtCompileTime); +#if EIGEN_HAS_CXX11 + VERIFY( (A(all, std::array{{1,3,2,4}})).ColsAtCompileTime == 4); + + VERIFY_IS_APPROX( (A(std::array{{1,3,5}}, std::array{{9,6,3,0}})), A(span(1,3,2), span(9,4,-3)) ); +#endif + } void test_indexed_view() From a875167d99cffa76a662de5475627d60238f0f36 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 6 Jan 2017 15:54:55 +0100 Subject: [PATCH 05/65] Propagate compile-time increment and strides. Had to introduce a UndefinedIncr constant for non structured list of indices. --- Eigen/src/Core/ArithmeticSequence.h | 27 ++++++++++++++++++++-- Eigen/src/Core/IndexedView.h | 35 +++++++++++++---------------- Eigen/src/Core/util/Constants.h | 4 ++++ test/indexed_view.cpp | 27 +++++++++++++++++++++- 4 files changed, 71 insertions(+), 22 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 06b6b53eb..1585c1dbf 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -160,7 +160,7 @@ span(FirstType first, SizeType size) { namespace internal { template struct get_compile_time_size { - enum { value = -1 }; + enum { value = Dynamic }; }; template struct get_compile_time_size::type> { @@ -173,6 +173,21 @@ template struct get_compile_time_size struct get_compile_time_incr { + enum { value = UndefinedIncr }; +}; + +template +struct get_compile_time_incr > { + enum { value = get_compile_time::value }; +}; + +template +struct get_compile_time_incr > { + enum { value = get_compile_time::value }; +}; + + // MakeIndexing/make_indexing turn an arbitrary object of type T into something usable by MatrixSlice template struct MakeIndexing { @@ -180,7 +195,7 @@ struct MakeIndexing { }; template -const T& make_indexing(const T& x, Index size) { return x; } +const T& make_indexing(const T& x, Index /*size*/) { return x; } struct IntAsArray { enum { @@ -192,6 +207,10 @@ struct IntAsArray { Index m_value; }; +template<> struct get_compile_time_incr { + enum { value = 1 }; // 1 or 0 ?? +}; + // Turn a single index into something that looks like an array (i.e., that exposes a .size(), and operatro[](int) methods) template struct MakeIndexing::value>::type> { @@ -254,6 +273,10 @@ template struct get_compile_time_size { enum { value = XprSize }; }; +template<> struct get_compile_time_incr { + enum { value = 1 }; +}; + } // end namespace internal } // end namespace Eigen diff --git a/Eigen/src/Core/IndexedView.h b/Eigen/src/Core/IndexedView.h index bc1eff8f9..26c048584 100644 --- a/Eigen/src/Core/IndexedView.h +++ b/Eigen/src/Core/IndexedView.h @@ -29,12 +29,24 @@ struct traits > : (MaxColsAtCompileTime==1&&MaxRowsAtCompileTime!=1) ? 0 : XprTypeIsRowMajor, + RowIncr = get_compile_time_incr::value, + ColIncr = get_compile_time_incr::value, + InnerIncr = IsRowMajor ? ColIncr : RowIncr, + OuterIncr = IsRowMajor ? RowIncr : ColIncr, + + HasSameStorageOrderAsXprType = (IsRowMajor == XprTypeIsRowMajor), + XprInnerStride = HasSameStorageOrderAsXprType ? int(inner_stride_at_compile_time::ret) : int(outer_stride_at_compile_time::ret), + XprOuterstride = HasSameStorageOrderAsXprType ? int(outer_stride_at_compile_time::ret) : int(inner_stride_at_compile_time::ret), + + InnerStrideAtCompileTime = InnerIncr<0 || InnerIncr==DynamicIndex || XprInnerStride==Dynamic ? Dynamic : XprInnerStride * InnerIncr, + OuterStrideAtCompileTime = OuterIncr<0 || OuterIncr==DynamicIndex || XprOuterstride==Dynamic ? Dynamic : XprOuterstride * OuterIncr, + + // 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, FlagsRowMajorBit = IsRowMajor ? RowMajorBit : 0, FlagsLvalueBit = is_lvalue::value ? LvalueBit : 0, - Flags = (traits::Flags & HereditaryBits) | FlagsLvalueBit | FlagsRowMajorBit, - //MatrixTypeInnerStride = inner_stride_at_compile_time::ret, - InnerStrideAtCompileTime = int(Dynamic), - OuterStrideAtCompileTime = int(Dynamic) + Flags = (traits::Flags & (HereditaryBits | DirectAccessMask)) | FlagsLvalueBit | FlagsRowMajorBit }; }; @@ -72,21 +84,6 @@ public: const RowIndices& rowIndices() const { return m_rowIndices; } const ColIndices& colIndices() const { return m_colIndices; } -// std::pair index(Index i, Index j) const { -// return std::pair(m_rowIndices[i], m_colIndices[j]); -// } -// -// void print() const { -// for(Index i=0; i k = index(i,j); -// std::cout << '(' << k.first << ',' << k.second << ") "; -// } -// std::cout << '\n'; -// } -// } protected: MatrixTypeNested m_xpr; RowIndices m_rowIndices; diff --git a/Eigen/src/Core/util/Constants.h b/Eigen/src/Core/util/Constants.h index 7587d6842..5d37e5d04 100644 --- a/Eigen/src/Core/util/Constants.h +++ b/Eigen/src/Core/util/Constants.h @@ -25,6 +25,10 @@ const int Dynamic = -1; */ const int DynamicIndex = 0xffffff; +/** This value means that the increment to go from one value to another in a sequence is not constant for each step. + */ +const int UndefinedIncr = 0xfffffe; + /** This value means +Infinity; it is currently used only as the p parameter to MatrixBase::lpNorm(). * The value Infinity there means the L-infinity norm. */ diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index 5d8ce16ee..bc69adf13 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -27,7 +27,8 @@ IndexPair decode(Index ij) { template bool match(const T& xpr, std::string ref, std::string str_xpr = "") { - std::cout << str_xpr << "\n" << xpr << "\n\n"; + EIGEN_UNUSED_VARIABLE(str_xpr); + //std::cout << str_xpr << "\n" << xpr << "\n\n"; std::stringstream str; str << xpr; return str.str() == ref; @@ -102,8 +103,28 @@ void check_indexed_view() ); Array44i B; + B.setRandom(); VERIFY( (A(span(2,5), 5)).ColsAtCompileTime == 1); VERIFY( (A(span(2,5), 5)).RowsAtCompileTime == Dynamic); + VERIFY_IS_EQUAL( (A(span(2,5), 5)).InnerStrideAtCompileTime , A.InnerStrideAtCompileTime); + VERIFY_IS_EQUAL( (A(span(2,5), 5)).OuterStrideAtCompileTime , A.col(5).OuterStrideAtCompileTime); + + VERIFY_IS_EQUAL( (A(5,span(2,5))).InnerStrideAtCompileTime , A.row(5).InnerStrideAtCompileTime); + VERIFY_IS_EQUAL( (A(5,span(2,5))).OuterStrideAtCompileTime , A.row(5).OuterStrideAtCompileTime); + VERIFY_IS_EQUAL( (B(1,span(1,2))).InnerStrideAtCompileTime , B.row(1).InnerStrideAtCompileTime); + VERIFY_IS_EQUAL( (B(1,span(1,2))).OuterStrideAtCompileTime , B.row(1).OuterStrideAtCompileTime); + + VERIFY_IS_EQUAL( (A(span(2,5), range(1,3))).InnerStrideAtCompileTime , A.InnerStrideAtCompileTime); + VERIFY_IS_EQUAL( (A(span(2,5), range(1,3))).OuterStrideAtCompileTime , A.OuterStrideAtCompileTime); + VERIFY_IS_EQUAL( (B(span(1,2), range(1,3))).InnerStrideAtCompileTime , B.InnerStrideAtCompileTime); + VERIFY_IS_EQUAL( (B(span(1,2), range(1,3))).OuterStrideAtCompileTime , B.OuterStrideAtCompileTime); + VERIFY_IS_EQUAL( (A(span(2,5,2), range(1,3,2))).InnerStrideAtCompileTime , Dynamic); + VERIFY_IS_EQUAL( (A(span(2,5,2), range(1,3,2))).OuterStrideAtCompileTime , Dynamic); + VERIFY_IS_EQUAL( (A(span(2,5,fix<2>), range(1,3,fix<3>))).InnerStrideAtCompileTime , 2); + VERIFY_IS_EQUAL( (A(span(2,5,fix<2>), range(1,3,fix<3>))).OuterStrideAtCompileTime , Dynamic); + VERIFY_IS_EQUAL( (B(span(1,2,fix<2>), range(1,3,fix<3>))).InnerStrideAtCompileTime , 2); + VERIFY_IS_EQUAL( (B(span(1,2,fix<2>), range(1,3,fix<3>))).OuterStrideAtCompileTime , 3*4); + VERIFY( (A(span(2,fix<5>), 5)).RowsAtCompileTime == 5); VERIFY( (A(4, all)).ColsAtCompileTime == Dynamic); VERIFY( (A(4, all)).RowsAtCompileTime == 1); @@ -113,6 +134,10 @@ void check_indexed_view() VERIFY( (B(all,1)).RowsAtCompileTime == 4); VERIFY( (A(all, eii)).ColsAtCompileTime == eii.SizeAtCompileTime); + VERIFY_IS_EQUAL( (A(eii, eii)).Flags&DirectAccessBit, (unsigned int)(0)); + VERIFY_IS_EQUAL( (A(eii, eii)).InnerStrideAtCompileTime, 0); + VERIFY_IS_EQUAL( (A(eii, eii)).OuterStrideAtCompileTime, 0); + #if EIGEN_HAS_CXX11 VERIFY( (A(all, std::array{{1,3,2,4}})).ColsAtCompileTime == 4); From 3264d3c761e6b08101e7577b4278119dea42ec09 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 6 Jan 2017 21:53:32 +0100 Subject: [PATCH 06/65] Add support for plain-array as indices, e.g., mat({1,2,3,4}) --- Eigen/src/Core/ArithmeticSequence.h | 6 ++++++ Eigen/src/Core/DenseBase.h | 7 +++++++ Eigen/src/Core/IndexedView.h | 4 ++-- test/indexed_view.cpp | 8 ++++++++ 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 1585c1dbf..bfc586a61 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -159,6 +159,12 @@ span(FirstType first, SizeType size) { namespace internal { +template +Index size(const T& x) { return x.size(); } + +template +Index size(const T (&x) [N]) { return N; } + template struct get_compile_time_size { enum { value = Dynamic }; }; diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index f8a6b2625..13aa3854a 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -566,6 +566,13 @@ template class DenseBase derived(), internal::make_indexing(rowIndices,derived().rows()), internal::make_indexing(colIndices,derived().cols())); } + template + IndexedView::type> + operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndices& colIndices) const { + return IndexedView::type>( + derived(), rowIndices, internal::make_indexing(colIndices,derived().cols())); + } + #define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::DenseBase #define EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL #define EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(COND) diff --git a/Eigen/src/Core/IndexedView.h b/Eigen/src/Core/IndexedView.h index 26c048584..5ff1c1837 100644 --- a/Eigen/src/Core/IndexedView.h +++ b/Eigen/src/Core/IndexedView.h @@ -70,8 +70,8 @@ public: IndexedView(XprType& xpr, const T0& rowIndices, const T1& colIndices) : m_xpr(xpr), m_rowIndices(rowIndices), m_colIndices(colIndices) {} - Index rows() const { return m_rowIndices.size(); } - Index cols() const { return m_colIndices.size(); } + Index rows() const { return internal::size(m_rowIndices); } + Index cols() const { return internal::size(m_colIndices); } /** \returns the nested expression */ const typename internal::remove_all::type& diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index bc69adf13..4ab1a5251 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -93,6 +93,7 @@ void check_indexed_view() "600 601 602 603 604 605 606 607 608 609\n" "500 501 502 503 504 505 506 507 508 509") ); + // takes the row numer 3, and repeat it 5 times VERIFY( MATCH( A(span(3,5,0), all), "300 301 302 303 304 305 306 307 308 309\n" @@ -138,10 +139,17 @@ void check_indexed_view() VERIFY_IS_EQUAL( (A(eii, eii)).InnerStrideAtCompileTime, 0); VERIFY_IS_EQUAL( (A(eii, eii)).OuterStrideAtCompileTime, 0); + + #if EIGEN_HAS_CXX11 VERIFY( (A(all, std::array{{1,3,2,4}})).ColsAtCompileTime == 4); VERIFY_IS_APPROX( (A(std::array{{1,3,5}}, std::array{{9,6,3,0}})), A(span(1,3,2), span(9,4,-3)) ); + +#if (!EIGEN_COMP_CLANG) || (EIGEN_COMP_CLANG>=308 && !defined(__apple_build_version__)) + VERIFY_IS_APPROX( A({3, 1, 6, 5}, all), A(std::array{{3, 1, 6, 5}}, all) ); +#endif + #endif } From 76e183bd52b5b008c32c2e07428f9672ab8e1c6f Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 6 Jan 2017 22:01:23 +0100 Subject: [PATCH 07/65] Propagate compile-time size for plain arrays --- Eigen/src/Core/ArithmeticSequence.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index bfc586a61..efab2d631 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -173,6 +173,10 @@ template struct get_compile_time_size struct get_compile_time_size { + enum { value = N }; +}; + #ifdef EIGEN_HAS_CXX11 template struct get_compile_time_size,XprSize> { enum { value = N }; From 233dff1b3505dcf0592f11a82ac442b28c577f87 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 6 Jan 2017 22:01:53 +0100 Subject: [PATCH 08/65] Add support for plain arrays for columns and both rows/columns --- Eigen/src/Core/DenseBase.h | 16 +++++++++++++++- test/indexed_view.cpp | 5 +++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index 13aa3854a..07057ce69 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -569,10 +569,24 @@ template class DenseBase template IndexedView::type> operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndices& colIndices) const { - return IndexedView::type>( + return IndexedView::type>( derived(), rowIndices, internal::make_indexing(colIndices,derived().cols())); } + template + IndexedView::type, const ColIndicesT (&)[ColIndicesN]> + operator()(const RowIndices& rowIndices, const ColIndicesT (&colIndices)[ColIndicesN]) const { + return IndexedView::type,const ColIndicesT (&)[ColIndicesN]>( + derived(), internal::make_indexing(rowIndices,derived().rows()), colIndices); + } + + template + IndexedView + operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndicesT (&colIndices)[ColIndicesN]) const { + return IndexedView( + derived(), rowIndices, colIndices); + } + #define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::DenseBase #define EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL #define EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(COND) diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index 4ab1a5251..5372a3a90 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -148,6 +148,11 @@ void check_indexed_view() #if (!EIGEN_COMP_CLANG) || (EIGEN_COMP_CLANG>=308 && !defined(__apple_build_version__)) VERIFY_IS_APPROX( A({3, 1, 6, 5}, all), A(std::array{{3, 1, 6, 5}}, all) ); + VERIFY_IS_APPROX( A(all,{3, 1, 6, 5}), A(all,std::array{{3, 1, 6, 5}}) ); + VERIFY_IS_APPROX( A({1,3,5},{3, 1, 6, 5}), A(std::array{{1,3,5}},std::array{{3, 1, 6, 5}}) ); + + VERIFY_IS_EQUAL( A({1,3,5},{3, 1, 6, 5}).RowsAtCompileTime, 3 ); + VERIFY_IS_EQUAL( A({1,3,5},{3, 1, 6, 5}).ColsAtCompileTime, 4 ); #endif #endif From 75aef5b37f17f780fdd42ccadd7e13a27a380771 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 6 Jan 2017 22:04:49 +0100 Subject: [PATCH 09/65] Fix extraction of compile-time size of std::array with gcc --- Eigen/src/Core/ArithmeticSequence.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index efab2d631..3b469ba6e 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -178,7 +178,7 @@ template struct get_compile_time_size struct get_compile_time_size,XprSize> { +template struct get_compile_time_size,XprSize> { enum { value = N }; }; #endif From 68064e14fac8c72c05faaeff98c1b70e2dae6ee7 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 9 Jan 2017 17:35:21 +0100 Subject: [PATCH 10/65] Rename span/range to seqN/seq --- Eigen/src/Core/ArithmeticSequence.h | 105 +++++++++++++++++----------- test/indexed_view.cpp | 52 +++++++------- 2 files changed, 88 insertions(+), 69 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 3b469ba6e..71301797a 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -87,22 +87,33 @@ inline fix_t fix() { return fix_t(); } #endif //-------------------------------------------------------------------------------- -// range(first,last,incr) and span(first,size,incr) +// seq(first,last,incr) and seqN(first,size,incr) //-------------------------------------------------------------------------------- -template > -struct Range_t { - Range_t(FirstType f, LastType l) : m_first(f), m_last(l) {} - Range_t(FirstType f, LastType l, IncrType s) : m_first(f), m_last(l), m_incr(s) {} +template > +class ArithemeticSequenceProxyWithBounds +{ +public: + ArithemeticSequenceProxyWithBounds(FirstType f, LastType l) : m_first(f), m_last(l) {} + ArithemeticSequenceProxyWithBounds(FirstType f, LastType l, IncrType s) : m_first(f), m_last(l), m_incr(s) {} + + enum { + SizeAtCompileTime = -1, + IncrAtCompileTime = get_compile_time::value + }; + + Index size() const { return (m_last-m_first+m_incr)/m_incr; } + Index operator[](Index i) const { return m_first + i * m_incr; } + + const FirstType& firstObject() const { return m_first; } + const LastType& lastObject() const { return m_last; } + const IncrType& incrObject() const { return m_incr; } + +protected: FirstType m_first; LastType m_last; IncrType m_incr; - - enum { SizeAtCompileTime = -1 }; - - Index size() const { return (m_last-m_first+m_incr)/m_incr; } - Index operator[] (Index k) const { return m_first + k*m_incr; } }; template struct cleanup_slice_type { typedef Index type; }; @@ -114,45 +125,55 @@ template struct cleanup_slice_type > { typedef fix_t type; }; template struct cleanup_slice_type (*)() > { typedef fix_t type; }; template -Range_t::type,typename cleanup_slice_type::type > -range(FirstType f, LastType l) { - return Range_t::type,typename cleanup_slice_type::type>(f,l); +ArithemeticSequenceProxyWithBounds::type,typename cleanup_slice_type::type > +seq(FirstType f, LastType l) { + return ArithemeticSequenceProxyWithBounds::type,typename cleanup_slice_type::type>(f,l); } template -Range_t::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type > -range(FirstType f, LastType l, IncrType s) { - return Range_t::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type>(f,l,typename cleanup_slice_type::type(s)); +ArithemeticSequenceProxyWithBounds::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type > +seq(FirstType f, LastType l, IncrType s) { + return ArithemeticSequenceProxyWithBounds::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type>(f,l,typename cleanup_slice_type::type(s)); } - - template > -struct Span_t { - Span_t(FirstType first, SizeType size) : m_first(first), m_size(size) {} - Span_t(FirstType first, SizeType size, IncrType incr) : m_first(first), m_size(size), m_incr(incr) {} +class ArithemeticSequenceProxyWithSize +{ +public: + ArithemeticSequenceProxyWithSize(FirstType first, SizeType size) : m_first(first), m_size(size) {} + ArithemeticSequenceProxyWithSize(FirstType first, SizeType size, IncrType incr) : m_first(first), m_size(size), m_incr(incr) {} + + enum { + SizeAtCompileTime = get_compile_time::value, + IncrAtCompileTime = get_compile_time::value + }; + + Index size() const { return m_size; } + Index operator[](Index i) const { return m_first + i * m_incr; } + + const FirstType& firstObject() const { return m_first; } + const SizeType& sizeObject() const { return m_size; } + const IncrType& incrObject() const { return m_incr; } + +protected: FirstType m_first; SizeType m_size; IncrType m_incr; - - enum { SizeAtCompileTime = get_compile_time::value }; - - Index size() const { return m_size; } - Index operator[] (Index k) const { return m_first + k*m_incr; } }; + template -Span_t::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type > -span(FirstType first, SizeType size, IncrType incr) { - return Span_t::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type>(first,size,incr); +ArithemeticSequenceProxyWithSize::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type > +seqN(FirstType first, SizeType size, IncrType incr) { + return ArithemeticSequenceProxyWithSize::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type>(first,size,incr); } template -Span_t::type,typename cleanup_slice_type::type > -span(FirstType first, SizeType size) { - return Span_t::type,typename cleanup_slice_type::type>(first,size); +ArithemeticSequenceProxyWithSize::type,typename cleanup_slice_type::type > +seqN(FirstType first, SizeType size) { + return ArithemeticSequenceProxyWithSize::type,typename cleanup_slice_type::type>(first,size); } @@ -188,12 +209,12 @@ template struct get_compile_time_incr { }; template -struct get_compile_time_incr > { +struct get_compile_time_incr > { enum { value = get_compile_time::value }; }; template -struct get_compile_time_incr > { +struct get_compile_time_incr > { enum { value = get_compile_time::value }; }; @@ -239,24 +260,24 @@ Index symbolic2value(shifted_end x, Index size) { return size+x.offset; } // Convert a symbolic range into a usable one (i.e., remove last/end "keywords") template -struct MakeIndexing > { - typedef Range_t type; +struct MakeIndexing > { + typedef ArithemeticSequenceProxyWithBounds type; }; template -Range_t make_indexing(const Range_t& ids, Index size) { - return Range_t(symbolic2value(ids.m_first,size),symbolic2value(ids.m_last,size),ids.m_incr); +ArithemeticSequenceProxyWithBounds make_indexing(const ArithemeticSequenceProxyWithBounds& ids, Index size) { + return ArithemeticSequenceProxyWithBounds(symbolic2value(ids.firstObject(),size),symbolic2value(ids.lastObject(),size),ids.incrObject()); } // Convert a symbolic span into a usable one (i.e., remove last/end "keywords") template -struct MakeIndexing > { - typedef Span_t type; +struct MakeIndexing > { + typedef ArithemeticSequenceProxyWithSize type; }; template -Span_t make_indexing(const Span_t& ids, Index size) { - return Span_t(symbolic2value(ids.m_first,size),ids.m_size,ids.m_incr); +ArithemeticSequenceProxyWithSize make_indexing(const ArithemeticSequenceProxyWithSize& ids, Index size) { + return ArithemeticSequenceProxyWithSize(symbolic2value(ids.firstObject(),size),ids.sizeObject(),ids.incrObject()); } // Convert a symbolic 'all' into a usable range diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index 5372a3a90..23ad2d743 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -52,11 +52,11 @@ void check_indexed_view() std::valarray vali(4); Map(&vali[0],4) = eii; std::vector veci(4); Map(veci.data(),4) = eii; - VERIFY( MATCH( A(3, range(9,3,-1)), + VERIFY( MATCH( A(3, seq(9,3,-1)), "309 308 307 306 305 304 303") ); - VERIFY( MATCH( A(span(2,5), range(9,3,-1)), + VERIFY( MATCH( A(seqN(2,5), seq(9,3,-1)), "209 208 207 206 205 204 203\n" "309 308 307 306 305 304 303\n" "409 408 407 406 405 404 403\n" @@ -64,7 +64,7 @@ void check_indexed_view() "609 608 607 606 605 604 603") ); - VERIFY( MATCH( A(span(2,5), 5), + VERIFY( MATCH( A(seqN(2,5), 5), "205\n" "305\n" "405\n" @@ -72,7 +72,7 @@ void check_indexed_view() "605") ); - VERIFY( MATCH( A(span(last,5,-1), range(2,last)), + VERIFY( MATCH( A(seqN(last,5,-1), seq(2,last)), "902 903 904 905 906 907 908 909\n" "802 803 804 805 806 807 808 809\n" "702 703 704 705 706 707 708 709\n" @@ -95,7 +95,7 @@ void check_indexed_view() ); // takes the row numer 3, and repeat it 5 times - VERIFY( MATCH( A(span(3,5,0), all), + VERIFY( MATCH( A(seqN(3,5,0), all), "300 301 302 303 304 305 306 307 308 309\n" "300 301 302 303 304 305 306 307 308 309\n" "300 301 302 303 304 305 306 307 308 309\n" @@ -105,28 +105,28 @@ void check_indexed_view() Array44i B; B.setRandom(); - VERIFY( (A(span(2,5), 5)).ColsAtCompileTime == 1); - VERIFY( (A(span(2,5), 5)).RowsAtCompileTime == Dynamic); - VERIFY_IS_EQUAL( (A(span(2,5), 5)).InnerStrideAtCompileTime , A.InnerStrideAtCompileTime); - VERIFY_IS_EQUAL( (A(span(2,5), 5)).OuterStrideAtCompileTime , A.col(5).OuterStrideAtCompileTime); + VERIFY( (A(seqN(2,5), 5)).ColsAtCompileTime == 1); + VERIFY( (A(seqN(2,5), 5)).RowsAtCompileTime == Dynamic); + VERIFY_IS_EQUAL( (A(seqN(2,5), 5)).InnerStrideAtCompileTime , A.InnerStrideAtCompileTime); + VERIFY_IS_EQUAL( (A(seqN(2,5), 5)).OuterStrideAtCompileTime , A.col(5).OuterStrideAtCompileTime); - VERIFY_IS_EQUAL( (A(5,span(2,5))).InnerStrideAtCompileTime , A.row(5).InnerStrideAtCompileTime); - VERIFY_IS_EQUAL( (A(5,span(2,5))).OuterStrideAtCompileTime , A.row(5).OuterStrideAtCompileTime); - VERIFY_IS_EQUAL( (B(1,span(1,2))).InnerStrideAtCompileTime , B.row(1).InnerStrideAtCompileTime); - VERIFY_IS_EQUAL( (B(1,span(1,2))).OuterStrideAtCompileTime , B.row(1).OuterStrideAtCompileTime); + VERIFY_IS_EQUAL( (A(5,seqN(2,5))).InnerStrideAtCompileTime , A.row(5).InnerStrideAtCompileTime); + VERIFY_IS_EQUAL( (A(5,seqN(2,5))).OuterStrideAtCompileTime , A.row(5).OuterStrideAtCompileTime); + VERIFY_IS_EQUAL( (B(1,seqN(1,2))).InnerStrideAtCompileTime , B.row(1).InnerStrideAtCompileTime); + VERIFY_IS_EQUAL( (B(1,seqN(1,2))).OuterStrideAtCompileTime , B.row(1).OuterStrideAtCompileTime); - VERIFY_IS_EQUAL( (A(span(2,5), range(1,3))).InnerStrideAtCompileTime , A.InnerStrideAtCompileTime); - VERIFY_IS_EQUAL( (A(span(2,5), range(1,3))).OuterStrideAtCompileTime , A.OuterStrideAtCompileTime); - VERIFY_IS_EQUAL( (B(span(1,2), range(1,3))).InnerStrideAtCompileTime , B.InnerStrideAtCompileTime); - VERIFY_IS_EQUAL( (B(span(1,2), range(1,3))).OuterStrideAtCompileTime , B.OuterStrideAtCompileTime); - VERIFY_IS_EQUAL( (A(span(2,5,2), range(1,3,2))).InnerStrideAtCompileTime , Dynamic); - VERIFY_IS_EQUAL( (A(span(2,5,2), range(1,3,2))).OuterStrideAtCompileTime , Dynamic); - VERIFY_IS_EQUAL( (A(span(2,5,fix<2>), range(1,3,fix<3>))).InnerStrideAtCompileTime , 2); - VERIFY_IS_EQUAL( (A(span(2,5,fix<2>), range(1,3,fix<3>))).OuterStrideAtCompileTime , Dynamic); - VERIFY_IS_EQUAL( (B(span(1,2,fix<2>), range(1,3,fix<3>))).InnerStrideAtCompileTime , 2); - VERIFY_IS_EQUAL( (B(span(1,2,fix<2>), range(1,3,fix<3>))).OuterStrideAtCompileTime , 3*4); + VERIFY_IS_EQUAL( (A(seqN(2,5), seq(1,3))).InnerStrideAtCompileTime , A.InnerStrideAtCompileTime); + VERIFY_IS_EQUAL( (A(seqN(2,5), seq(1,3))).OuterStrideAtCompileTime , A.OuterStrideAtCompileTime); + VERIFY_IS_EQUAL( (B(seqN(1,2), seq(1,3))).InnerStrideAtCompileTime , B.InnerStrideAtCompileTime); + VERIFY_IS_EQUAL( (B(seqN(1,2), seq(1,3))).OuterStrideAtCompileTime , B.OuterStrideAtCompileTime); + VERIFY_IS_EQUAL( (A(seqN(2,5,2), seq(1,3,2))).InnerStrideAtCompileTime , Dynamic); + VERIFY_IS_EQUAL( (A(seqN(2,5,2), seq(1,3,2))).OuterStrideAtCompileTime , Dynamic); + VERIFY_IS_EQUAL( (A(seqN(2,5,fix<2>), seq(1,3,fix<3>))).InnerStrideAtCompileTime , 2); + VERIFY_IS_EQUAL( (A(seqN(2,5,fix<2>), seq(1,3,fix<3>))).OuterStrideAtCompileTime , Dynamic); + VERIFY_IS_EQUAL( (B(seqN(1,2,fix<2>), seq(1,3,fix<3>))).InnerStrideAtCompileTime , 2); + VERIFY_IS_EQUAL( (B(seqN(1,2,fix<2>), seq(1,3,fix<3>))).OuterStrideAtCompileTime , 3*4); - VERIFY( (A(span(2,fix<5>), 5)).RowsAtCompileTime == 5); + VERIFY( (A(seqN(2,fix<5>), 5)).RowsAtCompileTime == 5); VERIFY( (A(4, all)).ColsAtCompileTime == Dynamic); VERIFY( (A(4, all)).RowsAtCompileTime == 1); VERIFY( (B(1, all)).ColsAtCompileTime == 4); @@ -139,12 +139,10 @@ void check_indexed_view() VERIFY_IS_EQUAL( (A(eii, eii)).InnerStrideAtCompileTime, 0); VERIFY_IS_EQUAL( (A(eii, eii)).OuterStrideAtCompileTime, 0); - - #if EIGEN_HAS_CXX11 VERIFY( (A(all, std::array{{1,3,2,4}})).ColsAtCompileTime == 4); - VERIFY_IS_APPROX( (A(std::array{{1,3,5}}, std::array{{9,6,3,0}})), A(span(1,3,2), span(9,4,-3)) ); + VERIFY_IS_APPROX( (A(std::array{{1,3,5}}, std::array{{9,6,3,0}})), A(seqN(1,3,2), seqN(9,4,-3)) ); #if (!EIGEN_COMP_CLANG) || (EIGEN_COMP_CLANG>=308 && !defined(__apple_build_version__)) VERIFY_IS_APPROX( A({3, 1, 6, 5}, all), A(std::array{{3, 1, 6, 5}}, all) ); From b50c3e967e1676f248c93c1a79e6574ae746e2fd Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 9 Jan 2017 23:42:16 +0100 Subject: [PATCH 11/65] Add a minimalistic symbolic scalar type with expression template and make use of it to define the last placeholder and to unify the return type of seq and seqN. --- Eigen/src/Core/ArithmeticSequence.h | 220 ++++++++++++++++++++++++---- test/indexed_view.cpp | 5 + 2 files changed, 197 insertions(+), 28 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 71301797a..9f4fe327b 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -34,7 +34,7 @@ struct last_t { int operator- (last_t) const { return 0; } int operator- (shifted_last x) const { return -x.offset; } }; -static const last_t last; +static const last_t last_legacy; struct shifted_end { @@ -52,7 +52,145 @@ struct end_t { int operator- (end_t) const { return 0; } int operator- (shifted_end x) const { return -x.offset; } }; -static const end_t end; +static const end_t end_legacy; + +// A simple wrapper around an Index to provide the eval method. +// We could also use a free-function symbolic_eval... +class symbolic_value_wrapper { +public: + symbolic_value_wrapper(Index val) : m_value(val) {} + template + Index eval(const T&) const { return m_value; } +protected: + Index m_value; +}; + +//-------------------------------------------------------------------------------- +// minimalistic symbolic scalar type +//-------------------------------------------------------------------------------- + +template class symbolic_symbol; +template class symbolic_negate; +template class symbolic_add; +template class symbolic_product; +template class symbolic_quotient; + +template +class symbolic_index_base +{ +public: + const Derived& derived() const { return *static_cast(this); } + + symbolic_negate operator-() const { return symbolic_negate(derived()); } + + symbolic_add operator+(Index b) const + { return symbolic_add(derived(), b); } + symbolic_add operator-(Index a) const + { return symbolic_add(derived(), -a); } + symbolic_quotient operator/(Index a) const + { return symbolic_quotient(derived(),a); } + + friend symbolic_add operator+(Index a, const symbolic_index_base& b) + { return symbolic_add(b.derived(), a); } + friend symbolic_add,symbolic_value_wrapper> operator-(Index a, const symbolic_index_base& b) + { return symbolic_add,symbolic_value_wrapper>(-b.derived(), a); } + friend symbolic_add operator/(Index a, const symbolic_index_base& b) + { return symbolic_add(a,b.derived()); } + + template + symbolic_add operator+(const symbolic_index_base &b) const + { return symbolic_add(derived(), b.derived()); } + + template + symbolic_add > operator-(const symbolic_index_base &b) const + { return symbolic_add >(derived(), -b.derived()); } + + template + symbolic_add operator/(const symbolic_index_base &b) const + { return symbolic_quotient(derived(), b.derived()); } +}; + +template +struct is_symbolic { + enum { value = internal::is_convertible >::value }; +}; + +template +class symbolic_value_pair +{ +public: + symbolic_value_pair(Index val) : m_value(val) {} + Index value() const { return m_value; } +protected: + Index m_value; +}; + +template +class symbolic_value : public symbolic_index_base > +{ +public: + symbolic_value() {} + + Index eval(const symbolic_value_pair &values) const { return values.value(); } + + // TODO add a c++14 eval taking a tuple of symbolic_value_pair and getting the value with std::get >... +}; + +template +class symbolic_negate : public symbolic_index_base > +{ +public: + symbolic_negate(const Arg0& arg0) : m_arg0(arg0) {} + + template + Index eval(const T& values) const { return -m_arg0.eval(values); } +protected: + Arg0 m_arg0; +}; + +template +class symbolic_add : public symbolic_index_base > +{ +public: + symbolic_add(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} + + template + Index eval(const T& values) const { return m_arg0.eval(values) + m_arg1.eval(values); } +protected: + Arg0 m_arg0; + Arg1 m_arg1; +}; + +template +class symbolic_product : public symbolic_index_base > +{ +public: + symbolic_product(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} + + template + Index eval(const T& values) const { return m_arg0.eval(values) * m_arg1.eval(values); } +protected: + Arg0 m_arg0; + Arg1 m_arg1; +}; + +template +class symbolic_quotient : public symbolic_index_base > +{ +public: + symbolic_quotient(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} + + template + Index eval(const T& values) const { return m_arg0.eval(values) / m_arg1.eval(values); } +protected: + Arg0 m_arg0; + Arg1 m_arg1; +}; + +struct symb_last_tag {}; + +static const symbolic_value last; +static const symbolic_add,symbolic_value_wrapper> end(last+1); //-------------------------------------------------------------------------------- // integral constant @@ -116,34 +254,30 @@ protected: IncrType m_incr; }; -template struct cleanup_slice_type { typedef Index type; }; -template<> struct cleanup_slice_type { typedef last_t type; }; -template<> struct cleanup_slice_type { typedef shifted_last type; }; -template<> struct cleanup_slice_type { typedef end_t type; }; -template<> struct cleanup_slice_type { typedef shifted_end type; }; -template struct cleanup_slice_type > { typedef fix_t type; }; -template struct cleanup_slice_type (*)() > { typedef fix_t type; }; +template struct cleanup_seq_type { typedef T type; }; +template struct cleanup_seq_type > { typedef fix_t type; }; +template struct cleanup_seq_type (*)() > { typedef fix_t type; }; template -ArithemeticSequenceProxyWithBounds::type,typename cleanup_slice_type::type > -seq(FirstType f, LastType l) { - return ArithemeticSequenceProxyWithBounds::type,typename cleanup_slice_type::type>(f,l); +ArithemeticSequenceProxyWithBounds::type,typename cleanup_seq_type::type > +seq_legacy(FirstType f, LastType l) { + return ArithemeticSequenceProxyWithBounds::type,typename cleanup_seq_type::type>(f,l); } template -ArithemeticSequenceProxyWithBounds::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type > -seq(FirstType f, LastType l, IncrType s) { - return ArithemeticSequenceProxyWithBounds::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type>(f,l,typename cleanup_slice_type::type(s)); +ArithemeticSequenceProxyWithBounds::type,typename cleanup_seq_type::type,typename cleanup_seq_type::type > +seq_legacy(FirstType f, LastType l, IncrType s) { + return ArithemeticSequenceProxyWithBounds::type,typename cleanup_seq_type::type,typename cleanup_seq_type::type>(f,l,typename cleanup_seq_type::type(s)); } template > -class ArithemeticSequenceProxyWithSize +class ArithemeticSequence { public: - ArithemeticSequenceProxyWithSize(FirstType first, SizeType size) : m_first(first), m_size(size) {} - ArithemeticSequenceProxyWithSize(FirstType first, SizeType size, IncrType incr) : m_first(first), m_size(size), m_incr(incr) {} + ArithemeticSequence(FirstType first, SizeType size) : m_first(first), m_size(size) {} + ArithemeticSequence(FirstType first, SizeType size, IncrType incr) : m_first(first), m_size(size), m_incr(incr) {} enum { SizeAtCompileTime = get_compile_time::value, @@ -165,18 +299,30 @@ protected: template -ArithemeticSequenceProxyWithSize::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type > +ArithemeticSequence::type,typename cleanup_seq_type::type,typename cleanup_seq_type::type > seqN(FirstType first, SizeType size, IncrType incr) { - return ArithemeticSequenceProxyWithSize::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type>(first,size,incr); + return ArithemeticSequence::type,typename cleanup_seq_type::type,typename cleanup_seq_type::type>(first,size,incr); } template -ArithemeticSequenceProxyWithSize::type,typename cleanup_slice_type::type > +ArithemeticSequence::type,typename cleanup_seq_type::type > seqN(FirstType first, SizeType size) { - return ArithemeticSequenceProxyWithSize::type,typename cleanup_slice_type::type>(first,size); + return ArithemeticSequence::type,typename cleanup_seq_type::type>(first,size); } +template +auto seq(FirstType f, LastType l) -> decltype(seqN(f,(l-f+1))) +{ + return seqN(f,(l-f+1)); +} +template +auto seq(FirstType f, LastType l, IncrType incr) + -> decltype(seqN(f,(l-f+typename cleanup_seq_type::type(incr))/typename cleanup_seq_type::type(incr),typename cleanup_seq_type::type(incr))) +{ + typedef typename cleanup_seq_type::type CleanedIncrType; + return seqN(f,(l-f+CleanedIncrType(incr))/CleanedIncrType(incr),CleanedIncrType(incr)); +} namespace internal { @@ -214,7 +360,7 @@ struct get_compile_time_incr -struct get_compile_time_incr > { +struct get_compile_time_incr > { enum { value = get_compile_time::value }; }; @@ -258,6 +404,17 @@ Index symbolic2value(shifted_last x, Index size) { return size+x.offset-1; } Index symbolic2value(end_t, Index size) { return size; } Index symbolic2value(shifted_end x, Index size) { return size+x.offset; } +template +fix_t symbolic2value(fix_t x, Index /*size*/) { return x; } + +template +Index symbolic2value(const symbolic_index_base &x, Index size) +{ + Index h=x.derived().eval(symbolic_value_pair(size-1)); + return x.derived().eval(symbolic_value_pair(size-1)); +} + + // Convert a symbolic range into a usable one (i.e., remove last/end "keywords") template struct MakeIndexing > { @@ -270,14 +427,21 @@ ArithemeticSequenceProxyWithBounds make_indexing(const Ari } // Convert a symbolic span into a usable one (i.e., remove last/end "keywords") -template -struct MakeIndexing > { - typedef ArithemeticSequenceProxyWithSize type; +template +struct make_size_type { + typedef typename internal::conditional::value, Index, T>::type type; }; template -ArithemeticSequenceProxyWithSize make_indexing(const ArithemeticSequenceProxyWithSize& ids, Index size) { - return ArithemeticSequenceProxyWithSize(symbolic2value(ids.firstObject(),size),ids.sizeObject(),ids.incrObject()); +struct MakeIndexing > { + typedef ArithemeticSequence::type,IncrType> type; +}; + +template +ArithemeticSequence::type,IncrType> +make_indexing(const ArithemeticSequence& ids, Index size) { + return ArithemeticSequence::type,IncrType>( + symbolic2value(ids.firstObject(),size),symbolic2value(ids.sizeObject(),size),ids.incrObject()); } // Convert a symbolic 'all' into a usable range diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index 23ad2d743..25a25499c 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -139,6 +139,11 @@ void check_indexed_view() VERIFY_IS_EQUAL( (A(eii, eii)).InnerStrideAtCompileTime, 0); VERIFY_IS_EQUAL( (A(eii, eii)).OuterStrideAtCompileTime, 0); + VERIFY_IS_APPROX( A(seq(n-1,2,-2), seqN(n-1-6,4)), A(seq(last,2,-2), seqN(last-6,4)) ); + VERIFY_IS_APPROX( A(seq(n-1-6,n-1-2), seqN(n-1-6,4)), A(seq(last-6,last-2), seqN(6+last-6-6,4)) ); + VERIFY_IS_APPROX( A(seq((n-1)/2,(n)/2+3), seqN(2,4)), A(seq(last/2,(last+1)/2+3), seqN(last+2-last,4)) ); + VERIFY_IS_APPROX( A(seq(n-2,2,-2), seqN(n-8,4)), A(seq(end-2,2,-2), seqN(end-8,4)) ); + #if EIGEN_HAS_CXX11 VERIFY( (A(all, std::array{{1,3,2,4}})).ColsAtCompileTime == 4); From ecd9cc54126c6d01859fbf26276cc1d03e370aec Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 10 Jan 2017 09:34:25 +0100 Subject: [PATCH 12/65] Isolate legacy code (we keep it for performance comparison purpose) --- Eigen/src/Core/ArithmeticSequence.h | 208 +++++++++++++++------------- test/indexed_view.cpp | 4 + 2 files changed, 113 insertions(+), 99 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 9f4fe327b..7c104ad91 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -19,41 +19,6 @@ namespace Eigen { struct all_t { all_t() {} }; static const all_t all; -struct shifted_last { - explicit shifted_last(int o) : offset(o) {} - int offset; - shifted_last operator+ (int x) const { return shifted_last(offset+x); } - shifted_last operator- (int x) const { return shifted_last(offset-x); } - int operator- (shifted_last x) const { return offset-x.offset; } -}; - -struct last_t { - last_t() {} - shifted_last operator- (int offset) const { return shifted_last(-offset); } - shifted_last operator+ (int offset) const { return shifted_last(+offset); } - int operator- (last_t) const { return 0; } - int operator- (shifted_last x) const { return -x.offset; } -}; -static const last_t last_legacy; - - -struct shifted_end { - explicit shifted_end(int o) : offset(o) {} - int offset; - shifted_end operator+ (int x) const { return shifted_end(offset+x); } - shifted_end operator- (int x) const { return shifted_end(offset-x); } - int operator- (shifted_end x) const { return offset-x.offset; } -}; - -struct end_t { - end_t() {} - shifted_end operator- (int offset) const { return shifted_end (-offset); } - shifted_end operator+ (int offset) const { return shifted_end ( offset); } - int operator- (end_t) const { return 0; } - int operator- (shifted_end x) const { return -x.offset; } -}; -static const end_t end_legacy; - // A simple wrapper around an Index to provide the eval method. // We could also use a free-function symbolic_eval... class symbolic_value_wrapper { @@ -228,49 +193,6 @@ inline fix_t fix() { return fix_t(); } // seq(first,last,incr) and seqN(first,size,incr) //-------------------------------------------------------------------------------- - -template > -class ArithemeticSequenceProxyWithBounds -{ -public: - ArithemeticSequenceProxyWithBounds(FirstType f, LastType l) : m_first(f), m_last(l) {} - ArithemeticSequenceProxyWithBounds(FirstType f, LastType l, IncrType s) : m_first(f), m_last(l), m_incr(s) {} - - enum { - SizeAtCompileTime = -1, - IncrAtCompileTime = get_compile_time::value - }; - - Index size() const { return (m_last-m_first+m_incr)/m_incr; } - Index operator[](Index i) const { return m_first + i * m_incr; } - - const FirstType& firstObject() const { return m_first; } - const LastType& lastObject() const { return m_last; } - const IncrType& incrObject() const { return m_incr; } - -protected: - FirstType m_first; - LastType m_last; - IncrType m_incr; -}; - -template struct cleanup_seq_type { typedef T type; }; -template struct cleanup_seq_type > { typedef fix_t type; }; -template struct cleanup_seq_type (*)() > { typedef fix_t type; }; - -template -ArithemeticSequenceProxyWithBounds::type,typename cleanup_seq_type::type > -seq_legacy(FirstType f, LastType l) { - return ArithemeticSequenceProxyWithBounds::type,typename cleanup_seq_type::type>(f,l); -} - -template -ArithemeticSequenceProxyWithBounds::type,typename cleanup_seq_type::type,typename cleanup_seq_type::type > -seq_legacy(FirstType f, LastType l, IncrType s) { - return ArithemeticSequenceProxyWithBounds::type,typename cleanup_seq_type::type,typename cleanup_seq_type::type>(f,l,typename cleanup_seq_type::type(s)); -} - - template > class ArithemeticSequence { @@ -297,6 +219,9 @@ protected: IncrType m_incr; }; +template struct cleanup_seq_type { typedef T type; }; +template struct cleanup_seq_type > { typedef fix_t type; }; +template struct cleanup_seq_type (*)() > { typedef fix_t type; }; template ArithemeticSequence::type,typename cleanup_seq_type::type,typename cleanup_seq_type::type > @@ -354,11 +279,6 @@ template struct get_compile_time_incr { enum { value = UndefinedIncr }; }; -template -struct get_compile_time_incr > { - enum { value = get_compile_time::value }; -}; - template struct get_compile_time_incr > { enum { value = get_compile_time::value }; @@ -399,10 +319,6 @@ struct MakeIndexing::val // Replace symbolic last/end "keywords" by their true runtime value Index symbolic2value(Index x, Index /* size */) { return x; } -Index symbolic2value(last_t, Index size) { return size-1; } -Index symbolic2value(shifted_last x, Index size) { return size+x.offset-1; } -Index symbolic2value(end_t, Index size) { return size; } -Index symbolic2value(shifted_end x, Index size) { return size+x.offset; } template fix_t symbolic2value(fix_t x, Index /*size*/) { return x; } @@ -414,18 +330,6 @@ Index symbolic2value(const symbolic_index_base &x, Index size) return x.derived().eval(symbolic_value_pair(size-1)); } - -// Convert a symbolic range into a usable one (i.e., remove last/end "keywords") -template -struct MakeIndexing > { - typedef ArithemeticSequenceProxyWithBounds type; -}; - -template -ArithemeticSequenceProxyWithBounds make_indexing(const ArithemeticSequenceProxyWithBounds& ids, Index size) { - return ArithemeticSequenceProxyWithBounds(symbolic2value(ids.firstObject(),size),symbolic2value(ids.lastObject(),size),ids.incrObject()); -} - // Convert a symbolic span into a usable one (i.e., remove last/end "keywords") template struct make_size_type { @@ -474,6 +378,112 @@ template<> struct get_compile_time_incr { } // end namespace internal +//-------------------------------------------------------------------------------- + +namespace legacy { +// Here are some initial code that I keep here for now to compare the quality of the code generated by the compilers + +struct shifted_last { + explicit shifted_last(int o) : offset(o) {} + int offset; + shifted_last operator+ (int x) const { return shifted_last(offset+x); } + shifted_last operator- (int x) const { return shifted_last(offset-x); } + int operator- (shifted_last x) const { return offset-x.offset; } +}; + +struct last_t { + last_t() {} + shifted_last operator- (int offset) const { return shifted_last(-offset); } + shifted_last operator+ (int offset) const { return shifted_last(+offset); } + int operator- (last_t) const { return 0; } + int operator- (shifted_last x) const { return -x.offset; } +}; +static const last_t last; + + +struct shifted_end { + explicit shifted_end(int o) : offset(o) {} + int offset; + shifted_end operator+ (int x) const { return shifted_end(offset+x); } + shifted_end operator- (int x) const { return shifted_end(offset-x); } + int operator- (shifted_end x) const { return offset-x.offset; } +}; + +struct end_t { + end_t() {} + shifted_end operator- (int offset) const { return shifted_end (-offset); } + shifted_end operator+ (int offset) const { return shifted_end ( offset); } + int operator- (end_t) const { return 0; } + int operator- (shifted_end x) const { return -x.offset; } +}; +static const end_t end; + +Index symbolic2value(last_t, Index size) { return size-1; } +Index symbolic2value(shifted_last x, Index size) { return size+x.offset-1; } +Index symbolic2value(end_t, Index size) { return size; } +Index symbolic2value(shifted_end x, Index size) { return size+x.offset; } + +template > +class ArithemeticSequenceProxyWithBounds +{ +public: + ArithemeticSequenceProxyWithBounds(FirstType f, LastType l) : m_first(f), m_last(l) {} + ArithemeticSequenceProxyWithBounds(FirstType f, LastType l, IncrType s) : m_first(f), m_last(l), m_incr(s) {} + + enum { + SizeAtCompileTime = -1, + IncrAtCompileTime = get_compile_time::value + }; + + Index size() const { return (m_last-m_first+m_incr)/m_incr; } + Index operator[](Index i) const { return m_first + i * m_incr; } + + const FirstType& firstObject() const { return m_first; } + const LastType& lastObject() const { return m_last; } + const IncrType& incrObject() const { return m_incr; } + +protected: + FirstType m_first; + LastType m_last; + IncrType m_incr; +}; + +template +ArithemeticSequenceProxyWithBounds::type,typename cleanup_seq_type::type > +seq(FirstType f, LastType l) { + return ArithemeticSequenceProxyWithBounds::type,typename cleanup_seq_type::type>(f,l); +} + +template +ArithemeticSequenceProxyWithBounds::type,typename cleanup_seq_type::type,typename cleanup_seq_type::type > +seq(FirstType f, LastType l, IncrType s) { + return ArithemeticSequenceProxyWithBounds::type,typename cleanup_seq_type::type,typename cleanup_seq_type::type>(f,l,typename cleanup_seq_type::type(s)); +} + +} + +namespace internal { + +template +struct get_compile_time_incr > { + enum { value = get_compile_time::value }; +}; + +// Convert a symbolic range into a usable one (i.e., remove last/end "keywords") +template +struct MakeIndexing > { + typedef legacy::ArithemeticSequenceProxyWithBounds type; +}; + +template +legacy::ArithemeticSequenceProxyWithBounds +make_indexing(const legacy::ArithemeticSequenceProxyWithBounds& ids, Index size) { + return legacy::ArithemeticSequenceProxyWithBounds( + symbolic2value(ids.firstObject(),size),symbolic2value(ids.lastObject(),size),ids.incrObject()); +} + +} + } // end namespace Eigen #endif // EIGEN_ARITHMETIC_SEQUENCE_H diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index 25a25499c..5c5cb5cde 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -160,6 +160,10 @@ void check_indexed_view() #endif + // check legacy code + VERIFY_IS_APPROX( A(legacy::seq(legacy::last,2,-2), legacy::seq(legacy::last-6,7)), A(seq(last,2,-2), seq(last-6,7)) ); + VERIFY_IS_APPROX( A(seqN(legacy::last,2,-2), seqN(legacy::last-6,3)), A(seqN(last,2,-2), seqN(last-6,3)) ); + } void test_indexed_view() From 1df2377d78c30b87099fd38b2b78021dc28f6181 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 10 Jan 2017 10:28:45 +0100 Subject: [PATCH 13/65] Implement c++98 version of seq() --- Eigen/src/Core/ArithmeticSequence.h | 85 +++++++++++++++++++++++++++-- test/indexed_view.cpp | 13 +++++ 2 files changed, 93 insertions(+), 5 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 7c104ad91..6c9cb9ef3 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -219,7 +219,8 @@ protected: IncrType m_incr; }; -template struct cleanup_seq_type { typedef T type; }; +template struct cleanup_seq_type { typedef T type; }; +template struct cleanup_seq_type::value>::type> { typedef Index type; }; template struct cleanup_seq_type > { typedef fix_t type; }; template struct cleanup_seq_type (*)() > { typedef fix_t type; }; @@ -235,10 +236,11 @@ seqN(FirstType first, SizeType size) { return ArithemeticSequence::type,typename cleanup_seq_type::type>(first,size); } +#if EIGEN_HAS_CXX11 template -auto seq(FirstType f, LastType l) -> decltype(seqN(f,(l-f+1))) +auto seq(FirstType f, LastType l) -> decltype(seqN(f,(l-f+fix<1>()))) { - return seqN(f,(l-f+1)); + return seqN(f,(l-f+fix<1>())); } template @@ -248,6 +250,80 @@ auto seq(FirstType f, LastType l, IncrType incr) typedef typename cleanup_seq_type::type CleanedIncrType; return seqN(f,(l-f+CleanedIncrType(incr))/CleanedIncrType(incr),CleanedIncrType(incr)); } +#else +template +typename internal::enable_if::value || is_symbolic::value), + ArithemeticSequence::type,Index> >::type +seq(FirstType f, LastType l) +{ + return seqN(f,(l-f+1)); +} + +template +typename internal::enable_if::value, + ArithemeticSequence,symbolic_value_wrapper>,symbolic_value_wrapper> > >::type +seq(const symbolic_index_base &f, LastType l) +{ + return seqN(f.derived(),(l-f.derived()+1)); +} + +template +typename internal::enable_if::value, + ArithemeticSequence::type,symbolic_add,symbolic_value_wrapper> > >::type +seq(FirstType f, const symbolic_index_base &l) +{ + return seqN(f,(l.derived()-f+1)); +} + +template +ArithemeticSequence >,symbolic_value_wrapper> > +seq(const symbolic_index_base &f, const symbolic_index_base &l) +{ + return seqN(f.derived(),(l.derived()-f.derived()+1)); +} + + +template +typename internal::enable_if::value || is_symbolic::value), + ArithemeticSequence::type,Index,typename cleanup_seq_type::type> >::type +seq(FirstType f, LastType l, IncrType incr) +{ + typedef typename cleanup_seq_type::type CleanedIncrType; + return seqN(f,(l-f+CleanedIncrType(incr))/CleanedIncrType(incr), incr); +} + +template +typename internal::enable_if::value, + ArithemeticSequence,symbolic_value_wrapper>,symbolic_value_wrapper>,symbolic_value_wrapper>, + typename cleanup_seq_type::type> >::type +seq(const symbolic_index_base &f, LastType l, IncrType incr) +{ + typedef typename cleanup_seq_type::type CleanedIncrType; + return seqN(f.derived(),(l-f.derived()+CleanedIncrType(incr))/CleanedIncrType(incr), incr); +} + +template +typename internal::enable_if::value, + ArithemeticSequence::type, + symbolic_quotient,symbolic_value_wrapper>,symbolic_value_wrapper>, + typename cleanup_seq_type::type> >::type +seq(FirstType f, const symbolic_index_base &l, IncrType incr) +{ + typedef typename cleanup_seq_type::type CleanedIncrType; + return seqN(f,(l.derived()-f+CleanedIncrType(incr))/CleanedIncrType(incr), incr); +} + +template +ArithemeticSequence >,symbolic_value_wrapper>,symbolic_value_wrapper>, + typename cleanup_seq_type::type> +seq(const symbolic_index_base &f, const symbolic_index_base &l, IncrType incr) +{ + typedef typename cleanup_seq_type::type CleanedIncrType; + return seqN(f.derived(),(l.derived()-f.derived()+CleanedIncrType(incr))/CleanedIncrType(incr), incr); +} +#endif namespace internal { @@ -255,7 +331,7 @@ template Index size(const T& x) { return x.size(); } template -Index size(const T (&x) [N]) { return N; } +Index size(const T (&) [N]) { return N; } template struct get_compile_time_size { enum { value = Dynamic }; @@ -326,7 +402,6 @@ fix_t symbolic2value(fix_t x, Index /*size*/) { return x; } template Index symbolic2value(const symbolic_index_base &x, Index size) { - Index h=x.derived().eval(symbolic_value_pair(size-1)); return x.derived().eval(symbolic_value_pair(size-1)); } diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index 5c5cb5cde..13eb1ef35 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -7,6 +7,11 @@ // 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/. +#ifdef EIGEN_TEST_PART_2 +// Make sure we also check c++98 implementation +#define EIGEN_MAX_CPP_VER 03 +#endif + #include #include #include "main.h" @@ -144,6 +149,13 @@ void check_indexed_view() VERIFY_IS_APPROX( A(seq((n-1)/2,(n)/2+3), seqN(2,4)), A(seq(last/2,(last+1)/2+3), seqN(last+2-last,4)) ); VERIFY_IS_APPROX( A(seq(n-2,2,-2), seqN(n-8,4)), A(seq(end-2,2,-2), seqN(end-8,4)) ); + // Check all combinations of seq: + VERIFY_IS_APPROX( A(seq(1,n-1-2,2), seq(1,n-1-2,2)), A(seq(1,last-2,2), seq(1,last-2,fix<2>)) ); + VERIFY_IS_APPROX( A(seq(n-1-5,n-1-2,2), seq(n-1-5,n-1-2,2)), A(seq(last-5,last-2,2), seq(last-5,last-2,fix<2>)) ); + VERIFY_IS_APPROX( A(seq(n-1-5,7,2), seq(n-1-5,7,2)), A(seq(last-5,7,2), seq(last-5,7,fix<2>)) ); + 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)) ); + #if EIGEN_HAS_CXX11 VERIFY( (A(all, std::array{{1,3,2,4}})).ColsAtCompileTime == 4); @@ -170,5 +182,6 @@ void test_indexed_view() { // for(int i = 0; i < g_repeat; i++) { CALL_SUBTEST_1( check_indexed_view() ); + CALL_SUBTEST_2( check_indexed_view() ); // } } From acd08900c9992de386c7ded14a593b2ba0a0f20e Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 10 Jan 2017 10:31:07 +0100 Subject: [PATCH 14/65] Move 'last' and 'end' to their own namespace --- Eigen/src/Core/ArithmeticSequence.h | 4 ++++ test/indexed_view.cpp | 3 +++ 2 files changed, 7 insertions(+) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 6c9cb9ef3..88954b4a6 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -154,9 +154,13 @@ protected: struct symb_last_tag {}; +namespace placeholders { + static const symbolic_value last; static const symbolic_add,symbolic_value_wrapper> end(last+1); +} // end namespace placeholders + //-------------------------------------------------------------------------------- // integral constant //-------------------------------------------------------------------------------- diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index 13eb1ef35..e04fe0cd4 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -43,6 +43,9 @@ bool match(const T& xpr, std::string ref, std::string str_xpr = "") { void check_indexed_view() { + using Eigen::placeholders::last; + using Eigen::placeholders::end; + Index n = 10; ArrayXXi A = ArrayXXi::NullaryExpr(n,n, std::ptr_fun(encode)); From 9eaab4f9e0c50bf8bfa8d8b79b809d3d564ccbf3 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 10 Jan 2017 10:57:08 +0100 Subject: [PATCH 15/65] Refactoring: move all symbolic stuff into its own namespace --- Eigen/src/Core/ArithmeticSequence.h | 171 ++++++++++++++++------------ 1 file changed, 98 insertions(+), 73 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 88954b4a6..72ca639db 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -19,93 +19,103 @@ namespace Eigen { struct all_t { all_t() {} }; static const all_t all; +//-------------------------------------------------------------------------------- +// minimalistic symbolic scalar type +//-------------------------------------------------------------------------------- + +namespace Symbolic { + +template class Symbol; +template class NegateExpr; +template class AddExpr; +template class ProductExpr; +template class QuotientExpr; + // A simple wrapper around an Index to provide the eval method. // We could also use a free-function symbolic_eval... -class symbolic_value_wrapper { +class ValueExpr { public: - symbolic_value_wrapper(Index val) : m_value(val) {} + ValueExpr(Index val) : m_value(val) {} template Index eval(const T&) const { return m_value; } protected: Index m_value; }; -//-------------------------------------------------------------------------------- -// minimalistic symbolic scalar type -//-------------------------------------------------------------------------------- - -template class symbolic_symbol; -template class symbolic_negate; -template class symbolic_add; -template class symbolic_product; -template class symbolic_quotient; - template -class symbolic_index_base +class BaseExpr { public: const Derived& derived() const { return *static_cast(this); } - symbolic_negate operator-() const { return symbolic_negate(derived()); } + NegateExpr operator-() const { return NegateExpr(derived()); } - symbolic_add operator+(Index b) const - { return symbolic_add(derived(), b); } - symbolic_add operator-(Index a) const - { return symbolic_add(derived(), -a); } - symbolic_quotient operator/(Index a) const - { return symbolic_quotient(derived(),a); } + AddExpr operator+(Index b) const + { return AddExpr(derived(), b); } + AddExpr operator-(Index a) const + { return AddExpr(derived(), -a); } + QuotientExpr operator/(Index a) const + { return QuotientExpr(derived(),a); } - friend symbolic_add operator+(Index a, const symbolic_index_base& b) - { return symbolic_add(b.derived(), a); } - friend symbolic_add,symbolic_value_wrapper> operator-(Index a, const symbolic_index_base& b) - { return symbolic_add,symbolic_value_wrapper>(-b.derived(), a); } - friend symbolic_add operator/(Index a, const symbolic_index_base& b) - { return symbolic_add(a,b.derived()); } + friend AddExpr operator+(Index a, const BaseExpr& b) + { return AddExpr(b.derived(), a); } + friend AddExpr,ValueExpr> operator-(Index a, const BaseExpr& b) + { return AddExpr,ValueExpr>(-b.derived(), a); } + friend AddExpr operator/(Index a, const BaseExpr& b) + { return AddExpr(a,b.derived()); } template - symbolic_add operator+(const symbolic_index_base &b) const - { return symbolic_add(derived(), b.derived()); } + AddExpr operator+(const BaseExpr &b) const + { return AddExpr(derived(), b.derived()); } template - symbolic_add > operator-(const symbolic_index_base &b) const - { return symbolic_add >(derived(), -b.derived()); } + AddExpr > operator-(const BaseExpr &b) const + { return AddExpr >(derived(), -b.derived()); } template - symbolic_add operator/(const symbolic_index_base &b) const - { return symbolic_quotient(derived(), b.derived()); } + AddExpr operator/(const BaseExpr &b) const + { return QuotientExpr(derived(), b.derived()); } }; template struct is_symbolic { - enum { value = internal::is_convertible >::value }; + // BaseExpr has no conversion ctor, so we only to check whether T can be staticaly cast to its base class BaseExpr. + enum { value = internal::is_convertible >::value }; }; template -class symbolic_value_pair +class SymbolValue { public: - symbolic_value_pair(Index val) : m_value(val) {} + SymbolValue(Index val) : m_value(val) {} Index value() const { return m_value; } protected: Index m_value; }; -template -class symbolic_value : public symbolic_index_base > +template +class SymbolExpr : public BaseExpr > { public: - symbolic_value() {} + typedef TagT Tag; + SymbolExpr() {} - Index eval(const symbolic_value_pair &values) const { return values.value(); } + Index eval(const SymbolValue &values) const { return values.value(); } - // TODO add a c++14 eval taking a tuple of symbolic_value_pair and getting the value with std::get >... + + // TODO add a c++14 eval taking a tuple of SymbolValue and getting the value with std::get >... }; +template +SymbolValue defineValue(SymbolExpr,Index val) { + return SymbolValue(val); +} + template -class symbolic_negate : public symbolic_index_base > +class NegateExpr : public BaseExpr > { public: - symbolic_negate(const Arg0& arg0) : m_arg0(arg0) {} + NegateExpr(const Arg0& arg0) : m_arg0(arg0) {} template Index eval(const T& values) const { return -m_arg0.eval(values); } @@ -114,10 +124,10 @@ protected: }; template -class symbolic_add : public symbolic_index_base > +class AddExpr : public BaseExpr > { public: - symbolic_add(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} + AddExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} template Index eval(const T& values) const { return m_arg0.eval(values) + m_arg1.eval(values); } @@ -127,10 +137,10 @@ protected: }; template -class symbolic_product : public symbolic_index_base > +class ProductExpr : public BaseExpr > { public: - symbolic_product(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} + ProductExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} template Index eval(const T& values) const { return m_arg0.eval(values) * m_arg1.eval(values); } @@ -140,10 +150,10 @@ protected: }; template -class symbolic_quotient : public symbolic_index_base > +class QuotientExpr : public BaseExpr > { public: - symbolic_quotient(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} + QuotientExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} template Index eval(const T& values) const { return m_arg0.eval(values) / m_arg1.eval(values); } @@ -152,12 +162,16 @@ protected: Arg1 m_arg1; }; -struct symb_last_tag {}; +} // end namespace Symbolic namespace placeholders { -static const symbolic_value last; -static const symbolic_add,symbolic_value_wrapper> end(last+1); +namespace internal { +struct symbolic_last_tag {}; +} + +static const Symbolic::SymbolExpr last; +static const Symbolic::AddExpr,Symbolic::ValueExpr> end(last+1); } // end namespace placeholders @@ -256,7 +270,7 @@ auto seq(FirstType f, LastType l, IncrType incr) } #else template -typename internal::enable_if::value || is_symbolic::value), +typename internal::enable_if::value || Symbolic::is_symbolic::value), ArithemeticSequence::type,Index> >::type seq(FirstType f, LastType l) { @@ -264,31 +278,34 @@ seq(FirstType f, LastType l) } template -typename internal::enable_if::value, - ArithemeticSequence,symbolic_value_wrapper>,symbolic_value_wrapper> > >::type -seq(const symbolic_index_base &f, LastType l) +typename internal::enable_if::value, + ArithemeticSequence,Symbolic::ValueExpr>, + Symbolic::ValueExpr> > >::type +seq(const Symbolic::BaseExpr &f, LastType l) { return seqN(f.derived(),(l-f.derived()+1)); } template -typename internal::enable_if::value, - ArithemeticSequence::type,symbolic_add,symbolic_value_wrapper> > >::type -seq(FirstType f, const symbolic_index_base &l) +typename internal::enable_if::value, + ArithemeticSequence::type, + Symbolic::AddExpr,Symbolic::ValueExpr> > >::type +seq(FirstType f, const Symbolic::BaseExpr &l) { return seqN(f,(l.derived()-f+1)); } template -ArithemeticSequence >,symbolic_value_wrapper> > -seq(const symbolic_index_base &f, const symbolic_index_base &l) +ArithemeticSequence >,Symbolic::ValueExpr> > +seq(const Symbolic::BaseExpr &f, const Symbolic::BaseExpr &l) { return seqN(f.derived(),(l.derived()-f.derived()+1)); } template -typename internal::enable_if::value || is_symbolic::value), +typename internal::enable_if::value || Symbolic::is_symbolic::value), ArithemeticSequence::type,Index,typename cleanup_seq_type::type> >::type seq(FirstType f, LastType l, IncrType incr) { @@ -297,22 +314,27 @@ seq(FirstType f, LastType l, IncrType incr) } template -typename internal::enable_if::value, +typename internal::enable_if::value, ArithemeticSequence,symbolic_value_wrapper>,symbolic_value_wrapper>,symbolic_value_wrapper>, - typename cleanup_seq_type::type> >::type -seq(const symbolic_index_base &f, LastType l, IncrType incr) + Symbolic::QuotientExpr, + Symbolic::ValueExpr>, + Symbolic::ValueExpr>, + Symbolic::ValueExpr>, + typename cleanup_seq_type::type> >::type +seq(const Symbolic::BaseExpr &f, LastType l, IncrType incr) { typedef typename cleanup_seq_type::type CleanedIncrType; return seqN(f.derived(),(l-f.derived()+CleanedIncrType(incr))/CleanedIncrType(incr), incr); } template -typename internal::enable_if::value, +typename internal::enable_if::value, ArithemeticSequence::type, - symbolic_quotient,symbolic_value_wrapper>,symbolic_value_wrapper>, + Symbolic::QuotientExpr, + Symbolic::ValueExpr>, + Symbolic::ValueExpr>, typename cleanup_seq_type::type> >::type -seq(FirstType f, const symbolic_index_base &l, IncrType incr) +seq(FirstType f, const Symbolic::BaseExpr &l, IncrType incr) { typedef typename cleanup_seq_type::type CleanedIncrType; return seqN(f,(l.derived()-f+CleanedIncrType(incr))/CleanedIncrType(incr), incr); @@ -320,9 +342,12 @@ seq(FirstType f, const symbolic_index_base &l, IncrType incr) template ArithemeticSequence >,symbolic_value_wrapper>,symbolic_value_wrapper>, + Symbolic::QuotientExpr >, + Symbolic::ValueExpr>, + Symbolic::ValueExpr>, typename cleanup_seq_type::type> -seq(const symbolic_index_base &f, const symbolic_index_base &l, IncrType incr) +seq(const Symbolic::BaseExpr &f, const Symbolic::BaseExpr &l, IncrType incr) { typedef typename cleanup_seq_type::type CleanedIncrType; return seqN(f.derived(),(l.derived()-f.derived()+CleanedIncrType(incr))/CleanedIncrType(incr), incr); @@ -404,15 +429,15 @@ template fix_t symbolic2value(fix_t x, Index /*size*/) { return x; } template -Index symbolic2value(const symbolic_index_base &x, Index size) +Index symbolic2value(const Symbolic::BaseExpr &x, Index size) { - return x.derived().eval(symbolic_value_pair(size-1)); + return x.derived().eval(Symbolic::defineValue(placeholders::last,size-1)); } // Convert a symbolic span into a usable one (i.e., remove last/end "keywords") template struct make_size_type { - typedef typename internal::conditional::value, Index, T>::type type; + typedef typename internal::conditional::value, Index, T>::type type; }; template From 13d954f2702a10bd192c46b01137df9193a7d214 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 10 Jan 2017 11:06:02 +0100 Subject: [PATCH 16/65] Cleanup Eigen's namespace --- Eigen/src/Core/ArithmeticSequence.h | 73 +++++++++++++++++------------ 1 file changed, 42 insertions(+), 31 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 72ca639db..38cc32aa3 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -237,21 +237,25 @@ protected: IncrType m_incr; }; +namespace internal { + template struct cleanup_seq_type { typedef T type; }; template struct cleanup_seq_type::value>::type> { typedef Index type; }; template struct cleanup_seq_type > { typedef fix_t type; }; template struct cleanup_seq_type (*)() > { typedef fix_t type; }; +} + template -ArithemeticSequence::type,typename cleanup_seq_type::type,typename cleanup_seq_type::type > +ArithemeticSequence::type,typename internal::cleanup_seq_type::type,typename internal::cleanup_seq_type::type > seqN(FirstType first, SizeType size, IncrType incr) { - return ArithemeticSequence::type,typename cleanup_seq_type::type,typename cleanup_seq_type::type>(first,size,incr); + return ArithemeticSequence::type,typename internal::cleanup_seq_type::type,typename internal::cleanup_seq_type::type>(first,size,incr); } template -ArithemeticSequence::type,typename cleanup_seq_type::type > +ArithemeticSequence::type,typename internal::cleanup_seq_type::type > seqN(FirstType first, SizeType size) { - return ArithemeticSequence::type,typename cleanup_seq_type::type>(first,size); + return ArithemeticSequence::type,typename internal::cleanup_seq_type::type>(first,size); } #if EIGEN_HAS_CXX11 @@ -263,15 +267,16 @@ auto seq(FirstType f, LastType l) -> decltype(seqN(f,(l-f+fix<1>()))) template auto seq(FirstType f, LastType l, IncrType incr) - -> decltype(seqN(f,(l-f+typename cleanup_seq_type::type(incr))/typename cleanup_seq_type::type(incr),typename cleanup_seq_type::type(incr))) + -> decltype(seqN(f, (l-f+typename internal::cleanup_seq_type::type(incr)) + / typename internal::cleanup_seq_type::type(incr),typename internal::cleanup_seq_type::type(incr))) { - typedef typename cleanup_seq_type::type CleanedIncrType; + typedef typename internal::cleanup_seq_type::type CleanedIncrType; return seqN(f,(l-f+CleanedIncrType(incr))/CleanedIncrType(incr),CleanedIncrType(incr)); } #else template typename internal::enable_if::value || Symbolic::is_symbolic::value), - ArithemeticSequence::type,Index> >::type + ArithemeticSequence::type,Index> >::type seq(FirstType f, LastType l) { return seqN(f,(l-f+1)); @@ -288,7 +293,7 @@ seq(const Symbolic::BaseExpr &f, LastType l) template typename internal::enable_if::value, - ArithemeticSequence::type, + ArithemeticSequence::type, Symbolic::AddExpr,Symbolic::ValueExpr> > >::type seq(FirstType f, const Symbolic::BaseExpr &l) { @@ -306,10 +311,10 @@ seq(const Symbolic::BaseExpr &f, const Symbolic::BaseExpr typename internal::enable_if::value || Symbolic::is_symbolic::value), - ArithemeticSequence::type,Index,typename cleanup_seq_type::type> >::type + ArithemeticSequence::type,Index,typename internal::cleanup_seq_type::type> >::type seq(FirstType f, LastType l, IncrType incr) { - typedef typename cleanup_seq_type::type CleanedIncrType; + typedef typename internal::cleanup_seq_type::type CleanedIncrType; return seqN(f,(l-f+CleanedIncrType(incr))/CleanedIncrType(incr), incr); } @@ -320,23 +325,23 @@ typename internal::enable_if::value, Symbolic::ValueExpr>, Symbolic::ValueExpr>, Symbolic::ValueExpr>, - typename cleanup_seq_type::type> >::type + typename internal::cleanup_seq_type::type> >::type seq(const Symbolic::BaseExpr &f, LastType l, IncrType incr) { - typedef typename cleanup_seq_type::type CleanedIncrType; + typedef typename internal::cleanup_seq_type::type CleanedIncrType; return seqN(f.derived(),(l-f.derived()+CleanedIncrType(incr))/CleanedIncrType(incr), incr); } template typename internal::enable_if::value, - ArithemeticSequence::type, + ArithemeticSequence::type, Symbolic::QuotientExpr, Symbolic::ValueExpr>, Symbolic::ValueExpr>, - typename cleanup_seq_type::type> >::type + typename internal::cleanup_seq_type::type> >::type seq(FirstType f, const Symbolic::BaseExpr &l, IncrType incr) { - typedef typename cleanup_seq_type::type CleanedIncrType; + typedef typename internal::cleanup_seq_type::type CleanedIncrType; return seqN(f,(l.derived()-f+CleanedIncrType(incr))/CleanedIncrType(incr), incr); } @@ -346,10 +351,10 @@ ArithemeticSequence >, Symbolic::ValueExpr>, Symbolic::ValueExpr>, - typename cleanup_seq_type::type> + typename internal::cleanup_seq_type::type> seq(const Symbolic::BaseExpr &f, const Symbolic::BaseExpr &l, IncrType incr) { - typedef typename cleanup_seq_type::type CleanedIncrType; + typedef typename internal::cleanup_seq_type::type CleanedIncrType; return seqN(f.derived(),(l.derived()-f.derived()+CleanedIncrType(incr))/CleanedIncrType(incr), incr); } #endif @@ -423,13 +428,13 @@ struct MakeIndexing::val }; // Replace symbolic last/end "keywords" by their true runtime value -Index symbolic2value(Index x, Index /* size */) { return x; } +Index eval_expr_given_size(Index x, Index /* size */) { return x; } template -fix_t symbolic2value(fix_t x, Index /*size*/) { return x; } +fix_t eval_expr_given_size(fix_t x, Index /*size*/) { return x; } template -Index symbolic2value(const Symbolic::BaseExpr &x, Index size) +Index eval_expr_given_size(const Symbolic::BaseExpr &x, Index size) { return x.derived().eval(Symbolic::defineValue(placeholders::last,size-1)); } @@ -449,7 +454,7 @@ template ArithemeticSequence::type,IncrType> make_indexing(const ArithemeticSequence& ids, Index size) { return ArithemeticSequence::type,IncrType>( - symbolic2value(ids.firstObject(),size),symbolic2value(ids.sizeObject(),size),ids.incrObject()); + eval_expr_given_size(ids.firstObject(),size),eval_expr_given_size(ids.sizeObject(),size),ids.incrObject()); } // Convert a symbolic 'all' into a usable range @@ -522,10 +527,10 @@ struct end_t { }; static const end_t end; -Index symbolic2value(last_t, Index size) { return size-1; } -Index symbolic2value(shifted_last x, Index size) { return size+x.offset-1; } -Index symbolic2value(end_t, Index size) { return size; } -Index symbolic2value(shifted_end x, Index size) { return size+x.offset; } +Index eval_expr_given_size(last_t, Index size) { return size-1; } +Index eval_expr_given_size(shifted_last x, Index size) { return size+x.offset-1; } +Index eval_expr_given_size(end_t, Index size) { return size; } +Index eval_expr_given_size(shifted_end x, Index size) { return size+x.offset; } template > class ArithemeticSequenceProxyWithBounds @@ -553,15 +558,21 @@ protected: }; template -ArithemeticSequenceProxyWithBounds::type,typename cleanup_seq_type::type > +ArithemeticSequenceProxyWithBounds::type,typename internal::cleanup_seq_type::type > seq(FirstType f, LastType l) { - return ArithemeticSequenceProxyWithBounds::type,typename cleanup_seq_type::type>(f,l); + return ArithemeticSequenceProxyWithBounds::type,typename internal::cleanup_seq_type::type>(f,l); } template -ArithemeticSequenceProxyWithBounds::type,typename cleanup_seq_type::type,typename cleanup_seq_type::type > -seq(FirstType f, LastType l, IncrType s) { - return ArithemeticSequenceProxyWithBounds::type,typename cleanup_seq_type::type,typename cleanup_seq_type::type>(f,l,typename cleanup_seq_type::type(s)); +ArithemeticSequenceProxyWithBounds< typename internal::cleanup_seq_type::type, + typename internal::cleanup_seq_type::type, + typename internal::cleanup_seq_type::type > +seq(FirstType f, LastType l, IncrType s) +{ + return ArithemeticSequenceProxyWithBounds::type, + typename internal::cleanup_seq_type::type, + typename internal::cleanup_seq_type::type> + (f,l,typename internal::cleanup_seq_type::type(s)); } } @@ -583,7 +594,7 @@ template legacy::ArithemeticSequenceProxyWithBounds make_indexing(const legacy::ArithemeticSequenceProxyWithBounds& ids, Index size) { return legacy::ArithemeticSequenceProxyWithBounds( - symbolic2value(ids.firstObject(),size),symbolic2value(ids.lastObject(),size),ids.incrObject()); + eval_expr_given_size(ids.firstObject(),size),eval_expr_given_size(ids.lastObject(),size),ids.incrObject()); } } From a98c7efb163a1183d61ae56cacc7d903057285f0 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 10 Jan 2017 11:46:29 +0100 Subject: [PATCH 17/65] Add a more generic evaluation mechanism and minimalistic doc. --- Eigen/src/Core/ArithmeticSequence.h | 55 ++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 38cc32aa3..dc346bac6 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -23,6 +23,29 @@ static const all_t all; // minimalistic symbolic scalar type //-------------------------------------------------------------------------------- + +/** This namespace defines a set of classes and functions to build and evaluate symbolic expressions of scalar type Index. + * Here is a simple example: + * + * \code + * // First step, defines symbols: + * struct x_tag {}; static const Symbolic::SymbolExpr x; + * struct y_tag {}; static const Symbolic::SymbolExpr y; + * struct z_tag {}; static const Symbolic::SymbolExpr z; + * + * // Defines an expression: + * auto expr = (x+3)/y+z; + * + * // And evaluate it: (c++14) + * std::cout << expr.eval(std::make_tuple(Symbolic::defineValue(x,6),Symbolic::defineValue(y,3),Symbolic::defineValue(z,-13))) << "\n"; + * + * // In c++98/11, only one symbol per expression is supported for now: + * auto expr98 = (3-x)/2; + * std::cout << expr98.eval(Symbolic::defineValue(x,6)) << "\n"; + * + * It is currently only used internally to define and minipulate the placeholders::last and placeholders::end symbols in Eigen::seq and Eigen::seqN. + * + */ namespace Symbolic { template class Symbol; @@ -42,12 +65,24 @@ protected: Index m_value; }; +/** \class BaseExpr + * Common base class of any symbolic expressions + */ template class BaseExpr { public: const Derived& derived() const { return *static_cast(this); } + /** Evaluate the expression given the \a values of the symbols. + * + * \param values defines the values of the symbols, it can either be a SymbolValue or a std::tuple of SymbolValue + * as constructed by the defineValue function. + * + */ + template + Index eval(const T& values) const { return derived().eval(values); } + NegateExpr operator-() const { return NegateExpr(derived()); } AddExpr operator+(Index b) const @@ -73,7 +108,7 @@ public: { return AddExpr >(derived(), -b.derived()); } template - AddExpr operator/(const BaseExpr &b) const + QuotientExpr operator/(const BaseExpr &b) const { return QuotientExpr(derived(), b.derived()); } }; @@ -83,11 +118,18 @@ struct is_symbolic { enum { value = internal::is_convertible >::value }; }; +/** Represents the actual value of a symbol identified by its tag + * + * It is the return type of defineValue(), and most of the time this is only way it is used. + */ template class SymbolValue { public: + /** Default constructor from the value \a val */ SymbolValue(Index val) : m_value(val) {} + + /** \returns the stored value of the symbol */ Index value() const { return m_value; } protected: Index m_value; @@ -102,12 +144,17 @@ public: Index eval(const SymbolValue &values) const { return values.value(); } - - // TODO add a c++14 eval taking a tuple of SymbolValue and getting the value with std::get >... +#if __cplusplus > 201103L + // C++14 versions suitable for multiple symbols + template + Index eval(const std::tuple& values) const { return std::get >(values).value(); } +#endif }; +/** Associate the value \a val to the symbol \a symb + */ template -SymbolValue defineValue(SymbolExpr,Index val) { +SymbolValue defineValue(SymbolExpr /*symb*/,Index val) { return SymbolValue(val); } From 87963f441c9abd8514b94b6b2c712652d646ed64 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 10 Jan 2017 14:25:30 +0100 Subject: [PATCH 18/65] Fallback to Block<> when possible (Index, all, seq with > increment). This is important to take advantage of the optimized implementations (evaluator, products, etc.), and to support sparse matrices. --- Eigen/src/Core/ArithmeticSequence.h | 6 ++++++ Eigen/src/Core/DenseBase.h | 27 ++++++++++++++++++++++++--- Eigen/src/Core/IndexedView.h | 6 ++++++ test/indexed_view.cpp | 17 +++++++++++++++++ 4 files changed, 53 insertions(+), 3 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index dc346bac6..dd24d0b05 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -272,6 +272,7 @@ public: }; Index size() const { return m_size; } + Index first() const { return m_first; } Index operator[](Index i) const { return m_first + i * m_incr; } const FirstType& firstObject() const { return m_first; } @@ -414,6 +415,9 @@ Index size(const T& x) { return x.size(); } template Index size(const T (&) [N]) { return N; } +template +Index first(const T& x) { return x.first(); } + template struct get_compile_time_size { enum { value = Dynamic }; }; @@ -458,6 +462,7 @@ struct IntAsArray { IntAsArray(Index val) : m_value(val) {} Index operator[](Index) const { return m_value; } Index size() const { return 1; } + Index first() const { return m_value; } Index m_value; }; @@ -512,6 +517,7 @@ struct AllRange { AllRange(Index size) : m_size(size) {} Index operator[](Index i) const { return i; } Index size() const { return m_size; } + Index first() const { return 0; } Index m_size; }; diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index 07057ce69..7c01e9328 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -557,15 +557,36 @@ template class DenseBase } EIGEN_DEVICE_FUNC void reverseInPlace(); + template + struct IndexedViewType { + typedef IndexedView::type,typename internal::MakeIndexing::type> type; + }; + template typename internal::enable_if< - !(internal::is_integral::value && internal::is_integral::value), - IndexedView::type,typename internal::MakeIndexing::type> >::type + ! (internal::traits::type>::IsBlockAlike + || (internal::is_integral::value && internal::is_integral::value)), + typename IndexedViewType::type >::type operator()(const RowIndices& rowIndices, const ColIndices& colIndices) const { - return IndexedView::type,typename internal::MakeIndexing::type>( + return typename IndexedViewType::type( derived(), internal::make_indexing(rowIndices,derived().rows()), internal::make_indexing(colIndices,derived().cols())); } + template + typename internal::enable_if< + internal::traits::type>::IsBlockAlike, + typename internal::traits::type>::BlockType>::type + operator()(const RowIndices& rowIndices, const ColIndices& colIndices) const { + typedef typename internal::traits::type>::BlockType BlockType; + typename internal::MakeIndexing::type actualRowIndices = internal::make_indexing(rowIndices,derived().rows()); + typename internal::MakeIndexing::type actualColIndices = internal::make_indexing(colIndices,derived().cols()); + return BlockType(derived(), + internal::first(actualRowIndices), + internal::first(actualColIndices), + internal::size(actualRowIndices), + internal::size(actualColIndices)); + } + template IndexedView::type> operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndices& colIndices) const { diff --git a/Eigen/src/Core/IndexedView.h b/Eigen/src/Core/IndexedView.h index 5ff1c1837..ab9f6b453 100644 --- a/Eigen/src/Core/IndexedView.h +++ b/Eigen/src/Core/IndexedView.h @@ -38,6 +38,9 @@ struct traits > XprInnerStride = HasSameStorageOrderAsXprType ? int(inner_stride_at_compile_time::ret) : int(outer_stride_at_compile_time::ret), XprOuterstride = HasSameStorageOrderAsXprType ? int(outer_stride_at_compile_time::ret) : int(inner_stride_at_compile_time::ret), + IsBlockAlike = InnerIncr==1 && OuterIncr==1, + IsInnerPannel = HasSameStorageOrderAsXprType && is_same::type>::value, + InnerStrideAtCompileTime = InnerIncr<0 || InnerIncr==DynamicIndex || XprInnerStride==Dynamic ? Dynamic : XprInnerStride * InnerIncr, OuterStrideAtCompileTime = OuterIncr<0 || OuterIncr==DynamicIndex || XprOuterstride==Dynamic ? Dynamic : XprOuterstride * OuterIncr, @@ -48,8 +51,11 @@ struct traits > FlagsLvalueBit = is_lvalue::value ? LvalueBit : 0, Flags = (traits::Flags & (HereditaryBits | DirectAccessMask)) | FlagsLvalueBit | FlagsRowMajorBit }; + + typedef Block BlockType; }; + } template diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index e04fe0cd4..fde3ee8f9 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -41,6 +41,13 @@ bool match(const T& xpr, std::string ref, std::string str_xpr = "") { #define MATCH(X,R) match(X, R, #X) +template +typename internal::enable_if::value,bool>::type +is_same_type(const T1& a, const T2& b) +{ + return (a == b).all(); +} + void check_indexed_view() { using Eigen::placeholders::last; @@ -159,6 +166,16 @@ 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)) ); + // Check fall-back to Block + { + const ArrayXXi& cA(A); + VERIFY( is_same_type(cA.col(0), cA(all,0)) ); + VERIFY( is_same_type(cA.row(0), cA(0,all)) ); + VERIFY( is_same_type(cA.block(0,0,2,2), cA(seqN(0,2),seq(0,1))) ); + VERIFY( is_same_type(cA.middleRows(2,4), cA(seqN(2,4),all)) ); + VERIFY( is_same_type(cA.middleCols(2,4), cA(all,seqN(2,4))) ); + } + #if EIGEN_HAS_CXX11 VERIFY( (A(all, std::array{{1,3,2,4}})).ColsAtCompileTime == 4); From b47a7e5c3a01018951a30fe51043b702dc7048be Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 10 Jan 2017 16:28:57 +0100 Subject: [PATCH 19/65] Add doc for IndexedView --- Eigen/src/Core/IndexedView.h | 47 ++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Core/IndexedView.h b/Eigen/src/Core/IndexedView.h index ab9f6b453..12e122030 100644 --- a/Eigen/src/Core/IndexedView.h +++ b/Eigen/src/Core/IndexedView.h @@ -55,13 +55,49 @@ struct traits > typedef Block BlockType; }; - } template class IndexedViewImpl; -// Expression of a generic slice + +/** \class IndexedView + * \ingroup Core_Module + * + * \brief Expression of a non-sequential sub-matrix defined by arbitrary sequences of row and column indices + * + * \tparam XprType the type of the expression in which we are taking the intersections of sub-rows and sub-columns + * \tparam RowIndices the type of the object defining the sequence of row indices + * \tparam ColIndices the type of the object defining the sequence of column indices + * + * This class represents an expression of a sub-matrix (or sub-vector) defined as the intersection + * of sub-sets of rows and columns, that are themself defined by generic sequences of row indices \f${r_0,r_1,..r_{m-1}\f$ + * and column indices \f${c_0,c_1,..c_{n-1}\f$. Let \f$ A \f$ be the nested matrix, then the resulting matrix \f$ B \f$ has \c m + * rows and \c n columns, and its entries are given by: \f$ B(i,j) = A(r_i,c_j) \f$. + * + * The \c RowIndices and \c ColIndices types must be compatible with the following API: + * \code + * operator[](Index) const; + * Index size() const; + * \endcode + * + * Typical supported types thus include: + * - std::vector + * - std::valarray + * - std::array + * - c++ arrays: int[N] + * - Eigen::ArrayXi + * - decltype(ArrayXi::LinSpaced(...)) + * - Any view/expressions of the previous types + * - Eigen::ArithmeticSequence + * - Eigen::AllRange (helper for Eigen::all) + * - Eigen::IntAsArray (helper for single index) + * - etc. + * + * In typical usages of %Eigen, this class should never be used directly. It is the return type of DenseBase::operator(). + * + * \sa class Block + */ template class IndexedView : public IndexedViewImpl::StorageKind> { @@ -76,7 +112,11 @@ public: IndexedView(XprType& xpr, const T0& rowIndices, const T1& colIndices) : m_xpr(xpr), m_rowIndices(rowIndices), m_colIndices(colIndices) {} + + /** \returns number of rows */ Index rows() const { return internal::size(m_rowIndices); } + + /** \returns number of columns */ Index cols() const { return internal::size(m_colIndices); } /** \returns the nested expression */ @@ -87,7 +127,10 @@ public: typename internal::remove_reference::type& nestedExpression() { return m_xpr.const_cast_derived(); } + /** \returns a const reference to the object storing/generating the row indices */ const RowIndices& rowIndices() const { return m_rowIndices; } + + /** \returns a const reference to the object storing/generating the column indices */ const ColIndices& colIndices() const { return m_colIndices; } protected: From 8e247744a41dab895fec206020b58a6e6f28b0f7 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 10 Jan 2017 16:32:06 +0100 Subject: [PATCH 20/65] Fix linking issue --- Eigen/src/Core/ArithmeticSequence.h | 10 +++++----- Eigen/src/Core/IndexedView.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index dd24d0b05..238601818 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -480,7 +480,7 @@ struct MakeIndexing::val }; // Replace symbolic last/end "keywords" by their true runtime value -Index eval_expr_given_size(Index x, Index /* size */) { return x; } +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; } @@ -580,10 +580,10 @@ struct end_t { }; static const end_t end; -Index eval_expr_given_size(last_t, Index size) { return size-1; } -Index eval_expr_given_size(shifted_last x, Index size) { return size+x.offset-1; } -Index eval_expr_given_size(end_t, Index size) { return size; } -Index eval_expr_given_size(shifted_end x, Index size) { return size+x.offset; } +inline Index eval_expr_given_size(last_t, Index size) { return size-1; } +inline Index eval_expr_given_size(shifted_last x, Index size) { return size+x.offset-1; } +inline Index eval_expr_given_size(end_t, Index size) { return size; } +inline Index eval_expr_given_size(shifted_end x, Index size) { return size+x.offset; } template > class ArithemeticSequenceProxyWithBounds diff --git a/Eigen/src/Core/IndexedView.h b/Eigen/src/Core/IndexedView.h index 12e122030..5aaf5b4e0 100644 --- a/Eigen/src/Core/IndexedView.h +++ b/Eigen/src/Core/IndexedView.h @@ -159,7 +159,7 @@ struct unary_evaluator, IndexBased> typedef IndexedView XprType; enum { - CoeffReadCost = evaluator::CoeffReadCost /* + cost of row/col index */, + CoeffReadCost = evaluator::CoeffReadCost /* TODO + cost of row/col index */, Flags = (evaluator::Flags & (HereditaryBits /*| LinearAccessBit | DirectAccessBit*/)), From e63678bc8969e76f0a767f0abf9a42f2a89c2d2a Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 10 Jan 2017 16:33:40 +0100 Subject: [PATCH 21/65] Fix ambiguous call --- Eigen/src/Core/DenseBase.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index 7c01e9328..779cb4549 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -574,7 +574,8 @@ template class DenseBase template typename internal::enable_if< - internal::traits::type>::IsBlockAlike, + internal::traits::type>::IsBlockAlike + && !(internal::is_integral::value && internal::is_integral::value), typename internal::traits::type>::BlockType>::type operator()(const RowIndices& rowIndices, const ColIndices& colIndices) const { typedef typename internal::traits::type>::BlockType BlockType; From 96e6cf9aa20a136068e4e7e2efcb4ecab8655ff0 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 10 Jan 2017 16:35:46 +0100 Subject: [PATCH 22/65] Fix linking issue. --- Eigen/src/Core/ArithmeticSequence.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 238601818..b425b7804 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -526,7 +526,7 @@ struct MakeIndexing { typedef AllRange type; }; -AllRange make_indexing(all_t , Index size) { +inline AllRange make_indexing(all_t , Index size) { return AllRange(size); } From 407e7b7a9376dd3f722f0fc08fb806b3970e594d Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 10 Jan 2017 16:45:32 +0100 Subject: [PATCH 23/65] Simplify symbolic API by using "symbol=value" to associate a runtime value to a symbol. --- Eigen/src/Core/ArithmeticSequence.h | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index b425b7804..01cc5e15b 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -37,11 +37,11 @@ static const all_t all; * auto expr = (x+3)/y+z; * * // And evaluate it: (c++14) - * std::cout << expr.eval(std::make_tuple(Symbolic::defineValue(x,6),Symbolic::defineValue(y,3),Symbolic::defineValue(z,-13))) << "\n"; + * std::cout << expr.eval(std::make_tuple(x=6,y=3,z=-13)) << "\n"; * * // In c++98/11, only one symbol per expression is supported for now: * auto expr98 = (3-x)/2; - * std::cout << expr98.eval(Symbolic::defineValue(x,6)) << "\n"; + * std::cout << expr98.eval(x=6) << "\n"; * * It is currently only used internally to define and minipulate the placeholders::last and placeholders::end symbols in Eigen::seq and Eigen::seqN. * @@ -77,7 +77,7 @@ public: /** Evaluate the expression given the \a values of the symbols. * * \param values defines the values of the symbols, it can either be a SymbolValue or a std::tuple of SymbolValue - * as constructed by the defineValue function. + * as constructed by SymbolExpr::operator= operator. * */ template @@ -120,7 +120,7 @@ struct is_symbolic { /** Represents the actual value of a symbol identified by its tag * - * It is the return type of defineValue(), and most of the time this is only way it is used. + * It is the return type of SymbolValue::operator=, and most of the time this is only way it is used. */ template class SymbolValue @@ -135,6 +135,7 @@ protected: Index m_value; }; +/** Expression of a symbol uniquely identified by the tag \tparam TagT */ template class SymbolExpr : public BaseExpr > { @@ -142,6 +143,14 @@ public: typedef TagT Tag; SymbolExpr() {} + /** Associate the value \a val to the given symbol \c *this, uniquely identified by its \c Tag. + * + * The returned object should be passed to ExprBase::eval() to evaluate a given expression with this specified runtime-time value. + */ + SymbolValue operator=(Index val) const { + return SymbolValue(val); + } + Index eval(const SymbolValue &values) const { return values.value(); } #if __cplusplus > 201103L @@ -151,13 +160,6 @@ public: #endif }; -/** Associate the value \a val to the symbol \a symb - */ -template -SymbolValue defineValue(SymbolExpr /*symb*/,Index val) { - return SymbolValue(val); -} - template class NegateExpr : public BaseExpr > { @@ -488,7 +490,7 @@ 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(Symbolic::defineValue(placeholders::last,size-1)); + return x.derived().eval(placeholders::last=size-1); } // Convert a symbolic span into a usable one (i.e., remove last/end "keywords") From c9d5e5c6dac14fac1a4bc16b6e1570479daeacb8 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 10 Jan 2017 16:55:07 +0100 Subject: [PATCH 24/65] Simplify Symbolic API: std::tuple is now used internally and automatically built. --- Eigen/src/Core/ArithmeticSequence.h | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 01cc5e15b..bbedd99c2 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -37,7 +37,7 @@ static const all_t all; * auto expr = (x+3)/y+z; * * // And evaluate it: (c++14) - * std::cout << expr.eval(std::make_tuple(x=6,y=3,z=-13)) << "\n"; + * std::cout << expr.eval(x=6,y=3,z=-13) << "\n"; * * // In c++98/11, only one symbol per expression is supported for now: * auto expr98 = (3-x)/2; @@ -60,7 +60,7 @@ class ValueExpr { public: ValueExpr(Index val) : m_value(val) {} template - Index eval(const T&) const { return m_value; } + Index eval_impl(const T&) const { return m_value; } protected: Index m_value; }; @@ -81,7 +81,12 @@ public: * */ template - Index eval(const T& values) const { return derived().eval(values); } + Index eval(const T& values) const { return derived().eval_impl(values); } + +#if __cplusplus > 201103L + template + Index eval(Types&&... values) const { return derived().eval_impl(std::make_tuple(values...)); } +#endif NegateExpr operator-() const { return NegateExpr(derived()); } @@ -151,12 +156,12 @@ public: return SymbolValue(val); } - Index eval(const SymbolValue &values) const { return values.value(); } + Index eval_impl(const SymbolValue &values) const { return values.value(); } #if __cplusplus > 201103L // C++14 versions suitable for multiple symbols template - Index eval(const std::tuple& values) const { return std::get >(values).value(); } + Index eval_impl(const std::tuple& values) const { return std::get >(values).value(); } #endif }; @@ -167,7 +172,7 @@ public: NegateExpr(const Arg0& arg0) : m_arg0(arg0) {} template - Index eval(const T& values) const { return -m_arg0.eval(values); } + Index eval_impl(const T& values) const { return -m_arg0.eval_impl(values); } protected: Arg0 m_arg0; }; @@ -179,7 +184,7 @@ public: AddExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} template - Index eval(const T& values) const { return m_arg0.eval(values) + m_arg1.eval(values); } + Index eval_impl(const T& values) const { return m_arg0.eval_impl(values) + m_arg1.eval_impl(values); } protected: Arg0 m_arg0; Arg1 m_arg1; @@ -192,7 +197,7 @@ public: ProductExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} template - Index eval(const T& values) const { return m_arg0.eval(values) * m_arg1.eval(values); } + Index eval_impl(const T& values) const { return m_arg0.eval_impl(values) * m_arg1.eval_impl(values); } protected: Arg0 m_arg0; Arg1 m_arg1; @@ -205,7 +210,7 @@ public: QuotientExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} template - Index eval(const T& values) const { return m_arg0.eval(values) / m_arg1.eval(values); } + Index eval_impl(const T& values) const { return m_arg0.eval_impl(values) / m_arg1.eval_impl(values); } protected: Arg0 m_arg0; Arg1 m_arg1; From d072fc4b1432b193d24e44d70885b636d4132405 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 10 Jan 2017 17:10:35 +0100 Subject: [PATCH 25/65] add writeable IndexedView --- Eigen/src/Core/DenseBase.h | 66 ++++++++++++++++++++++++++++++++---- Eigen/src/Core/IndexedView.h | 7 ++++ test/indexed_view.cpp | 15 ++++++++ 3 files changed, 81 insertions(+), 7 deletions(-) diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index 779cb4549..909fa0f12 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -558,27 +558,27 @@ template class DenseBase EIGEN_DEVICE_FUNC void reverseInPlace(); template - struct IndexedViewType { + struct ConstIndexedViewType { typedef IndexedView::type,typename internal::MakeIndexing::type> type; }; template typename internal::enable_if< - ! (internal::traits::type>::IsBlockAlike + ! (internal::traits::type>::IsBlockAlike || (internal::is_integral::value && internal::is_integral::value)), - typename IndexedViewType::type >::type + typename ConstIndexedViewType::type >::type operator()(const RowIndices& rowIndices, const ColIndices& colIndices) const { - return typename IndexedViewType::type( + return typename ConstIndexedViewType::type( derived(), internal::make_indexing(rowIndices,derived().rows()), internal::make_indexing(colIndices,derived().cols())); } template typename internal::enable_if< - internal::traits::type>::IsBlockAlike + internal::traits::type>::IsBlockAlike && !(internal::is_integral::value && internal::is_integral::value), - typename internal::traits::type>::BlockType>::type + typename internal::traits::type>::BlockType>::type operator()(const RowIndices& rowIndices, const ColIndices& colIndices) const { - typedef typename internal::traits::type>::BlockType BlockType; + typedef typename internal::traits::type>::BlockType BlockType; typename internal::MakeIndexing::type actualRowIndices = internal::make_indexing(rowIndices,derived().rows()); typename internal::MakeIndexing::type actualColIndices = internal::make_indexing(colIndices,derived().cols()); return BlockType(derived(), @@ -609,6 +609,58 @@ template class DenseBase derived(), rowIndices, colIndices); } + template + struct IndexedViewType { + typedef IndexedView::type,typename internal::MakeIndexing::type> type; + }; + + template + typename internal::enable_if< + ! (internal::traits::type>::IsBlockAlike + || (internal::is_integral::value && internal::is_integral::value)), + typename IndexedViewType::type >::type + operator()(const RowIndices& rowIndices, const ColIndices& colIndices) { + return typename IndexedViewType::type( + derived(), internal::make_indexing(rowIndices,derived().rows()), internal::make_indexing(colIndices,derived().cols())); + } + + template + typename internal::enable_if< + internal::traits::type>::IsBlockAlike + && !(internal::is_integral::value && internal::is_integral::value), + typename internal::traits::type>::BlockType>::type + operator()(const RowIndices& rowIndices, const ColIndices& colIndices) { + typedef typename internal::traits::type>::BlockType BlockType; + typename internal::MakeIndexing::type actualRowIndices = internal::make_indexing(rowIndices,derived().rows()); + typename internal::MakeIndexing::type actualColIndices = internal::make_indexing(colIndices,derived().cols()); + return BlockType(derived(), + internal::first(actualRowIndices), + internal::first(actualColIndices), + internal::size(actualRowIndices), + internal::size(actualColIndices)); + } + + template + IndexedView::type> + operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndices& colIndices) { + return IndexedView::type>( + derived(), rowIndices, internal::make_indexing(colIndices,derived().cols())); + } + + template + IndexedView::type, const ColIndicesT (&)[ColIndicesN]> + operator()(const RowIndices& rowIndices, const ColIndicesT (&colIndices)[ColIndicesN]) { + return IndexedView::type,const ColIndicesT (&)[ColIndicesN]>( + derived(), internal::make_indexing(rowIndices,derived().rows()), colIndices); + } + + template + IndexedView + operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndicesT (&colIndices)[ColIndicesN]) { + return IndexedView( + derived(), rowIndices, colIndices); + } + #define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::DenseBase #define EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL #define EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(COND) diff --git a/Eigen/src/Core/IndexedView.h b/Eigen/src/Core/IndexedView.h index 5aaf5b4e0..81ff53758 100644 --- a/Eigen/src/Core/IndexedView.h +++ b/Eigen/src/Core/IndexedView.h @@ -104,6 +104,7 @@ class IndexedView : public IndexedViewImpl::StorageKind>::Base Base; EIGEN_GENERIC_PUBLIC_INTERFACE(IndexedView) + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(IndexedView) typedef typename internal::ref_selector::non_const_type MatrixTypeNested; typedef typename internal::remove_all::type NestedExpression; @@ -180,6 +181,12 @@ struct unary_evaluator, IndexBased> return m_argImpl.coeff(m_xpr.rowIndices()[row], m_xpr.colIndices()[col]); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index row, Index col) + { + return m_argImpl.coeffRef(m_xpr.rowIndices()[row], m_xpr.colIndices()[col]); + } + protected: evaluator m_argImpl; diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index fde3ee8f9..42d136847 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -168,6 +168,12 @@ void check_indexed_view() // Check fall-back to Block { + VERIFY( is_same_type(A.col(0), A(all,0)) ); + VERIFY( is_same_type(A.row(0), A(0,all)) ); + VERIFY( is_same_type(A.block(0,0,2,2), A(seqN(0,2),seq(0,1))) ); + 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))) ); + const ArrayXXi& cA(A); VERIFY( is_same_type(cA.col(0), cA(all,0)) ); VERIFY( is_same_type(cA.row(0), cA(0,all)) ); @@ -176,6 +182,15 @@ void check_indexed_view() VERIFY( is_same_type(cA.middleCols(2,4), cA(all,seqN(2,4))) ); } + ArrayXXi A1=A, A2 = ArrayXXi::Random(4,4); + ArrayXi range25(4); range25 << 3,2,4,5; + A1(seqN(3,4),seq(2,5)) = A2; + VERIFY_IS_APPROX( A1.block(3,2,4,4), A2 ); + A1 = A; + A2.setOnes(); + A1(seq(6,3,-1),range25) = A2; + VERIFY_IS_APPROX( A1.block(3,2,4,4), A2 ); + #if EIGEN_HAS_CXX11 VERIFY( (A(all, std::array{{1,3,2,4}})).ColsAtCompileTime == 4); From 17eac60446650dc31bde7156a4febe504ab347b7 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 10 Jan 2017 21:45:55 +0100 Subject: [PATCH 26/65] Factorize const and non-const version of the generic operator() method. --- Eigen/src/Core/DenseBase.h | 105 +------------------------ Eigen/src/Core/IndexedView.h | 4 +- Eigen/src/plugins/IndexedViewMethods.h | 81 +++++++++++++++++++ 3 files changed, 84 insertions(+), 106 deletions(-) create mode 100644 Eigen/src/plugins/IndexedViewMethods.h diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index 909fa0f12..a8229cf03 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -557,116 +557,13 @@ template class DenseBase } EIGEN_DEVICE_FUNC void reverseInPlace(); - template - struct ConstIndexedViewType { - typedef IndexedView::type,typename internal::MakeIndexing::type> type; - }; - - template - typename internal::enable_if< - ! (internal::traits::type>::IsBlockAlike - || (internal::is_integral::value && internal::is_integral::value)), - typename ConstIndexedViewType::type >::type - operator()(const RowIndices& rowIndices, const ColIndices& colIndices) const { - return typename ConstIndexedViewType::type( - derived(), internal::make_indexing(rowIndices,derived().rows()), internal::make_indexing(colIndices,derived().cols())); - } - - template - typename internal::enable_if< - internal::traits::type>::IsBlockAlike - && !(internal::is_integral::value && internal::is_integral::value), - typename internal::traits::type>::BlockType>::type - operator()(const RowIndices& rowIndices, const ColIndices& colIndices) const { - typedef typename internal::traits::type>::BlockType BlockType; - typename internal::MakeIndexing::type actualRowIndices = internal::make_indexing(rowIndices,derived().rows()); - typename internal::MakeIndexing::type actualColIndices = internal::make_indexing(colIndices,derived().cols()); - return BlockType(derived(), - internal::first(actualRowIndices), - internal::first(actualColIndices), - internal::size(actualRowIndices), - internal::size(actualColIndices)); - } - - template - IndexedView::type> - operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndices& colIndices) const { - return IndexedView::type>( - derived(), rowIndices, internal::make_indexing(colIndices,derived().cols())); - } - - template - IndexedView::type, const ColIndicesT (&)[ColIndicesN]> - operator()(const RowIndices& rowIndices, const ColIndicesT (&colIndices)[ColIndicesN]) const { - return IndexedView::type,const ColIndicesT (&)[ColIndicesN]>( - derived(), internal::make_indexing(rowIndices,derived().rows()), colIndices); - } - - template - IndexedView - operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndicesT (&colIndices)[ColIndicesN]) const { - return IndexedView( - derived(), rowIndices, colIndices); - } - - template - struct IndexedViewType { - typedef IndexedView::type,typename internal::MakeIndexing::type> type; - }; - - template - typename internal::enable_if< - ! (internal::traits::type>::IsBlockAlike - || (internal::is_integral::value && internal::is_integral::value)), - typename IndexedViewType::type >::type - operator()(const RowIndices& rowIndices, const ColIndices& colIndices) { - return typename IndexedViewType::type( - derived(), internal::make_indexing(rowIndices,derived().rows()), internal::make_indexing(colIndices,derived().cols())); - } - - template - typename internal::enable_if< - internal::traits::type>::IsBlockAlike - && !(internal::is_integral::value && internal::is_integral::value), - typename internal::traits::type>::BlockType>::type - operator()(const RowIndices& rowIndices, const ColIndices& colIndices) { - typedef typename internal::traits::type>::BlockType BlockType; - typename internal::MakeIndexing::type actualRowIndices = internal::make_indexing(rowIndices,derived().rows()); - typename internal::MakeIndexing::type actualColIndices = internal::make_indexing(colIndices,derived().cols()); - return BlockType(derived(), - internal::first(actualRowIndices), - internal::first(actualColIndices), - internal::size(actualRowIndices), - internal::size(actualColIndices)); - } - - template - IndexedView::type> - operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndices& colIndices) { - return IndexedView::type>( - derived(), rowIndices, internal::make_indexing(colIndices,derived().cols())); - } - - template - IndexedView::type, const ColIndicesT (&)[ColIndicesN]> - operator()(const RowIndices& rowIndices, const ColIndicesT (&colIndices)[ColIndicesN]) { - return IndexedView::type,const ColIndicesT (&)[ColIndicesN]>( - derived(), internal::make_indexing(rowIndices,derived().rows()), colIndices); - } - - template - IndexedView - operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndicesT (&colIndices)[ColIndicesN]) { - return IndexedView( - derived(), rowIndices, colIndices); - } - #define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::DenseBase #define EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL #define EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(COND) #define EIGEN_DOC_UNARY_ADDONS(X,Y) # include "../plugins/CommonCwiseUnaryOps.h" # include "../plugins/BlockMethods.h" +# include "../plugins/IndexedViewMethods.h" # ifdef EIGEN_DENSEBASE_PLUGIN # include EIGEN_DENSEBASE_PLUGIN # endif diff --git a/Eigen/src/Core/IndexedView.h b/Eigen/src/Core/IndexedView.h index 81ff53758..269882e78 100644 --- a/Eigen/src/Core/IndexedView.h +++ b/Eigen/src/Core/IndexedView.h @@ -71,8 +71,8 @@ class IndexedViewImpl; * \tparam ColIndices the type of the object defining the sequence of column indices * * This class represents an expression of a sub-matrix (or sub-vector) defined as the intersection - * of sub-sets of rows and columns, that are themself defined by generic sequences of row indices \f${r_0,r_1,..r_{m-1}\f$ - * and column indices \f${c_0,c_1,..c_{n-1}\f$. Let \f$ A \f$ be the nested matrix, then the resulting matrix \f$ B \f$ has \c m + * of sub-sets of rows and columns, that are themself defined by generic sequences of row indices \f$ \{r_0,r_1,..r_{m-1}\} \f$ + * and column indices \f$ \{c_0,c_1,..c_{n-1} \}\f$. Let \f$ A \f$ be the nested matrix, then the resulting matrix \f$ B \f$ has \c m * rows and \c n columns, and its entries are given by: \f$ B(i,j) = A(r_i,c_j) \f$. * * The \c RowIndices and \c ColIndices types must be compatible with the following API: diff --git a/Eigen/src/plugins/IndexedViewMethods.h b/Eigen/src/plugins/IndexedViewMethods.h new file mode 100644 index 000000000..53eff093c --- /dev/null +++ b/Eigen/src/plugins/IndexedViewMethods.h @@ -0,0 +1,81 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2017 Gael Guennebaud +// +// 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/. + + +// This file is automatically included twice to generate const and non-const versions + +#ifndef EIGEN_INDEXED_VIEW_METHOD_2ND_PASS +#define EIGEN_INDEXED_VIEW_METHOD_CONST const +#define EIGEN_INDEXED_VIEW_METHOD_TYPE ConstIndexedViewType +#else +#define EIGEN_INDEXED_VIEW_METHOD_CONST +#define EIGEN_INDEXED_VIEW_METHOD_TYPE IndexedViewType +#endif + +template +struct EIGEN_INDEXED_VIEW_METHOD_TYPE { + typedef IndexedView::type,typename internal::MakeIndexing::type> type; +}; + +template +typename internal::enable_if< + ! (internal::traits::type>::IsBlockAlike + || (internal::is_integral::value && internal::is_integral::value)), + typename EIGEN_INDEXED_VIEW_METHOD_TYPE::type >::type +operator()(const RowIndices& rowIndices, const ColIndices& colIndices) EIGEN_INDEXED_VIEW_METHOD_CONST { + return typename EIGEN_INDEXED_VIEW_METHOD_TYPE::type( + derived(), internal::make_indexing(rowIndices,derived().rows()), internal::make_indexing(colIndices,derived().cols())); +} + +template +typename internal::enable_if< + internal::traits::type>::IsBlockAlike + && !(internal::is_integral::value && internal::is_integral::value), + typename internal::traits::type>::BlockType>::type +operator()(const RowIndices& rowIndices, const ColIndices& colIndices) EIGEN_INDEXED_VIEW_METHOD_CONST { + typedef typename internal::traits::type>::BlockType BlockType; + typename internal::MakeIndexing::type actualRowIndices = internal::make_indexing(rowIndices,derived().rows()); + typename internal::MakeIndexing::type actualColIndices = internal::make_indexing(colIndices,derived().cols()); + return BlockType(derived(), + internal::first(actualRowIndices), + internal::first(actualColIndices), + internal::size(actualRowIndices), + internal::size(actualColIndices)); +} + +template +IndexedView::type> +operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndices& colIndices) EIGEN_INDEXED_VIEW_METHOD_CONST { + return IndexedView::type>( + derived(), rowIndices, internal::make_indexing(colIndices,derived().cols())); +} + +template +IndexedView::type, const ColIndicesT (&)[ColIndicesN]> +operator()(const RowIndices& rowIndices, const ColIndicesT (&colIndices)[ColIndicesN]) EIGEN_INDEXED_VIEW_METHOD_CONST { + return IndexedView::type,const ColIndicesT (&)[ColIndicesN]>( + derived(), internal::make_indexing(rowIndices,derived().rows()), colIndices); +} + +template +IndexedView +operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndicesT (&colIndices)[ColIndicesN]) EIGEN_INDEXED_VIEW_METHOD_CONST { + return IndexedView( + derived(), rowIndices, colIndices); +} + +#undef EIGEN_INDEXED_VIEW_METHOD_CONST +#undef EIGEN_INDEXED_VIEW_METHOD_TYPE + +#ifndef EIGEN_INDEXED_VIEW_METHOD_2ND_PASS +#define EIGEN_INDEXED_VIEW_METHOD_2ND_PASS +#include "IndexedViewMethods.h" +#undef EIGEN_INDEXED_VIEW_METHOD_2ND_PASS +#endif + From 1b5570988bd2d6f783874e2d4fd6b7be45c8ac3c Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 10 Jan 2017 22:58:58 +0100 Subject: [PATCH 27/65] Add doc to seq, seqN, ArithmeticSequence, operator(), etc. --- Eigen/src/Core/ArithmeticSequence.h | 91 +++++++++++++++++++++++++- Eigen/src/Core/IndexedView.h | 4 +- Eigen/src/plugins/IndexedViewMethods.h | 88 ++++++++++++++++++++----- 3 files changed, 162 insertions(+), 21 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index bbedd99c2..0fadfb86c 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -17,6 +17,8 @@ namespace Eigen { //-------------------------------------------------------------------------------- struct all_t { all_t() {} }; + +/** Can be used as a parameter to DenseBase::operator()(const RowIndices&, const ColIndices&) to index all rows or columns */ static const all_t all; //-------------------------------------------------------------------------------- @@ -24,7 +26,10 @@ static const all_t all; //-------------------------------------------------------------------------------- -/** This namespace defines a set of classes and functions to build and evaluate symbolic expressions of scalar type Index. +/** \namespace Symbolic + * \ingroup Core_Module + * + * This namespace defines a set of classes and functions to build and evaluate symbolic expressions of scalar type Index. * Here is a simple example: * * \code @@ -42,6 +47,7 @@ static const all_t all; * // In c++98/11, only one symbol per expression is supported for now: * auto expr98 = (3-x)/2; * std::cout << expr98.eval(x=6) << "\n"; + * \endcode * * It is currently only used internally to define and minipulate the placeholders::last and placeholders::end symbols in Eigen::seq and Eigen::seqN. * @@ -218,13 +224,39 @@ protected: } // end namespace Symbolic +/** \namespace placeholders + */ namespace placeholders { namespace internal { struct symbolic_last_tag {}; } +/** Can be used as a parameter to seq and 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; + +/** Can be used as a parameter to seq and 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 + */ static const Symbolic::AddExpr,Symbolic::ValueExpr> end(last+1); } // end namespace placeholders @@ -265,6 +297,24 @@ inline fix_t fix() { return fix_t(); } // seq(first,last,incr) and seqN(first,size,incr) //-------------------------------------------------------------------------------- +/** \class ArithemeticSequence + * + * This class represents an arithmetic progression \f$ a_0, a_1, a_2, ..., a_{n-1}\f$ defined by + * its \em first value \f$ a_0 \f$, its \em size (aka length) \em n, and the \em increment (aka stride) + * that is equal to \f$ a_{i+1}-a_{i}\f$ for any \em i. + * + * It is internally used as the return type of the seq and seqN functions, and as the input arguments + * of DenseBase::operator()(const RowIndices&, const ColIndices&), and most of the time this is the + * only way it is used. + * + * \tparam FirstType type of the first element, usually an Index, + * but internally it can be a symbolic expression + * \tparam SizeType type representing the size of the sequence, usually an Index + * or a compile time integral constant. Internally, it can also be a symbolic expression + * \tparam IncrType type of the increment, can be a runtime Index, or a compile time integral constant (default is compile-time 1) + * + * \sa seq, seqN, DenseBase::operator()(const RowIndices&, const ColIndices&), class IndexedView + */ template > class ArithemeticSequence { @@ -278,8 +328,13 @@ public: IncrAtCompileTime = get_compile_time::value }; + /** \returns the size, i.e., number of elements, of the sequence */ Index size() const { return m_size; } + + /** \returns the first element \f$ a_0 \f$ in the sequence */ Index first() const { return m_first; } + + /** \returns the value \f$ a_i \f$ at index \a i in the sequence. */ Index operator[](Index i) const { return m_first + i * m_incr; } const FirstType& firstObject() const { return m_first; } @@ -301,18 +356,50 @@ template struct cleanup_seq_type (*)() > { typedef fix_t type } +/** \returns an ArithemeticSequence starting at \a first, of length \a size, and increment \a incr + * \sa seqN(FirstType,SizeType), seq(FirstType,LastType,IncrType) */ template ArithemeticSequence::type,typename internal::cleanup_seq_type::type,typename internal::cleanup_seq_type::type > seqN(FirstType first, SizeType size, IncrType incr) { return ArithemeticSequence::type,typename internal::cleanup_seq_type::type,typename internal::cleanup_seq_type::type>(first,size,incr); } +/** \returns an ArithemeticSequence starting at \a first, of length \a size, and unit increment + * \sa seqN(FirstType,SizeType,IncrType), seq(FirstType,LastType) */ template ArithemeticSequence::type,typename internal::cleanup_seq_type::type > seqN(FirstType first, SizeType size) { return ArithemeticSequence::type,typename internal::cleanup_seq_type::type>(first,size); } +#ifdef EIGEN_PARSED_BY_DOXYGEN + +/** \returns an ArithemeticSequence starting at \a f, up (or down) to \a l, and unit increment + * + * It is essentially an alias to: + * \code + * seqN(f,l-f+1); + * \endcode + * + * \sa seqN(FirstType,SizeType), seq(FirstType,LastType,IncrType) + */ +template +auto seq(FirstType f, LastType l); + +/** \returns an ArithemeticSequence starting at \a f, up (or down) to \a l, and with positive (or negative) increment \a incr + * + * It is essentially an alias to: + * \code + * seqN(f, (l-f+incr)/incr, incr); + * \endcode + * + * \sa seqN(FirstType,SizeType,IncrType), seq(FirstType,LastType) + */ +template +auto seq(FirstType f, LastType l, IncrType incr); + +#else // EIGEN_PARSED_BY_DOXYGEN + #if EIGEN_HAS_CXX11 template auto seq(FirstType f, LastType l) -> decltype(seqN(f,(l-f+fix<1>()))) @@ -414,6 +501,8 @@ seq(const Symbolic::BaseExpr &f, const Symbolic::BaseExpr diff --git a/Eigen/src/Core/IndexedView.h b/Eigen/src/Core/IndexedView.h index 269882e78..781cebd4e 100644 --- a/Eigen/src/Core/IndexedView.h +++ b/Eigen/src/Core/IndexedView.h @@ -85,7 +85,7 @@ class IndexedViewImpl; * - std::vector * - std::valarray * - std::array - * - c++ arrays: int[N] + * - Plain C arrays: int[N] * - Eigen::ArrayXi * - decltype(ArrayXi::LinSpaced(...)) * - Any view/expressions of the previous types @@ -94,7 +94,7 @@ class IndexedViewImpl; * - Eigen::IntAsArray (helper for single index) * - etc. * - * In typical usages of %Eigen, this class should never be used directly. It is the return type of DenseBase::operator(). + * In typical usages of %Eigen, this class should never be used directly. It is the return type of DenseBase::operator()(const RowIndices&, const ColIndices&). * * \sa class Block */ diff --git a/Eigen/src/plugins/IndexedViewMethods.h b/Eigen/src/plugins/IndexedViewMethods.h index 53eff093c..ea1aa6e2e 100644 --- a/Eigen/src/plugins/IndexedViewMethods.h +++ b/Eigen/src/plugins/IndexedViewMethods.h @@ -7,6 +7,7 @@ // 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_PARSED_BY_DOXYGEN // This file is automatically included twice to generate const and non-const versions @@ -20,54 +21,67 @@ template struct EIGEN_INDEXED_VIEW_METHOD_TYPE { - typedef IndexedView::type,typename internal::MakeIndexing::type> type; + typedef IndexedView::type, + typename internal::MakeIndexing::type> type; }; +// This is the generic version + template typename internal::enable_if< ! (internal::traits::type>::IsBlockAlike || (internal::is_integral::value && internal::is_integral::value)), typename EIGEN_INDEXED_VIEW_METHOD_TYPE::type >::type -operator()(const RowIndices& rowIndices, const ColIndices& colIndices) EIGEN_INDEXED_VIEW_METHOD_CONST { - return typename EIGEN_INDEXED_VIEW_METHOD_TYPE::type( - derived(), internal::make_indexing(rowIndices,derived().rows()), internal::make_indexing(colIndices,derived().cols())); +operator()(const RowIndices& rowIndices, const ColIndices& colIndices) EIGEN_INDEXED_VIEW_METHOD_CONST +{ + return typename EIGEN_INDEXED_VIEW_METHOD_TYPE::type + (derived(), internal::make_indexing(rowIndices,derived().rows()), internal::make_indexing(colIndices,derived().cols())); } +// 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::traits::type>::BlockType>::type -operator()(const RowIndices& rowIndices, const ColIndices& colIndices) EIGEN_INDEXED_VIEW_METHOD_CONST { +operator()(const RowIndices& rowIndices, const ColIndices& colIndices) EIGEN_INDEXED_VIEW_METHOD_CONST +{ typedef typename internal::traits::type>::BlockType BlockType; typename internal::MakeIndexing::type actualRowIndices = internal::make_indexing(rowIndices,derived().rows()); typename internal::MakeIndexing::type actualColIndices = internal::make_indexing(colIndices,derived().cols()); return BlockType(derived(), - internal::first(actualRowIndices), - internal::first(actualColIndices), - internal::size(actualRowIndices), - internal::size(actualColIndices)); + internal::first(actualRowIndices), + internal::first(actualColIndices), + internal::size(actualRowIndices), + internal::size(actualColIndices)); } +// The folowing three overloads are needed to handle raw Index[N] arrays. + template IndexedView::type> -operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndices& colIndices) EIGEN_INDEXED_VIEW_METHOD_CONST { - return IndexedView::type>( - derived(), rowIndices, internal::make_indexing(colIndices,derived().cols())); +operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndices& colIndices) EIGEN_INDEXED_VIEW_METHOD_CONST +{ + return IndexedView::type> + (derived(), rowIndices, internal::make_indexing(colIndices,derived().cols())); } template IndexedView::type, const ColIndicesT (&)[ColIndicesN]> -operator()(const RowIndices& rowIndices, const ColIndicesT (&colIndices)[ColIndicesN]) EIGEN_INDEXED_VIEW_METHOD_CONST { - return IndexedView::type,const ColIndicesT (&)[ColIndicesN]>( - derived(), internal::make_indexing(rowIndices,derived().rows()), colIndices); +operator()(const RowIndices& rowIndices, const ColIndicesT (&colIndices)[ColIndicesN]) EIGEN_INDEXED_VIEW_METHOD_CONST +{ + return IndexedView::type,const ColIndicesT (&)[ColIndicesN]> + (derived(), internal::make_indexing(rowIndices,derived().rows()), colIndices); } template IndexedView -operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndicesT (&colIndices)[ColIndicesN]) EIGEN_INDEXED_VIEW_METHOD_CONST { - return IndexedView( - derived(), rowIndices, colIndices); +operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndicesT (&colIndices)[ColIndicesN]) EIGEN_INDEXED_VIEW_METHOD_CONST +{ + return IndexedView + (derived(), rowIndices, colIndices); } #undef EIGEN_INDEXED_VIEW_METHOD_CONST @@ -79,3 +93,41 @@ operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndicesT (&col #undef EIGEN_INDEXED_VIEW_METHOD_2ND_PASS #endif +#else // EIGEN_PARSED_BY_DOXYGEN + +/** + * \returns a generic submatrix view defined by the rows and columns indexed \a rowIndices and \a colIndices respectively. + * + * Each parameter must either be: + * - An integer indexing a single row or column + * - Eigen::all indexing the full set of respective rows or columns in increasing order + * - An ArithemeticSequence as returned by the seq and seqN functions + * - Any %Eigen's vector/array of integers or expressions + * - Plain C arrays: \c int[N] + * - And more generally any type exposing the following two member functions: + * \code + * operator[]() const; + * size() const; + * \endcode + * where \c stands for any integer type compatible with Eigen::Index (i.e. \c std::ptrdiff_t). + * + * The last statement implies compatibility with \c std::vector, \c std::valarray, \c std::array, many of the Range-v3's ranges, etc. + * + * If the submatrix can be represented using a starting position \c (i,j) and positive sizes \c (rows,columns), then this + * method will returns a Block object after extraction of the relevant information from the passed arguments. This is the case + * when all arguments are either: + * - An integer + * - Eigen::all + * - An ArithemeticSequence with compile-time increment strictly equal to 1, as returned by seq(a,b), and seqN(a,N). + * + * Otherwise a more general IndexedView object will be returned, after conversion of the inputs + * to more suitable types \c RowIndices' and \c ColIndices'. + * + * \sa class Block, class IndexedView, DenseBase::block(Index,Index,Index,Index) + */ +template +IndexedView_or_Block +operator()(const RowIndices& rowIndices, const ColIndices& colIndices); + +#endif // EIGEN_PARSED_BY_DOXYGEN + From 04397f17e2493663a73db37a1dfe0a01d191d4b6 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 11 Jan 2017 13:17:09 +0100 Subject: [PATCH 28/65] Add 1D overloads of operator() --- Eigen/src/plugins/IndexedViewMethods.h | 70 +++++++++++++++++++++++++- test/indexed_view.cpp | 32 ++++++++++-- 2 files changed, 97 insertions(+), 5 deletions(-) diff --git a/Eigen/src/plugins/IndexedViewMethods.h b/Eigen/src/plugins/IndexedViewMethods.h index ea1aa6e2e..7d63f8d62 100644 --- a/Eigen/src/plugins/IndexedViewMethods.h +++ b/Eigen/src/plugins/IndexedViewMethods.h @@ -13,7 +13,7 @@ #ifndef EIGEN_INDEXED_VIEW_METHOD_2ND_PASS #define EIGEN_INDEXED_VIEW_METHOD_CONST const -#define EIGEN_INDEXED_VIEW_METHOD_TYPE ConstIndexedViewType +#define EIGEN_INDEXED_VIEW_METHOD_TYPE ConstIndexedViewType #else #define EIGEN_INDEXED_VIEW_METHOD_CONST #define EIGEN_INDEXED_VIEW_METHOD_TYPE IndexedViewType @@ -84,6 +84,62 @@ operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndicesT (&col (derived(), rowIndices, colIndices); } +// Overloads for 1D vectors/arrays + +template +typename internal::enable_if< + IsRowMajor && (!(internal::get_compile_time_incr::type>::value==1 || internal::is_integral::value)), + IndexedView::type,typename internal::MakeIndexing::type> >::type +operator()(const Indices& indices) EIGEN_INDEXED_VIEW_METHOD_CONST +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return IndexedView::type,typename internal::MakeIndexing::type> + (derived(), internal::make_indexing(0,derived().rows()), internal::make_indexing(indices,derived().cols())); +} + +template +typename internal::enable_if< + (!IsRowMajor) && (!(internal::get_compile_time_incr::type>::value==1 || internal::is_integral::value)), + IndexedView::type,typename internal::MakeIndexing::type> >::type +operator()(const Indices& indices) EIGEN_INDEXED_VIEW_METHOD_CONST +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return IndexedView::type,typename internal::MakeIndexing::type> + (derived(), internal::make_indexing(indices,derived().rows()), internal::make_indexing(Index(0),derived().cols())); +} + +template +typename internal::enable_if< + (internal::get_compile_time_incr::type>::value==1) && (!internal::is_integral::value), + VectorBlock::value> >::type +operator()(const Indices& indices) EIGEN_INDEXED_VIEW_METHOD_CONST +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + typename internal::MakeIndexing::type actualIndices = internal::make_indexing(indices,derived().size()); + return VectorBlock::value> + (derived(), internal::first(actualIndices), internal::size(actualIndices)); +} + +template +typename internal::enable_if::type,const IndicesT (&)[IndicesN]> >::type +operator()(const IndicesT (&indices)[IndicesN]) EIGEN_INDEXED_VIEW_METHOD_CONST +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return IndexedView::type,const IndicesT (&)[IndicesN]> + (derived(), internal::make_indexing(0,derived().rows()), indices); +} + +template +typename internal::enable_if::type> >::type +operator()(const IndicesT (&indices)[IndicesN]) EIGEN_INDEXED_VIEW_METHOD_CONST +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return IndexedView::type> + (derived(), indices, internal::make_indexing(0,derived().rows())); +} + #undef EIGEN_INDEXED_VIEW_METHOD_CONST #undef EIGEN_INDEXED_VIEW_METHOD_TYPE @@ -123,11 +179,21 @@ operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndicesT (&col * Otherwise a more general IndexedView object will be returned, after conversion of the inputs * to more suitable types \c RowIndices' and \c ColIndices'. * - * \sa class Block, class IndexedView, DenseBase::block(Index,Index,Index,Index) + * For 1D vectors and arrays, you better use the operator()(const Indices&) overload, which behave the same way but taking a single parameter. + * + * \sa operator()(const Indices&), class Block, class IndexedView, DenseBase::block(Index,Index,Index,Index) */ template IndexedView_or_Block operator()(const RowIndices& rowIndices, const ColIndices& colIndices); +/** This is an overload of operator()(const RowIndices&, const ColIndices&) for 1D vectors or arrays + * + * \only_for_vectors + */ +template +IndexedView_or_VectorBlock +operator()(const Indices& indices); + #endif // EIGEN_PARSED_BY_DOXYGEN diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index 42d136847..c15a8306a 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -33,9 +33,10 @@ IndexPair decode(Index ij) { template bool match(const T& xpr, std::string ref, std::string str_xpr = "") { EIGEN_UNUSED_VARIABLE(str_xpr); - //std::cout << str_xpr << "\n" << xpr << "\n\n"; std::stringstream str; str << xpr; + if(!(str.str() == ref)) + std::cout << str_xpr << "\n" << xpr << "\n\n"; return str.str() == ref; } @@ -55,15 +56,16 @@ void check_indexed_view() Index n = 10; + ArrayXd a = ArrayXd::LinSpaced(n,0,n-1); + Array b = a.transpose(); + ArrayXXi A = ArrayXXi::NullaryExpr(n,n, std::ptr_fun(encode)); for(Index i=0; i vala(10); Map(&vala[0],10) = eia; std::valarray vali(4); Map(&vali[0],4) = eii; std::vector veci(4); Map(veci.data(),4) = eii; @@ -118,6 +120,19 @@ void check_indexed_view() "300 301 302 303 304 305 306 307 308 309") ); + VERIFY( MATCH( a(seqN(3,3),0), "3\n4\n5" ) ); + VERIFY( MATCH( a(seq(3,5)), "3\n4\n5" ) ); + VERIFY( MATCH( a(seqN(3,3,1)), "3\n4\n5" ) ); + VERIFY( MATCH( a(seqN(5,3,-1)), "5\n4\n3" ) ); + + VERIFY( MATCH( b(0,seqN(3,3)), "3 4 5" ) ); + VERIFY( MATCH( b(seq(3,5)), "3 4 5" ) ); + VERIFY( MATCH( b(seqN(3,3,1)), "3 4 5" ) ); + VERIFY( MATCH( b(seqN(5,3,-1)), "5 4 3" ) ); + + VERIFY( MATCH( b(all), "0 1 2 3 4 5 6 7 8 9" ) ); + VERIFY( MATCH( b(eii), "3 1 6 5" ) ); + Array44i B; B.setRandom(); VERIFY( (A(seqN(2,5), 5)).ColsAtCompileTime == 1); @@ -180,6 +195,11 @@ void check_indexed_view() VERIFY( is_same_type(cA.block(0,0,2,2), cA(seqN(0,2),seq(0,1))) ); VERIFY( is_same_type(cA.middleRows(2,4), cA(seqN(2,4),all)) ); VERIFY( is_same_type(cA.middleCols(2,4), cA(all,seqN(2,4))) ); + + VERIFY( is_same_type(a.head(4), a(seq(0,3))) ); + VERIFY( is_same_type(a.tail(4), a(seqN(last-3,4))) ); + VERIFY( is_same_type(a.tail(4), a(seq(end-4,last))) ); + VERIFY( is_same_type(a.segment<4>(3), a(seqN(3,fix<4>))) ); } ArrayXXi A1=A, A2 = ArrayXXi::Random(4,4); @@ -203,6 +223,12 @@ void check_indexed_view() VERIFY_IS_EQUAL( A({1,3,5},{3, 1, 6, 5}).RowsAtCompileTime, 3 ); VERIFY_IS_EQUAL( A({1,3,5},{3, 1, 6, 5}).ColsAtCompileTime, 4 ); + + VERIFY_IS_APPROX( a({3, 1, 6, 5}), a(std::array{{3, 1, 6, 5}}) ); + VERIFY_IS_EQUAL( a({1,3,5}).SizeAtCompileTime, 3 ); + + VERIFY_IS_APPROX( b({3, 1, 6, 5}), b(std::array{{3, 1, 6, 5}}) ); + VERIFY_IS_EQUAL( b({1,3,5}).SizeAtCompileTime, 3 ); #endif #endif From b1dc0fa81321b5c46c3d1d654d29969b7a337c85 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 11 Jan 2017 14:28:28 +0100 Subject: [PATCH 29/65] Move fix and symbolic to their own file, and improve doxygen compatibility --- Eigen/Core | 2 + Eigen/src/Core/ArithmeticSequence.h | 302 ++++--------------------- Eigen/src/Core/IndexedView.h | 3 +- Eigen/src/Core/util/IntegralConstant.h | 87 +++++++ Eigen/src/Core/util/SymbolicIndex.h | 218 ++++++++++++++++++ Eigen/src/plugins/IndexedViewMethods.h | 4 +- 6 files changed, 356 insertions(+), 260 deletions(-) create mode 100644 Eigen/src/Core/util/IntegralConstant.h create mode 100644 Eigen/src/Core/util/SymbolicIndex.h diff --git a/Eigen/Core b/Eigen/Core index a93e3ce65..563a71ff8 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -354,6 +354,8 @@ 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/NumTraits.h" #include "src/Core/MathFunctions.h" diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 0fadfb86c..c221afcfd 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -16,215 +16,22 @@ namespace Eigen { // Pseudo keywords: all, last, end //-------------------------------------------------------------------------------- +namespace internal { + struct all_t { all_t() {} }; -/** Can be used as a parameter to DenseBase::operator()(const RowIndices&, const ColIndices&) to index all rows or columns */ -static const all_t all; +} -//-------------------------------------------------------------------------------- -// minimalistic symbolic scalar type -//-------------------------------------------------------------------------------- +/** \var all + * \ingroup Core_Module + * Can be used as a parameter to DenseBase::operator()(const RowIndices&, const ColIndices&) to index all rows or columns + */ +static const internal::all_t all; - -/** \namespace Symbolic +/** \namespace Eigen::placeholders * \ingroup Core_Module * - * This namespace defines a set of classes and functions to build and evaluate symbolic expressions of scalar type Index. - * Here is a simple example: - * - * \code - * // First step, defines symbols: - * struct x_tag {}; static const Symbolic::SymbolExpr x; - * struct y_tag {}; static const Symbolic::SymbolExpr y; - * struct z_tag {}; static const Symbolic::SymbolExpr z; - * - * // Defines an expression: - * auto expr = (x+3)/y+z; - * - * // And evaluate it: (c++14) - * std::cout << expr.eval(x=6,y=3,z=-13) << "\n"; - * - * // In c++98/11, only one symbol per expression is supported for now: - * auto expr98 = (3-x)/2; - * std::cout << expr98.eval(x=6) << "\n"; - * \endcode - * - * It is currently only used internally to define and minipulate the placeholders::last and placeholders::end symbols in Eigen::seq and Eigen::seqN. - * - */ -namespace Symbolic { - -template class Symbol; -template class NegateExpr; -template class AddExpr; -template class ProductExpr; -template class QuotientExpr; - -// A simple wrapper around an Index to provide the eval method. -// We could also use a free-function symbolic_eval... -class ValueExpr { -public: - ValueExpr(Index val) : m_value(val) {} - template - Index eval_impl(const T&) const { return m_value; } -protected: - Index m_value; -}; - -/** \class BaseExpr - * Common base class of any symbolic expressions - */ -template -class BaseExpr -{ -public: - const Derived& derived() const { return *static_cast(this); } - - /** Evaluate the expression given the \a values of the symbols. - * - * \param values defines the values of the symbols, it can either be a SymbolValue or a std::tuple of SymbolValue - * as constructed by SymbolExpr::operator= operator. - * - */ - template - Index eval(const T& values) const { return derived().eval_impl(values); } - -#if __cplusplus > 201103L - template - Index eval(Types&&... values) const { return derived().eval_impl(std::make_tuple(values...)); } -#endif - - NegateExpr operator-() const { return NegateExpr(derived()); } - - AddExpr operator+(Index b) const - { return AddExpr(derived(), b); } - AddExpr operator-(Index a) const - { return AddExpr(derived(), -a); } - QuotientExpr operator/(Index a) const - { return QuotientExpr(derived(),a); } - - friend AddExpr operator+(Index a, const BaseExpr& b) - { return AddExpr(b.derived(), a); } - friend AddExpr,ValueExpr> operator-(Index a, const BaseExpr& b) - { return AddExpr,ValueExpr>(-b.derived(), a); } - friend AddExpr operator/(Index a, const BaseExpr& b) - { return AddExpr(a,b.derived()); } - - template - AddExpr operator+(const BaseExpr &b) const - { return AddExpr(derived(), b.derived()); } - - template - AddExpr > operator-(const BaseExpr &b) const - { return AddExpr >(derived(), -b.derived()); } - - template - QuotientExpr operator/(const BaseExpr &b) const - { return QuotientExpr(derived(), b.derived()); } -}; - -template -struct is_symbolic { - // BaseExpr has no conversion ctor, so we only to check whether T can be staticaly cast to its base class BaseExpr. - enum { value = internal::is_convertible >::value }; -}; - -/** Represents the actual value of a symbol identified by its tag - * - * It is the return type of SymbolValue::operator=, and most of the time this is only way it is used. - */ -template -class SymbolValue -{ -public: - /** Default constructor from the value \a val */ - SymbolValue(Index val) : m_value(val) {} - - /** \returns the stored value of the symbol */ - Index value() const { return m_value; } -protected: - Index m_value; -}; - -/** Expression of a symbol uniquely identified by the tag \tparam TagT */ -template -class SymbolExpr : public BaseExpr > -{ -public: - typedef TagT Tag; - SymbolExpr() {} - - /** Associate the value \a val to the given symbol \c *this, uniquely identified by its \c Tag. - * - * The returned object should be passed to ExprBase::eval() to evaluate a given expression with this specified runtime-time value. - */ - SymbolValue operator=(Index val) const { - return SymbolValue(val); - } - - Index eval_impl(const SymbolValue &values) const { return values.value(); } - -#if __cplusplus > 201103L - // C++14 versions suitable for multiple symbols - template - Index eval_impl(const std::tuple& values) const { return std::get >(values).value(); } -#endif -}; - -template -class NegateExpr : public BaseExpr > -{ -public: - NegateExpr(const Arg0& arg0) : m_arg0(arg0) {} - - template - Index eval_impl(const T& values) const { return -m_arg0.eval_impl(values); } -protected: - Arg0 m_arg0; -}; - -template -class AddExpr : public BaseExpr > -{ -public: - AddExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} - - template - Index eval_impl(const T& values) const { return m_arg0.eval_impl(values) + m_arg1.eval_impl(values); } -protected: - Arg0 m_arg0; - Arg1 m_arg1; -}; - -template -class ProductExpr : public BaseExpr > -{ -public: - ProductExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} - - template - Index eval_impl(const T& values) const { return m_arg0.eval_impl(values) * m_arg1.eval_impl(values); } -protected: - Arg0 m_arg0; - Arg1 m_arg1; -}; - -template -class QuotientExpr : public BaseExpr > -{ -public: - QuotientExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} - - template - Index eval_impl(const T& values) const { return m_arg0.eval_impl(values) / m_arg1.eval_impl(values); } -protected: - Arg0 m_arg0; - Arg1 m_arg1; -}; - -} // end namespace Symbolic - -/** \namespace placeholders + * Namespace containing symbolic placeholders */ namespace placeholders { @@ -232,7 +39,10 @@ namespace internal { struct symbolic_last_tag {}; } -/** Can be used as a parameter to seq and seqN functions to symbolically reference the last element/row/columns +/** \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. @@ -249,7 +59,10 @@ struct symbolic_last_tag {}; */ static const Symbolic::SymbolExpr last; -/** Can be used as a parameter to seq and seqN functions to symbolically reference the last+1 element/row/columns +/** \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. @@ -257,53 +70,26 @@ static const Symbolic::SymbolExpr last; * * \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 -//-------------------------------------------------------------------------------- -// integral constant -//-------------------------------------------------------------------------------- - -template struct fix_t { - static const int value = N; - operator int() const { return value; } - fix_t (fix_t (*)() ) {} - fix_t() {} - // Needed in C++14 to allow fix(): - fix_t operator() () const { return *this; } -}; - -template struct get_compile_time { - enum { value = Default }; -}; - -template struct get_compile_time,Default> { - enum { value = N }; -}; - -template struct is_compile_time { enum { value = false }; }; -template struct is_compile_time > { enum { value = true }; }; - -#if __cplusplus > 201103L -template -static const fix_t fix{}; -#else -template -inline fix_t fix() { return fix_t(); } -#endif - //-------------------------------------------------------------------------------- // seq(first,last,incr) and seqN(first,size,incr) //-------------------------------------------------------------------------------- /** \class ArithemeticSequence + * \ingroup Core_Module * * This class represents an arithmetic progression \f$ a_0, a_1, a_2, ..., a_{n-1}\f$ defined by * its \em first value \f$ a_0 \f$, its \em size (aka length) \em n, and the \em increment (aka stride) * that is equal to \f$ a_{i+1}-a_{i}\f$ for any \em i. * - * It is internally used as the return type of the seq and seqN functions, and as the input arguments + * It is internally used as the return type of the Eigen::seq and Eigen::seqN functions, and as the input arguments * of DenseBase::operator()(const RowIndices&, const ColIndices&), and most of the time this is the * only way it is used. * @@ -313,9 +99,9 @@ inline fix_t fix() { return fix_t(); } * or a compile time integral constant. Internally, it can also be a symbolic expression * \tparam IncrType type of the increment, can be a runtime Index, or a compile time integral constant (default is compile-time 1) * - * \sa seq, seqN, DenseBase::operator()(const RowIndices&, const ColIndices&), class IndexedView + * \sa Eigen::seq, Eigen::seqN, DenseBase::operator()(const RowIndices&, const ColIndices&), class IndexedView */ -template > +template > class ArithemeticSequence { @@ -324,8 +110,8 @@ public: ArithemeticSequence(FirstType first, SizeType size, IncrType incr) : m_first(first), m_size(size), m_incr(incr) {} enum { - SizeAtCompileTime = get_compile_time::value, - IncrAtCompileTime = get_compile_time::value + SizeAtCompileTime = internal::get_compile_time::value, + IncrAtCompileTime = internal::get_compile_time::value }; /** \returns the size, i.e., number of elements, of the sequence */ @@ -357,7 +143,8 @@ template struct cleanup_seq_type (*)() > { typedef fix_t type } /** \returns an ArithemeticSequence starting at \a first, of length \a size, and increment \a incr - * \sa seqN(FirstType,SizeType), seq(FirstType,LastType,IncrType) */ + * + * \sa seqN(FirstType,SizeType), seq(FirstType,LastType,IncrType) */ template ArithemeticSequence::type,typename internal::cleanup_seq_type::type,typename internal::cleanup_seq_type::type > seqN(FirstType first, SizeType size, IncrType incr) { @@ -365,6 +152,7 @@ seqN(FirstType first, SizeType size, IncrType incr) { } /** \returns an ArithemeticSequence starting at \a first, of length \a size, and unit increment + * * \sa seqN(FirstType,SizeType,IncrType), seq(FirstType,LastType) */ template ArithemeticSequence::type,typename internal::cleanup_seq_type::type > @@ -374,18 +162,6 @@ seqN(FirstType first, SizeType size) { #ifdef EIGEN_PARSED_BY_DOXYGEN -/** \returns an ArithemeticSequence starting at \a f, up (or down) to \a l, and unit increment - * - * It is essentially an alias to: - * \code - * seqN(f,l-f+1); - * \endcode - * - * \sa seqN(FirstType,SizeType), seq(FirstType,LastType,IncrType) - */ -template -auto seq(FirstType f, LastType l); - /** \returns an ArithemeticSequence starting at \a f, up (or down) to \a l, and with positive (or negative) increment \a incr * * It is essentially an alias to: @@ -398,6 +174,18 @@ auto seq(FirstType f, LastType l); template auto seq(FirstType f, LastType l, IncrType incr); +/** \returns an ArithemeticSequence starting at \a f, up (or down) to \a l, and unit increment + * + * It is essentially an alias to: + * \code + * seqN(f,l-f+1); + * \endcode + * + * \sa seqN(FirstType,SizeType), seq(FirstType,LastType,IncrType) + */ +template +auto seq(FirstType f, LastType l); + #else // EIGEN_PARSED_BY_DOXYGEN #if EIGEN_HAS_CXX11 @@ -681,7 +469,7 @@ inline Index eval_expr_given_size(shifted_last x, Index size) { return size+x.o inline Index eval_expr_given_size(end_t, Index size) { return size; } inline Index eval_expr_given_size(shifted_end x, Index size) { return size+x.offset; } -template > +template > class ArithemeticSequenceProxyWithBounds { public: @@ -690,7 +478,7 @@ public: enum { SizeAtCompileTime = -1, - IncrAtCompileTime = get_compile_time::value + IncrAtCompileTime = internal::get_compile_time::value }; Index size() const { return (m_last-m_first+m_incr)/m_incr; } diff --git a/Eigen/src/Core/IndexedView.h b/Eigen/src/Core/IndexedView.h index 781cebd4e..d975c6e80 100644 --- a/Eigen/src/Core/IndexedView.h +++ b/Eigen/src/Core/IndexedView.h @@ -94,7 +94,8 @@ class IndexedViewImpl; * - Eigen::IntAsArray (helper for single index) * - etc. * - * In typical usages of %Eigen, this class should never be used directly. It is the return type of DenseBase::operator()(const RowIndices&, const ColIndices&). + * In typical usages of %Eigen, this class should never be used directly. It is the return type of + * DenseBase::operator()(const RowIndices&, const ColIndices&). * * \sa class Block */ diff --git a/Eigen/src/Core/util/IntegralConstant.h b/Eigen/src/Core/util/IntegralConstant.h new file mode 100644 index 000000000..f6b206275 --- /dev/null +++ b/Eigen/src/Core/util/IntegralConstant.h @@ -0,0 +1,87 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2017 Gael Guennebaud +// +// 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_INTEGRAL_CONSTANT_H +#define EIGEN_INTEGRAL_CONSTANT_H + +namespace Eigen { + +namespace internal { + +template struct fix_t { + static const int value = N; + operator int() const { return value; } + fix_t (fix_t (*)() ) {} + fix_t() {} + // Needed in C++14 to allow fix(): + fix_t operator() () const { return *this; } +}; + +template struct get_compile_time { + enum { value = Default }; +}; + +template struct get_compile_time,Default> { + enum { value = N }; +}; + +template struct is_compile_time { enum { value = false }; }; +template struct is_compile_time > { enum { value = true }; }; + +} // end namespace internal + +#ifndef EIGEN_PARSED_BY_DOXYGEN + +#if __cplusplus > 201103L +template +static const internal::fix_t fix{}; +#else +template +inline internal::fix_t fix() { return internal::fix_t(); } +#endif + +#else // EIGEN_PARSED_BY_DOXYGEN + +/** \var fix + * \ingroup Core_Module + * + * This \em identifier permits to construct an object embedding a compile-time integer \c N. + * + * \tparam N the compile-time integer value + * + * It is typically used in conjunction with the Eigen::seq and Eigen::seqN functions to pass compile-time values to them: + * \code + * seqN(10,fix<4>,fix<-3>) // <=> [10 7 4 1] + * \endcode + * + * In c++14, it is implemented as: + * \code + * template static const internal::fix_t fix{}; + * \endcode + * where internal::fix_t is an internal template class similar to + * \c std::integral_constant + * Here, \c fix is thus an object of type \c internal::fix_t. + * + * In c++98/11, it is implemented as a function: + * \code + * template inline internal::fix_t fix(); + * \endcode + * Here internal::fix_t is thus a pointer to function. + * + * If for some reason you want a true object in c++98 then you can write: \code fix() \endcode which is also valid in c++14. + */ +template +static const auto fix; + +#endif // EIGEN_PARSED_BY_DOXYGEN + +} // end namespace Eigen + +#endif // EIGEN_INTEGRAL_CONSTANT_H diff --git a/Eigen/src/Core/util/SymbolicIndex.h b/Eigen/src/Core/util/SymbolicIndex.h new file mode 100644 index 000000000..03086d6fa --- /dev/null +++ b/Eigen/src/Core/util/SymbolicIndex.h @@ -0,0 +1,218 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2017 Gael Guennebaud +// +// 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_SYMBOLIC_INDEX_H +#define EIGEN_SYMBOLIC_INDEX_H + +namespace Eigen { + +/** \namespace Eigen::Symbolic + * \ingroup Core_Module + * + * This namespace defines a set of classes and functions to build and evaluate symbolic expressions of scalar type Index. + * Here is a simple example: + * + * \code + * // First step, defines symbols: + * struct x_tag {}; static const Symbolic::SymbolExpr x; + * struct y_tag {}; static const Symbolic::SymbolExpr y; + * struct z_tag {}; static const Symbolic::SymbolExpr z; + * + * // Defines an expression: + * auto expr = (x+3)/y+z; + * + * // And evaluate it: (c++14) + * std::cout << expr.eval(x=6,y=3,z=-13) << "\n"; + * + * // In c++98/11, only one symbol per expression is supported for now: + * auto expr98 = (3-x)/2; + * std::cout << expr98.eval(x=6) << "\n"; + * \endcode + * + * It is currently only used internally to define and minipulate the placeholders::last and placeholders::end symbols in Eigen::seq and Eigen::seqN. + * + */ +namespace Symbolic { + +template class Symbol; +template class NegateExpr; +template class AddExpr; +template class ProductExpr; +template class QuotientExpr; + +// A simple wrapper around an Index to provide the eval method. +// We could also use a free-function symbolic_eval... +class ValueExpr { +public: + ValueExpr(Index val) : m_value(val) {} + template + Index eval_impl(const T&) const { return m_value; } +protected: + Index m_value; +}; + +/** \class BaseExpr + * \ingroup Core_Module + * Common base class of any symbolic expressions + */ +template +class BaseExpr +{ +public: + const Derived& derived() const { return *static_cast(this); } + + /** Evaluate the expression given the \a values of the symbols. + * + * \param values defines the values of the symbols, it can either be a SymbolValue or a std::tuple of SymbolValue + * as constructed by SymbolExpr::operator= operator. + * + */ + template + Index eval(const T& values) const { return derived().eval_impl(values); } + +#if __cplusplus > 201103L + template + Index eval(Types&&... values) const { return derived().eval_impl(std::make_tuple(values...)); } +#endif + + NegateExpr operator-() const { return NegateExpr(derived()); } + + AddExpr operator+(Index b) const + { return AddExpr(derived(), b); } + AddExpr operator-(Index a) const + { return AddExpr(derived(), -a); } + QuotientExpr operator/(Index a) const + { return QuotientExpr(derived(),a); } + + friend AddExpr operator+(Index a, const BaseExpr& b) + { return AddExpr(b.derived(), a); } + friend AddExpr,ValueExpr> operator-(Index a, const BaseExpr& b) + { return AddExpr,ValueExpr>(-b.derived(), a); } + friend AddExpr operator/(Index a, const BaseExpr& b) + { return AddExpr(a,b.derived()); } + + template + AddExpr operator+(const BaseExpr &b) const + { return AddExpr(derived(), b.derived()); } + + template + AddExpr > operator-(const BaseExpr &b) const + { return AddExpr >(derived(), -b.derived()); } + + template + QuotientExpr operator/(const BaseExpr &b) const + { return QuotientExpr(derived(), b.derived()); } +}; + +template +struct is_symbolic { + // BaseExpr has no conversion ctor, so we only have to check whether T can be staticaly cast to its base class BaseExpr. + enum { value = internal::is_convertible >::value }; +}; + +/** Represents the actual value of a symbol identified by its tag + * + * It is the return type of SymbolValue::operator=, and most of the time this is only way it is used. + */ +template +class SymbolValue +{ +public: + /** Default constructor from the value \a val */ + SymbolValue(Index val) : m_value(val) {} + + /** \returns the stored value of the symbol */ + Index value() const { return m_value; } +protected: + Index m_value; +}; + +/** Expression of a symbol uniquely identified by the template parameter type \c tag */ +template +class SymbolExpr : public BaseExpr > +{ +public: + /** Alias to the template parameter \c tag */ + typedef tag Tag; + + SymbolExpr() {} + + /** Associate the value \a val to the given symbol \c *this, uniquely identified by its \c Tag. + * + * The returned object should be passed to ExprBase::eval() to evaluate a given expression with this specified runtime-time value. + */ + SymbolValue operator=(Index val) const { + return SymbolValue(val); + } + + Index eval_impl(const SymbolValue &values) const { return values.value(); } + +#if __cplusplus > 201103L + // C++14 versions suitable for multiple symbols + template + Index eval_impl(const std::tuple& values) const { return std::get >(values).value(); } +#endif +}; + +template +class NegateExpr : public BaseExpr > +{ +public: + NegateExpr(const Arg0& arg0) : m_arg0(arg0) {} + + template + Index eval_impl(const T& values) const { return -m_arg0.eval_impl(values); } +protected: + Arg0 m_arg0; +}; + +template +class AddExpr : public BaseExpr > +{ +public: + AddExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} + + template + Index eval_impl(const T& values) const { return m_arg0.eval_impl(values) + m_arg1.eval_impl(values); } +protected: + Arg0 m_arg0; + Arg1 m_arg1; +}; + +template +class ProductExpr : public BaseExpr > +{ +public: + ProductExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} + + template + Index eval_impl(const T& values) const { return m_arg0.eval_impl(values) * m_arg1.eval_impl(values); } +protected: + Arg0 m_arg0; + Arg1 m_arg1; +}; + +template +class QuotientExpr : public BaseExpr > +{ +public: + QuotientExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} + + template + Index eval_impl(const T& values) const { return m_arg0.eval_impl(values) / m_arg1.eval_impl(values); } +protected: + Arg0 m_arg0; + Arg1 m_arg1; +}; + +} // end namespace Symbolic + +} // end namespace Eigen + +#endif // EIGEN_SYMBOLIC_INDEX_H diff --git a/Eigen/src/plugins/IndexedViewMethods.h b/Eigen/src/plugins/IndexedViewMethods.h index 7d63f8d62..ae817e90b 100644 --- a/Eigen/src/plugins/IndexedViewMethods.h +++ b/Eigen/src/plugins/IndexedViewMethods.h @@ -157,7 +157,7 @@ operator()(const IndicesT (&indices)[IndicesN]) EIGEN_INDEXED_VIEW_METHOD_CONST * Each parameter must either be: * - An integer indexing a single row or column * - Eigen::all indexing the full set of respective rows or columns in increasing order - * - An ArithemeticSequence as returned by the seq and seqN functions + * - An ArithemeticSequence as returned by the Eigen::seq and Eigen::seqN functions * - Any %Eigen's vector/array of integers or expressions * - Plain C arrays: \c int[N] * - And more generally any type exposing the following two member functions: @@ -174,7 +174,7 @@ operator()(const IndicesT (&indices)[IndicesN]) EIGEN_INDEXED_VIEW_METHOD_CONST * when all arguments are either: * - An integer * - Eigen::all - * - An ArithemeticSequence with compile-time increment strictly equal to 1, as returned by seq(a,b), and seqN(a,N). + * - An ArithemeticSequence with compile-time increment strictly equal to 1, as returned by Eigen::seq(a,b), and Eigen::seqN(a,N). * * Otherwise a more general IndexedView object will be returned, after conversion of the inputs * to more suitable types \c RowIndices' and \c ColIndices'. From 152cd57bb7d38d3805c3845757ef72563e53a510 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 11 Jan 2017 14:29:20 +0100 Subject: [PATCH 30/65] Enable generation of doc for static variables in Eigen's namespace. --- doc/Doxyfile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index 48bb0a8ec..b42de1bdb 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -409,7 +409,7 @@ EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. -EXTRACT_STATIC = NO +EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. From c020d307a657a3783c593c4ce2b6a8325a04cd70 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 11 Jan 2017 17:08:05 +0100 Subject: [PATCH 31/65] Make variable_if_dynamic implicitely convertible to T --- Eigen/src/Core/util/XprHelper.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Eigen/src/Core/util/XprHelper.h b/Eigen/src/Core/util/XprHelper.h index b94dd61ff..640753047 100644 --- a/Eigen/src/Core/util/XprHelper.h +++ b/Eigen/src/Core/util/XprHelper.h @@ -109,6 +109,7 @@ template class variable_if_dynamic EIGEN_EMPTY_STRUCT_CTOR(variable_if_dynamic) EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit variable_if_dynamic(T v) { EIGEN_ONLY_USED_FOR_DEBUG(v); eigen_assert(v == T(Value)); } EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE T value() { return T(Value); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE operator T() const { return T(Value); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void setValue(T) {} }; @@ -119,6 +120,7 @@ template class variable_if_dynamic public: EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit variable_if_dynamic(T value) : m_value(value) {} EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T value() const { return m_value; } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE operator T() const { return m_value; } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void setValue(T value) { m_value = value; } }; From f93d1c58e09b8435191a55f123873d8f496620b6 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 11 Jan 2017 17:08:59 +0100 Subject: [PATCH 32/65] Make get_compile_time compatible with variable_if_dynamic --- Eigen/src/Core/util/IntegralConstant.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Eigen/src/Core/util/IntegralConstant.h b/Eigen/src/Core/util/IntegralConstant.h index f6b206275..a4394c464 100644 --- a/Eigen/src/Core/util/IntegralConstant.h +++ b/Eigen/src/Core/util/IntegralConstant.h @@ -32,6 +32,12 @@ template struct get_compile_time,Default> { enum { value = N }; }; +template +struct get_compile_time,Default> { + enum { value = N }; +}; + + template struct is_compile_time { enum { value = false }; }; template struct is_compile_time > { enum { value = true }; }; From 752bd92ba53de344eba66b8cec4480f9d3207025 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 11 Jan 2017 17:24:02 +0100 Subject: [PATCH 33/65] Large code refactoring: - generalize some utilities and move them to Meta (size(), array_size()) - move handling of all and single indices to IndexedViewHelper.h - several cleanup changes --- Eigen/Core | 1 + Eigen/src/Core/ArithmeticSequence.h | 135 +++--------------------- Eigen/src/Core/IndexedView.h | 7 +- Eigen/src/Core/util/IndexedViewHelper.h | 111 +++++++++++++++++++ Eigen/src/Core/util/Meta.h | 47 +++++++++ Eigen/src/plugins/IndexedViewMethods.h | 96 ++++++++++++----- test/indexed_view.cpp | 1 + 7 files changed, 244 insertions(+), 154 deletions(-) create mode 100644 Eigen/src/Core/util/IndexedViewHelper.h diff --git a/Eigen/Core b/Eigen/Core index 563a71ff8..38306e11d 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -420,6 +420,7 @@ using std::ptrdiff_t; // on CUDA devices #include "src/Core/arch/CUDA/Complex.h" +#include "src/Core/util/IndexedViewHelper.h" #include "src/Core/ArithmeticSequence.h" #include "src/Core/DenseCoeffsBase.h" #include "src/Core/DenseBase.h" diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index c221afcfd..afb014ac5 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -12,26 +12,10 @@ namespace Eigen { -//-------------------------------------------------------------------------------- -// Pseudo keywords: all, last, end -//-------------------------------------------------------------------------------- - -namespace internal { - -struct all_t { all_t() {} }; - -} - -/** \var all - * \ingroup Core_Module - * Can be used as a parameter to DenseBase::operator()(const RowIndices&, const ColIndices&) to index all rows or columns - */ -static const internal::all_t all; - /** \namespace Eigen::placeholders * \ingroup Core_Module * - * Namespace containing symbolic placeholders + * Namespace containing symbolic placeholder and identifiers */ namespace placeholders { @@ -268,7 +252,7 @@ typename internal::enable_if::value, Symbolic::QuotientExpr, Symbolic::ValueExpr>, Symbolic::ValueExpr>, - typename internal::cleanup_seq_type::type> >::type + typename internal::cleanup_seq_type::type> >::type seq(FirstType f, const Symbolic::BaseExpr &l, IncrType incr) { typedef typename internal::cleanup_seq_type::type CleanedIncrType; @@ -281,7 +265,7 @@ ArithemeticSequence >, Symbolic::ValueExpr>, Symbolic::ValueExpr>, - typename internal::cleanup_seq_type::type> + typename internal::cleanup_seq_type::type> seq(const Symbolic::BaseExpr &f, const Symbolic::BaseExpr &l, IncrType incr) { typedef typename internal::cleanup_seq_type::type CleanedIncrType; @@ -293,76 +277,6 @@ seq(const Symbolic::BaseExpr &f, const Symbolic::BaseExpr -Index size(const T& x) { return x.size(); } - -template -Index size(const T (&) [N]) { return N; } - -template -Index first(const T& x) { return x.first(); } - -template struct get_compile_time_size { - enum { value = Dynamic }; -}; - -template struct get_compile_time_size::type> { - enum { value = T::SizeAtCompileTime }; -}; - -template struct get_compile_time_size { - enum { value = N }; -}; - -#ifdef EIGEN_HAS_CXX11 -template struct get_compile_time_size,XprSize> { - enum { value = N }; -}; -#endif - -template struct get_compile_time_incr { - enum { value = UndefinedIncr }; -}; - -template -struct get_compile_time_incr > { - enum { value = get_compile_time::value }; -}; - - -// MakeIndexing/make_indexing turn an arbitrary object of type T into something usable by MatrixSlice -template -struct MakeIndexing { - typedef T type; -}; - -template -const T& make_indexing(const T& x, Index /*size*/) { return x; } - -struct IntAsArray { - enum { - SizeAtCompileTime = 1 - }; - IntAsArray(Index val) : m_value(val) {} - Index operator[](Index) const { return m_value; } - Index size() const { return 1; } - Index first() const { return m_value; } - Index m_value; -}; - -template<> struct get_compile_time_incr { - enum { value = 1 }; // 1 or 0 ?? -}; - -// Turn a single index into something that looks like an array (i.e., that exposes a .size(), and operatro[](int) methods) -template -struct MakeIndexing::value>::type> { - // Here we could simply use Array, but maybe it's less work for the compiler to use - // a simpler wrapper as IntAsArray - //typedef Eigen::Array type; - typedef IntAsArray type; -}; - // Replace symbolic last/end "keywords" by their true runtime value inline Index eval_expr_given_size(Index x, Index /* size */) { return x; } @@ -381,45 +295,21 @@ struct make_size_type { typedef typename internal::conditional::value, Index, T>::type type; }; -template -struct MakeIndexing > { +template +struct IndexedViewCompatibleType, XprSize> { typedef ArithemeticSequence::type,IncrType> type; }; template ArithemeticSequence::type,IncrType> -make_indexing(const ArithemeticSequence& ids, Index size) { +makeIndexedViewCompatible(const ArithemeticSequence& ids, Index size) { return ArithemeticSequence::type,IncrType>( eval_expr_given_size(ids.firstObject(),size),eval_expr_given_size(ids.sizeObject(),size),ids.incrObject()); } -// Convert a symbolic 'all' into a usable range -// Implementation-wise, it would be more efficient to not having to store m_size since -// this information is already in the nested expression. To this end, we would need a -// get_size(indices, underlying_size); function returning indices.size() by default. -struct AllRange { - AllRange(Index size) : m_size(size) {} - Index operator[](Index i) const { return i; } - Index size() const { return m_size; } - Index first() const { return 0; } - Index m_size; -}; - -template<> -struct MakeIndexing { - typedef AllRange type; -}; - -inline AllRange make_indexing(all_t , Index size) { - return AllRange(size); -} - -template struct get_compile_time_size { - enum { value = XprSize }; -}; - -template<> struct get_compile_time_incr { - enum { value = 1 }; +template +struct get_compile_time_incr > { + enum { value = get_compile_time::value }; }; } // end namespace internal @@ -428,6 +318,7 @@ template<> struct get_compile_time_incr { namespace legacy { // Here are some initial code that I keep here for now to compare the quality of the code generated by the compilers +// This part will be removed once we have checked everything is right. struct shifted_last { explicit shifted_last(int o) : offset(o) {} @@ -522,14 +413,14 @@ struct get_compile_time_incr -struct MakeIndexing > { +template +struct IndexedViewCompatibleType,XprSize> { typedef legacy::ArithemeticSequenceProxyWithBounds type; }; template legacy::ArithemeticSequenceProxyWithBounds -make_indexing(const legacy::ArithemeticSequenceProxyWithBounds& ids, Index size) { +makeIndexedViewCompatible(const legacy::ArithemeticSequenceProxyWithBounds& ids, Index size) { return legacy::ArithemeticSequenceProxyWithBounds( 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 d975c6e80..38ee69638 100644 --- a/Eigen/src/Core/IndexedView.h +++ b/Eigen/src/Core/IndexedView.h @@ -19,8 +19,8 @@ struct traits > : traits { enum { - RowsAtCompileTime = get_compile_time_size::RowsAtCompileTime>::value, - ColsAtCompileTime = get_compile_time_size::ColsAtCompileTime>::value, + RowsAtCompileTime = array_size::value, + ColsAtCompileTime = array_size::value, MaxRowsAtCompileTime = RowsAtCompileTime != Dynamic ? int(RowsAtCompileTime) : int(traits::MaxRowsAtCompileTime), MaxColsAtCompileTime = ColsAtCompileTime != Dynamic ? int(ColsAtCompileTime) : int(traits::MaxColsAtCompileTime), @@ -38,8 +38,9 @@ struct traits > XprInnerStride = HasSameStorageOrderAsXprType ? int(inner_stride_at_compile_time::ret) : int(outer_stride_at_compile_time::ret), XprOuterstride = HasSameStorageOrderAsXprType ? int(outer_stride_at_compile_time::ret) : int(inner_stride_at_compile_time::ret), + InnerSize = XprTypeIsRowMajor ? ColsAtCompileTime : RowsAtCompileTime, IsBlockAlike = InnerIncr==1 && OuterIncr==1, - IsInnerPannel = HasSameStorageOrderAsXprType && is_same::type>::value, + IsInnerPannel = HasSameStorageOrderAsXprType && is_same,typename conditional::type>::value, InnerStrideAtCompileTime = InnerIncr<0 || InnerIncr==DynamicIndex || XprInnerStride==Dynamic ? Dynamic : XprInnerStride * InnerIncr, OuterStrideAtCompileTime = OuterIncr<0 || OuterIncr==DynamicIndex || XprOuterstride==Dynamic ? Dynamic : XprOuterstride * OuterIncr, diff --git a/Eigen/src/Core/util/IndexedViewHelper.h b/Eigen/src/Core/util/IndexedViewHelper.h new file mode 100644 index 000000000..4f6dd065e --- /dev/null +++ b/Eigen/src/Core/util/IndexedViewHelper.h @@ -0,0 +1,111 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2017 Gael Guennebaud +// +// 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_INDEXED_VIEW_HELPER_H +#define EIGEN_INDEXED_VIEW_HELPER_H + +namespace Eigen { + +namespace internal { + +// Extract increment/step at compile time +template struct get_compile_time_incr { + enum { value = UndefinedIncr }; +}; + +// Analogue of std::get<0>(x), but tailored for our needs. +template +Index first(const T& x) { return x.first(); } + +// IndexedViewCompatibleType/makeIndexedViewCompatible turn an arbitrary object of type T into something usable by MatrixSlice +// The generic implementation is a no-op +template +struct IndexedViewCompatibleType { + typedef T type; +}; + +template +const T& makeIndexedViewCompatible(const T& x, Index /*size*/) { return x; } + +//-------------------------------------------------------------------------------- +// Handling of a single Index +//-------------------------------------------------------------------------------- + +struct SingleRange { + enum { + SizeAtCompileTime = 1 + }; + SingleRange(Index val) : m_value(val) {} + Index operator[](Index) const { return m_value; } + Index size() const { return 1; } + Index first() const { return m_value; } + Index m_value; +}; + +template<> struct get_compile_time_incr { + enum { value = 1 }; // 1 or 0 ?? +}; + +// Turn a single index into something that looks like an array (i.e., that exposes a .size(), and operatro[](int) methods) +template +struct IndexedViewCompatibleType::value>::type> { + // Here we could simply use Array, but maybe it's less work for the compiler to use + // a simpler wrapper as SingleRange + //typedef Eigen::Array type; + typedef SingleRange type; +}; + +//-------------------------------------------------------------------------------- +// Handling of all +//-------------------------------------------------------------------------------- + +struct all_t { all_t() {} }; + +// Convert a symbolic 'all' into a usable range type +template +struct AllRange { + enum { SizeAtCompileTime = XprSize }; + AllRange(Index size = XprSize) : m_size(size) {} + Index operator[](Index i) const { return i; } + Index size() const { return m_size.value(); } + Index first() const { return 0; } + variable_if_dynamic m_size; +}; + +template +struct IndexedViewCompatibleType { + typedef AllRange type; +}; + +template +inline AllRange::value> makeIndexedViewCompatible(all_t , XprSizeType size) { + return AllRange::value>(size); +} + +template struct get_compile_time_incr > { + enum { value = 1 }; +}; + +} // end namespace internal + + +namespace placeholders { + +/** \var all + * \ingroup Core_Module + * Can be used as a parameter to DenseBase::operator()(const RowIndices&, const ColIndices&) to index all rows or columns + */ +static const Eigen::internal::all_t all; + +} + +} // end namespace Eigen + +#endif // EIGEN_INDEXED_VIEW_HELPER_H diff --git a/Eigen/src/Core/util/Meta.h b/Eigen/src/Core/util/Meta.h index 7f6370755..804657f7b 100755 --- a/Eigen/src/Core/util/Meta.h +++ b/Eigen/src/Core/util/Meta.h @@ -278,6 +278,53 @@ protected: EIGEN_DEVICE_FUNC ~noncopyable() {} }; +/** \internal + * Provides access to the number of elements in the object of as a compile-time constant expression. + * It "returns" Eigen::Dynamic if the size cannot be resolved at compile-time (default). + * + * Similar to std::tuple_size, but more general. + * + * It currently supports: + * - any types T defining T::SizeAtCompileTime + * - plain C arrays as T[N] + * - std::array (c++11) + * - some internal types such as SingleRange and AllRange + * + * The second template parameter ease SFINAE-based specializations. + */ +template struct array_size { + enum { value = Dynamic }; +}; + +template struct array_size::type> { + enum { value = T::SizeAtCompileTime }; +}; + +template struct array_size { + enum { value = N }; +}; + +#ifdef EIGEN_HAS_CXX11 +template struct array_size > { + enum { value = N }; +}; +#endif + +/** \internal + * Analogue of the std::size free function. + * It returns the size of the container or view \a x of type \c T + * + * It currently supports: + * - any types T defining a member T::size() const + * - plain C arrays as T[N] + * + */ +template +Index size(const T& x) { return x.size(); } + +template +Index size(const T (&) [N]) { return N; } + /** \internal * Convenient struct to get the result type of a unary or binary functor. * diff --git a/Eigen/src/plugins/IndexedViewMethods.h b/Eigen/src/plugins/IndexedViewMethods.h index ae817e90b..774a5cbe5 100644 --- a/Eigen/src/plugins/IndexedViewMethods.h +++ b/Eigen/src/plugins/IndexedViewMethods.h @@ -19,11 +19,49 @@ #define EIGEN_INDEXED_VIEW_METHOD_TYPE IndexedViewType #endif +#ifndef EIGEN_INDEXED_VIEW_METHOD_2ND_PASS +protected: + +// define some aliases to ease readability + +template +struct IvcRowType : public internal::IndexedViewCompatibleType {}; + +template +struct IvcColType : public internal::IndexedViewCompatibleType {}; + +template +struct IvcType : public internal::IndexedViewCompatibleType {}; + +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())); +}; + +template +typename IvcColType::type +ivcCol(const Indices& indices) const { + return internal::makeIndexedViewCompatible(indices, internal::variable_if_dynamic(derived().cols())); +}; + +template +typename IvcColType::type +ivcSize(const Indices& indices) const { + return internal::makeIndexedViewCompatible(indices, internal::variable_if_dynamic(derived().size())); +}; + +public: + +#endif + template struct EIGEN_INDEXED_VIEW_METHOD_TYPE { typedef IndexedView::type, - typename internal::MakeIndexing::type> type; + typename IvcRowType::type, + typename IvcColType::type> type; }; // This is the generic version @@ -36,7 +74,7 @@ typename internal::enable_if< operator()(const RowIndices& rowIndices, const ColIndices& colIndices) EIGEN_INDEXED_VIEW_METHOD_CONST { return typename EIGEN_INDEXED_VIEW_METHOD_TYPE::type - (derived(), internal::make_indexing(rowIndices,derived().rows()), internal::make_indexing(colIndices,derived().cols())); + (derived(), ivcRow(rowIndices), ivcCol(colIndices)); } // The folowing overload returns a Block<> object @@ -49,8 +87,8 @@ typename internal::enable_if< operator()(const RowIndices& rowIndices, const ColIndices& colIndices) EIGEN_INDEXED_VIEW_METHOD_CONST { typedef typename internal::traits::type>::BlockType BlockType; - typename internal::MakeIndexing::type actualRowIndices = internal::make_indexing(rowIndices,derived().rows()); - typename internal::MakeIndexing::type actualColIndices = internal::make_indexing(colIndices,derived().cols()); + typename IvcRowType::type actualRowIndices = ivcRow(rowIndices); + typename IvcColType::type actualColIndices = ivcCol(colIndices); return BlockType(derived(), internal::first(actualRowIndices), internal::first(actualColIndices), @@ -61,19 +99,19 @@ operator()(const RowIndices& rowIndices, const ColIndices& colIndices) EIGEN_IND // The folowing three overloads are needed to handle raw Index[N] arrays. template -IndexedView::type> +IndexedView::type> operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndices& colIndices) EIGEN_INDEXED_VIEW_METHOD_CONST { - return IndexedView::type> - (derived(), rowIndices, internal::make_indexing(colIndices,derived().cols())); + return IndexedView::type> + (derived(), rowIndices, ivcCol(colIndices)); } template -IndexedView::type, const ColIndicesT (&)[ColIndicesN]> +IndexedView::type, const ColIndicesT (&)[ColIndicesN]> operator()(const RowIndices& rowIndices, const ColIndicesT (&colIndices)[ColIndicesN]) EIGEN_INDEXED_VIEW_METHOD_CONST { - return IndexedView::type,const ColIndicesT (&)[ColIndicesN]> - (derived(), internal::make_indexing(rowIndices,derived().rows()), colIndices); + return IndexedView::type,const ColIndicesT (&)[ColIndicesN]> + (derived(), ivcRow(rowIndices), colIndices); } template @@ -88,56 +126,56 @@ operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndicesT (&col template typename internal::enable_if< - IsRowMajor && (!(internal::get_compile_time_incr::type>::value==1 || internal::is_integral::value)), - IndexedView::type,typename internal::MakeIndexing::type> >::type + IsRowMajor && (!(internal::get_compile_time_incr::type>::value==1 || internal::is_integral::value)), + IndexedView::type> >::type operator()(const Indices& indices) EIGEN_INDEXED_VIEW_METHOD_CONST { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return IndexedView::type,typename internal::MakeIndexing::type> - (derived(), internal::make_indexing(0,derived().rows()), internal::make_indexing(indices,derived().cols())); + return IndexedView::type> + (derived(), IvcIndex(0), ivcCol(indices)); } template typename internal::enable_if< - (!IsRowMajor) && (!(internal::get_compile_time_incr::type>::value==1 || internal::is_integral::value)), - IndexedView::type,typename internal::MakeIndexing::type> >::type + (!IsRowMajor) && (!(internal::get_compile_time_incr::type>::value==1 || internal::is_integral::value)), + IndexedView::type,IvcIndex> >::type operator()(const Indices& indices) EIGEN_INDEXED_VIEW_METHOD_CONST { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return IndexedView::type,typename internal::MakeIndexing::type> - (derived(), internal::make_indexing(indices,derived().rows()), internal::make_indexing(Index(0),derived().cols())); + return IndexedView::type,IvcIndex> + (derived(), ivcRow(indices), IvcIndex(0)); } template typename internal::enable_if< - (internal::get_compile_time_incr::type>::value==1) && (!internal::is_integral::value), - VectorBlock::value> >::type + (internal::get_compile_time_incr::type>::value==1) && (!internal::is_integral::value), + VectorBlock::value> >::type operator()(const Indices& indices) EIGEN_INDEXED_VIEW_METHOD_CONST { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - typename internal::MakeIndexing::type actualIndices = internal::make_indexing(indices,derived().size()); - return VectorBlock::value> + typename IvcType::type actualIndices = ivcSize(indices); + return VectorBlock::value> (derived(), internal::first(actualIndices), internal::size(actualIndices)); } template typename internal::enable_if::type,const IndicesT (&)[IndicesN]> >::type + IndexedView >::type operator()(const IndicesT (&indices)[IndicesN]) EIGEN_INDEXED_VIEW_METHOD_CONST { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return IndexedView::type,const IndicesT (&)[IndicesN]> - (derived(), internal::make_indexing(0,derived().rows()), indices); + return IndexedView + (derived(), IvcIndex(0), indices); } template typename internal::enable_if::type> >::type + IndexedView >::type operator()(const IndicesT (&indices)[IndicesN]) EIGEN_INDEXED_VIEW_METHOD_CONST { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return IndexedView::type> - (derived(), indices, internal::make_indexing(0,derived().rows())); + return IndexedView + (derived(), indices, IvcIndex(0)); } #undef EIGEN_INDEXED_VIEW_METHOD_CONST diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index c15a8306a..e2c0e886d 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -51,6 +51,7 @@ is_same_type(const T1& a, const T2& b) void check_indexed_view() { + using Eigen::placeholders::all; using Eigen::placeholders::last; using Eigen::placeholders::end; From 6e97698161275db750868afb99f405cdb849f412 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 16 Jan 2017 16:13:37 +0100 Subject: [PATCH 34/65] Introduce a EIGEN_HAS_CXX14 macro --- Eigen/src/Core/util/Macros.h | 5 +++++ Eigen/src/Core/util/SymbolicIndex.h | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/util/Macros.h b/Eigen/src/Core/util/Macros.h index 14addd8fb..7462dc5cf 100644 --- a/Eigen/src/Core/util/Macros.h +++ b/Eigen/src/Core/util/Macros.h @@ -362,6 +362,11 @@ #define EIGEN_HAS_CXX11 0 #endif +#if EIGEN_MAX_CPP_VER>=14 && (defined(__cplusplus) && (__cplusplus > 201103L) || EIGEN_COMP_MSVC >= 1900) +#define EIGEN_HAS_CXX14 1 +#else +#define EIGEN_HAS_CXX14 0 +#endif // Do we support r-value references? #ifndef EIGEN_HAS_RVALUE_REFERENCES diff --git a/Eigen/src/Core/util/SymbolicIndex.h b/Eigen/src/Core/util/SymbolicIndex.h index 03086d6fa..6f603f301 100644 --- a/Eigen/src/Core/util/SymbolicIndex.h +++ b/Eigen/src/Core/util/SymbolicIndex.h @@ -76,7 +76,7 @@ public: template Index eval(const T& values) const { return derived().eval_impl(values); } -#if __cplusplus > 201103L +#if EIGEN_HAS_CXX14 template Index eval(Types&&... values) const { return derived().eval_impl(std::make_tuple(values...)); } #endif From a9232af845702d62d81c49b4d92b39f29410cea0 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 16 Jan 2017 16:17:01 +0100 Subject: [PATCH 35/65] Introduce a variable_or_fixed proxy returned by fix(val) to pass both a compile-time and runtime fallback value in case N means "runtime". This mechanism is used by the seq/seqN functions. The proxy object is immediately converted to pure compile-time (as fix) or pure runtime (i.e., an Index) to avoid redundant template instantiations. --- Eigen/src/Core/ArithmeticSequence.h | 56 +++++++++++++-------- Eigen/src/Core/util/IntegralConstant.h | 69 +++++++++++++++++++++++++- test/indexed_view.cpp | 31 +++++++++++- 3 files changed, 133 insertions(+), 23 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index afb014ac5..bafc00f14 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -119,10 +119,26 @@ protected: namespace internal { -template struct cleanup_seq_type { typedef T type; }; -template struct cleanup_seq_type::value>::type> { typedef Index type; }; -template struct cleanup_seq_type > { typedef fix_t type; }; -template struct cleanup_seq_type (*)() > { typedef fix_t type; }; +// Cleanup return types: + +// By default, no change: +template struct cleanup_seq_type { typedef T type; }; + +// Convert short, int, unsigned int, etc. to Eigen::Index +template struct cleanup_seq_type::value>::type> { typedef Index type; }; + +// In c++98/c++11, fix is a pointer to function that we better cleanup to a true fix_t: +template struct cleanup_seq_type (*)(), DynamicKey> { typedef fix_t type; }; + +// If variable_or_fixed does not match DynamicKey, then we turn it to a pure compile-time value: +template struct cleanup_seq_type, DynamicKey> { typedef fix_t type; }; +// If variable_or_fixed matches DynamicKey, then we turn it to a pure runtime-value (aka Index): +template struct cleanup_seq_type, DynamicKey> { typedef Index type; }; + +// Helper to cleanup the type of the increment: +template struct cleanup_seq_incr { + typedef typename cleanup_seq_type::type type; +}; } @@ -130,9 +146,9 @@ template struct cleanup_seq_type (*)() > { typedef fix_t type * * \sa seqN(FirstType,SizeType), seq(FirstType,LastType,IncrType) */ template -ArithemeticSequence::type,typename internal::cleanup_seq_type::type,typename internal::cleanup_seq_type::type > +ArithemeticSequence::type,typename internal::cleanup_seq_type::type,typename internal::cleanup_seq_incr::type > seqN(FirstType first, SizeType size, IncrType incr) { - return ArithemeticSequence::type,typename internal::cleanup_seq_type::type,typename internal::cleanup_seq_type::type>(first,size,incr); + return ArithemeticSequence::type,typename internal::cleanup_seq_type::type,typename internal::cleanup_seq_incr::type>(first,size,incr); } /** \returns an ArithemeticSequence starting at \a first, of length \a size, and unit increment @@ -181,10 +197,10 @@ auto seq(FirstType f, LastType l) -> decltype(seqN(f,(l-f+fix<1>()))) template auto seq(FirstType f, LastType l, IncrType incr) - -> decltype(seqN(f, (l-f+typename internal::cleanup_seq_type::type(incr)) - / typename internal::cleanup_seq_type::type(incr),typename internal::cleanup_seq_type::type(incr))) + -> decltype(seqN(f, (l-f+typename internal::cleanup_seq_incr::type(incr)) + / typename internal::cleanup_seq_incr::type(incr),typename internal::cleanup_seq_incr::type(incr))) { - typedef typename internal::cleanup_seq_type::type CleanedIncrType; + typedef typename internal::cleanup_seq_incr::type CleanedIncrType; return seqN(f,(l-f+CleanedIncrType(incr))/CleanedIncrType(incr),CleanedIncrType(incr)); } #else @@ -225,10 +241,10 @@ seq(const Symbolic::BaseExpr &f, const Symbolic::BaseExpr typename internal::enable_if::value || Symbolic::is_symbolic::value), - ArithemeticSequence::type,Index,typename internal::cleanup_seq_type::type> >::type + ArithemeticSequence::type,Index,typename internal::cleanup_seq_incr::type> >::type seq(FirstType f, LastType l, IncrType incr) { - typedef typename internal::cleanup_seq_type::type CleanedIncrType; + typedef typename internal::cleanup_seq_incr::type CleanedIncrType; return seqN(f,(l-f+CleanedIncrType(incr))/CleanedIncrType(incr), incr); } @@ -239,10 +255,10 @@ typename internal::enable_if::value, Symbolic::ValueExpr>, Symbolic::ValueExpr>, Symbolic::ValueExpr>, - typename internal::cleanup_seq_type::type> >::type + typename internal::cleanup_seq_incr::type> >::type seq(const Symbolic::BaseExpr &f, LastType l, IncrType incr) { - typedef typename internal::cleanup_seq_type::type CleanedIncrType; + typedef typename internal::cleanup_seq_incr::type CleanedIncrType; return seqN(f.derived(),(l-f.derived()+CleanedIncrType(incr))/CleanedIncrType(incr), incr); } @@ -252,10 +268,10 @@ typename internal::enable_if::value, Symbolic::QuotientExpr, Symbolic::ValueExpr>, Symbolic::ValueExpr>, - typename internal::cleanup_seq_type::type> >::type + typename internal::cleanup_seq_incr::type> >::type seq(FirstType f, const Symbolic::BaseExpr &l, IncrType incr) { - typedef typename internal::cleanup_seq_type::type CleanedIncrType; + typedef typename internal::cleanup_seq_incr::type CleanedIncrType; return seqN(f,(l.derived()-f+CleanedIncrType(incr))/CleanedIncrType(incr), incr); } @@ -265,10 +281,10 @@ ArithemeticSequence >, Symbolic::ValueExpr>, Symbolic::ValueExpr>, - typename internal::cleanup_seq_type::type> + typename internal::cleanup_seq_incr::type> seq(const Symbolic::BaseExpr &f, const Symbolic::BaseExpr &l, IncrType incr) { - typedef typename internal::cleanup_seq_type::type CleanedIncrType; + typedef typename internal::cleanup_seq_incr::type CleanedIncrType; return seqN(f.derived(),(l.derived()-f.derived()+CleanedIncrType(incr))/CleanedIncrType(incr), incr); } #endif @@ -394,13 +410,13 @@ seq(FirstType f, LastType l) { template ArithemeticSequenceProxyWithBounds< typename internal::cleanup_seq_type::type, typename internal::cleanup_seq_type::type, - typename internal::cleanup_seq_type::type > + typename internal::cleanup_seq_incr::type > seq(FirstType f, LastType l, IncrType s) { return ArithemeticSequenceProxyWithBounds::type, typename internal::cleanup_seq_type::type, - typename internal::cleanup_seq_type::type> - (f,l,typename internal::cleanup_seq_type::type(s)); + typename internal::cleanup_seq_incr::type> + (f,l,typename internal::cleanup_seq_incr::type(s)); } } diff --git a/Eigen/src/Core/util/IntegralConstant.h b/Eigen/src/Core/util/IntegralConstant.h index a4394c464..dc8c8413d 100644 --- a/Eigen/src/Core/util/IntegralConstant.h +++ b/Eigen/src/Core/util/IntegralConstant.h @@ -15,13 +15,35 @@ namespace Eigen { namespace internal { +template struct fix_t; +template class variable_or_fixed; + template struct fix_t { static const int value = N; operator int() const { return value; } - fix_t (fix_t (*)() ) {} fix_t() {} + fix_t(variable_or_fixed other) { + EIGEN_ONLY_USED_FOR_DEBUG(other); + eigen_internal_assert(int(other)==N); + } + +#if EIGEN_HAS_CXX14 // Needed in C++14 to allow fix(): fix_t operator() () const { return *this; } + + variable_or_fixed operator() (int val) const { return variable_or_fixed(val); } +#else + fix_t (fix_t (*)() ) {} +#endif +}; + +template class variable_or_fixed { +public: + static const int value = N; + operator int() const { return m_value; } + variable_or_fixed(int val) { m_value = val; } +protected: + int m_value; }; template struct get_compile_time { @@ -32,6 +54,10 @@ template struct get_compile_time,Default> { enum { value = N }; }; +template struct get_compile_time,Default> { + enum { value = N }; +}; + template struct get_compile_time,Default> { enum { value = N }; @@ -45,12 +71,17 @@ template struct is_compile_time > { enum { value = true }; }; #ifndef EIGEN_PARSED_BY_DOXYGEN -#if __cplusplus > 201103L +#if EIGEN_HAS_CXX14 template static const internal::fix_t fix{}; #else template inline internal::fix_t fix() { return internal::fix_t(); } + +// The generic typename T is mandatory. Otherwise, a code like fix could refer to either the function above or this next overload. +// This way a code like fix can only refer to the previous function. +template +inline internal::variable_or_fixed fix(T val) { return internal::variable_or_fixed(val); } #endif #else // EIGEN_PARSED_BY_DOXYGEN @@ -67,6 +98,8 @@ inline internal::fix_t fix() { return internal::fix_t(); } * seqN(10,fix<4>,fix<-3>) // <=> [10 7 4 1] * \endcode * + * See also the function fix(int) to pass both a compile-time and runtime value. + * * In c++14, it is implemented as: * \code * template static const internal::fix_t fix{}; @@ -82,10 +115,42 @@ inline internal::fix_t fix() { return internal::fix_t(); } * Here internal::fix_t is thus a pointer to function. * * If for some reason you want a true object in c++98 then you can write: \code fix() \endcode which is also valid in c++14. + * + * \sa fix(int), seq, seqN */ template static const auto fix; +/** \fn fix(int) + * \ingroup Core_Module + * + * This function returns an object embedding both a compile-time integer \c N, and a runtime value \a val. + * + * \tparam N the compile-time integer value + * \param val the runtime integer value + * + * This function is a more general version of the \ref fix identifier/function that can be used in template code + * where the compile-time value coudl turned out to actually mean "undefined at compile-time". For positive integers + * such as a size of a dimension, this case is identified by Eigen::Dynamic, whereas runtime signed integers (e.g., an increment/stride) are identified + * as Eigen::DynamicIndex. + * + * A typical use case would be: + * \code + * template void foo(const MatrixBase &mat) { + * const int N = Derived::RowsAtCompileTime==Dynamic ? Dynamic : Derived::RowsAtCompileTime/2; + * const int n = mat.rows()/2; + * ... mat( seqN(0,fix(n) ) ...; + * } + * \endcode + * In this example, the function Eigen::seqN knows that the second argument is expected to be a size. + * If the passed compile-time value N equals Eigen::Dynamic, then the proxy object returned by fix will be dissmissed, and converted to an Eigen::Index of value \c n. + * Otherwise, the runtime-value \c n will be dissmissed, and the returned ArithmeticSequence will be of the exact same type as seqN(0,fix) . + * + * \sa fix, seqN, class ArithmeticSequence + */ +template +static const auto fix(int val); + #endif // EIGEN_PARSED_BY_DOXYGEN } // end namespace Eigen diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index e2c0e886d..472268010 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -8,7 +8,12 @@ // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifdef EIGEN_TEST_PART_2 -// Make sure we also check c++98 implementation +// Make sure we also check c++11 max implementation +#define EIGEN_MAX_CPP_VER 11 +#endif + +#ifdef EIGEN_TEST_PART_3 +// Make sure we also check c++98 max implementation #define EIGEN_MAX_CPP_VER 03 #endif @@ -49,6 +54,13 @@ is_same_type(const T1& a, const T2& b) return (a == b).all(); } +template +typename internal::enable_if::value,bool>::type +is_same_seq_type(const T1& a, const T2& b) +{ + return a.size() == b.size() && a.first()==b.first() && Index(a.incrObject())==Index(b.incrObject()); +} + void check_indexed_view() { using Eigen::placeholders::all; @@ -157,6 +169,23 @@ void check_indexed_view() VERIFY_IS_EQUAL( (B(seqN(1,2,fix<2>), seq(1,3,fix<3>))).InnerStrideAtCompileTime , 2); VERIFY_IS_EQUAL( (B(seqN(1,2,fix<2>), seq(1,3,fix<3>))).OuterStrideAtCompileTime , 3*4); + VERIFY_IS_EQUAL( (A(seqN(2,fix<5>), seqN(1,fix<3>))).RowsAtCompileTime, 5); + VERIFY_IS_EQUAL( (A(seqN(2,fix<5>), seqN(1,fix<3>))).ColsAtCompileTime, 3); + VERIFY_IS_EQUAL( (A(seqN(2,fix<5>(5)), seqN(1,fix<3>(3)))).RowsAtCompileTime, 5); + VERIFY_IS_EQUAL( (A(seqN(2,fix<5>(5)), seqN(1,fix<3>(3)))).ColsAtCompileTime, 3); + VERIFY_IS_EQUAL( (A(seqN(2,fix(5)), seqN(1,fix(3)))).RowsAtCompileTime, Dynamic); + VERIFY_IS_EQUAL( (A(seqN(2,fix(5)), seqN(1,fix(3)))).ColsAtCompileTime, Dynamic); + VERIFY_IS_EQUAL( (A(seqN(2,fix(5)), seqN(1,fix(3)))).rows(), 5); + VERIFY_IS_EQUAL( (A(seqN(2,fix(5)), seqN(1,fix(3)))).cols(), 3); + + VERIFY( is_same_seq_type( seqN(2,5,fix<-1>), seqN(2,5,fix<-1>(-1)) ) ); + VERIFY( is_same_seq_type( seqN(2,5), seqN(2,5,fix<1>(1)) ) ); + VERIFY( is_same_seq_type( seqN(2,5,3), seqN(2,5,fix(3)) ) ); + VERIFY( is_same_seq_type( seq(2,7,fix<3>), seqN(2,2,fix<3>) ) ); + VERIFY( is_same_seq_type( seqN(2,fix(5),3), seqN(2,5,fix(3)) ) ); + VERIFY( is_same_seq_type( seqN(2,fix<5>(5),fix<-2>), seqN(2,fix<5>,fix<-2>()) ) ); + + VERIFY( (A(seqN(2,fix<5>), 5)).RowsAtCompileTime == 5); VERIFY( (A(4, all)).ColsAtCompileTime == Dynamic); VERIFY( (A(4, all)).RowsAtCompileTime == 1); From e70c4c97faf89b844dc9986e664257c9423c7ff6 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 16 Jan 2017 16:20:16 +0100 Subject: [PATCH 36/65] Typo --- Eigen/src/Core/ArithmeticSequence.h | 78 +++++++++++++------------- Eigen/src/plugins/IndexedViewMethods.h | 4 +- 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index bafc00f14..79e6bb74e 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -66,7 +66,7 @@ static const Symbolic::AddExpr // seq(first,last,incr) and seqN(first,size,incr) //-------------------------------------------------------------------------------- -/** \class ArithemeticSequence +/** \class ArithmeticSequence * \ingroup Core_Module * * This class represents an arithmetic progression \f$ a_0, a_1, a_2, ..., a_{n-1}\f$ defined by @@ -86,12 +86,12 @@ static const Symbolic::AddExpr * \sa Eigen::seq, Eigen::seqN, DenseBase::operator()(const RowIndices&, const ColIndices&), class IndexedView */ template > -class ArithemeticSequence +class ArithmeticSequence { public: - ArithemeticSequence(FirstType first, SizeType size) : m_first(first), m_size(size) {} - ArithemeticSequence(FirstType first, SizeType size, IncrType incr) : m_first(first), m_size(size), m_incr(incr) {} + ArithmeticSequence(FirstType first, SizeType size) : m_first(first), m_size(size) {} + ArithmeticSequence(FirstType first, SizeType size, IncrType incr) : m_first(first), m_size(size), m_incr(incr) {} enum { SizeAtCompileTime = internal::get_compile_time::value, @@ -142,27 +142,27 @@ template struct cleanup_seq_incr { } -/** \returns an ArithemeticSequence starting at \a first, of length \a size, and increment \a incr +/** \returns an ArithmeticSequence starting at \a first, of length \a size, and increment \a incr * * \sa seqN(FirstType,SizeType), seq(FirstType,LastType,IncrType) */ template -ArithemeticSequence::type,typename internal::cleanup_seq_type::type,typename internal::cleanup_seq_incr::type > +ArithmeticSequence::type,typename internal::cleanup_seq_type::type,typename internal::cleanup_seq_incr::type > seqN(FirstType first, SizeType size, IncrType incr) { - return ArithemeticSequence::type,typename internal::cleanup_seq_type::type,typename internal::cleanup_seq_incr::type>(first,size,incr); + return ArithmeticSequence::type,typename internal::cleanup_seq_type::type,typename internal::cleanup_seq_incr::type>(first,size,incr); } -/** \returns an ArithemeticSequence starting at \a first, of length \a size, and unit increment +/** \returns an ArithmeticSequence starting at \a first, of length \a size, and unit increment * * \sa seqN(FirstType,SizeType,IncrType), seq(FirstType,LastType) */ template -ArithemeticSequence::type,typename internal::cleanup_seq_type::type > +ArithmeticSequence::type,typename internal::cleanup_seq_type::type > seqN(FirstType first, SizeType size) { - return ArithemeticSequence::type,typename internal::cleanup_seq_type::type>(first,size); + return ArithmeticSequence::type,typename internal::cleanup_seq_type::type>(first,size); } #ifdef EIGEN_PARSED_BY_DOXYGEN -/** \returns an ArithemeticSequence starting at \a f, up (or down) to \a l, and with positive (or negative) increment \a incr +/** \returns an ArithmeticSequence starting at \a f, up (or down) to \a l, and with positive (or negative) increment \a incr * * It is essentially an alias to: * \code @@ -174,7 +174,7 @@ seqN(FirstType first, SizeType size) { template auto seq(FirstType f, LastType l, IncrType incr); -/** \returns an ArithemeticSequence starting at \a f, up (or down) to \a l, and unit increment +/** \returns an ArithmeticSequence starting at \a f, up (or down) to \a l, and unit increment * * It is essentially an alias to: * \code @@ -206,7 +206,7 @@ auto seq(FirstType f, LastType l, IncrType incr) #else template typename internal::enable_if::value || Symbolic::is_symbolic::value), - ArithemeticSequence::type,Index> >::type + ArithmeticSequence::type,Index> >::type seq(FirstType f, LastType l) { return seqN(f,(l-f+1)); @@ -214,7 +214,7 @@ seq(FirstType f, LastType l) template typename internal::enable_if::value, - ArithemeticSequence,Symbolic::ValueExpr>, + ArithmeticSequence,Symbolic::ValueExpr>, Symbolic::ValueExpr> > >::type seq(const Symbolic::BaseExpr &f, LastType l) { @@ -223,7 +223,7 @@ seq(const Symbolic::BaseExpr &f, LastType l) template typename internal::enable_if::value, - ArithemeticSequence::type, + ArithmeticSequence::type, Symbolic::AddExpr,Symbolic::ValueExpr> > >::type seq(FirstType f, const Symbolic::BaseExpr &l) { @@ -231,7 +231,7 @@ seq(FirstType f, const Symbolic::BaseExpr &l) } template -ArithemeticSequence >,Symbolic::ValueExpr> > seq(const Symbolic::BaseExpr &f, const Symbolic::BaseExpr &l) { @@ -241,7 +241,7 @@ seq(const Symbolic::BaseExpr &f, const Symbolic::BaseExpr typename internal::enable_if::value || Symbolic::is_symbolic::value), - ArithemeticSequence::type,Index,typename internal::cleanup_seq_incr::type> >::type + ArithmeticSequence::type,Index,typename internal::cleanup_seq_incr::type> >::type seq(FirstType f, LastType l, IncrType incr) { typedef typename internal::cleanup_seq_incr::type CleanedIncrType; @@ -250,7 +250,7 @@ seq(FirstType f, LastType l, IncrType incr) template typename internal::enable_if::value, - ArithemeticSequence, Symbolic::ValueExpr>, Symbolic::ValueExpr>, @@ -264,7 +264,7 @@ seq(const Symbolic::BaseExpr &f, LastType l, IncrType incr) template typename internal::enable_if::value, - ArithemeticSequence::type, + ArithmeticSequence::type, Symbolic::QuotientExpr, Symbolic::ValueExpr>, Symbolic::ValueExpr>, @@ -276,7 +276,7 @@ seq(FirstType f, const Symbolic::BaseExpr &l, IncrType incr) } template -ArithemeticSequence >, Symbolic::ValueExpr>, @@ -312,19 +312,19 @@ struct make_size_type { }; template -struct IndexedViewCompatibleType, XprSize> { - typedef ArithemeticSequence::type,IncrType> type; +struct IndexedViewCompatibleType, XprSize> { + typedef ArithmeticSequence::type,IncrType> type; }; template -ArithemeticSequence::type,IncrType> -makeIndexedViewCompatible(const ArithemeticSequence& ids, Index size) { - return ArithemeticSequence::type,IncrType>( +ArithmeticSequence::type,IncrType> +makeIndexedViewCompatible(const ArithmeticSequence& ids, Index size) { + return ArithmeticSequence::type,IncrType>( eval_expr_given_size(ids.firstObject(),size),eval_expr_given_size(ids.sizeObject(),size),ids.incrObject()); } template -struct get_compile_time_incr > { +struct get_compile_time_incr > { enum { value = get_compile_time::value }; }; @@ -377,11 +377,11 @@ inline Index eval_expr_given_size(end_t, Index size) { return size; } inline Index eval_expr_given_size(shifted_end x, Index size) { return size+x.offset; } template > -class ArithemeticSequenceProxyWithBounds +class ArithmeticSequenceProxyWithBounds { public: - ArithemeticSequenceProxyWithBounds(FirstType f, LastType l) : m_first(f), m_last(l) {} - ArithemeticSequenceProxyWithBounds(FirstType f, LastType l, IncrType s) : m_first(f), m_last(l), m_incr(s) {} + ArithmeticSequenceProxyWithBounds(FirstType f, LastType l) : m_first(f), m_last(l) {} + ArithmeticSequenceProxyWithBounds(FirstType f, LastType l, IncrType s) : m_first(f), m_last(l), m_incr(s) {} enum { SizeAtCompileTime = -1, @@ -402,18 +402,18 @@ protected: }; template -ArithemeticSequenceProxyWithBounds::type,typename internal::cleanup_seq_type::type > +ArithmeticSequenceProxyWithBounds::type,typename internal::cleanup_seq_type::type > seq(FirstType f, LastType l) { - return ArithemeticSequenceProxyWithBounds::type,typename internal::cleanup_seq_type::type>(f,l); + return ArithmeticSequenceProxyWithBounds::type,typename internal::cleanup_seq_type::type>(f,l); } template -ArithemeticSequenceProxyWithBounds< typename internal::cleanup_seq_type::type, +ArithmeticSequenceProxyWithBounds< typename internal::cleanup_seq_type::type, typename internal::cleanup_seq_type::type, typename internal::cleanup_seq_incr::type > seq(FirstType f, LastType l, IncrType s) { - return ArithemeticSequenceProxyWithBounds::type, + return ArithmeticSequenceProxyWithBounds::type, typename internal::cleanup_seq_type::type, typename internal::cleanup_seq_incr::type> (f,l,typename internal::cleanup_seq_incr::type(s)); @@ -424,20 +424,20 @@ seq(FirstType f, LastType l, IncrType s) namespace internal { template -struct get_compile_time_incr > { +struct get_compile_time_incr > { enum { value = get_compile_time::value }; }; // Convert a symbolic range into a usable one (i.e., remove last/end "keywords") template -struct IndexedViewCompatibleType,XprSize> { - typedef legacy::ArithemeticSequenceProxyWithBounds type; +struct IndexedViewCompatibleType,XprSize> { + typedef legacy::ArithmeticSequenceProxyWithBounds type; }; template -legacy::ArithemeticSequenceProxyWithBounds -makeIndexedViewCompatible(const legacy::ArithemeticSequenceProxyWithBounds& ids, Index size) { - return legacy::ArithemeticSequenceProxyWithBounds( +legacy::ArithmeticSequenceProxyWithBounds +makeIndexedViewCompatible(const legacy::ArithmeticSequenceProxyWithBounds& ids, Index size) { + return legacy::ArithmeticSequenceProxyWithBounds( eval_expr_given_size(ids.firstObject(),size),eval_expr_given_size(ids.lastObject(),size),ids.incrObject()); } diff --git a/Eigen/src/plugins/IndexedViewMethods.h b/Eigen/src/plugins/IndexedViewMethods.h index 774a5cbe5..0584a5926 100644 --- a/Eigen/src/plugins/IndexedViewMethods.h +++ b/Eigen/src/plugins/IndexedViewMethods.h @@ -195,7 +195,7 @@ operator()(const IndicesT (&indices)[IndicesN]) EIGEN_INDEXED_VIEW_METHOD_CONST * Each parameter must either be: * - An integer indexing a single row or column * - Eigen::all indexing the full set of respective rows or columns in increasing order - * - An ArithemeticSequence as returned by the Eigen::seq and Eigen::seqN functions + * - An ArithmeticSequence as returned by the Eigen::seq and Eigen::seqN functions * - Any %Eigen's vector/array of integers or expressions * - Plain C arrays: \c int[N] * - And more generally any type exposing the following two member functions: @@ -212,7 +212,7 @@ operator()(const IndicesT (&indices)[IndicesN]) EIGEN_INDEXED_VIEW_METHOD_CONST * when all arguments are either: * - An integer * - Eigen::all - * - An ArithemeticSequence with compile-time increment strictly equal to 1, as returned by Eigen::seq(a,b), and Eigen::seqN(a,N). + * - An ArithmeticSequence with compile-time increment strictly equal to 1, as returned by Eigen::seq(a,b), and Eigen::seqN(a,N). * * Otherwise a more general IndexedView object will be returned, after conversion of the inputs * to more suitable types \c RowIndices' and \c ColIndices'. From 12e22a2844d060cfbeab7a48512046ee59709e53 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 16 Jan 2017 16:31:19 +0100 Subject: [PATCH 37/65] typos in doc --- Eigen/src/Core/util/IntegralConstant.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Eigen/src/Core/util/IntegralConstant.h b/Eigen/src/Core/util/IntegralConstant.h index dc8c8413d..57538060c 100644 --- a/Eigen/src/Core/util/IntegralConstant.h +++ b/Eigen/src/Core/util/IntegralConstant.h @@ -124,15 +124,16 @@ static const auto fix; /** \fn fix(int) * \ingroup Core_Module * - * This function returns an object embedding both a compile-time integer \c N, and a runtime value \a val. + * This function returns an object embedding both a compile-time integer \c N, and a fallback runtime value \a val. * * \tparam N the compile-time integer value - * \param val the runtime integer value + * \param val the fallback runtime integer value * * This function is a more general version of the \ref fix identifier/function that can be used in template code - * where the compile-time value coudl turned out to actually mean "undefined at compile-time". For positive integers - * such as a size of a dimension, this case is identified by Eigen::Dynamic, whereas runtime signed integers (e.g., an increment/stride) are identified - * as Eigen::DynamicIndex. + * where the compile-time value could turn out to actually mean "undefined at compile-time". For positive integers + * such as a size or a dimension, this case is identified by Eigen::Dynamic, whereas runtime signed integers + * (e.g., an increment/stride) are identified as Eigen::DynamicIndex. In such a case, the runtime value \a val + * will be used as a fallback. * * A typical use case would be: * \code From 4989922be2708378b2438db5a843640ec468ce4c Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 16 Jan 2017 22:21:23 +0100 Subject: [PATCH 38/65] 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)) ); From edff32c2c2377ed02ec7af299fccc8ef09070d62 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 17 Jan 2017 10:29:33 +0100 Subject: [PATCH 39/65] Disambiguate the two versions of fix for doxygen --- Eigen/src/Core/util/IntegralConstant.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Eigen/src/Core/util/IntegralConstant.h b/Eigen/src/Core/util/IntegralConstant.h index 57538060c..7f99863a1 100644 --- a/Eigen/src/Core/util/IntegralConstant.h +++ b/Eigen/src/Core/util/IntegralConstant.h @@ -86,7 +86,7 @@ inline internal::variable_or_fixed fix(T val) { return internal::variable_or_ #else // EIGEN_PARSED_BY_DOXYGEN -/** \var fix +/** \var fix() * \ingroup Core_Module * * This \em identifier permits to construct an object embedding a compile-time integer \c N. @@ -116,12 +116,12 @@ inline internal::variable_or_fixed fix(T val) { return internal::variable_or_ * * If for some reason you want a true object in c++98 then you can write: \code fix() \endcode which is also valid in c++14. * - * \sa fix(int), seq, seqN + * \sa fix(int), seq, seqN */ template -static const auto fix; +static const auto fix(); -/** \fn fix(int) +/** \fn fix(int) * \ingroup Core_Module * * This function returns an object embedding both a compile-time integer \c N, and a fallback runtime value \a val. From 23bfcfc15ffca75a0a90440c50781d384ce3fe0c Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 17 Jan 2017 10:30:21 +0100 Subject: [PATCH 40/65] Add missing overload of get_compile_time for c++98/11 --- Eigen/src/Core/util/IntegralConstant.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Eigen/src/Core/util/IntegralConstant.h b/Eigen/src/Core/util/IntegralConstant.h index 7f99863a1..003856b20 100644 --- a/Eigen/src/Core/util/IntegralConstant.h +++ b/Eigen/src/Core/util/IntegralConstant.h @@ -47,20 +47,24 @@ protected: }; template struct get_compile_time { - enum { value = Default }; + static const int value = Default; }; template struct get_compile_time,Default> { - enum { value = N }; + static const int value = N; +}; + +template struct get_compile_time (*)(),Default> { + static const int value = N; }; template struct get_compile_time,Default> { - enum { value = N }; + static const int value = N ; }; template struct get_compile_time,Default> { - enum { value = N }; + static const int value = N; }; From 59801a32509635b753c9f025d95d2efb9a9fb1d4 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 17 Jan 2017 10:31:28 +0100 Subject: [PATCH 41/65] Add \newin{3.x} doxygen command --- doc/Doxyfile.in | 3 ++- doc/eigendoxy.css | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index b42de1bdb..2109978fe 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -229,7 +229,8 @@ ALIASES = "only_for_vectors=This is only for vectors (either row- "blank= " \ "cpp11=[c++11]" \ "cpp14=[c++14]" \ - "cpp17=[c++17]" + "cpp17=[c++17]" \ + "newin{1}=New in %Eigen \1." ALIASES += "eigenAutoToc= " diff --git a/doc/eigendoxy.css b/doc/eigendoxy.css index 6274e6c70..6ce2b839b 100644 --- a/doc/eigendoxy.css +++ b/doc/eigendoxy.css @@ -181,6 +181,11 @@ span.cpp11,span.cpp14,span.cpp17 { font-weight: bold; } +.newin3x { + color: #a37c1a; + font-weight: bold; +} + /**** old Eigen's styles ****/ From 71e5b713563ba9a61ab58901f3034d7248a879d7 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 17 Jan 2017 11:33:57 +0100 Subject: [PATCH 42/65] Add a get_runtime_value helper to deal with pointer-to-function hack, plus some refactoring to make the internals more consistent. --- Eigen/src/Core/ArithmeticSequence.h | 56 +++++++++---------------- Eigen/src/Core/util/IndexedViewHelper.h | 4 +- Eigen/src/Core/util/IntegralConstant.h | 35 ++++++++++++---- 3 files changed, 50 insertions(+), 45 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 056ace1f2..2ad4c0906 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -44,8 +44,8 @@ public: ArithmeticSequence(FirstType first, SizeType size, IncrType incr) : m_first(first), m_size(size), m_incr(incr) {} enum { - SizeAtCompileTime = internal::get_compile_time::value, - IncrAtCompileTime = internal::get_compile_time::value + SizeAtCompileTime = internal::get_fixed_value::value, + IncrAtCompileTime = internal::get_fixed_value::value }; /** \returns the size, i.e., number of elements, of the sequence */ @@ -69,25 +69,9 @@ protected: namespace internal { -// Cleanup return types: - -// By default, no change: -template struct cleanup_seq_type { typedef T type; }; - -// Convert short, int, unsigned int, etc. to Eigen::Index -template struct cleanup_seq_type::value>::type> { typedef Index type; }; - -// In c++98/c++11, fix is a pointer to function that we better cleanup to a true fix_t: -template struct cleanup_seq_type (*)(), DynamicKey> { typedef fix_t type; }; - -// If variable_or_fixed does not match DynamicKey, then we turn it to a pure compile-time value: -template struct cleanup_seq_type, DynamicKey> { typedef fix_t type; }; -// If variable_or_fixed matches DynamicKey, then we turn it to a pure runtime-value (aka Index): -template struct cleanup_seq_type, DynamicKey> { typedef Index type; }; - // Helper to cleanup the type of the increment: template struct cleanup_seq_incr { - typedef typename cleanup_seq_type::type type; + typedef typename cleanup_index_type::type type; }; } @@ -96,18 +80,18 @@ template struct cleanup_seq_incr { * * \sa seqN(FirstType,SizeType), seq(FirstType,LastType,IncrType) */ template -ArithmeticSequence::type,typename internal::cleanup_seq_type::type,typename internal::cleanup_seq_incr::type > +ArithmeticSequence::type,typename internal::cleanup_index_type::type,typename internal::cleanup_seq_incr::type > seqN(FirstType first, SizeType size, IncrType incr) { - return ArithmeticSequence::type,typename internal::cleanup_seq_type::type,typename internal::cleanup_seq_incr::type>(first,size,incr); + return ArithmeticSequence::type,typename internal::cleanup_index_type::type,typename internal::cleanup_seq_incr::type>(first,size,incr); } /** \returns an ArithmeticSequence starting at \a first, of length \a size, and unit increment * * \sa seqN(FirstType,SizeType,IncrType), seq(FirstType,LastType) */ template -ArithmeticSequence::type,typename internal::cleanup_seq_type::type > +ArithmeticSequence::type,typename internal::cleanup_index_type::type > seqN(FirstType first, SizeType size) { - return ArithmeticSequence::type,typename internal::cleanup_seq_type::type>(first,size); + return ArithmeticSequence::type,typename internal::cleanup_index_type::type>(first,size); } #ifdef EIGEN_PARSED_BY_DOXYGEN @@ -156,7 +140,7 @@ auto seq(FirstType f, LastType l, IncrType incr) #else template typename internal::enable_if::value || Symbolic::is_symbolic::value), - ArithmeticSequence::type,Index> >::type + ArithmeticSequence::type,Index> >::type seq(FirstType f, LastType l) { return seqN(f,(l-f+1)); @@ -173,7 +157,7 @@ seq(const Symbolic::BaseExpr &f, LastType l) template typename internal::enable_if::value, - ArithmeticSequence::type, + ArithmeticSequence::type, Symbolic::AddExpr,Symbolic::ValueExpr> > >::type seq(FirstType f, const Symbolic::BaseExpr &l) { @@ -191,7 +175,7 @@ seq(const Symbolic::BaseExpr &f, const Symbolic::BaseExpr typename internal::enable_if::value || Symbolic::is_symbolic::value), - ArithmeticSequence::type,Index,typename internal::cleanup_seq_incr::type> >::type + ArithmeticSequence::type,Index,typename internal::cleanup_seq_incr::type> >::type seq(FirstType f, LastType l, IncrType incr) { typedef typename internal::cleanup_seq_incr::type CleanedIncrType; @@ -214,7 +198,7 @@ seq(const Symbolic::BaseExpr &f, LastType l, IncrType incr) template typename internal::enable_if::value, - ArithmeticSequence::type, + ArithmeticSequence::type, Symbolic::QuotientExpr, Symbolic::ValueExpr>, Symbolic::ValueExpr>, @@ -263,7 +247,7 @@ makeIndexedViewCompatible(const ArithmeticSequence& template struct get_compile_time_incr > { - enum { value = get_compile_time::value }; + enum { value = get_fixed_value::value }; }; } // end namespace internal @@ -323,7 +307,7 @@ public: enum { SizeAtCompileTime = -1, - IncrAtCompileTime = internal::get_compile_time::value + IncrAtCompileTime = internal::get_fixed_value::value }; Index size() const { return (m_last-m_first+m_incr)/m_incr; } @@ -340,19 +324,19 @@ protected: }; template -ArithmeticSequenceProxyWithBounds::type,typename internal::cleanup_seq_type::type > +ArithmeticSequenceProxyWithBounds::type,typename internal::cleanup_index_type::type > seq(FirstType f, LastType l) { - return ArithmeticSequenceProxyWithBounds::type,typename internal::cleanup_seq_type::type>(f,l); + return ArithmeticSequenceProxyWithBounds::type,typename internal::cleanup_index_type::type>(f,l); } template -ArithmeticSequenceProxyWithBounds< typename internal::cleanup_seq_type::type, - typename internal::cleanup_seq_type::type, +ArithmeticSequenceProxyWithBounds< typename internal::cleanup_index_type::type, + typename internal::cleanup_index_type::type, typename internal::cleanup_seq_incr::type > seq(FirstType f, LastType l, IncrType s) { - return ArithmeticSequenceProxyWithBounds::type, - typename internal::cleanup_seq_type::type, + return ArithmeticSequenceProxyWithBounds::type, + typename internal::cleanup_index_type::type, typename internal::cleanup_seq_incr::type> (f,l,typename internal::cleanup_seq_incr::type(s)); } @@ -363,7 +347,7 @@ namespace internal { template struct get_compile_time_incr > { - enum { value = get_compile_time::value }; + enum { value = get_fixed_value::value }; }; // Convert a symbolic range into a usable one (i.e., remove last/end "keywords") diff --git a/Eigen/src/Core/util/IndexedViewHelper.h b/Eigen/src/Core/util/IndexedViewHelper.h index 09637a157..b4f7c0dd7 100644 --- a/Eigen/src/Core/util/IndexedViewHelper.h +++ b/Eigen/src/Core/util/IndexedViewHelper.h @@ -159,8 +159,8 @@ struct IndexedViewCompatibleType { }; template -inline AllRange::value> makeIndexedViewCompatible(all_t , XprSizeType size, SpecializedType) { - return AllRange::value>(size); +inline AllRange::value> makeIndexedViewCompatible(all_t , XprSizeType size, SpecializedType) { + return AllRange::value>(size); } template struct get_compile_time_incr > { diff --git a/Eigen/src/Core/util/IntegralConstant.h b/Eigen/src/Core/util/IntegralConstant.h index 003856b20..2402baeec 100644 --- a/Eigen/src/Core/util/IntegralConstant.h +++ b/Eigen/src/Core/util/IntegralConstant.h @@ -46,30 +46,51 @@ protected: int m_value; }; -template struct get_compile_time { +template struct get_fixed_value { static const int value = Default; }; -template struct get_compile_time,Default> { +template struct get_fixed_value,Default> { static const int value = N; }; -template struct get_compile_time (*)(),Default> { +#if !EIGEN_HAS_CXX14 +template struct get_fixed_value (*)(),Default> { static const int value = N; }; +#endif -template struct get_compile_time,Default> { +template struct get_fixed_value,Default> { static const int value = N ; }; template -struct get_compile_time,Default> { +struct get_fixed_value,Default> { static const int value = N; }; +template Index get_runtime_value(const T &x) { return x; } +#if !EIGEN_HAS_CXX14 +template Index get_runtime_value(fix_t (*)()) { return N; } +#endif -template struct is_compile_time { enum { value = false }; }; -template struct is_compile_time > { enum { value = true }; }; +// Cleanup integer/fix_t/variable_or_fixed/etc types: + +// By default, no cleanup: +template struct cleanup_index_type { typedef T type; }; + +// Convert any integral type (e.g., short, int, unsigned int, etc.) to Eigen::Index +template struct cleanup_index_type::value>::type> { typedef Index type; }; + +#if !EIGEN_HAS_CXX14 +// In c++98/c++11, fix is a pointer to function that we better cleanup to a true fix_t: +template struct cleanup_index_type (*)(), DynamicKey> { typedef fix_t type; }; +#endif + +// If variable_or_fixed does not match DynamicKey, then we turn it to a pure compile-time value: +template struct cleanup_index_type, DynamicKey> { typedef fix_t type; }; +// If variable_or_fixed matches DynamicKey, then we turn it to a pure runtime-value (aka Index): +template struct cleanup_index_type, DynamicKey> { typedef Index type; }; } // end namespace internal From 4f36dcfda88be7737fbbe5145c52fca6d164ca91 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 17 Jan 2017 11:34:28 +0100 Subject: [PATCH 43/65] Add a generic block() method compatible with Eigen::fix --- Eigen/src/plugins/BlockMethods.h | 60 ++++++++++++++++++++++++++++++-- test/block.cpp | 12 +++++++ test/indexed_view.cpp | 45 +++++++++++++++--------- 3 files changed, 99 insertions(+), 18 deletions(-) diff --git a/Eigen/src/plugins/BlockMethods.h b/Eigen/src/plugins/BlockMethods.h index ac35a0086..38020730c 100644 --- a/Eigen/src/plugins/BlockMethods.h +++ b/Eigen/src/plugins/BlockMethods.h @@ -773,7 +773,7 @@ inline typename ConstNColsBlockXpr::Type middleCols(Index startCol, Index n = /// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa block(Index,Index,NRowsType,NColsType), class Block, block(Index,Index,Index,Index) /// template EIGEN_DEVICE_FUNC @@ -809,7 +809,7 @@ inline const typename ConstFixedBlockXpr::Type block(Index startRow /// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa block(Index,Index,NRowsType,NColsType), block(Index,Index,Index,Index), class Block /// template inline typename FixedBlockXpr::Type block(Index startRow, Index startCol, @@ -826,6 +826,62 @@ inline const typename ConstFixedBlockXpr::Type block(Index startRow return typename ConstFixedBlockXpr::Type(derived(), startRow, startCol, blockRows, blockCols); } +/// \returns an expression of a block in \c *this. +/// +/// \tparam NRowsType the type of the object handling the number of rows in the block, can be any integral type (e.g., int, Index) or any returned by Eigen::fix or Eigen::fix(n). +/// \tparam NColsType analogue of NRowsType but for the number of columns. +/// \param startRow the first row in the block +/// \param startCol the first column in the block +/// \param blockRows number of rows in the block as specified at either run-time or compile-time +/// \param blockCols number of columns in the block as specified at either run-time or compile-time +/// +/// \newin{3.4} +/// +/// This function covers the same versatility as block(Index, Index), and block(Index, Index, Index, Index) +/// but with less redundancy and more consistency as it does not modify the argument order +/// and seamlessly enable hybrid fixed/dynamic sizes. +/// The one-to-one full equivalences are as follows: +/// +/// \code +/// mat.template block(i,j) <--> mat.block(i,j,fix,fix) +/// mat.template block(i,j,rows,cols) <--> mat.block(i,j,fix(rows),fix(cols)) +/// \endcode +/// +/// but of course, with this version one of the compile-time parameter can be completely +/// omitted if it turns out to be a pure runtime one: +/// \code +/// mat.template block(i,j,rows,cols) <--> mat.block(i,j,fix,cols) +/// \endcode +/// +EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL +/// +/// \sa class Block, block(Index,Index,Index,Index), fix +/// +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename FixedBlockXpr::value,internal::get_fixed_value::value>::Type +#else +inline typename FixedBlockXpr<...,...>::Type +#endif +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)); +} + +/// This is the const version of block(Index,Index,NRowsType,NColsType) +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename ConstFixedBlockXpr::value,internal::get_fixed_value::value>::Type +#else +inline typename ConstFixedBlockXpr<...,...>::Type +#endif +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)); +} + /// \returns an expression of the \a i-th column of *this. Note that the numbering starts at 0. /// /// Example: \include MatrixBase_col.cpp diff --git a/test/block.cpp b/test/block.cpp index 1eeb2da27..80e24fd5b 100644 --- a/test/block.cpp +++ b/test/block.cpp @@ -29,6 +29,13 @@ block_real_only(const MatrixType &, Index, Index, Index, Index, const Scalar&) { return Scalar(0); } +// Check at compile-time that T1==T2, and at runtime-time that a==b +template +typename internal::enable_if::value,bool>::type +is_same_block(const T1& a, const T2& b) +{ + return a.isApprox(b); +} template void block(const MatrixType& m) { @@ -106,6 +113,11 @@ template void block(const MatrixType& m) m1.template block(1,1,BlockRows,BlockCols)(0,3) = m1.template block<2,5>(1,1)(1,2); Matrix b2 = m1.template block(3,3,2,5); VERIFY_IS_EQUAL(b2, m1.block(3,3,BlockRows,BlockCols)); + + VERIFY(is_same_block(m1.block(3,3,BlockRows,BlockCols), m1.block(3,3,fix(BlockRows),fix(BlockCols)))); + VERIFY(is_same_block(m1.template block(1,1,BlockRows,BlockCols), m1.block(1,1,fix,BlockCols))); + VERIFY(is_same_block(m1.template block(1,1,BlockRows,BlockCols), m1.block(1,1,fix(),fix))); + VERIFY(is_same_block(m1.template block(1,1,BlockRows,BlockCols), m1.block(1,1,fix,fix(BlockCols)))); } if (rows>2) diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index 88211f05e..5a055376d 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -49,7 +49,7 @@ bool match(const T& xpr, std::string ref, std::string str_xpr = "") { template typename internal::enable_if::value,bool>::type -is_same_type(const T1& a, const T2& b) +is_same_eq(const T1& a, const T2& b) { return (a == b).all(); } @@ -219,25 +219,25 @@ void check_indexed_view() // Check fall-back to Block { - VERIFY( is_same_type(A.col(0), A(all,0)) ); - VERIFY( is_same_type(A.row(0), A(0,all)) ); - VERIFY( is_same_type(A.block(0,0,2,2), A(seqN(0,2),seq(0,1))) ); - 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_eq(A.col(0), A(all,0)) ); + VERIFY( is_same_eq(A.row(0), A(0,all)) ); + VERIFY( is_same_eq(A.block(0,0,2,2), A(seqN(0,2),seq(0,1))) ); + VERIFY( is_same_eq(A.middleRows(2,4), A(seqN(2,4),all)) ); + VERIFY( is_same_eq(A.middleCols(2,4), A(all,seqN(2,4))) ); - VERIFY( is_same_type(A.col(A.cols()-1), A(all,last)) ); + VERIFY( is_same_eq(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)) ); - VERIFY( is_same_type(cA.block(0,0,2,2), cA(seqN(0,2),seq(0,1))) ); - VERIFY( is_same_type(cA.middleRows(2,4), cA(seqN(2,4),all)) ); - VERIFY( is_same_type(cA.middleCols(2,4), cA(all,seqN(2,4))) ); + VERIFY( is_same_eq(cA.col(0), cA(all,0)) ); + VERIFY( is_same_eq(cA.row(0), cA(0,all)) ); + VERIFY( is_same_eq(cA.block(0,0,2,2), cA(seqN(0,2),seq(0,1))) ); + VERIFY( is_same_eq(cA.middleRows(2,4), cA(seqN(2,4),all)) ); + VERIFY( is_same_eq(cA.middleCols(2,4), cA(all,seqN(2,4))) ); - VERIFY( is_same_type(a.head(4), a(seq(0,3))) ); - VERIFY( is_same_type(a.tail(4), a(seqN(last-3,4))) ); - VERIFY( is_same_type(a.tail(4), a(seq(end-4,last))) ); - VERIFY( is_same_type(a.segment<4>(3), a(seqN(3,fix<4>))) ); + VERIFY( is_same_eq(a.head(4), a(seq(0,3))) ); + VERIFY( is_same_eq(a.tail(4), a(seqN(last-3,4))) ); + VERIFY( is_same_eq(a.tail(4), a(seq(end-4,last))) ); + VERIFY( is_same_eq(a.segment<4>(3), a(seqN(3,fix<4>))) ); } ArrayXXi A1=A, A2 = ArrayXXi::Random(4,4); @@ -275,6 +275,18 @@ void check_indexed_view() VERIFY_IS_APPROX( A(legacy::seq(legacy::last,2,-2), legacy::seq(legacy::last-6,7)), A(seq(last,2,-2), seq(last-6,7)) ); VERIFY_IS_APPROX( A(seqN(legacy::last,2,-2), seqN(legacy::last-6,3)), A(seqN(last,2,-2), seqN(last-6,3)) ); + // check extended block API + { + VERIFY( is_same_eq( A.block<3,4>(1,1), A.block(1,1,fix<3>,fix<4>)) ); + VERIFY( is_same_eq( A.block<3,4>(1,1,3,4), A.block(1,1,fix<3>(),fix<4>(4))) ); + VERIFY( is_same_eq( A.block<3,Dynamic>(1,1,3,4), A.block(1,1,fix<3>,4)) ); + VERIFY( is_same_eq( A.block(1,1,3,4), A.block(1,1,fix(3),fix<4>)) ); + VERIFY( is_same_eq( A.block(1,1,3,4), A.block(1,1,fix(3),fix(4))) ); + + const ArrayXXi& cA(A); + VERIFY( is_same_eq( cA.block(1,1,3,4), cA.block(1,1,fix(3),fix<4>)) ); + } + } void test_indexed_view() @@ -282,5 +294,6 @@ void test_indexed_view() // for(int i = 0; i < g_repeat; i++) { CALL_SUBTEST_1( check_indexed_view() ); CALL_SUBTEST_2( check_indexed_view() ); + CALL_SUBTEST_3( check_indexed_view() ); // } } From f7852c3d16b7a5636dd8e0603b30034a06c80ac8 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 17 Jan 2017 16:05:58 +0100 Subject: [PATCH 44/65] Fix -Wunnamed-type-template-args --- test/indexed_view.cpp | 56 ++++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index 5a055376d..d4d82c54d 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -61,6 +61,8 @@ is_same_seq_type(const T1& a, const T2& b) return a.size() == b.size() && a.first()==b.first() && Index(a.incrObject())==Index(b.incrObject()); } +#define VERIFY_EQ_INT(A,B) VERIFY_IS_APPROX(int(A),int(B)) + void check_indexed_view() { using Eigen::placeholders::all; @@ -150,33 +152,33 @@ void check_indexed_view() B.setRandom(); VERIFY( (A(seqN(2,5), 5)).ColsAtCompileTime == 1); VERIFY( (A(seqN(2,5), 5)).RowsAtCompileTime == Dynamic); - VERIFY_IS_EQUAL( (A(seqN(2,5), 5)).InnerStrideAtCompileTime , A.InnerStrideAtCompileTime); - VERIFY_IS_EQUAL( (A(seqN(2,5), 5)).OuterStrideAtCompileTime , A.col(5).OuterStrideAtCompileTime); + VERIFY_EQ_INT( (A(seqN(2,5), 5)).InnerStrideAtCompileTime , A.InnerStrideAtCompileTime); + VERIFY_EQ_INT( (A(seqN(2,5), 5)).OuterStrideAtCompileTime , A.col(5).OuterStrideAtCompileTime); - VERIFY_IS_EQUAL( (A(5,seqN(2,5))).InnerStrideAtCompileTime , A.row(5).InnerStrideAtCompileTime); - VERIFY_IS_EQUAL( (A(5,seqN(2,5))).OuterStrideAtCompileTime , A.row(5).OuterStrideAtCompileTime); - VERIFY_IS_EQUAL( (B(1,seqN(1,2))).InnerStrideAtCompileTime , B.row(1).InnerStrideAtCompileTime); - VERIFY_IS_EQUAL( (B(1,seqN(1,2))).OuterStrideAtCompileTime , B.row(1).OuterStrideAtCompileTime); + VERIFY_EQ_INT( (A(5,seqN(2,5))).InnerStrideAtCompileTime , A.row(5).InnerStrideAtCompileTime); + VERIFY_EQ_INT( (A(5,seqN(2,5))).OuterStrideAtCompileTime , A.row(5).OuterStrideAtCompileTime); + VERIFY_EQ_INT( (B(1,seqN(1,2))).InnerStrideAtCompileTime , B.row(1).InnerStrideAtCompileTime); + VERIFY_EQ_INT( (B(1,seqN(1,2))).OuterStrideAtCompileTime , B.row(1).OuterStrideAtCompileTime); - VERIFY_IS_EQUAL( (A(seqN(2,5), seq(1,3))).InnerStrideAtCompileTime , A.InnerStrideAtCompileTime); - VERIFY_IS_EQUAL( (A(seqN(2,5), seq(1,3))).OuterStrideAtCompileTime , A.OuterStrideAtCompileTime); - VERIFY_IS_EQUAL( (B(seqN(1,2), seq(1,3))).InnerStrideAtCompileTime , B.InnerStrideAtCompileTime); - VERIFY_IS_EQUAL( (B(seqN(1,2), seq(1,3))).OuterStrideAtCompileTime , B.OuterStrideAtCompileTime); - VERIFY_IS_EQUAL( (A(seqN(2,5,2), seq(1,3,2))).InnerStrideAtCompileTime , Dynamic); - VERIFY_IS_EQUAL( (A(seqN(2,5,2), seq(1,3,2))).OuterStrideAtCompileTime , Dynamic); - VERIFY_IS_EQUAL( (A(seqN(2,5,fix<2>), seq(1,3,fix<3>))).InnerStrideAtCompileTime , 2); - VERIFY_IS_EQUAL( (A(seqN(2,5,fix<2>), seq(1,3,fix<3>))).OuterStrideAtCompileTime , Dynamic); - VERIFY_IS_EQUAL( (B(seqN(1,2,fix<2>), seq(1,3,fix<3>))).InnerStrideAtCompileTime , 2); - VERIFY_IS_EQUAL( (B(seqN(1,2,fix<2>), seq(1,3,fix<3>))).OuterStrideAtCompileTime , 3*4); + VERIFY_EQ_INT( (A(seqN(2,5), seq(1,3))).InnerStrideAtCompileTime , A.InnerStrideAtCompileTime); + VERIFY_EQ_INT( (A(seqN(2,5), seq(1,3))).OuterStrideAtCompileTime , A.OuterStrideAtCompileTime); + VERIFY_EQ_INT( (B(seqN(1,2), seq(1,3))).InnerStrideAtCompileTime , B.InnerStrideAtCompileTime); + VERIFY_EQ_INT( (B(seqN(1,2), seq(1,3))).OuterStrideAtCompileTime , B.OuterStrideAtCompileTime); + VERIFY_EQ_INT( (A(seqN(2,5,2), seq(1,3,2))).InnerStrideAtCompileTime , Dynamic); + VERIFY_EQ_INT( (A(seqN(2,5,2), seq(1,3,2))).OuterStrideAtCompileTime , Dynamic); + VERIFY_EQ_INT( (A(seqN(2,5,fix<2>), seq(1,3,fix<3>))).InnerStrideAtCompileTime , 2); + VERIFY_EQ_INT( (A(seqN(2,5,fix<2>), seq(1,3,fix<3>))).OuterStrideAtCompileTime , Dynamic); + VERIFY_EQ_INT( (B(seqN(1,2,fix<2>), seq(1,3,fix<3>))).InnerStrideAtCompileTime , 2); + VERIFY_EQ_INT( (B(seqN(1,2,fix<2>), seq(1,3,fix<3>))).OuterStrideAtCompileTime , 3*4); - VERIFY_IS_EQUAL( (A(seqN(2,fix<5>), seqN(1,fix<3>))).RowsAtCompileTime, 5); - VERIFY_IS_EQUAL( (A(seqN(2,fix<5>), seqN(1,fix<3>))).ColsAtCompileTime, 3); - VERIFY_IS_EQUAL( (A(seqN(2,fix<5>(5)), seqN(1,fix<3>(3)))).RowsAtCompileTime, 5); - VERIFY_IS_EQUAL( (A(seqN(2,fix<5>(5)), seqN(1,fix<3>(3)))).ColsAtCompileTime, 3); - VERIFY_IS_EQUAL( (A(seqN(2,fix(5)), seqN(1,fix(3)))).RowsAtCompileTime, Dynamic); - VERIFY_IS_EQUAL( (A(seqN(2,fix(5)), seqN(1,fix(3)))).ColsAtCompileTime, Dynamic); - VERIFY_IS_EQUAL( (A(seqN(2,fix(5)), seqN(1,fix(3)))).rows(), 5); - VERIFY_IS_EQUAL( (A(seqN(2,fix(5)), seqN(1,fix(3)))).cols(), 3); + VERIFY_EQ_INT( (A(seqN(2,fix<5>), seqN(1,fix<3>))).RowsAtCompileTime, 5); + VERIFY_EQ_INT( (A(seqN(2,fix<5>), seqN(1,fix<3>))).ColsAtCompileTime, 3); + VERIFY_EQ_INT( (A(seqN(2,fix<5>(5)), seqN(1,fix<3>(3)))).RowsAtCompileTime, 5); + VERIFY_EQ_INT( (A(seqN(2,fix<5>(5)), seqN(1,fix<3>(3)))).ColsAtCompileTime, 3); + VERIFY_EQ_INT( (A(seqN(2,fix(5)), seqN(1,fix(3)))).RowsAtCompileTime, Dynamic); + VERIFY_EQ_INT( (A(seqN(2,fix(5)), seqN(1,fix(3)))).ColsAtCompileTime, Dynamic); + VERIFY_EQ_INT( (A(seqN(2,fix(5)), seqN(1,fix(3)))).rows(), 5); + VERIFY_EQ_INT( (A(seqN(2,fix(5)), seqN(1,fix(3)))).cols(), 3); VERIFY( is_same_seq_type( seqN(2,5,fix<-1>), seqN(2,5,fix<-1>(-1)) ) ); VERIFY( is_same_seq_type( seqN(2,5), seqN(2,5,fix<1>(1)) ) ); @@ -195,9 +197,9 @@ void check_indexed_view() VERIFY( (B(all,1)).RowsAtCompileTime == 4); VERIFY( (A(all, eii)).ColsAtCompileTime == eii.SizeAtCompileTime); - VERIFY_IS_EQUAL( (A(eii, eii)).Flags&DirectAccessBit, (unsigned int)(0)); - VERIFY_IS_EQUAL( (A(eii, eii)).InnerStrideAtCompileTime, 0); - VERIFY_IS_EQUAL( (A(eii, eii)).OuterStrideAtCompileTime, 0); + VERIFY_EQ_INT( (A(eii, eii)).Flags&DirectAccessBit, (unsigned int)(0)); + VERIFY_EQ_INT( (A(eii, eii)).InnerStrideAtCompileTime, 0); + VERIFY_EQ_INT( (A(eii, eii)).OuterStrideAtCompileTime, 0); VERIFY_IS_APPROX( A(seq(n-1,2,-2), seqN(n-1-6,4)), A(seq(last,2,-2), seqN(last-6,4)) ); VERIFY_IS_APPROX( A(seq(n-1-6,n-1-2), seqN(n-1-6,4)), A(seq(last-6,last-2), seqN(6+last-6-6,4)) ); From 5e36ec3b6f3cf5513357e8520230083ff9ecb938 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 17 Jan 2017 17:10:16 +0100 Subject: [PATCH 45/65] Fix regression when passing enums to operator() --- Eigen/src/plugins/IndexedViewMethods.h | 6 ++++-- test/indexed_view.cpp | 10 ++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Eigen/src/plugins/IndexedViewMethods.h b/Eigen/src/plugins/IndexedViewMethods.h index 90ade05ed..e6098bfc7 100644 --- a/Eigen/src/plugins/IndexedViewMethods.h +++ b/Eigen/src/plugins/IndexedViewMethods.h @@ -55,7 +55,9 @@ ivcSize(const Indices& indices) const { template struct valid_indexed_view_overload { - enum { value = !(internal::is_integral::value && internal::is_integral::value) }; + // Here we use is_convertible to Index instead of is_integral in order to treat enums as Index. + // In c++11 we could use is_integral && is_enum if is_convertible appears to be too permissive. + enum { value = !(internal::is_convertible::value && internal::is_convertible::value) }; }; public: @@ -81,7 +83,7 @@ operator()(const RowIndices& rowIndices, const ColIndices& colIndices) EIGEN_IND (derived(), ivcRow(rowIndices), ivcCol(colIndices)); } -// The folowing overload returns a Block<> object +// The following overload returns a Block<> object template typename internal::enable_if::value diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index d4d82c54d..3ea8e7c00 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -277,6 +277,16 @@ void check_indexed_view() VERIFY_IS_APPROX( A(legacy::seq(legacy::last,2,-2), legacy::seq(legacy::last-6,7)), A(seq(last,2,-2), seq(last-6,7)) ); VERIFY_IS_APPROX( A(seqN(legacy::last,2,-2), seqN(legacy::last-6,3)), A(seqN(last,2,-2), seqN(last-6,3)) ); + // check mat(i,j) with weird types for i and j + { + VERIFY_IS_APPROX( A(B.RowsAtCompileTime-1, 1), A(3,1) ); + VERIFY_IS_APPROX( A(B.RowsAtCompileTime, 1), A(3,1) ); + VERIFY_IS_APPROX( A(B.RowsAtCompileTime-1, B.ColsAtCompileTime-1), A(3,3) ); + VERIFY_IS_APPROX( A(B.RowsAtCompileTime, B.ColsAtCompileTime), A(3,3) ); + enum { I = 3, J = 4 }; + VERIFY_IS_APPROX( A(I,J), A(3,4) ); + } + // check extended block API { VERIFY( is_same_eq( A.block<3,4>(1,1), A.block(1,1,fix<3>,fix<4>)) ); From 5484ddd353168c5b989be0e3ce6568b93b94093c Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 17 Jan 2017 22:11:46 +0100 Subject: [PATCH 46/65] Merge the generic and dynamic overloads of block() --- Eigen/src/plugins/BlockMethods.h | 175 +++++++++++++++---------------- 1 file changed, 82 insertions(+), 93 deletions(-) diff --git a/Eigen/src/plugins/BlockMethods.h b/Eigen/src/plugins/BlockMethods.h index 38020730c..060d79db4 100644 --- a/Eigen/src/plugins/BlockMethods.h +++ b/Eigen/src/plugins/BlockMethods.h @@ -42,40 +42,69 @@ template struct ConstFixedSegmentReturnType { typedef const VectorBloc #endif // not EIGEN_PARSED_BY_DOXYGEN -/// \returns a dynamic-size expression of a block in *this. +/// \returns an expression of a block in \c *this with either dynamic or fixed sizes. /// -/// \param startRow the first row in the block -/// \param startCol the first column in the block -/// \param blockRows the number of rows in the block -/// \param blockCols the number of columns in the block +/// \param startRow the first row in the block +/// \param startCol the first column in the block +/// \param blockRows number of rows in the block, specified at either run-time or compile-time +/// \param blockCols number of columns in the block, specified at either run-time or compile-time +/// \tparam NRowsType the type of the value handling the number of rows in the block, typically Index. +/// \tparam NColsType the type of the value handling the number of columns in the block, typically Index. /// -/// Example: \include MatrixBase_block_int_int_int_int.cpp +/// Example using runtime (aka dynamic) sizes: \include MatrixBase_block_int_int_int_int.cpp /// Output: \verbinclude MatrixBase_block_int_int_int_int.out /// -/// \note Even though the returned expression has dynamic size, in the case +/// \newin{3.4}: +/// +/// The number of rows \a blockRows and columns \a blockCols can also be specified at compile-time by passing Eigen::fix, +/// or Eigen::fix(n) as arguments. In the later case, \c n plays the role of a runtime fallback value in case \c N equals Eigen::Dynamic. +/// Here is an example with a fixed number of rows \c NRows and dynamic number of columns \c cols: +/// \code +/// mat.block(i,j,fix,cols) +/// \endcode +/// +/// This function thus fully covers the features offered by the following overloads block(Index, Index), +/// and block(Index, Index, Index, Index) that are thus obsolete. Indeed, this generic version avoids +/// redundancy, it preserves the argument order, and prevents the need to rely on the template keyword in templated code. +/// +/// but with less redundancy and more consistency as it does not modify the argument order +/// and seamlessly enable hybrid fixed/dynamic sizes. +/// +/// \note Even in the case that the returned expression has dynamic size, in the case /// when it is applied to a fixed-size matrix, it inherits a fixed maximal size, /// which means that evaluating it does not cause a dynamic memory allocation. /// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa class Block, block(Index,Index) +/// \sa class Block, fix, fix(int) /// -EIGEN_DEVICE_FUNC -inline BlockXpr block(Index startRow, Index startCol, Index blockRows, Index blockCols) +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename FixedBlockXpr::value,internal::get_fixed_value::value>::Type +#else +inline typename FixedBlockXpr<...,...>::Type +#endif +block(Index startRow, Index startCol, NRowsType blockRows, NColsType blockCols) { - return BlockXpr(derived(), startRow, startCol, blockRows, blockCols); + return typename FixedBlockXpr::value,internal::get_fixed_value::value>::Type( + derived(), startRow, startCol, internal::get_runtime_value(blockRows), internal::get_runtime_value(blockCols)); } -/// This is the const version of block(Index,Index,Index,Index). */ -EIGEN_DEVICE_FUNC -inline const ConstBlockXpr block(Index startRow, Index startCol, Index blockRows, Index blockCols) const +/// This is the const version of block(Index,Index,NRowsType,NColsType) +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename ConstFixedBlockXpr::value,internal::get_fixed_value::value>::Type +#else +inline typename ConstFixedBlockXpr<...,...>::Type +#endif +block(Index startRow, Index startCol, NRowsType blockRows, NColsType blockCols) const { - return ConstBlockXpr(derived(), startRow, startCol, blockRows, blockCols); + return typename ConstFixedBlockXpr::value,internal::get_fixed_value::value>::Type( + derived(), startRow, startCol, internal::get_runtime_value(blockRows), internal::get_runtime_value(blockCols)); } - /// \returns a dynamic-size expression of a top-right corner of *this. /// /// \param cRows the number of rows in the corner @@ -86,7 +115,7 @@ inline const ConstBlockXpr block(Index startRow, Index startCol, Index blockRows /// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// EIGEN_DEVICE_FUNC inline BlockXpr topRightCorner(Index cRows, Index cCols) @@ -172,7 +201,7 @@ inline const typename ConstFixedBlockXpr::Type topRightCorner(Index /// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// EIGEN_DEVICE_FUNC inline BlockXpr topLeftCorner(Index cRows, Index cCols) @@ -196,7 +225,7 @@ inline const ConstBlockXpr topLeftCorner(Index cRows, Index cCols) const /// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// template EIGEN_DEVICE_FUNC @@ -257,7 +286,7 @@ inline const typename ConstFixedBlockXpr::Type topLeftCorner(Index /// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// EIGEN_DEVICE_FUNC inline BlockXpr bottomRightCorner(Index cRows, Index cCols) @@ -281,7 +310,7 @@ inline const ConstBlockXpr bottomRightCorner(Index cRows, Index cCols) const /// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// template EIGEN_DEVICE_FUNC @@ -342,7 +371,7 @@ inline const typename ConstFixedBlockXpr::Type bottomRightCorner(In /// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// EIGEN_DEVICE_FUNC inline BlockXpr bottomLeftCorner(Index cRows, Index cCols) @@ -366,7 +395,7 @@ inline const ConstBlockXpr bottomLeftCorner(Index cRows, Index cCols) const /// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// template EIGEN_DEVICE_FUNC @@ -426,7 +455,7 @@ inline const typename ConstFixedBlockXpr::Type bottomLeftCorner(Ind /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// EIGEN_DEVICE_FUNC inline RowsBlockXpr topRows(Index n) @@ -454,7 +483,7 @@ inline ConstRowsBlockXpr topRows(Index n) const /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// template EIGEN_DEVICE_FUNC @@ -482,7 +511,7 @@ inline typename ConstNRowsBlockXpr::Type topRows(Index n = N) const /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// EIGEN_DEVICE_FUNC inline RowsBlockXpr bottomRows(Index n) @@ -510,7 +539,7 @@ inline ConstRowsBlockXpr bottomRows(Index n) const /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// template EIGEN_DEVICE_FUNC @@ -539,7 +568,7 @@ inline typename ConstNRowsBlockXpr::Type bottomRows(Index n = N) const /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// EIGEN_DEVICE_FUNC inline RowsBlockXpr middleRows(Index startRow, Index n) @@ -568,7 +597,7 @@ inline ConstRowsBlockXpr middleRows(Index startRow, Index n) const /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// template EIGEN_DEVICE_FUNC @@ -596,7 +625,7 @@ inline typename ConstNRowsBlockXpr::Type middleRows(Index startRow, Index n = /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// EIGEN_DEVICE_FUNC inline ColsBlockXpr leftCols(Index n) @@ -624,7 +653,7 @@ inline ConstColsBlockXpr leftCols(Index n) const /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// template EIGEN_DEVICE_FUNC @@ -652,7 +681,7 @@ inline typename ConstNColsBlockXpr::Type leftCols(Index n = N) const /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// EIGEN_DEVICE_FUNC inline ColsBlockXpr rightCols(Index n) @@ -680,7 +709,7 @@ inline ConstColsBlockXpr rightCols(Index n) const /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// template EIGEN_DEVICE_FUNC @@ -709,7 +738,7 @@ inline typename ConstNColsBlockXpr::Type rightCols(Index n = N) const /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// EIGEN_DEVICE_FUNC inline ColsBlockXpr middleCols(Index startCol, Index numCols) @@ -738,7 +767,7 @@ inline ConstColsBlockXpr middleCols(Index startCol, Index numCols) const /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// template EIGEN_DEVICE_FUNC @@ -768,12 +797,18 @@ inline typename ConstNColsBlockXpr::Type middleCols(Index startCol, Index n = /// 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, block(Index,Index,Index,Index) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// template EIGEN_DEVICE_FUNC @@ -807,9 +842,19 @@ inline const typename ConstFixedBlockXpr::Type block(Index startRow /// Example: \include MatrixBase_template_int_int_block_int_int_int_int.cpp /// Output: \verbinclude MatrixBase_template_int_int_block_int_int_int_int.cpp /// +/// \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), block(Index,Index,Index,Index), class Block +/// \sa block(Index,Index,NRowsType,NColsType), block(Index,Index,NRowsType,NColsType), class Block /// template inline typename FixedBlockXpr::Type block(Index startRow, Index startCol, @@ -826,62 +871,6 @@ inline const typename ConstFixedBlockXpr::Type block(Index startRow return typename ConstFixedBlockXpr::Type(derived(), startRow, startCol, blockRows, blockCols); } -/// \returns an expression of a block in \c *this. -/// -/// \tparam NRowsType the type of the object handling the number of rows in the block, can be any integral type (e.g., int, Index) or any returned by Eigen::fix or Eigen::fix(n). -/// \tparam NColsType analogue of NRowsType but for the number of columns. -/// \param startRow the first row in the block -/// \param startCol the first column in the block -/// \param blockRows number of rows in the block as specified at either run-time or compile-time -/// \param blockCols number of columns in the block as specified at either run-time or compile-time -/// -/// \newin{3.4} -/// -/// This function covers the same versatility as block(Index, Index), and block(Index, Index, Index, Index) -/// but with less redundancy and more consistency as it does not modify the argument order -/// and seamlessly enable hybrid fixed/dynamic sizes. -/// The one-to-one full equivalences are as follows: -/// -/// \code -/// mat.template block(i,j) <--> mat.block(i,j,fix,fix) -/// mat.template block(i,j,rows,cols) <--> mat.block(i,j,fix(rows),fix(cols)) -/// \endcode -/// -/// but of course, with this version one of the compile-time parameter can be completely -/// omitted if it turns out to be a pure runtime one: -/// \code -/// mat.template block(i,j,rows,cols) <--> mat.block(i,j,fix,cols) -/// \endcode -/// -EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL -/// -/// \sa class Block, block(Index,Index,Index,Index), fix -/// -template -#ifndef EIGEN_PARSED_BY_DOXYGEN -inline typename FixedBlockXpr::value,internal::get_fixed_value::value>::Type -#else -inline typename FixedBlockXpr<...,...>::Type -#endif -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)); -} - -/// This is the const version of block(Index,Index,NRowsType,NColsType) -template -#ifndef EIGEN_PARSED_BY_DOXYGEN -inline typename ConstFixedBlockXpr::value,internal::get_fixed_value::value>::Type -#else -inline typename ConstFixedBlockXpr<...,...>::Type -#endif -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)); -} - /// \returns an expression of the \a i-th column of *this. Note that the numbering starts at 0. /// /// Example: \include MatrixBase_col.cpp From 198507141b35aee322a95110dd9aab182db58f29 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 18 Jan 2017 09:43:58 +0100 Subject: [PATCH 47/65] Update all block expressions to accept compile-time sizes passed by fix or fix(n) --- Eigen/src/plugins/BlockMethods.h | 505 +++++++++++++++++++++++-------- test/indexed_view.cpp | 34 ++- 2 files changed, 411 insertions(+), 128 deletions(-) diff --git a/Eigen/src/plugins/BlockMethods.h b/Eigen/src/plugins/BlockMethods.h index 060d79db4..2d5a4e507 100644 --- a/Eigen/src/plugins/BlockMethods.h +++ b/Eigen/src/plugins/BlockMethods.h @@ -78,6 +78,7 @@ EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// /// \sa class Block, fix, fix(int) /// +EIGEN_DEVICE_FUNC template #ifndef EIGEN_PARSED_BY_DOXYGEN inline typename FixedBlockXpr::value,internal::get_fixed_value::value>::Type @@ -91,11 +92,12 @@ block(Index startRow, Index startCol, NRowsType blockRows, NColsType blockCols) } /// This is the const version of block(Index,Index,NRowsType,NColsType) +EIGEN_DEVICE_FUNC template #ifndef EIGEN_PARSED_BY_DOXYGEN -inline typename ConstFixedBlockXpr::value,internal::get_fixed_value::value>::Type +inline const typename ConstFixedBlockXpr::value,internal::get_fixed_value::value>::Type #else -inline typename ConstFixedBlockXpr<...,...>::Type +inline const typename ConstFixedBlockXpr<...,...>::Type #endif block(Index startRow, Index startCol, NRowsType blockRows, NColsType blockCols) const { @@ -105,32 +107,51 @@ block(Index startRow, Index startCol, NRowsType blockRows, NColsType blockCols) -/// \returns a dynamic-size expression of a top-right corner of *this. +/// \returns a expression of a top-right corner of \c *this with either dynamic or fixed sizes. /// /// \param cRows the number of rows in the corner /// \param cCols the number of columns in the corner +/// \tparam NRowsType the type of the value handling the number of rows in the block, typically Index. +/// \tparam NColsType the type of the value handling the number of columns in the block, typically Index. /// -/// Example: \include MatrixBase_topRightCorner_int_int.cpp +/// Example with dynamic sizes: \include MatrixBase_topRightCorner_int_int.cpp /// Output: \verbinclude MatrixBase_topRightCorner_int_int.out /// +/// The number of rows \a blockRows and columns \a blockCols 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. +/// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// EIGEN_DEVICE_FUNC -inline BlockXpr topRightCorner(Index cRows, Index cCols) +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename FixedBlockXpr::value,internal::get_fixed_value::value>::Type +#else +inline typename FixedBlockXpr<...,...>::Type +#endif +topRightCorner(NRowsType cRows, NColsType cCols) { - return BlockXpr(derived(), 0, cols() - cCols, cRows, 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)); } -/// This is the const version of topRightCorner(Index, Index). +/// This is the const version of topRightCorner(NRowsType, NColsType). EIGEN_DEVICE_FUNC -inline const ConstBlockXpr topRightCorner(Index cRows, Index cCols) const +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline const typename ConstFixedBlockXpr::value,internal::get_fixed_value::value>::Type +#else +inline const typename ConstFixedBlockXpr<...,...>::Type +#endif +topRightCorner(NRowsType cRows, NColsType cCols) const { - return ConstBlockXpr(derived(), 0, cols() - cCols, cRows, cCols); + 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)); } -/// \returns an expression of a fixed-size top-right corner of *this. +/// \returns an expression of a fixed-size top-right corner of \c *this. /// /// \tparam CRows the number of rows in the corner /// \tparam CCols the number of columns in the corner @@ -157,7 +178,7 @@ inline const typename ConstFixedBlockXpr::Type topRightCorner() con return typename ConstFixedBlockXpr::Type(derived(), 0, cols() - CCols); } -/// \returns an expression of a top-right corner of *this. +/// \returns an expression of a top-right corner of \c *this. /// /// \tparam CRows number of rows in corner as specified at compile-time /// \tparam CCols number of columns in corner as specified at compile-time @@ -191,32 +212,51 @@ inline const typename ConstFixedBlockXpr::Type topRightCorner(Index -/// \returns a dynamic-size expression of a top-left corner of *this. +/// \returns an expression of a top-left corner of \c *this with either dynamic or fixed sizes. /// /// \param cRows the number of rows in the corner /// \param cCols the number of columns in the corner +/// \tparam NRowsType the type of the value handling the number of rows in the block, typically Index. +/// \tparam NColsType the type of the value handling the number of columns in the block, typically Index. /// /// Example: \include MatrixBase_topLeftCorner_int_int.cpp /// Output: \verbinclude MatrixBase_topLeftCorner_int_int.out /// +/// The number of rows \a blockRows and columns \a blockCols 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. +/// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// EIGEN_DEVICE_FUNC -inline BlockXpr topLeftCorner(Index cRows, Index cCols) +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename FixedBlockXpr::value,internal::get_fixed_value::value>::Type +#else +inline typename FixedBlockXpr<...,...>::Type +#endif +topLeftCorner(NRowsType cRows, NColsType cCols) { - return BlockXpr(derived(), 0, 0, cRows, cCols); + return typename FixedBlockXpr::value,internal::get_fixed_value::value>::Type + (derived(), 0, 0, internal::get_runtime_value(cRows), internal::get_runtime_value(cCols)); } /// This is the const version of topLeftCorner(Index, Index). EIGEN_DEVICE_FUNC -inline const ConstBlockXpr topLeftCorner(Index cRows, Index cCols) const +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline const typename ConstFixedBlockXpr::value,internal::get_fixed_value::value>::Type +#else +inline const typename ConstFixedBlockXpr<...,...>::Type +#endif +topLeftCorner(NRowsType cRows, NColsType cCols) const { - return ConstBlockXpr(derived(), 0, 0, cRows, cCols); + return typename ConstFixedBlockXpr::value,internal::get_fixed_value::value>::Type + (derived(), 0, 0, internal::get_runtime_value(cRows), internal::get_runtime_value(cCols)); } -/// \returns an expression of a fixed-size top-left corner of *this. +/// \returns an expression of a fixed-size top-left corner of \c *this. /// /// The template parameters CRows and CCols are the number of rows and columns in the corner. /// @@ -225,7 +265,7 @@ inline const ConstBlockXpr topLeftCorner(Index cRows, Index cCols) const /// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// template EIGEN_DEVICE_FUNC @@ -242,7 +282,7 @@ inline const typename ConstFixedBlockXpr::Type topLeftCorner() cons return typename ConstFixedBlockXpr::Type(derived(), 0, 0); } -/// \returns an expression of a top-left corner of *this. +/// \returns an expression of a top-left corner of \c *this. /// /// \tparam CRows number of rows in corner as specified at compile-time /// \tparam CCols number of columns in corner as specified at compile-time @@ -276,32 +316,53 @@ inline const typename ConstFixedBlockXpr::Type topLeftCorner(Index -/// \returns a dynamic-size expression of a bottom-right corner of *this. +/// \returns an expression of a bottom-right corner of \c *this with either dynamic or fixed sizes. /// /// \param cRows the number of rows in the corner /// \param cCols the number of columns in the corner +/// \tparam NRowsType the type of the value handling the number of rows in the block, typically Index. +/// \tparam NColsType the type of the value handling the number of columns in the block, typically Index. /// /// Example: \include MatrixBase_bottomRightCorner_int_int.cpp /// Output: \verbinclude MatrixBase_bottomRightCorner_int_int.out /// +/// The number of rows \a blockRows and columns \a blockCols 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. +/// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// EIGEN_DEVICE_FUNC -inline BlockXpr bottomRightCorner(Index cRows, Index cCols) +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename FixedBlockXpr::value,internal::get_fixed_value::value>::Type +#else +inline typename FixedBlockXpr<...,...>::Type +#endif +bottomRightCorner(NRowsType cRows, NColsType cCols) { - return BlockXpr(derived(), rows() - cRows, cols() - cCols, cRows, 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)); } -/// This is the const version of bottomRightCorner(Index, Index). +/// This is the const version of bottomRightCorner(NRowsType, NColsType). EIGEN_DEVICE_FUNC -inline const ConstBlockXpr bottomRightCorner(Index cRows, Index cCols) const +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline const typename ConstFixedBlockXpr::value,internal::get_fixed_value::value>::Type +#else +inline const typename ConstFixedBlockXpr<...,...>::Type +#endif +bottomRightCorner(NRowsType cRows, NColsType cCols) const { - return ConstBlockXpr(derived(), rows() - cRows, cols() - cCols, cRows, cCols); + 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)); } -/// \returns an expression of a fixed-size bottom-right corner of *this. +/// \returns an expression of a fixed-size bottom-right corner of \c *this. /// /// The template parameters CRows and CCols are the number of rows and columns in the corner. /// @@ -310,7 +371,7 @@ inline const ConstBlockXpr bottomRightCorner(Index cRows, Index cCols) const /// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// template EIGEN_DEVICE_FUNC @@ -327,7 +388,7 @@ inline const typename ConstFixedBlockXpr::Type bottomRightCorner() return typename ConstFixedBlockXpr::Type(derived(), rows() - CRows, cols() - CCols); } -/// \returns an expression of a bottom-right corner of *this. +/// \returns an expression of a bottom-right corner of \c *this. /// /// \tparam CRows number of rows in corner as specified at compile-time /// \tparam CCols number of columns in corner as specified at compile-time @@ -361,32 +422,53 @@ inline const typename ConstFixedBlockXpr::Type bottomRightCorner(In -/// \returns a dynamic-size expression of a bottom-left corner of *this. +/// \returns an expression of a bottom-left corner of \c *this with either dynamic or fixed sizes. /// /// \param cRows the number of rows in the corner /// \param cCols the number of columns in the corner +/// \tparam NRowsType the type of the value handling the number of rows in the block, typically Index. +/// \tparam NColsType the type of the value handling the number of columns in the block, typically Index. /// /// Example: \include MatrixBase_bottomLeftCorner_int_int.cpp /// Output: \verbinclude MatrixBase_bottomLeftCorner_int_int.out /// +/// The number of rows \a blockRows and columns \a blockCols 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. +/// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// EIGEN_DEVICE_FUNC -inline BlockXpr bottomLeftCorner(Index cRows, Index cCols) +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename FixedBlockXpr::value,internal::get_fixed_value::value>::Type +#else +inline typename FixedBlockXpr<...,...>::Type +#endif +bottomLeftCorner(NRowsType cRows, NColsType cCols) { - return BlockXpr(derived(), rows() - cRows, 0, cRows, 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)); } -/// This is the const version of bottomLeftCorner(Index, Index). +/// This is the const version of bottomLeftCorner(NRowsType, NColsType). EIGEN_DEVICE_FUNC -inline const ConstBlockXpr bottomLeftCorner(Index cRows, Index cCols) const +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename ConstFixedBlockXpr::value,internal::get_fixed_value::value>::Type +#else +inline typename ConstFixedBlockXpr<...,...>::Type +#endif +bottomLeftCorner(NRowsType cRows, NColsType cCols) const { - return ConstBlockXpr(derived(), rows() - cRows, 0, cRows, cCols); + 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)); } -/// \returns an expression of a fixed-size bottom-left corner of *this. +/// \returns an expression of a fixed-size bottom-left corner of \c *this. /// /// The template parameters CRows and CCols are the number of rows and columns in the corner. /// @@ -395,7 +477,7 @@ inline const ConstBlockXpr bottomLeftCorner(Index cRows, Index cCols) const /// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// template EIGEN_DEVICE_FUNC @@ -412,7 +494,7 @@ inline const typename ConstFixedBlockXpr::Type bottomLeftCorner() c return typename ConstFixedBlockXpr::Type(derived(), rows() - CRows, 0); } -/// \returns an expression of a bottom-left corner of *this. +/// \returns an expression of a bottom-left corner of \c *this. /// /// \tparam CRows number of rows in corner as specified at compile-time /// \tparam CCols number of columns in corner as specified at compile-time @@ -446,31 +528,50 @@ inline const typename ConstFixedBlockXpr::Type bottomLeftCorner(Ind -/// \returns a block consisting of the top rows of *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_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. +/// See \link block(Index,Index,NRowsType,NColsType) block() \endlink for the details. +/// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// EIGEN_DEVICE_FUNC -inline RowsBlockXpr topRows(Index n) +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename NRowsBlockXpr::value>::Type +#else +inline typename NRowsBlockXpr<...>::Type +#endif +topRows(NRowsType n) { - return RowsBlockXpr(derived(), 0, 0, n, cols()); + return typename NRowsBlockXpr::value>::Type + (derived(), 0, 0, internal::get_runtime_value(n), cols()); } -/// This is the const version of topRows(Index). +/// This is the const version of topRows(NRowsType). EIGEN_DEVICE_FUNC -inline ConstRowsBlockXpr topRows(Index n) const +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline const typename ConstNRowsBlockXpr::value>::Type +#else +inline const typename ConstNRowsBlockXpr<...>::Type +#endif +topRows(NRowsType n) const { - return ConstRowsBlockXpr(derived(), 0, 0, n, cols()); + return typename ConstNRowsBlockXpr::value>::Type + (derived(), 0, 0, internal::get_runtime_value(n), cols()); } -/// \returns a block consisting of the top rows of *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 @@ -483,7 +584,7 @@ inline ConstRowsBlockXpr topRows(Index n) const /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// template EIGEN_DEVICE_FUNC @@ -502,31 +603,50 @@ inline typename ConstNRowsBlockXpr::Type topRows(Index n = N) const -/// \returns a block consisting of the bottom rows of *this. +/// \returns a block consisting of the bottom 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 /// +/// The number of rows \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. +/// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// EIGEN_DEVICE_FUNC -inline RowsBlockXpr bottomRows(Index n) +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename NRowsBlockXpr::value>::Type +#else +inline typename NRowsBlockXpr<...>::Type +#endif +bottomRows(NRowsType n) { - return RowsBlockXpr(derived(), rows() - n, 0, n, cols()); + return typename NRowsBlockXpr::value>::Type + (derived(), rows() - internal::get_runtime_value(n), 0, internal::get_runtime_value(n), cols()); } -/// This is the const version of bottomRows(Index). +/// This is the const version of bottomRows(NRowsType). EIGEN_DEVICE_FUNC -inline ConstRowsBlockXpr bottomRows(Index n) const +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline const typename ConstNRowsBlockXpr::value>::Type +#else +inline const typename ConstNRowsBlockXpr<...>::Type +#endif +bottomRows(NRowsType n) const { - return ConstRowsBlockXpr(derived(), rows() - n, 0, n, cols()); + return typename ConstNRowsBlockXpr::value>::Type + (derived(), rows() - internal::get_runtime_value(n), 0, internal::get_runtime_value(n), cols()); } -/// \returns a block consisting of the bottom rows of *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 n the number of rows in the block as specified at run-time @@ -539,7 +659,7 @@ inline ConstRowsBlockXpr bottomRows(Index n) const /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// template EIGEN_DEVICE_FUNC @@ -558,32 +678,51 @@ inline typename ConstNRowsBlockXpr::Type bottomRows(Index n = N) const -/// \returns a block consisting of a range of rows of *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 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. +/// See \link block(Index,Index,NRowsType,NColsType) block() \endlink for the details. +/// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// EIGEN_DEVICE_FUNC -inline RowsBlockXpr middleRows(Index startRow, Index n) +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename NRowsBlockXpr::value>::Type +#else +inline typename NRowsBlockXpr<...>::Type +#endif +middleRows(Index startRow, NRowsType n) { - return RowsBlockXpr(derived(), startRow, 0, n, cols()); + return typename NRowsBlockXpr::value>::Type + (derived(), startRow, 0, internal::get_runtime_value(n), cols()); } -/// This is the const version of middleRows(Index,Index). +/// This is the const version of middleRows(Index,NRowsType). EIGEN_DEVICE_FUNC -inline ConstRowsBlockXpr middleRows(Index startRow, Index n) const +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline const typename ConstNRowsBlockXpr::value>::Type +#else +inline const typename ConstNRowsBlockXpr<...>::Type +#endif +middleRows(Index startRow, NRowsType n) const { - return ConstRowsBlockXpr(derived(), startRow, 0, n, cols()); + return typename ConstNRowsBlockXpr::value>::Type + (derived(), startRow, 0, internal::get_runtime_value(n), cols()); } -/// \returns a block consisting of a range of rows of *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 @@ -597,7 +736,7 @@ inline ConstRowsBlockXpr middleRows(Index startRow, Index n) const /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// template EIGEN_DEVICE_FUNC @@ -616,31 +755,50 @@ inline typename ConstNRowsBlockXpr::Type middleRows(Index startRow, Index n = -/// \returns a block consisting of the left columns of *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_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. +/// See \link block(Index,Index,NRowsType,NColsType) block() \endlink for the details. +/// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// EIGEN_DEVICE_FUNC -inline ColsBlockXpr leftCols(Index n) +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename NColsBlockXpr::value>::Type +#else +inline typename NColsBlockXpr<...>::Type +#endif +leftCols(NColsType n) { - return ColsBlockXpr(derived(), 0, 0, rows(), n); + return typename NColsBlockXpr::value>::Type + (derived(), 0, 0, rows(), internal::get_runtime_value(n)); } -/// This is the const version of leftCols(Index). +/// This is the const version of leftCols(NColsType). EIGEN_DEVICE_FUNC -inline ConstColsBlockXpr leftCols(Index n) const +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline const typename ConstNColsBlockXpr::value>::Type +#else +inline const typename ConstNColsBlockXpr<...>::Type +#endif +leftCols(NColsType n) const { - return ConstColsBlockXpr(derived(), 0, 0, rows(), n); + return typename ConstNColsBlockXpr::value>::Type + (derived(), 0, 0, rows(), internal::get_runtime_value(n)); } -/// \returns a block consisting of the left columns of *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 @@ -653,7 +811,7 @@ inline ConstColsBlockXpr leftCols(Index n) const /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// template EIGEN_DEVICE_FUNC @@ -672,31 +830,50 @@ inline typename ConstNColsBlockXpr::Type leftCols(Index n = N) const -/// \returns a block consisting of the right columns of *this. +/// \returns a block consisting of the right 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 /// +/// The number of columns \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. +/// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// EIGEN_DEVICE_FUNC -inline ColsBlockXpr rightCols(Index n) +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename NColsBlockXpr::value>::Type +#else +inline typename NColsBlockXpr<...>::Type +#endif +rightCols(NColsType n) { - return ColsBlockXpr(derived(), 0, cols() - n, rows(), n); + return typename NColsBlockXpr::value>::Type + (derived(), 0, cols() - internal::get_runtime_value(n), rows(), internal::get_runtime_value(n)); } -/// This is the const version of rightCols(Index). +/// This is the const version of rightCols(NColsType). EIGEN_DEVICE_FUNC -inline ConstColsBlockXpr rightCols(Index n) const +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline const typename ConstNColsBlockXpr::value>::Type +#else +inline const typename ConstNColsBlockXpr<...>::Type +#endif +rightCols(NColsType n) const { - return ConstColsBlockXpr(derived(), 0, cols() - n, rows(), n); + return typename ConstNColsBlockXpr::value>::Type + (derived(), 0, cols() - internal::get_runtime_value(n), rows(), internal::get_runtime_value(n)); } -/// \returns a block consisting of the right columns of *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 n the number of columns in the block as specified at run-time @@ -709,7 +886,7 @@ inline ConstColsBlockXpr rightCols(Index n) const /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// template EIGEN_DEVICE_FUNC @@ -728,32 +905,51 @@ inline typename ConstNColsBlockXpr::Type rightCols(Index n = N) const -/// \returns a block consisting of a range of columns of *this. +/// \returns a block consisting of a range of columns of \c *this. /// /// \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 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. +/// See \link block(Index,Index,NRowsType,NColsType) block() \endlink for the details. +/// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// EIGEN_DEVICE_FUNC -inline ColsBlockXpr middleCols(Index startCol, Index numCols) +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename NColsBlockXpr::value>::Type +#else +inline typename NColsBlockXpr<...>::Type +#endif +middleCols(Index startCol, NColsType numCols) { - return ColsBlockXpr(derived(), 0, startCol, rows(), numCols); + return typename NColsBlockXpr::value>::Type + (derived(), 0, startCol, rows(), internal::get_runtime_value(numCols)); } -/// This is the const version of middleCols(Index,Index). +/// This is the const version of middleCols(Index,NColsType). EIGEN_DEVICE_FUNC -inline ConstColsBlockXpr middleCols(Index startCol, Index numCols) const +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline const typename ConstNColsBlockXpr::value>::Type +#else +inline const typename ConstNColsBlockXpr<...>::Type +#endif +middleCols(Index startCol, NColsType numCols) const { - return ConstColsBlockXpr(derived(), 0, startCol, rows(), numCols); + return typename ConstNColsBlockXpr::value>::Type + (derived(), 0, startCol, rows(), internal::get_runtime_value(numCols)); } -/// \returns a block consisting of a range of columns of *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 @@ -767,7 +963,7 @@ inline ConstColsBlockXpr middleCols(Index startCol, Index numCols) const /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// template EIGEN_DEVICE_FUNC @@ -786,7 +982,7 @@ inline typename ConstNColsBlockXpr::Type middleCols(Index startCol, Index n = -/// \returns a fixed-size expression of a block in *this. +/// \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. @@ -825,7 +1021,7 @@ inline const typename ConstFixedBlockXpr::Type block(Index startRow return typename ConstFixedBlockXpr::Type(derived(), startRow, startCol); } -/// \returns an expression of a block in *this. +/// \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 @@ -854,7 +1050,7 @@ inline const typename ConstFixedBlockXpr::Type block(Index startRow /// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa block(Index,Index,NRowsType,NColsType), block(Index,Index,NRowsType,NColsType), class Block +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// template inline typename FixedBlockXpr::Type block(Index startRow, Index startCol, @@ -871,7 +1067,7 @@ inline const typename ConstFixedBlockXpr::Type block(Index startRow return typename ConstFixedBlockXpr::Type(derived(), startRow, startCol, blockRows, blockCols); } -/// \returns an expression of the \a i-th column of *this. Note that the numbering starts at 0. +/// \returns an expression of the \a i-th column of \c *this. Note that the numbering starts at 0. /// /// Example: \include MatrixBase_col.cpp /// Output: \verbinclude MatrixBase_col.out @@ -892,7 +1088,7 @@ inline ConstColXpr col(Index i) const return ConstColXpr(derived(), i); } -/// \returns an expression of the \a i-th row of *this. Note that the numbering starts at 0. +/// \returns an expression of the \a i-th row of \c *this. Note that the numbering starts at 0. /// /// Example: \include MatrixBase_row.cpp /// Output: \verbinclude MatrixBase_row.out @@ -913,96 +1109,153 @@ inline ConstRowXpr row(Index i) const return ConstRowXpr(derived(), i); } -/// \returns a dynamic-size expression of a segment (i.e. a vector block) in *this. +/// \returns an expression of a segment (i.e. a vector block) in \c *this with either dynamic or fixed sizes. /// /// \only_for_vectors /// /// \param start the first coefficient in the segment /// \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_segment_int_int.cpp /// Output: \verbinclude MatrixBase_segment_int_int.out /// -/// \note Even though the returned expression has dynamic size, in the case +/// 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. +/// +/// \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. /// -/// \sa class Block, segment(Index) +/// \sa block(Index,Index,NRowsType,NColsType), fix, fix(int), class Block /// EIGEN_DEVICE_FUNC -inline SegmentReturnType segment(Index start, Index n) +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename FixedSegmentReturnType::value>::Type +#else +inline typename FixedSegmentReturnType<...>::Type +#endif +segment(Index start, NType n) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return SegmentReturnType(derived(), start, n); + return typename FixedSegmentReturnType::value>::Type + (derived(), start, internal::get_runtime_value(n)); } -/// This is the const version of segment(Index,Index). +/// This is the const version of segment(Index,NType). EIGEN_DEVICE_FUNC -inline ConstSegmentReturnType segment(Index start, Index n) const +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline const typename ConstFixedSegmentReturnType::value>::Type +#else +inline const typename ConstFixedSegmentReturnType<...>::Type +#endif +segment(Index start, NType n) const { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return ConstSegmentReturnType(derived(), start, n); + return typename ConstFixedSegmentReturnType::value>::Type + (derived(), start, internal::get_runtime_value(n)); } -/// \returns a dynamic-size expression of the first coefficients of *this. +/// \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_start_int.cpp /// Output: \verbinclude MatrixBase_start_int.out /// -/// \note Even though the returned expression has dynamic size, in the case +/// 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. +/// +/// \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. /// /// \sa class Block, block(Index,Index) /// EIGEN_DEVICE_FUNC -inline SegmentReturnType head(Index n) +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename FixedSegmentReturnType::value>::Type +#else +inline typename FixedSegmentReturnType<...>::Type +#endif +head(NType n) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return SegmentReturnType(derived(), 0, n); + return typename FixedSegmentReturnType::value>::Type + (derived(), 0, internal::get_runtime_value(n)); } -/// This is the const version of head(Index). +/// This is the const version of head(NType). EIGEN_DEVICE_FUNC -inline ConstSegmentReturnType head(Index n) const +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline const typename ConstFixedSegmentReturnType::value>::Type +#else +inline const typename ConstFixedSegmentReturnType<...>::Type +#endif +head(NType n) const { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return ConstSegmentReturnType(derived(), 0, n); + return typename ConstFixedSegmentReturnType::value>::Type + (derived(), 0, internal::get_runtime_value(n)); } -/// \returns a dynamic-size expression of the last coefficients of *this. +/// \returns an expression of a last 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 /// -/// \note Even though the returned expression has dynamic size, in the case +/// 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. +/// +/// \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. /// /// \sa class Block, block(Index,Index) /// EIGEN_DEVICE_FUNC -inline SegmentReturnType tail(Index n) +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename FixedSegmentReturnType::value>::Type +#else +inline typename FixedSegmentReturnType<...>::Type +#endif +tail(NType n) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return SegmentReturnType(derived(), this->size() - n, n); + return typename FixedSegmentReturnType::value>::Type + (derived(), this->size() - internal::get_runtime_value(n), internal::get_runtime_value(n)); } /// This is the const version of tail(Index). EIGEN_DEVICE_FUNC -inline ConstSegmentReturnType tail(Index n) const +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline const typename ConstFixedSegmentReturnType::value>::Type +#else +inline const typename ConstFixedSegmentReturnType<...>::Type +#endif +tail(NType n) const { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return ConstSegmentReturnType(derived(), this->size() - n, n); + return typename ConstFixedSegmentReturnType::value>::Type + (derived(), this->size() - internal::get_runtime_value(n), internal::get_runtime_value(n)); } /// \returns a fixed-size expression of a segment (i.e. a vector block) in \c *this @@ -1019,7 +1272,7 @@ inline ConstSegmentReturnType tail(Index n) const /// Example: \include MatrixBase_template_int_segment.cpp /// Output: \verbinclude MatrixBase_template_int_segment.out /// -/// \sa class Block +/// \sa segment(Index,NType), class Block /// template EIGEN_DEVICE_FUNC @@ -1038,7 +1291,7 @@ inline typename ConstFixedSegmentReturnType::Type segment(Index start, Index return typename ConstFixedSegmentReturnType::Type(derived(), start, n); } -/// \returns a fixed-size expression of the first coefficients of *this. +/// \returns a fixed-size expression of the first coefficients of \c *this. /// /// \only_for_vectors /// @@ -1051,7 +1304,7 @@ inline typename ConstFixedSegmentReturnType::Type segment(Index start, Index /// Example: \include MatrixBase_template_int_start.cpp /// Output: \verbinclude MatrixBase_template_int_start.out /// -/// \sa class Block +/// \sa head(NType), class Block /// template EIGEN_DEVICE_FUNC @@ -1070,7 +1323,7 @@ inline typename ConstFixedSegmentReturnType::Type head(Index n = N) const return typename ConstFixedSegmentReturnType::Type(derived(), 0, n); } -/// \returns a fixed-size expression of the last coefficients of *this. +/// \returns a fixed-size expression of the last coefficients of \c *this. /// /// \only_for_vectors /// @@ -1083,7 +1336,7 @@ inline typename ConstFixedSegmentReturnType::Type head(Index n = N) const /// Example: \include MatrixBase_template_int_end.cpp /// Output: \verbinclude MatrixBase_template_int_end.out /// -/// \sa class Block +/// \sa tail(NType), class Block /// template EIGEN_DEVICE_FUNC diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index 3ea8e7c00..47c454976 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -280,9 +280,9 @@ void check_indexed_view() // check mat(i,j) with weird types for i and j { VERIFY_IS_APPROX( A(B.RowsAtCompileTime-1, 1), A(3,1) ); - VERIFY_IS_APPROX( A(B.RowsAtCompileTime, 1), A(3,1) ); + VERIFY_IS_APPROX( A(B.RowsAtCompileTime, 1), A(4,1) ); VERIFY_IS_APPROX( A(B.RowsAtCompileTime-1, B.ColsAtCompileTime-1), A(3,3) ); - VERIFY_IS_APPROX( A(B.RowsAtCompileTime, B.ColsAtCompileTime), A(3,3) ); + VERIFY_IS_APPROX( A(B.RowsAtCompileTime, B.ColsAtCompileTime), A(4,4) ); enum { I = 3, J = 4 }; VERIFY_IS_APPROX( A(I,J), A(3,4) ); } @@ -295,8 +295,38 @@ void check_indexed_view() VERIFY( is_same_eq( A.block(1,1,3,4), A.block(1,1,fix(3),fix<4>)) ); VERIFY( is_same_eq( A.block(1,1,3,4), A.block(1,1,fix(3),fix(4))) ); + VERIFY( is_same_eq( A.topLeftCorner<3,4>(), A.topLeftCorner(fix<3>,fix<4>)) ); + VERIFY( is_same_eq( A.bottomLeftCorner<3,4>(), A.bottomLeftCorner(fix<3>,fix<4>)) ); + VERIFY( is_same_eq( A.bottomRightCorner<3,4>(), A.bottomRightCorner(fix<3>,fix<4>)) ); + VERIFY( is_same_eq( A.topRightCorner<3,4>(), A.topRightCorner(fix<3>,fix<4>)) ); + + VERIFY( is_same_eq( A.leftCols<3>(), A.leftCols(fix<3>)) ); + VERIFY( is_same_eq( A.rightCols<3>(), A.rightCols(fix<3>)) ); + VERIFY( is_same_eq( A.middleCols<3>(1), A.middleCols(1,fix<3>)) ); + + VERIFY( is_same_eq( A.topRows<3>(), A.topRows(fix<3>)) ); + VERIFY( is_same_eq( A.bottomRows<3>(), A.bottomRows(fix<3>)) ); + VERIFY( is_same_eq( A.middleRows<3>(1), A.middleRows(1,fix<3>)) ); + + VERIFY( is_same_eq( a.segment<3>(1), a.segment(1,fix<3>)) ); + VERIFY( is_same_eq( a.head<3>(), a.head(fix<3>)) ); + VERIFY( is_same_eq( a.tail<3>(), a.tail(fix<3>)) ); + const ArrayXXi& cA(A); VERIFY( is_same_eq( cA.block(1,1,3,4), cA.block(1,1,fix(3),fix<4>)) ); + + VERIFY( is_same_eq( cA.topLeftCorner<3,4>(), cA.topLeftCorner(fix<3>,fix<4>)) ); + VERIFY( is_same_eq( cA.bottomLeftCorner<3,4>(), cA.bottomLeftCorner(fix<3>,fix<4>)) ); + VERIFY( is_same_eq( cA.bottomRightCorner<3,4>(), cA.bottomRightCorner(fix<3>,fix<4>)) ); + VERIFY( is_same_eq( cA.topRightCorner<3,4>(), cA.topRightCorner(fix<3>,fix<4>)) ); + + VERIFY( is_same_eq( cA.leftCols<3>(), cA.leftCols(fix<3>)) ); + VERIFY( is_same_eq( cA.rightCols<3>(), cA.rightCols(fix<3>)) ); + VERIFY( is_same_eq( cA.middleCols<3>(1), cA.middleCols(1,fix<3>)) ); + + VERIFY( is_same_eq( cA.topRows<3>(), cA.topRows(fix<3>)) ); + VERIFY( is_same_eq( cA.bottomRows<3>(), cA.bottomRows(fix<3>)) ); + VERIFY( is_same_eq( cA.middleRows<3>(1), cA.middleRows(1,fix<3>)) ); } } From e4f8dd860afb5405031c3dc14576983557b199d6 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 18 Jan 2017 10:49:01 +0100 Subject: [PATCH 48/65] Add missing operator* --- Eigen/src/Core/util/SymbolicIndex.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Core/util/SymbolicIndex.h b/Eigen/src/Core/util/SymbolicIndex.h index 6f603f301..beb9d4c13 100644 --- a/Eigen/src/Core/util/SymbolicIndex.h +++ b/Eigen/src/Core/util/SymbolicIndex.h @@ -87,6 +87,8 @@ public: { return AddExpr(derived(), b); } AddExpr operator-(Index a) const { return AddExpr(derived(), -a); } + ProductExpr operator*(Index a) const + { return ProductExpr(derived(),a); } QuotientExpr operator/(Index a) const { return QuotientExpr(derived(),a); } @@ -94,8 +96,10 @@ public: { return AddExpr(b.derived(), a); } friend AddExpr,ValueExpr> operator-(Index a, const BaseExpr& b) { return AddExpr,ValueExpr>(-b.derived(), a); } - friend AddExpr operator/(Index a, const BaseExpr& b) - { return AddExpr(a,b.derived()); } + friend ProductExpr operator*(Index a, const BaseExpr& b) + { return ProductExpr(a,b.derived()); } + friend QuotientExpr operator/(Index a, const BaseExpr& b) + { return QuotientExpr(a,b.derived()); } template AddExpr operator+(const BaseExpr &b) const @@ -105,6 +109,10 @@ public: AddExpr > operator-(const BaseExpr &b) const { return AddExpr >(derived(), -b.derived()); } + template + ProductExpr operator*(const BaseExpr &b) const + { return ProductExpr(derived(), b.derived()); } + template QuotientExpr operator/(const BaseExpr &b) const { return QuotientExpr(derived(), b.derived()); } From 15471432fe809f47e1d4986e9d81547a949e3e07 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 18 Jan 2017 11:35:27 +0100 Subject: [PATCH 49/65] Add a .reverse() member to ArithmeticSequence. --- Eigen/src/Core/ArithmeticSequence.h | 88 ++++++++++++++++++++++---- Eigen/src/Core/util/IntegralConstant.h | 2 + test/indexed_view.cpp | 22 ++++++- 3 files changed, 98 insertions(+), 14 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 2ad4c0906..0f9c72e2e 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -12,10 +12,69 @@ namespace Eigen { +namespace internal { + +#if !EIGEN_HAS_CXX11 +template struct aseq_negate {}; + +template<> struct aseq_negate { + typedef Index type; +}; + +template struct aseq_negate > { + typedef fix_t<-N> type; +}; + +// Compilation error in the following case: +template<> struct aseq_negate > {}; + +template::value, + bool SizeIsSymbolic =Symbolic::is_symbolic::value> +struct aseq_reverse_first_type { + typedef Index type; +}; + +template +struct aseq_reverse_first_type { + typedef Symbolic::AddExpr, + Symbolic::ValueExpr> + > type; +}; + +template +struct aseq_reverse_first_type { + typedef Symbolic::AddExpr type; +}; + +template +struct aseq_reverse_first_type { + typedef Symbolic::AddExpr,Symbolic::ValueExpr>, + Symbolic::ValueExpr> type; +}; +#endif + +// Helper to cleanup the type of the increment: +template struct cleanup_seq_incr { + typedef typename cleanup_index_type::type type; +}; + +} + //-------------------------------------------------------------------------------- // seq(first,last,incr) and seqN(first,size,incr) //-------------------------------------------------------------------------------- +template > +class ArithmeticSequence; + +template +ArithmeticSequence::type, + typename internal::cleanup_index_type::type, + typename internal::cleanup_seq_incr::type > +seqN(FirstType first, SizeType size, IncrType incr); + /** \class ArithmeticSequence * \ingroup Core_Module * @@ -35,10 +94,9 @@ namespace Eigen { * * \sa Eigen::seq, Eigen::seqN, DenseBase::operator()(const RowIndices&, const ColIndices&), class IndexedView */ -template > +template class ArithmeticSequence { - public: ArithmeticSequence(FirstType first, SizeType size) : m_first(first), m_size(size) {} ArithmeticSequence(FirstType first, SizeType size, IncrType incr) : m_first(first), m_size(size), m_incr(incr) {} @@ -65,17 +123,25 @@ protected: FirstType m_first; SizeType m_size; IncrType m_incr; + +public: + +#if EIGEN_HAS_CXX11 + auto reverse() const -> decltype(Eigen::seqN(m_first+(m_size-1)*Index(m_incr),m_size,-m_incr)) { + return seqN(m_first+(m_size-1)*Index(m_incr),m_size,-m_incr); + } +#else +protected: + typedef typename internal::aseq_negate::type ReverseIncrType; + typedef typename internal::aseq_reverse_first_type::type ReverseFirstType; +public: + ArithmeticSequence + reverse() const { + return seqN(m_first+(m_size-1)*Index(m_incr),m_size,-m_incr); + } +#endif }; -namespace internal { - -// Helper to cleanup the type of the increment: -template struct cleanup_seq_incr { - typedef typename cleanup_index_type::type type; -}; - -} - /** \returns an ArithmeticSequence starting at \a first, of length \a size, and increment \a incr * * \sa seqN(FirstType,SizeType), seq(FirstType,LastType,IncrType) */ diff --git a/Eigen/src/Core/util/IntegralConstant.h b/Eigen/src/Core/util/IntegralConstant.h index 2402baeec..354aa8c4c 100644 --- a/Eigen/src/Core/util/IntegralConstant.h +++ b/Eigen/src/Core/util/IntegralConstant.h @@ -27,6 +27,8 @@ template struct fix_t { eigen_internal_assert(int(other)==N); } + fix_t<-N> operator-() const { return fix_t<-N>(); } + #if EIGEN_HAS_CXX14 // Needed in C++14 to allow fix(): fix_t operator() () const { return *this; } diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index 47c454976..f8b3838a4 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -58,7 +58,13 @@ template typename internal::enable_if::value,bool>::type is_same_seq_type(const T1& a, const T2& b) { - return a.size() == b.size() && a.first()==b.first() && Index(a.incrObject())==Index(b.incrObject()); + bool ok = a.first()==b.first() && a.size() == b.size() && Index(a.incrObject())==Index(b.incrObject());; + if(!ok) + { + std::cerr << "seqN(" << a.first() << ", " << a.size() << ", " << Index(a.incrObject()) << ") != "; + std::cerr << "seqN(" << b.first() << ", " << b.size() << ", " << Index(b.incrObject()) << ")\n"; + } + return ok; } #define VERIFY_EQ_INT(A,B) VERIFY_IS_APPROX(int(A),int(B)) @@ -187,7 +193,6 @@ void check_indexed_view() VERIFY( is_same_seq_type( seqN(2,fix(5),3), seqN(2,5,fix(3)) ) ); VERIFY( is_same_seq_type( seqN(2,fix<5>(5),fix<-2>), seqN(2,fix<5>,fix<-2>()) ) ); - VERIFY( (A(seqN(2,fix<5>), 5)).RowsAtCompileTime == 5); VERIFY( (A(4, all)).ColsAtCompileTime == Dynamic); VERIFY( (A(4, all)).RowsAtCompileTime == 1); @@ -201,6 +206,8 @@ void check_indexed_view() VERIFY_EQ_INT( (A(eii, eii)).InnerStrideAtCompileTime, 0); VERIFY_EQ_INT( (A(eii, eii)).OuterStrideAtCompileTime, 0); + VERIFY_IS_APPROX( A(seq(n-1,2,-2), seqN(n-1-6,3,-1)), A(seq(last,2,fix<-2>), seqN(last-6,3,fix<-1>)) ); + VERIFY_IS_APPROX( A(seq(n-1,2,-2), seqN(n-1-6,4)), A(seq(last,2,-2), seqN(last-6,4)) ); VERIFY_IS_APPROX( A(seq(n-1-6,n-1-2), seqN(n-1-6,4)), A(seq(last-6,last-2), seqN(6+last-6-6,4)) ); VERIFY_IS_APPROX( A(seq((n-1)/2,(n)/2+3), seqN(2,4)), A(seq(last/2,(last+1)/2+3), seqN(last+2-last,4)) ); @@ -218,7 +225,6 @@ void check_indexed_view() 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_eq(A.col(0), A(all,0)) ); @@ -251,6 +257,16 @@ void check_indexed_view() A1(seq(6,3,-1),range25) = A2; VERIFY_IS_APPROX( A1.block(3,2,4,4), A2 ); + // check reverse + { + VERIFY( is_same_seq_type( seq(3,7).reverse(), seqN(7,5,fix<-1>) ) ); + VERIFY( is_same_seq_type( seq(7,3,fix<-2>).reverse(), seqN(3,3,fix<2>) ) ); + VERIFY_IS_APPROX( a(seqN(2,last/2).reverse()), a(seqN(2+(last/2-1)*1,last/2,fix<-1>)) ); + VERIFY_IS_APPROX( a(seqN(last/2,fix<4>).reverse()),a(seqN(last/2,fix<4>)).reverse() ); + VERIFY_IS_APPROX( A(seq(last-5,last-1,2).reverse(), seqN(last-3,3,fix<-2>).reverse()), + A(seq(last-5,last-1,2), seqN(last-3,3,fix<-2>)).reverse() ); + } + #if EIGEN_HAS_CXX11 VERIFY( (A(all, std::array{{1,3,2,4}})).ColsAtCompileTime == 4); From f3ccbe0419cd86feb1c5f5ec624e65a8e770859a Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 18 Jan 2017 23:16:32 +0100 Subject: [PATCH 50/65] Add a Symbolic::FixedExpr helper expression to make sure the compiler fully optimize the usage of last and end. --- Eigen/src/Core/ArithmeticSequence.h | 1 + Eigen/src/Core/util/IndexedViewHelper.h | 4 +++- Eigen/src/Core/util/SymbolicIndex.h | 11 +++++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 0f9c72e2e..5ab044442 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -378,6 +378,7 @@ public: Index size() const { return (m_last-m_first+m_incr)/m_incr; } Index operator[](Index i) const { return m_first + i * m_incr; } + Index first() const { return m_first; } const FirstType& firstObject() const { return m_first; } const LastType& lastObject() const { return m_last; } diff --git a/Eigen/src/Core/util/IndexedViewHelper.h b/Eigen/src/Core/util/IndexedViewHelper.h index b4f7c0dd7..a8259bb2c 100644 --- a/Eigen/src/Core/util/IndexedViewHelper.h +++ b/Eigen/src/Core/util/IndexedViewHelper.h @@ -58,7 +58,9 @@ static const Symbolic::SymbolExpr last; #ifdef EIGEN_PARSED_BY_DOXYGEN static const auto end = last+1; #else -static const Symbolic::AddExpr,Symbolic::ValueExpr> end(last+1); +// Using a FixedExpr<1> expression is important here to make sure the compiler +// can fully optimize the computation starting indices with zero overhead. +static const Symbolic::AddExpr,Symbolic::FixedExpr<1> > end(last+Symbolic::FixedExpr<1>()); #endif } // end namespace placeholders diff --git a/Eigen/src/Core/util/SymbolicIndex.h b/Eigen/src/Core/util/SymbolicIndex.h index beb9d4c13..cee5d908a 100644 --- a/Eigen/src/Core/util/SymbolicIndex.h +++ b/Eigen/src/Core/util/SymbolicIndex.h @@ -124,6 +124,17 @@ struct is_symbolic { enum { value = internal::is_convertible >::value }; }; +// Simple wrapper around a compile-time value, +// It is similar to ValueExpr(N) but this version helps the compiler to generate better code. +template +class FixedExpr : public BaseExpr > { +public: + FixedExpr() {} + template + Index eval_impl(const T&) const { return N; } +}; + + /** Represents the actual value of a symbol identified by its tag * * It is the return type of SymbolValue::operator=, and most of the time this is only way it is used. From e84ed7b6ef09653fb8e042c5f3fda386de1b192e Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 18 Jan 2017 23:18:28 +0100 Subject: [PATCH 51/65] Remove dead code --- Eigen/src/Core/ArithmeticSequence.h | 114 ---------------------------- test/indexed_view.cpp | 4 - 2 files changed, 118 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 5ab044442..b84930a19 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -318,120 +318,6 @@ struct get_compile_time_incr > { } // end namespace internal -//-------------------------------------------------------------------------------- - -namespace legacy { -// Here are some initial code that I keep here for now to compare the quality of the code generated by the compilers -// This part will be removed once we have checked everything is right. - -struct shifted_last { - explicit shifted_last(int o) : offset(o) {} - int offset; - shifted_last operator+ (int x) const { return shifted_last(offset+x); } - shifted_last operator- (int x) const { return shifted_last(offset-x); } - int operator- (shifted_last x) const { return offset-x.offset; } -}; - -struct last_t { - last_t() {} - shifted_last operator- (int offset) const { return shifted_last(-offset); } - shifted_last operator+ (int offset) const { return shifted_last(+offset); } - int operator- (last_t) const { return 0; } - int operator- (shifted_last x) const { return -x.offset; } -}; -static const last_t last; - - -struct shifted_end { - explicit shifted_end(int o) : offset(o) {} - int offset; - shifted_end operator+ (int x) const { return shifted_end(offset+x); } - shifted_end operator- (int x) const { return shifted_end(offset-x); } - int operator- (shifted_end x) const { return offset-x.offset; } -}; - -struct end_t { - end_t() {} - shifted_end operator- (int offset) const { return shifted_end (-offset); } - shifted_end operator+ (int offset) const { return shifted_end ( offset); } - int operator- (end_t) const { return 0; } - int operator- (shifted_end x) const { return -x.offset; } -}; -static const end_t end; - -inline Index eval_expr_given_size(last_t, Index size) { return size-1; } -inline Index eval_expr_given_size(shifted_last x, Index size) { return size+x.offset-1; } -inline Index eval_expr_given_size(end_t, Index size) { return size; } -inline Index eval_expr_given_size(shifted_end x, Index size) { return size+x.offset; } - -template > -class ArithmeticSequenceProxyWithBounds -{ -public: - ArithmeticSequenceProxyWithBounds(FirstType f, LastType l) : m_first(f), m_last(l) {} - ArithmeticSequenceProxyWithBounds(FirstType f, LastType l, IncrType s) : m_first(f), m_last(l), m_incr(s) {} - - enum { - SizeAtCompileTime = -1, - IncrAtCompileTime = internal::get_fixed_value::value - }; - - Index size() const { return (m_last-m_first+m_incr)/m_incr; } - Index operator[](Index i) const { return m_first + i * m_incr; } - Index first() const { return m_first; } - - const FirstType& firstObject() const { return m_first; } - const LastType& lastObject() const { return m_last; } - const IncrType& incrObject() const { return m_incr; } - -protected: - FirstType m_first; - LastType m_last; - IncrType m_incr; -}; - -template -ArithmeticSequenceProxyWithBounds::type,typename internal::cleanup_index_type::type > -seq(FirstType f, LastType l) { - return ArithmeticSequenceProxyWithBounds::type,typename internal::cleanup_index_type::type>(f,l); -} - -template -ArithmeticSequenceProxyWithBounds< typename internal::cleanup_index_type::type, - typename internal::cleanup_index_type::type, - typename internal::cleanup_seq_incr::type > -seq(FirstType f, LastType l, IncrType s) -{ - return ArithmeticSequenceProxyWithBounds::type, - typename internal::cleanup_index_type::type, - typename internal::cleanup_seq_incr::type> - (f,l,typename internal::cleanup_seq_incr::type(s)); -} - -} - -namespace internal { - -template -struct get_compile_time_incr > { - enum { value = get_fixed_value::value }; -}; - -// Convert a symbolic range into a usable one (i.e., remove last/end "keywords") -template -struct IndexedViewCompatibleType,XprSize> { - typedef legacy::ArithmeticSequenceProxyWithBounds type; -}; - -template -legacy::ArithmeticSequenceProxyWithBounds -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()); -} - -} - } // end namespace Eigen #endif // EIGEN_ARITHMETIC_SEQUENCE_H diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index f8b3838a4..751f98344 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -289,10 +289,6 @@ void check_indexed_view() #endif - // check legacy code - VERIFY_IS_APPROX( A(legacy::seq(legacy::last,2,-2), legacy::seq(legacy::last-6,7)), A(seq(last,2,-2), seq(last-6,7)) ); - VERIFY_IS_APPROX( A(seqN(legacy::last,2,-2), seqN(legacy::last-6,3)), A(seqN(last,2,-2), seqN(last-6,3)) ); - // check mat(i,j) with weird types for i and j { VERIFY_IS_APPROX( A(B.RowsAtCompileTime-1, 1), A(3,1) ); From 7691723e3486196576c183045e50892b5d734170 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 19 Jan 2017 19:25:29 +0100 Subject: [PATCH 52/65] Add support for fixed-value in symbolic expression, c++11 only for now. --- Eigen/Core | 2 +- Eigen/src/Core/util/IndexedViewHelper.h | 2 +- Eigen/src/Core/util/SymbolicIndex.h | 50 +++++++++++++++++++------ 3 files changed, 41 insertions(+), 13 deletions(-) diff --git a/Eigen/Core b/Eigen/Core index 2ce2dd6b2..b9149659a 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -354,8 +354,8 @@ 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/SymbolicIndex.h" #include "src/Core/util/IntegralConstant.h" +#include "src/Core/util/SymbolicIndex.h" #include "src/Core/NumTraits.h" diff --git a/Eigen/src/Core/util/IndexedViewHelper.h b/Eigen/src/Core/util/IndexedViewHelper.h index a8259bb2c..5dca1926c 100644 --- a/Eigen/src/Core/util/IndexedViewHelper.h +++ b/Eigen/src/Core/util/IndexedViewHelper.h @@ -60,7 +60,7 @@ static const auto end = last+1; #else // Using a FixedExpr<1> expression is important here to make sure the compiler // can fully optimize the computation starting indices with zero overhead. -static const Symbolic::AddExpr,Symbolic::FixedExpr<1> > end(last+Symbolic::FixedExpr<1>()); +static const Symbolic::AddExpr,Symbolic::FixedExpr<1> > end(last+fix<1>()); #endif } // end namespace placeholders diff --git a/Eigen/src/Core/util/SymbolicIndex.h b/Eigen/src/Core/util/SymbolicIndex.h index cee5d908a..fcc5921e6 100644 --- a/Eigen/src/Core/util/SymbolicIndex.h +++ b/Eigen/src/Core/util/SymbolicIndex.h @@ -57,6 +57,17 @@ protected: Index m_value; }; +// Simple wrapper around a compile-time value, +// It is similar to ValueExpr(N) but this version helps the compiler to generate better code. +template +class FixedExpr { +public: + FixedExpr() {} + template + Index eval_impl(const T&) const { return N; } +}; + + /** \class BaseExpr * \ingroup Core_Module * Common base class of any symbolic expressions @@ -101,6 +112,34 @@ public: friend QuotientExpr operator/(Index a, const BaseExpr& b) { return QuotientExpr(a,b.derived()); } + + template + AddExpr > operator+(internal::fix_t) const + { return AddExpr >(derived(), FixedExpr()); } + template + AddExpr > operator-(internal::fix_t) const + { return AddExpr >(derived(), FixedExpr<-N>()); } + template + ProductExpr > operator*(internal::fix_t) const + { return ProductExpr >(derived(),FixedExpr()); } + template + QuotientExpr > operator/(internal::fix_t) const + { return QuotientExpr >(derived(),FixedExpr()); } + + template + friend AddExpr > operator+(internal::fix_t, const BaseExpr& b) + { return AddExpr >(b.derived(), FixedExpr()); } + template + friend AddExpr,FixedExpr > operator-(internal::fix_t, const BaseExpr& b) + { return AddExpr,FixedExpr >(-b.derived(), FixedExpr()); } + template + friend ProductExpr,Derived> operator*(internal::fix_t, const BaseExpr& b) + { return ProductExpr,Derived>(FixedExpr(),b.derived()); } + template + friend QuotientExpr,Derived> operator/(internal::fix_t, const BaseExpr& b) + { return QuotientExpr ,Derived>(FixedExpr(),b.derived()); } + + template AddExpr operator+(const BaseExpr &b) const { return AddExpr(derived(), b.derived()); } @@ -124,17 +163,6 @@ struct is_symbolic { enum { value = internal::is_convertible >::value }; }; -// Simple wrapper around a compile-time value, -// It is similar to ValueExpr(N) but this version helps the compiler to generate better code. -template -class FixedExpr : public BaseExpr > { -public: - FixedExpr() {} - template - Index eval_impl(const T&) const { return N; } -}; - - /** Represents the actual value of a symbol identified by its tag * * It is the return type of SymbolValue::operator=, and most of the time this is only way it is used. From 54f3fbee246744d2cb3aeeb9c52ee32a159b29c5 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 19 Jan 2017 19:57:32 +0100 Subject: [PATCH 53/65] Exploit fixed values in seq and reverse with C++98 compatibility --- Eigen/src/Core/ArithmeticSequence.h | 67 +++++++++++---------- Eigen/src/Core/util/IndexedViewHelper.h | 2 +- Eigen/src/Core/util/SymbolicIndex.h | 80 ++++++++++++------------- 3 files changed, 76 insertions(+), 73 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index b84930a19..1f3a9e583 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -28,30 +28,31 @@ template struct aseq_negate > { // Compilation error in the following case: template<> struct aseq_negate > {}; -template::value, bool SizeIsSymbolic =Symbolic::is_symbolic::value> struct aseq_reverse_first_type { typedef Index type; }; -template -struct aseq_reverse_first_type { +template +struct aseq_reverse_first_type { typedef Symbolic::AddExpr, - Symbolic::ValueExpr> + Symbolic::ProductExpr > >, + Symbolic::ValueExpr > > type; }; -template -struct aseq_reverse_first_type { - typedef Symbolic::AddExpr type; +template +struct aseq_reverse_first_type { + typedef Symbolic::AddExpr > type; }; -template -struct aseq_reverse_first_type { - typedef Symbolic::AddExpr,Symbolic::ValueExpr>, - Symbolic::ValueExpr> type; +template +struct aseq_reverse_first_type { + typedef Symbolic::AddExpr > >, + Symbolic::ValueExpr >, + Symbolic::ValueExpr<> > type; }; #endif @@ -127,17 +128,17 @@ protected: public: #if EIGEN_HAS_CXX11 - auto reverse() const -> decltype(Eigen::seqN(m_first+(m_size-1)*Index(m_incr),m_size,-m_incr)) { - return seqN(m_first+(m_size-1)*Index(m_incr),m_size,-m_incr); + auto reverse() const -> decltype(Eigen::seqN(m_first+(m_size+fix<-1>())*m_incr,m_size,-m_incr)) { + return seqN(m_first+(m_size+fix<-1>())*m_incr,m_size,-m_incr); } #else protected: typedef typename internal::aseq_negate::type ReverseIncrType; - typedef typename internal::aseq_reverse_first_type::type ReverseFirstType; + typedef typename internal::aseq_reverse_first_type::type ReverseFirstType; public: ArithmeticSequence reverse() const { - return seqN(m_first+(m_size-1)*Index(m_incr),m_size,-m_incr); + return seqN(m_first+(m_size+fix<-1>())*m_incr,m_size,-m_incr); } #endif }; @@ -204,38 +205,40 @@ auto seq(FirstType f, LastType l, IncrType incr) return seqN(f,(l-f+CleanedIncrType(incr))/CleanedIncrType(incr),CleanedIncrType(incr)); } #else + template typename internal::enable_if::value || Symbolic::is_symbolic::value), ArithmeticSequence::type,Index> >::type seq(FirstType f, LastType l) { - return seqN(f,(l-f+1)); + return seqN(f,(l-f+fix<1>())); } template typename internal::enable_if::value, - ArithmeticSequence,Symbolic::ValueExpr>, - Symbolic::ValueExpr> > >::type + ArithmeticSequence,Symbolic::ValueExpr<> >, + Symbolic::ValueExpr > > > >::type seq(const Symbolic::BaseExpr &f, LastType l) { - return seqN(f.derived(),(l-f.derived()+1)); + return seqN(f.derived(),(l-f.derived()+fix<1>())); } template typename internal::enable_if::value, ArithmeticSequence::type, - Symbolic::AddExpr,Symbolic::ValueExpr> > >::type + Symbolic::AddExpr >, + Symbolic::ValueExpr > > > >::type seq(FirstType f, const Symbolic::BaseExpr &l) { - return seqN(f,(l.derived()-f+1)); + return seqN(f,(l.derived()-f+fix<1>())); } template ArithmeticSequence >,Symbolic::ValueExpr> > + Symbolic::AddExpr >,Symbolic::ValueExpr > > > seq(const Symbolic::BaseExpr &f, const Symbolic::BaseExpr &l) { - return seqN(f.derived(),(l.derived()-f.derived()+1)); + return seqN(f.derived(),(l.derived()-f.derived()+fix<1>())); } @@ -252,9 +255,9 @@ template typename internal::enable_if::value, ArithmeticSequence, - Symbolic::ValueExpr>, - Symbolic::ValueExpr>, - Symbolic::ValueExpr>, + Symbolic::ValueExpr<> >, + Symbolic::ValueExpr::type> >, + Symbolic::ValueExpr::type> >, typename internal::cleanup_seq_incr::type> >::type seq(const Symbolic::BaseExpr &f, LastType l, IncrType incr) { @@ -265,9 +268,9 @@ seq(const Symbolic::BaseExpr &f, LastType l, IncrType incr) template typename internal::enable_if::value, ArithmeticSequence::type, - Symbolic::QuotientExpr, - Symbolic::ValueExpr>, - Symbolic::ValueExpr>, + Symbolic::QuotientExpr >, + Symbolic::ValueExpr::type> >, + Symbolic::ValueExpr::type> >, typename internal::cleanup_seq_incr::type> >::type seq(FirstType f, const Symbolic::BaseExpr &l, IncrType incr) { @@ -279,8 +282,8 @@ template ArithmeticSequence >, - Symbolic::ValueExpr>, - Symbolic::ValueExpr>, + Symbolic::ValueExpr::type> >, + Symbolic::ValueExpr::type> >, typename internal::cleanup_seq_incr::type> seq(const Symbolic::BaseExpr &f, const Symbolic::BaseExpr &l, IncrType incr) { diff --git a/Eigen/src/Core/util/IndexedViewHelper.h b/Eigen/src/Core/util/IndexedViewHelper.h index 5dca1926c..1171b2b2e 100644 --- a/Eigen/src/Core/util/IndexedViewHelper.h +++ b/Eigen/src/Core/util/IndexedViewHelper.h @@ -60,7 +60,7 @@ static const auto end = last+1; #else // Using a FixedExpr<1> expression is important here to make sure the compiler // can fully optimize the computation starting indices with zero overhead. -static const Symbolic::AddExpr,Symbolic::FixedExpr<1> > end(last+fix<1>()); +static const Symbolic::AddExpr,Symbolic::ValueExpr > > end(last+fix<1>()); #endif } // end namespace placeholders diff --git a/Eigen/src/Core/util/SymbolicIndex.h b/Eigen/src/Core/util/SymbolicIndex.h index fcc5921e6..5e9465db8 100644 --- a/Eigen/src/Core/util/SymbolicIndex.h +++ b/Eigen/src/Core/util/SymbolicIndex.h @@ -46,23 +46,24 @@ template class AddExpr; template class ProductExpr; template class QuotientExpr; -// A simple wrapper around an Index to provide the eval method. +// A simple wrapper around an integral value to provide the eval method. // We could also use a free-function symbolic_eval... +template class ValueExpr { public: - ValueExpr(Index val) : m_value(val) {} + ValueExpr(IndexType val) : m_value(val) {} template - Index eval_impl(const T&) const { return m_value; } + IndexType eval_impl(const T&) const { return m_value; } protected: - Index m_value; + IndexType m_value; }; -// Simple wrapper around a compile-time value, +// Specialization for compile-time value, // It is similar to ValueExpr(N) but this version helps the compiler to generate better code. template -class FixedExpr { +class ValueExpr > { public: - FixedExpr() {} + ValueExpr() {} template Index eval_impl(const T&) const { return N; } }; @@ -94,50 +95,49 @@ public: NegateExpr operator-() const { return NegateExpr(derived()); } - AddExpr operator+(Index b) const - { return AddExpr(derived(), b); } - AddExpr operator-(Index a) const - { return AddExpr(derived(), -a); } - ProductExpr operator*(Index a) const - { return ProductExpr(derived(),a); } - QuotientExpr operator/(Index a) const - { return QuotientExpr(derived(),a); } - - friend AddExpr operator+(Index a, const BaseExpr& b) - { return AddExpr(b.derived(), a); } - friend AddExpr,ValueExpr> operator-(Index a, const BaseExpr& b) - { return AddExpr,ValueExpr>(-b.derived(), a); } - friend ProductExpr operator*(Index a, const BaseExpr& b) - { return ProductExpr(a,b.derived()); } - friend QuotientExpr operator/(Index a, const BaseExpr& b) - { return QuotientExpr(a,b.derived()); } + AddExpr > operator+(Index b) const + { return AddExpr >(derived(), b); } + AddExpr > operator-(Index a) const + { return AddExpr >(derived(), -a); } + ProductExpr > operator*(Index a) const + { return ProductExpr >(derived(),a); } + QuotientExpr > operator/(Index a) const + { return QuotientExpr >(derived(),a); } + friend AddExpr > operator+(Index a, const BaseExpr& b) + { return AddExpr >(b.derived(), a); } + friend AddExpr,ValueExpr<> > operator-(Index a, const BaseExpr& b) + { return AddExpr,ValueExpr<> >(-b.derived(), a); } + friend ProductExpr,Derived> operator*(Index a, const BaseExpr& b) + { return ProductExpr,Derived>(a,b.derived()); } + friend QuotientExpr,Derived> operator/(Index a, const BaseExpr& b) + { return QuotientExpr,Derived>(a,b.derived()); } template - AddExpr > operator+(internal::fix_t) const - { return AddExpr >(derived(), FixedExpr()); } + AddExpr > > operator+(internal::fix_t) const + { return AddExpr > >(derived(), ValueExpr >()); } template - AddExpr > operator-(internal::fix_t) const - { return AddExpr >(derived(), FixedExpr<-N>()); } + AddExpr > > operator-(internal::fix_t) const + { return AddExpr > >(derived(), ValueExpr >()); } template - ProductExpr > operator*(internal::fix_t) const - { return ProductExpr >(derived(),FixedExpr()); } + ProductExpr > > operator*(internal::fix_t) const + { return ProductExpr > >(derived(),ValueExpr >()); } template - QuotientExpr > operator/(internal::fix_t) const - { return QuotientExpr >(derived(),FixedExpr()); } + QuotientExpr > > operator/(internal::fix_t) const + { return QuotientExpr > >(derived(),ValueExpr >()); } template - friend AddExpr > operator+(internal::fix_t, const BaseExpr& b) - { return AddExpr >(b.derived(), FixedExpr()); } + friend AddExpr > > operator+(internal::fix_t, const BaseExpr& b) + { return AddExpr > >(b.derived(), ValueExpr >()); } template - friend AddExpr,FixedExpr > operator-(internal::fix_t, const BaseExpr& b) - { return AddExpr,FixedExpr >(-b.derived(), FixedExpr()); } + friend AddExpr,ValueExpr > > operator-(internal::fix_t, const BaseExpr& b) + { return AddExpr,ValueExpr > >(-b.derived(), ValueExpr >()); } template - friend ProductExpr,Derived> operator*(internal::fix_t, const BaseExpr& b) - { return ProductExpr,Derived>(FixedExpr(),b.derived()); } + friend ProductExpr >,Derived> operator*(internal::fix_t, const BaseExpr& b) + { return ProductExpr >,Derived>(ValueExpr >(),b.derived()); } template - friend QuotientExpr,Derived> operator/(internal::fix_t, const BaseExpr& b) - { return QuotientExpr ,Derived>(FixedExpr(),b.derived()); } + friend QuotientExpr >,Derived> operator/(internal::fix_t, const BaseExpr& b) + { return QuotientExpr > ,Derived>(ValueExpr >(),b.derived()); } template From 4d302a080c775290acf23935f233cebbe19540f4 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 19 Jan 2017 20:34:18 +0100 Subject: [PATCH 54/65] Recover compile-time size from seq(A,B) when A and B are fixed values. (c++11 only) --- Eigen/src/Core/ArithmeticSequence.h | 27 ++++++++++++++++---------- Eigen/src/Core/util/IntegralConstant.h | 4 ++++ Eigen/src/Core/util/SymbolicIndex.h | 7 +++++++ test/indexed_view.cpp | 20 +++++++++++++++++-- 4 files changed, 46 insertions(+), 12 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 1f3a9e583..646eb5770 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -191,18 +191,22 @@ auto seq(FirstType f, LastType l); #if EIGEN_HAS_CXX11 template -auto seq(FirstType f, LastType l) -> decltype(seqN(f,(l-f+fix<1>()))) +auto seq(FirstType f, LastType l) -> decltype(seqN(f,( typename internal::cleanup_index_type::type(l) + - typename internal::cleanup_index_type::type(f)+fix<1>()))) { - return seqN(f,(l-f+fix<1>())); + return seqN(f,(typename internal::cleanup_index_type::type(l) + -typename internal::cleanup_index_type::type(f)+fix<1>())); } template auto seq(FirstType f, LastType l, IncrType incr) - -> decltype(seqN(f, (l-f+typename internal::cleanup_seq_incr::type(incr)) + -> decltype(seqN(f, ( typename internal::cleanup_index_type::type(l) + - typename internal::cleanup_index_type::type(f)+typename internal::cleanup_seq_incr::type(incr)) / typename internal::cleanup_seq_incr::type(incr),typename internal::cleanup_seq_incr::type(incr))) { typedef typename internal::cleanup_seq_incr::type CleanedIncrType; - return seqN(f,(l-f+CleanedIncrType(incr))/CleanedIncrType(incr),CleanedIncrType(incr)); + return seqN(f,(typename internal::cleanup_index_type::type(l) + -typename internal::cleanup_index_type::type(f)+CleanedIncrType(incr)) / CleanedIncrType(incr),CleanedIncrType(incr)); } #else @@ -211,7 +215,8 @@ typename internal::enable_if::value || Symbol ArithmeticSequence::type,Index> >::type seq(FirstType f, LastType l) { - return seqN(f,(l-f+fix<1>())); + return seqN(typename internal::cleanup_index_type::type(f), + Index((typename internal::cleanup_index_type::type(l)-typename internal::cleanup_index_type::type(f)+fix<1>()))); } template @@ -220,7 +225,7 @@ typename internal::enable_if::value, Symbolic::ValueExpr > > > >::type seq(const Symbolic::BaseExpr &f, LastType l) { - return seqN(f.derived(),(l-f.derived()+fix<1>())); + return seqN(f.derived(),(typename internal::cleanup_index_type::type(l)-f.derived()+fix<1>())); } template @@ -230,7 +235,7 @@ typename internal::enable_if::value, Symbolic::ValueExpr > > > >::type seq(FirstType f, const Symbolic::BaseExpr &l) { - return seqN(f,(l.derived()-f+fix<1>())); + return seqN(typename internal::cleanup_index_type::type(f),(l.derived()-typename internal::cleanup_index_type::type(f)+fix<1>())); } template @@ -248,7 +253,8 @@ typename internal::enable_if::value || Symbol seq(FirstType f, LastType l, IncrType incr) { typedef typename internal::cleanup_seq_incr::type CleanedIncrType; - return seqN(f,(l-f+CleanedIncrType(incr))/CleanedIncrType(incr), incr); + return seqN(typename internal::cleanup_index_type::type(f), + Index((typename internal::cleanup_index_type::type(l)-typename internal::cleanup_index_type::type(f)+CleanedIncrType(incr))/CleanedIncrType(incr)), incr); } template @@ -262,7 +268,7 @@ typename internal::enable_if::value, seq(const Symbolic::BaseExpr &f, LastType l, IncrType incr) { typedef typename internal::cleanup_seq_incr::type CleanedIncrType; - return seqN(f.derived(),(l-f.derived()+CleanedIncrType(incr))/CleanedIncrType(incr), incr); + return seqN(f.derived(),(typename internal::cleanup_index_type::type(l)-f.derived()+CleanedIncrType(incr))/CleanedIncrType(incr), incr); } template @@ -275,7 +281,8 @@ typename internal::enable_if::value, seq(FirstType f, const Symbolic::BaseExpr &l, IncrType incr) { typedef typename internal::cleanup_seq_incr::type CleanedIncrType; - return seqN(f,(l.derived()-f+CleanedIncrType(incr))/CleanedIncrType(incr), incr); + return seqN(typename internal::cleanup_index_type::type(f), + (l.derived()-typename internal::cleanup_index_type::type(f)+CleanedIncrType(incr))/CleanedIncrType(incr), incr); } template diff --git a/Eigen/src/Core/util/IntegralConstant.h b/Eigen/src/Core/util/IntegralConstant.h index 354aa8c4c..178e4893c 100644 --- a/Eigen/src/Core/util/IntegralConstant.h +++ b/Eigen/src/Core/util/IntegralConstant.h @@ -28,6 +28,10 @@ template struct fix_t { } fix_t<-N> operator-() const { return fix_t<-N>(); } + template + fix_t operator+(fix_t) const { return fix_t(); } + template + fix_t operator-(fix_t) const { return fix_t(); } #if EIGEN_HAS_CXX14 // Needed in C++14 to allow fix(): diff --git a/Eigen/src/Core/util/SymbolicIndex.h b/Eigen/src/Core/util/SymbolicIndex.h index 5e9465db8..62058760b 100644 --- a/Eigen/src/Core/util/SymbolicIndex.h +++ b/Eigen/src/Core/util/SymbolicIndex.h @@ -163,6 +163,13 @@ struct is_symbolic { enum { value = internal::is_convertible >::value }; }; +// Specialization for functions, because is_convertible fails in this case. +// Useful in c++98/11 mode when testing is_symbolic)> +template +struct is_symbolic { + enum { value = false }; +}; + /** Represents the actual value of a symbol identified by its tag * * It is the return type of SymbolValue::operator=, and most of the time this is only way it is used. diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index 751f98344..e70a9c616 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -55,8 +55,7 @@ is_same_eq(const T1& a, const T2& b) } template -typename internal::enable_if::value,bool>::type -is_same_seq_type(const T1& a, const T2& b) +bool is_same_seq(const T1& a, const T2& b) { bool ok = a.first()==b.first() && a.size() == b.size() && Index(a.incrObject())==Index(b.incrObject());; if(!ok) @@ -67,6 +66,15 @@ is_same_seq_type(const T1& a, const T2& b) return ok; } +template +typename internal::enable_if::value,bool>::type +is_same_seq_type(const T1& a, const T2& b) +{ + return is_same_seq(a,b); +} + + + #define VERIFY_EQ_INT(A,B) VERIFY_IS_APPROX(int(A),int(B)) void check_indexed_view() @@ -193,6 +201,14 @@ void check_indexed_view() VERIFY( is_same_seq_type( seqN(2,fix(5),3), seqN(2,5,fix(3)) ) ); VERIFY( is_same_seq_type( seqN(2,fix<5>(5),fix<-2>), seqN(2,fix<5>,fix<-2>()) ) ); + VERIFY( is_same_seq_type( seq(2,fix<5>), seqN(2,4) ) ); +#if EIGEN_HAS_CXX11 + VERIFY( is_same_seq_type( seq(fix<2>,fix<5>), seqN(fix<2>,fix<4>) ) ); +#else + // sorry, no compile-time size recovery in c++98/03 + VERIFY( is_same_seq( seq(fix<2>,fix<5>), seqN(fix<2>,fix<4>) ) ); +#endif + VERIFY( (A(seqN(2,fix<5>), 5)).RowsAtCompileTime == 5); VERIFY( (A(4, all)).ColsAtCompileTime == Dynamic); VERIFY( (A(4, all)).RowsAtCompileTime == 1); From 41c523a0ab8432a3f3276abaeb8a869cccab6b93 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 24 Jan 2017 09:39:49 +0100 Subject: [PATCH 55/65] Rename fix_t to FixedInt --- Eigen/src/Core/ArithmeticSequence.h | 18 +++---- Eigen/src/Core/util/IndexedViewHelper.h | 4 +- Eigen/src/Core/util/IntegralConstant.h | 67 +++++++++++++------------ Eigen/src/Core/util/SymbolicIndex.h | 34 ++++++------- 4 files changed, 63 insertions(+), 60 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 646eb5770..c5c8bb105 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -21,12 +21,12 @@ template<> struct aseq_negate { typedef Index type; }; -template struct aseq_negate > { - typedef fix_t<-N> type; +template struct aseq_negate > { + typedef FixedInt<-N> type; }; // Compilation error in the following case: -template<> struct aseq_negate > {}; +template<> struct aseq_negate > {}; template::value, @@ -38,7 +38,7 @@ struct aseq_reverse_first_type { template struct aseq_reverse_first_type { typedef Symbolic::AddExpr > >, + Symbolic::ProductExpr > >, Symbolic::ValueExpr > > type; }; @@ -50,7 +50,7 @@ struct aseq_reverse_first_type { template struct aseq_reverse_first_type { - typedef Symbolic::AddExpr > >, + typedef Symbolic::AddExpr > >, Symbolic::ValueExpr >, Symbolic::ValueExpr<> > type; }; @@ -67,7 +67,7 @@ template struct cleanup_seq_incr { // seq(first,last,incr) and seqN(first,size,incr) //-------------------------------------------------------------------------------- -template > +template > class ArithmeticSequence; template @@ -222,7 +222,7 @@ seq(FirstType f, LastType l) template typename internal::enable_if::value, ArithmeticSequence,Symbolic::ValueExpr<> >, - Symbolic::ValueExpr > > > >::type + Symbolic::ValueExpr > > > >::type seq(const Symbolic::BaseExpr &f, LastType l) { return seqN(f.derived(),(typename internal::cleanup_index_type::type(l)-f.derived()+fix<1>())); @@ -232,7 +232,7 @@ template typename internal::enable_if::value, ArithmeticSequence::type, Symbolic::AddExpr >, - Symbolic::ValueExpr > > > >::type + Symbolic::ValueExpr > > > >::type seq(FirstType f, const Symbolic::BaseExpr &l) { return seqN(typename internal::cleanup_index_type::type(f),(l.derived()-typename internal::cleanup_index_type::type(f)+fix<1>())); @@ -240,7 +240,7 @@ seq(FirstType f, const Symbolic::BaseExpr &l) template ArithmeticSequence >,Symbolic::ValueExpr > > > + Symbolic::AddExpr >,Symbolic::ValueExpr > > > seq(const Symbolic::BaseExpr &f, const Symbolic::BaseExpr &l) { return seqN(f.derived(),(l.derived()-f.derived()+fix<1>())); diff --git a/Eigen/src/Core/util/IndexedViewHelper.h b/Eigen/src/Core/util/IndexedViewHelper.h index 1171b2b2e..ab01c857f 100644 --- a/Eigen/src/Core/util/IndexedViewHelper.h +++ b/Eigen/src/Core/util/IndexedViewHelper.h @@ -60,7 +60,7 @@ static const auto end = last+1; #else // Using a FixedExpr<1> expression is important here to make sure the compiler // can fully optimize the computation starting indices with zero overhead. -static const Symbolic::AddExpr,Symbolic::ValueExpr > > end(last+fix<1>()); +static const Symbolic::AddExpr,Symbolic::ValueExpr > > end(last+fix<1>()); #endif } // end namespace placeholders @@ -71,7 +71,7 @@ namespace internal { 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; } +FixedInt eval_expr_given_size(FixedInt x, Index /*size*/) { return x; } template Index eval_expr_given_size(const Symbolic::BaseExpr &x, Index size) diff --git a/Eigen/src/Core/util/IntegralConstant.h b/Eigen/src/Core/util/IntegralConstant.h index 178e4893c..e81cc45f2 100644 --- a/Eigen/src/Core/util/IntegralConstant.h +++ b/Eigen/src/Core/util/IntegralConstant.h @@ -15,39 +15,42 @@ namespace Eigen { namespace internal { -template struct fix_t; -template class variable_or_fixed; +template class FixedInt; +template class VariableAndFixedInt; -template struct fix_t { +template class FixedInt +{ +public: static const int value = N; operator int() const { return value; } - fix_t() {} - fix_t(variable_or_fixed other) { + FixedInt() {} + FixedInt( VariableAndFixedInt other) { EIGEN_ONLY_USED_FOR_DEBUG(other); eigen_internal_assert(int(other)==N); } - fix_t<-N> operator-() const { return fix_t<-N>(); } + FixedInt<-N> operator-() const { return FixedInt<-N>(); } template - fix_t operator+(fix_t) const { return fix_t(); } + FixedInt operator+( FixedInt) const { return FixedInt(); } template - fix_t operator-(fix_t) const { return fix_t(); } + FixedInt operator-( FixedInt) const { return FixedInt(); } #if EIGEN_HAS_CXX14 // Needed in C++14 to allow fix(): - fix_t operator() () const { return *this; } + FixedInt operator() () const { return *this; } - variable_or_fixed operator() (int val) const { return variable_or_fixed(val); } + VariableAndFixedInt operator() (int val) const { return VariableAndFixedInt(val); } #else - fix_t (fix_t (*)() ) {} + FixedInt ( FixedInt (*)() ) {} #endif }; -template class variable_or_fixed { +template class VariableAndFixedInt +{ public: static const int value = N; operator int() const { return m_value; } - variable_or_fixed(int val) { m_value = val; } + VariableAndFixedInt(int val) { m_value = val; } protected: int m_value; }; @@ -56,17 +59,17 @@ template struct get_fixed_value { static const int value = Default; }; -template struct get_fixed_value,Default> { +template struct get_fixed_value,Default> { static const int value = N; }; #if !EIGEN_HAS_CXX14 -template struct get_fixed_value (*)(),Default> { +template struct get_fixed_value (*)(),Default> { static const int value = N; }; #endif -template struct get_fixed_value,Default> { +template struct get_fixed_value,Default> { static const int value = N ; }; @@ -77,10 +80,10 @@ struct get_fixed_value,Default> { template Index get_runtime_value(const T &x) { return x; } #if !EIGEN_HAS_CXX14 -template Index get_runtime_value(fix_t (*)()) { return N; } +template Index get_runtime_value(FixedInt (*)()) { return N; } #endif -// Cleanup integer/fix_t/variable_or_fixed/etc types: +// Cleanup integer/FixedInt/VariableAndFixedInt/etc types: // By default, no cleanup: template struct cleanup_index_type { typedef T type; }; @@ -89,14 +92,14 @@ template struct clea template struct cleanup_index_type::value>::type> { typedef Index type; }; #if !EIGEN_HAS_CXX14 -// In c++98/c++11, fix is a pointer to function that we better cleanup to a true fix_t: -template struct cleanup_index_type (*)(), DynamicKey> { typedef fix_t type; }; +// In c++98/c++11, fix is a pointer to function that we better cleanup to a true FixedInt: +template struct cleanup_index_type (*)(), DynamicKey> { typedef FixedInt type; }; #endif -// If variable_or_fixed does not match DynamicKey, then we turn it to a pure compile-time value: -template struct cleanup_index_type, DynamicKey> { typedef fix_t type; }; -// If variable_or_fixed matches DynamicKey, then we turn it to a pure runtime-value (aka Index): -template struct cleanup_index_type, DynamicKey> { typedef Index type; }; +// If VariableAndFixedInt does not match DynamicKey, then we turn it to a pure compile-time value: +template struct cleanup_index_type, DynamicKey> { typedef FixedInt type; }; +// If VariableAndFixedInt matches DynamicKey, then we turn it to a pure runtime-value (aka Index): +template struct cleanup_index_type, DynamicKey> { typedef Index type; }; } // end namespace internal @@ -104,15 +107,15 @@ template struct cleanup_index_type #if EIGEN_HAS_CXX14 template -static const internal::fix_t fix{}; +static const internal::FixedInt fix{}; #else template -inline internal::fix_t fix() { return internal::fix_t(); } +inline internal::FixedInt fix() { return internal::FixedInt(); } // The generic typename T is mandatory. Otherwise, a code like fix could refer to either the function above or this next overload. // This way a code like fix can only refer to the previous function. template -inline internal::variable_or_fixed fix(T val) { return internal::variable_or_fixed(val); } +inline internal::VariableAndFixedInt fix(T val) { return internal::VariableAndFixedInt(val); } #endif #else // EIGEN_PARSED_BY_DOXYGEN @@ -133,17 +136,17 @@ inline internal::variable_or_fixed fix(T val) { return internal::variable_or_ * * In c++14, it is implemented as: * \code - * template static const internal::fix_t fix{}; + * template static const internal::FixedInt fix{}; * \endcode - * where internal::fix_t is an internal template class similar to + * where internal::FixedInt is an internal template class similar to * \c std::integral_constant - * Here, \c fix is thus an object of type \c internal::fix_t. + * Here, \c fix is thus an object of type \c internal::FixedInt. * * In c++98/11, it is implemented as a function: * \code - * template inline internal::fix_t fix(); + * template inline internal::FixedInt fix(); * \endcode - * Here internal::fix_t is thus a pointer to function. + * Here internal::FixedInt is thus a pointer to function. * * If for some reason you want a true object in c++98 then you can write: \code fix() \endcode which is also valid in c++14. * diff --git a/Eigen/src/Core/util/SymbolicIndex.h b/Eigen/src/Core/util/SymbolicIndex.h index 62058760b..a52510f6a 100644 --- a/Eigen/src/Core/util/SymbolicIndex.h +++ b/Eigen/src/Core/util/SymbolicIndex.h @@ -61,7 +61,7 @@ protected: // Specialization for compile-time value, // It is similar to ValueExpr(N) but this version helps the compiler to generate better code. template -class ValueExpr > { +class ValueExpr > { public: ValueExpr() {} template @@ -114,30 +114,30 @@ public: { return QuotientExpr,Derived>(a,b.derived()); } template - AddExpr > > operator+(internal::fix_t) const - { return AddExpr > >(derived(), ValueExpr >()); } + AddExpr > > operator+(internal::FixedInt) const + { return AddExpr > >(derived(), ValueExpr >()); } template - AddExpr > > operator-(internal::fix_t) const - { return AddExpr > >(derived(), ValueExpr >()); } + AddExpr > > operator-(internal::FixedInt) const + { return AddExpr > >(derived(), ValueExpr >()); } template - ProductExpr > > operator*(internal::fix_t) const - { return ProductExpr > >(derived(),ValueExpr >()); } + ProductExpr > > operator*(internal::FixedInt) const + { return ProductExpr > >(derived(),ValueExpr >()); } template - QuotientExpr > > operator/(internal::fix_t) const - { return QuotientExpr > >(derived(),ValueExpr >()); } + QuotientExpr > > operator/(internal::FixedInt) const + { return QuotientExpr > >(derived(),ValueExpr >()); } template - friend AddExpr > > operator+(internal::fix_t, const BaseExpr& b) - { return AddExpr > >(b.derived(), ValueExpr >()); } + friend AddExpr > > operator+(internal::FixedInt, const BaseExpr& b) + { return AddExpr > >(b.derived(), ValueExpr >()); } template - friend AddExpr,ValueExpr > > operator-(internal::fix_t, const BaseExpr& b) - { return AddExpr,ValueExpr > >(-b.derived(), ValueExpr >()); } + friend AddExpr,ValueExpr > > operator-(internal::FixedInt, const BaseExpr& b) + { return AddExpr,ValueExpr > >(-b.derived(), ValueExpr >()); } template - friend ProductExpr >,Derived> operator*(internal::fix_t, const BaseExpr& b) - { return ProductExpr >,Derived>(ValueExpr >(),b.derived()); } + friend ProductExpr >,Derived> operator*(internal::FixedInt, const BaseExpr& b) + { return ProductExpr >,Derived>(ValueExpr >(),b.derived()); } template - friend QuotientExpr >,Derived> operator/(internal::fix_t, const BaseExpr& b) - { return QuotientExpr > ,Derived>(ValueExpr >(),b.derived()); } + friend QuotientExpr >,Derived> operator/(internal::FixedInt, const BaseExpr& b) + { return QuotientExpr > ,Derived>(ValueExpr >(),b.derived()); } template From bb52f74e6290cb0f84202866a27aa9c4c1ec9fc9 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 24 Jan 2017 10:13:35 +0100 Subject: [PATCH 56/65] Add internal doc --- Eigen/src/Core/util/IntegralConstant.h | 59 ++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/Eigen/src/Core/util/IntegralConstant.h b/Eigen/src/Core/util/IntegralConstant.h index e81cc45f2..b25601ed3 100644 --- a/Eigen/src/Core/util/IntegralConstant.h +++ b/Eigen/src/Core/util/IntegralConstant.h @@ -18,6 +18,36 @@ namespace internal { template class FixedInt; template class VariableAndFixedInt; +/** \internal + * \class FixedInt + * + * This class embeds a compile-time integer \c N. + * + * It is similar to c++11 std::integral_constant but with some additional features + * such as: + * - implicit conversion to int + * - arithmetic operators: -, +, * + * - c++98/14 compatibility with fix and fix() syntax to define integral constants. + * + * It is strongly discouraged to directly deal with this class FixedInt. Instances are expcected to + * be created by the user using Eigen::fix or Eigen::fix(). In C++98-11, the former syntax does + * not create a FixedInt instance but rather a point to function that needs to be \em cleaned-up + * using the generic helper: + * \code + * internal::cleanup_index_type::type + * internal::cleanup_index_type::type + * \endcode + * where T can a FixedInt, a pointer to function FixedInt (*)(), or numerous other integer-like representations. + * \c DynamicKey is either Dynamic (default) or DynamicIndex and used to identify true compile-time values. + * + * For convenience, you can extract the compile-time value \c N in a generic way using the following helper: + * \code + * internal::get_fixed_value::value + * \endcode + * that will give you \c N if T equals FixedInt or FixedInt (*)(), and \c DefaultVal if T does not embed any compile-time value (e.g., T==int). + * + * \sa fix, class VariableAndFixedInt + */ template class FixedInt { public: @@ -45,6 +75,35 @@ public: #endif }; +/** \internal + * \class VariableAndFixedInt + * + * This class embeds both a compile-time integer \c N and a runtime integer. + * Both values are supposed to be equal unless the compile-time value \c N has a special + * value meaning that the runtime-value should be used. Depending on the context, this special + * value can be either Eigen::Dynamic (for positive quantities) or Eigen::DynamicIndex (for + * quantities that can be negative). + * + * It is the return-type of the function Eigen::fix(int), and most of the time this is the only + * way it is used. It is strongly discouraged to directly deal with instances of VariableAndFixedInt. + * Indeed, in order to write generic code, it is the responsibility of the callee to properly convert + * it to either a true compile-time quantity (i.e. a FixedInt), or to a runtime quantity (e.g., an Index) + * using the following generic helper: + * \code + * internal::cleanup_index_type::type + * internal::cleanup_index_type::type + * \endcode + * where T can be a template instantiation of VariableAndFixedInt or numerous other integer-like representations. + * \c DynamicKey is either Dynamic (default) or DynamicIndex and used to identify true compile-time values. + * + * For convenience, you can also extract the compile-time value \c N using the following helper: + * \code + * internal::get_fixed_value::value + * \endcode + * that will give you \c N if T equals VariableAndFixedInt, and \c DefaultVal if T does not embed any compile-time value (e.g., T==int). + * + * \sa fix(int), class FixedInt + */ template class VariableAndFixedInt { public: From 228fef1b3ac3f635b5d7b7546a1c8bd0dd4c57be Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 24 Jan 2017 10:53:51 +0100 Subject: [PATCH 57/65] Extended the set of arithmetic operators supported by FixedInt (-,+,*,/,%,&,|) --- Eigen/src/Core/util/IntegralConstant.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/util/IntegralConstant.h b/Eigen/src/Core/util/IntegralConstant.h index b25601ed3..f7baf1060 100644 --- a/Eigen/src/Core/util/IntegralConstant.h +++ b/Eigen/src/Core/util/IntegralConstant.h @@ -26,7 +26,7 @@ template class VariableAndFixedInt; * It is similar to c++11 std::integral_constant but with some additional features * such as: * - implicit conversion to int - * - arithmetic operators: -, +, * + * - arithmetic and some bitwise operators: -, +, *, /, %, &, | * - c++98/14 compatibility with fix and fix() syntax to define integral constants. * * It is strongly discouraged to directly deal with this class FixedInt. Instances are expcected to @@ -64,6 +64,16 @@ public: FixedInt operator+( FixedInt) const { return FixedInt(); } template FixedInt operator-( FixedInt) const { return FixedInt(); } + template + FixedInt operator*( FixedInt) const { return FixedInt(); } + template + FixedInt operator/( FixedInt) const { return FixedInt(); } + template + FixedInt operator%( FixedInt) const { return FixedInt(); } + template + FixedInt operator|( FixedInt) const { return FixedInt(); } + template + FixedInt operator&( FixedInt) const { return FixedInt(); } #if EIGEN_HAS_CXX14 // Needed in C++14 to allow fix(): From ddd83f82d88592d12124040ad2c76c03013da62a Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 24 Jan 2017 10:54:42 +0100 Subject: [PATCH 58/65] Add support for "SymbolicExpr op fix" in C++98/11 mode. --- Eigen/src/Core/util/SymbolicIndex.h | 30 ++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/util/SymbolicIndex.h b/Eigen/src/Core/util/SymbolicIndex.h index a52510f6a..f9a2e6311 100644 --- a/Eigen/src/Core/util/SymbolicIndex.h +++ b/Eigen/src/Core/util/SymbolicIndex.h @@ -117,7 +117,7 @@ public: AddExpr > > operator+(internal::FixedInt) const { return AddExpr > >(derived(), ValueExpr >()); } template - AddExpr > > operator-(internal::FixedInt) const + AddExpr > > operator-(internal::FixedInt) const { return AddExpr > >(derived(), ValueExpr >()); } template ProductExpr > > operator*(internal::FixedInt) const @@ -139,6 +139,34 @@ public: friend QuotientExpr >,Derived> operator/(internal::FixedInt, const BaseExpr& b) { return QuotientExpr > ,Derived>(ValueExpr >(),b.derived()); } +#if (!EIGEN_HAS_CXX14) + template + AddExpr > > operator+(internal::FixedInt (*)()) const + { return AddExpr > >(derived(), ValueExpr >()); } + template + AddExpr > > operator-(internal::FixedInt (*)()) const + { return AddExpr > >(derived(), ValueExpr >()); } + template + ProductExpr > > operator*(internal::FixedInt (*)()) const + { return ProductExpr > >(derived(),ValueExpr >()); } + template + QuotientExpr > > operator/(internal::FixedInt (*)()) const + { return QuotientExpr > >(derived(),ValueExpr >()); } + + template + friend AddExpr > > operator+(internal::FixedInt (*)(), const BaseExpr& b) + { return AddExpr > >(b.derived(), ValueExpr >()); } + template + friend AddExpr,ValueExpr > > operator-(internal::FixedInt (*)(), const BaseExpr& b) + { return AddExpr,ValueExpr > >(-b.derived(), ValueExpr >()); } + template + friend ProductExpr >,Derived> operator*(internal::FixedInt (*)(), const BaseExpr& b) + { return ProductExpr >,Derived>(ValueExpr >(),b.derived()); } + template + friend QuotientExpr >,Derived> operator/(internal::FixedInt (*)(), const BaseExpr& b) + { return QuotientExpr > ,Derived>(ValueExpr >(),b.derived()); } +#endif + template AddExpr operator+(const BaseExpr &b) const From 5783158e8f240418d33b0745b4276f9cc977be64 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 24 Jan 2017 10:55:12 +0100 Subject: [PATCH 59/65] Add unit test for FixedInt and Symbolic --- test/CMakeLists.txt | 1 + test/symbolic_index.cpp | 94 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 test/symbolic_index.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 921d9688c..84a21b3df 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -161,6 +161,7 @@ ei_add_test(redux) ei_add_test(visitor) ei_add_test(block) ei_add_test(corners) +ei_add_test(symbolic_index) ei_add_test(indexed_view) ei_add_test(swap) ei_add_test(resize) diff --git a/test/symbolic_index.cpp b/test/symbolic_index.cpp new file mode 100644 index 000000000..83f105cb8 --- /dev/null +++ b/test/symbolic_index.cpp @@ -0,0 +1,94 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2017 Gael Guennebaud +// +// 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/. + +#ifdef EIGEN_TEST_PART_2 +#define EIGEN_MAX_CPP_VER 03 +#endif + +#include "main.h" + +template +bool match(const T& xpr, std::string ref, std::string str_xpr = "") { + EIGEN_UNUSED_VARIABLE(str_xpr); + std::stringstream str; + str << xpr; + if(!(str.str() == ref)) + std::cout << str_xpr << "\n" << xpr << "\n\n"; + return str.str() == ref; +} + +#define MATCH(X,R) match(X, R, #X) + +template +typename internal::enable_if::value,bool>::type +is_same_fixed(const T1& a, const T2& b) +{ + return (Index(a) == Index(b)); +} + +template +bool is_same_seq(const T1& a, const T2& b) +{ + bool ok = a.first()==b.first() && a.size() == b.size() && Index(a.incrObject())==Index(b.incrObject());; + if(!ok) + { + std::cerr << "seqN(" << a.first() << ", " << a.size() << ", " << Index(a.incrObject()) << ") != "; + std::cerr << "seqN(" << b.first() << ", " << b.size() << ", " << Index(b.incrObject()) << ")\n"; + } + return ok; +} + +template +typename internal::enable_if::value,bool>::type +is_same_type(const T1&, const T2&) +{ + return true; +} + +template +bool is_same_symb(const T1& a, const T2& b, Index size) +{ + using Eigen::placeholders::last; + return a.eval(last=size-1) == b.eval(last=size-1); +} + + +#define VERIFY_EQ_INT(A,B) VERIFY_IS_APPROX(int(A),int(B)) + +void check_symbolic_index() +{ + using Eigen::placeholders::last; + using Eigen::placeholders::end; + + Index size=100; + + // First, let's check FixedInt arithmetic: + VERIFY( is_same_type( (fix<5>()-fix<3>())*fix<9>()/(-fix<3>()), fix<-(5-3)*9/3>() ) ); + VERIFY( is_same_type( (fix<5>()-fix<3>())*fix<9>()/fix<2>(), fix<(5-3)*9/2>() ) ); + VERIFY( is_same_type( fix<9>()/fix<2>(), fix<9/2>() ) ); + VERIFY( is_same_type( fix<9>()%fix<2>(), fix<9%2>() ) ); + VERIFY( is_same_type( fix<9>()&fix<2>(), fix<9&2>() ) ); + VERIFY( is_same_type( fix<9>()|fix<2>(), fix<9|2>() ) ); + VERIFY( is_same_type( fix<9>()/2, int(9/2) ) ); + + VERIFY( is_same_symb( end-1, last, size) ); + VERIFY( is_same_symb( end-fix<1>, last, size) ); + + VERIFY_IS_EQUAL( ( (last*5-2)/3 ).eval(last=size-1), ((size-1)*5-2)/3 ); + VERIFY_IS_EQUAL( ( (last*fix<5>-fix<2>)/fix<3> ).eval(last=size-1), ((size-1)*5-2)/3 ); + VERIFY_IS_EQUAL( ( -last*end ).eval(last=size-1), -(size-1)*size ); + VERIFY_IS_EQUAL( ( end-3*last ).eval(last=size-1), size- 3*(size-1) ); + VERIFY_IS_EQUAL( ( (end-3*last)/end ).eval(last=size-1), (size- 3*(size-1))/size ); +} + +void test_symbolic_index() +{ + CALL_SUBTEST_1( check_symbolic_index() ); + CALL_SUBTEST_2( check_symbolic_index() ); +} From c43d254d1376c24c76df45bb274dda74ddfa2e19 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 24 Jan 2017 11:36:43 +0100 Subject: [PATCH 60/65] Fix seq().reverse() in c++98 --- Eigen/src/Core/ArithmeticSequence.h | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index c5c8bb105..6c10ecc02 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -43,9 +43,20 @@ struct aseq_reverse_first_type { > type; }; +template +struct aseq_reverse_first_type_aux { + typedef Index type; +}; + +template +struct aseq_reverse_first_type_aux::type> { + typedef FixedInt<(SizeType::value-1)*IncrType::value> type; +}; + template struct aseq_reverse_first_type { - typedef Symbolic::AddExpr > type; + typedef typename aseq_reverse_first_type_aux::type Aux; + typedef Symbolic::AddExpr > type; }; template From bc1020185407a324be81f613d88ce4b162f6774d Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 24 Jan 2017 16:27:51 +0100 Subject: [PATCH 61/65] Add test for multiple symbols --- Eigen/src/Core/util/SymbolicIndex.h | 2 +- test/symbolic_index.cpp | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/util/SymbolicIndex.h b/Eigen/src/Core/util/SymbolicIndex.h index f9a2e6311..bb6349eb9 100644 --- a/Eigen/src/Core/util/SymbolicIndex.h +++ b/Eigen/src/Core/util/SymbolicIndex.h @@ -235,7 +235,7 @@ public: Index eval_impl(const SymbolValue &values) const { return values.value(); } -#if __cplusplus > 201103L +#if EIGEN_HAS_CXX14 // C++14 versions suitable for multiple symbols template Index eval_impl(const std::tuple& values) const { return std::get >(values).value(); } diff --git a/test/symbolic_index.cpp b/test/symbolic_index.cpp index 83f105cb8..1db85144b 100644 --- a/test/symbolic_index.cpp +++ b/test/symbolic_index.cpp @@ -85,6 +85,16 @@ void check_symbolic_index() VERIFY_IS_EQUAL( ( -last*end ).eval(last=size-1), -(size-1)*size ); VERIFY_IS_EQUAL( ( end-3*last ).eval(last=size-1), size- 3*(size-1) ); VERIFY_IS_EQUAL( ( (end-3*last)/end ).eval(last=size-1), (size- 3*(size-1))/size ); + +#if EIGEN_HAS_CXX14 + { + struct x_tag {}; static const Symbolic::SymbolExpr x; + struct y_tag {}; static const Symbolic::SymbolExpr y; + struct z_tag {}; static const Symbolic::SymbolExpr z; + + VERIFY_IS_APPROX( int(((x+3)/y+z).eval(x=6,y=3,z=-13)), (6+3)/3+(-13) ); + } +#endif } void test_symbolic_index() From d83db761a2b9cedcb25519b3e556b5e495adc115 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 24 Jan 2017 16:28:12 +0100 Subject: [PATCH 62/65] Add support for std::integral_constant --- Eigen/src/Core/ArithmeticSequence.h | 24 +++++++++++++++--------- Eigen/src/Core/util/IntegralConstant.h | 8 ++++++++ test/indexed_view.cpp | 9 +++++++++ 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 6c10ecc02..99b954432 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -202,22 +202,28 @@ auto seq(FirstType f, LastType l); #if EIGEN_HAS_CXX11 template -auto seq(FirstType f, LastType l) -> decltype(seqN(f,( typename internal::cleanup_index_type::type(l) - - typename internal::cleanup_index_type::type(f)+fix<1>()))) +auto seq(FirstType f, LastType l) -> decltype(seqN(typename internal::cleanup_index_type::type(f), + ( typename internal::cleanup_index_type::type(l) + - typename internal::cleanup_index_type::type(f)+fix<1>()))) { - return seqN(f,(typename internal::cleanup_index_type::type(l) - -typename internal::cleanup_index_type::type(f)+fix<1>())); + return seqN(typename internal::cleanup_index_type::type(f), + (typename internal::cleanup_index_type::type(l) + -typename internal::cleanup_index_type::type(f)+fix<1>())); } template auto seq(FirstType f, LastType l, IncrType incr) - -> decltype(seqN(f, ( typename internal::cleanup_index_type::type(l) - - typename internal::cleanup_index_type::type(f)+typename internal::cleanup_seq_incr::type(incr)) - / typename internal::cleanup_seq_incr::type(incr),typename internal::cleanup_seq_incr::type(incr))) + -> decltype(seqN(typename internal::cleanup_index_type::type(f), + ( typename internal::cleanup_index_type::type(l) + - typename internal::cleanup_index_type::type(f)+typename internal::cleanup_seq_incr::type(incr) + ) / typename internal::cleanup_seq_incr::type(incr), + typename internal::cleanup_seq_incr::type(incr))) { typedef typename internal::cleanup_seq_incr::type CleanedIncrType; - return seqN(f,(typename internal::cleanup_index_type::type(l) - -typename internal::cleanup_index_type::type(f)+CleanedIncrType(incr)) / CleanedIncrType(incr),CleanedIncrType(incr)); + return seqN(typename internal::cleanup_index_type::type(f), + ( typename internal::cleanup_index_type::type(l) + -typename internal::cleanup_index_type::type(f)+CleanedIncrType(incr)) / CleanedIncrType(incr), + CleanedIncrType(incr)); } #else diff --git a/Eigen/src/Core/util/IntegralConstant.h b/Eigen/src/Core/util/IntegralConstant.h index f7baf1060..ae41015bd 100644 --- a/Eigen/src/Core/util/IntegralConstant.h +++ b/Eigen/src/Core/util/IntegralConstant.h @@ -83,6 +83,10 @@ public: #else FixedInt ( FixedInt (*)() ) {} #endif + +#if EIGEN_HAS_CXX11 + FixedInt(std::integral_constant) {} +#endif }; /** \internal @@ -170,6 +174,10 @@ template struct cleanup_index_type // If VariableAndFixedInt matches DynamicKey, then we turn it to a pure runtime-value (aka Index): template struct cleanup_index_type, DynamicKey> { typedef Index type; }; +#if EIGEN_HAS_CXX11 +template struct cleanup_index_type, DynamicKey> { typedef FixedInt type; }; +#endif + } // end namespace internal #ifndef EIGEN_PARSED_BY_DOXYGEN diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index e70a9c616..8fa1c16f4 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -204,6 +204,15 @@ void check_indexed_view() VERIFY( is_same_seq_type( seq(2,fix<5>), seqN(2,4) ) ); #if EIGEN_HAS_CXX11 VERIFY( is_same_seq_type( seq(fix<2>,fix<5>), seqN(fix<2>,fix<4>) ) ); + VERIFY( is_same_seq( seqN(2,std::integral_constant(),std::integral_constant()), seqN(2,fix<5>,fix<-2>()) ) ); + VERIFY( is_same_seq( seq(std::integral_constant(),std::integral_constant(),std::integral_constant()), + seq(fix<1>,fix<5>,fix<2>()) ) ); + VERIFY( is_same_seq_type( seqN(2,std::integral_constant(),std::integral_constant()), seqN(2,fix<5>,fix<-2>()) ) ); + VERIFY( is_same_seq_type( seq(std::integral_constant(),std::integral_constant(),std::integral_constant()), + seq(fix<1>,fix<5>,fix<2>()) ) ); + + VERIFY( is_same_seq_type( seqN(2,std::integral_constant()), seqN(2,fix<5>) ) ); + VERIFY( is_same_seq_type( seq(std::integral_constant(),std::integral_constant()), seq(fix<1>,fix<5>) ) ); #else // sorry, no compile-time size recovery in c++98/03 VERIFY( is_same_seq( seq(fix<2>,fix<5>), seqN(fix<2>,fix<4>) ) ); From 607be65a03aace70d17f0b968d76986ff09acc78 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 25 Jan 2017 22:53:58 +0100 Subject: [PATCH 63/65] Fix duplicates of array_size bewteen unsupported and Core --- Eigen/src/Core/util/Meta.h | 10 ++++++++-- unsupported/Eigen/CXX11/src/util/EmulateArray.h | 12 ------------ 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/Eigen/src/Core/util/Meta.h b/Eigen/src/Core/util/Meta.h index 804657f7b..ee0531b32 100755 --- a/Eigen/src/Core/util/Meta.h +++ b/Eigen/src/Core/util/Meta.h @@ -290,7 +290,7 @@ protected: * - std::array (c++11) * - some internal types such as SingleRange and AllRange * - * The second template parameter ease SFINAE-based specializations. + * The second template parameter eases SFINAE-based specializations. */ template struct array_size { enum { value = Dynamic }; @@ -303,8 +303,14 @@ template struct array_size struct array_size { enum { value = N }; }; +template struct array_size { + enum { value = N }; +}; -#ifdef EIGEN_HAS_CXX11 +#if EIGEN_HAS_CXX11 +template struct array_size > { + enum { value = N }; +}; template struct array_size > { enum { value = N }; }; diff --git a/unsupported/Eigen/CXX11/src/util/EmulateArray.h b/unsupported/Eigen/CXX11/src/util/EmulateArray.h index 30d3ebcff..03169d591 100644 --- a/unsupported/Eigen/CXX11/src/util/EmulateArray.h +++ b/unsupported/Eigen/CXX11/src/util/EmulateArray.h @@ -200,19 +200,15 @@ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const T& array_get(const array& a) { return a[I]; } -template struct array_size; template struct array_size > { static const size_t value = N; }; -template struct array_size; template struct array_size& > { static const size_t value = N; }; -template struct array_size; template struct array_size > { static const size_t value = N; }; -template struct array_size; template struct array_size& > { static const size_t value = N; }; @@ -251,14 +247,6 @@ template constexpr inline T const& array_ #undef STD_GET_ARR_HACK -template struct array_size; -template struct array_size > { - static const size_t value = N; -}; -template struct array_size; -template struct array_size > { - static const size_t value = N; -}; } // end namespace internal } // end namespace Eigen From 28351073d865d327edf08bc4b1e814ab0626f415 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 25 Jan 2017 22:54:51 +0100 Subject: [PATCH 64/65] Fix unamed type as template argument (ok in c++11 only) --- Eigen/src/Core/util/Macros.h | 3 ++- test/indexed_view.cpp | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Eigen/src/Core/util/Macros.h b/Eigen/src/Core/util/Macros.h index 7462dc5cf..8045a2879 100644 --- a/Eigen/src/Core/util/Macros.h +++ b/Eigen/src/Core/util/Macros.h @@ -870,7 +870,8 @@ namespace Eigen { typedef typename Eigen::internal::ref_selector::type Nested; \ typedef typename Eigen::internal::traits::StorageKind StorageKind; \ typedef typename Eigen::internal::traits::StorageIndex StorageIndex; \ - enum { RowsAtCompileTime = Eigen::internal::traits::RowsAtCompileTime, \ + enum CompileTimeTraits \ + { RowsAtCompileTime = Eigen::internal::traits::RowsAtCompileTime, \ ColsAtCompileTime = Eigen::internal::traits::ColsAtCompileTime, \ Flags = Eigen::internal::traits::Flags, \ SizeAtCompileTime = Base::SizeAtCompileTime, \ diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index 8fa1c16f4..909d2351d 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -226,7 +226,7 @@ void check_indexed_view() VERIFY( (B(all,1)).ColsAtCompileTime == 1); VERIFY( (B(all,1)).RowsAtCompileTime == 4); - VERIFY( (A(all, eii)).ColsAtCompileTime == eii.SizeAtCompileTime); + VERIFY(int( (A(all, eii)).ColsAtCompileTime) == int(eii.SizeAtCompileTime)); VERIFY_EQ_INT( (A(eii, eii)).Flags&DirectAccessBit, (unsigned int)(0)); VERIFY_EQ_INT( (A(eii, eii)).InnerStrideAtCompileTime, 0); VERIFY_EQ_INT( (A(eii, eii)).OuterStrideAtCompileTime, 0); @@ -320,7 +320,7 @@ void check_indexed_view() VERIFY_IS_APPROX( A(B.RowsAtCompileTime, 1), A(4,1) ); VERIFY_IS_APPROX( A(B.RowsAtCompileTime-1, B.ColsAtCompileTime-1), A(3,3) ); VERIFY_IS_APPROX( A(B.RowsAtCompileTime, B.ColsAtCompileTime), A(4,4) ); - enum { I = 3, J = 4 }; + const Index I = 3, J = 4; VERIFY_IS_APPROX( A(I,J), A(3,4) ); } From 98dfe0c13f717c0572c55527f077ed01c110972c Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 25 Jan 2017 22:55:04 +0100 Subject: [PATCH 65/65] Fix useless ';' warning --- Eigen/src/plugins/IndexedViewMethods.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Eigen/src/plugins/IndexedViewMethods.h b/Eigen/src/plugins/IndexedViewMethods.h index e6098bfc7..b2cc2944a 100644 --- a/Eigen/src/plugins/IndexedViewMethods.h +++ b/Eigen/src/plugins/IndexedViewMethods.h @@ -39,19 +39,19 @@ template typename IvcRowType::type ivcRow(const Indices& indices) const { 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()),Specialized); -}; +} template typename IvcColType::type ivcSize(const Indices& indices) const { return internal::makeIndexedViewCompatible(indices, internal::variable_if_dynamic(derived().size()),Specialized); -}; +} template struct valid_indexed_view_overload {