// 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 { //-------------------------------------------------------------------------------- // Pseudo keywords: all, last, end //-------------------------------------------------------------------------------- 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 ValueExpr { public: ValueExpr(Index val) : m_value(val) {} template Index eval(const T&) const { return m_value; } protected: Index m_value; }; template class BaseExpr { public: const Derived& derived() const { return *static_cast(this); } 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 AddExpr 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 }; }; template class SymbolValue { public: SymbolValue(Index val) : m_value(val) {} Index value() const { return m_value; } protected: Index m_value; }; template class SymbolExpr : public BaseExpr > { public: typedef TagT Tag; SymbolExpr() {} 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 >... }; template SymbolValue defineValue(SymbolExpr,Index val) { return SymbolValue(val); } template class NegateExpr : public BaseExpr > { public: NegateExpr(const Arg0& arg0) : m_arg0(arg0) {} template Index eval(const T& values) const { return -m_arg0.eval(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(const T& values) const { return m_arg0.eval(values) + m_arg1.eval(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(const T& values) const { return m_arg0.eval(values) * m_arg1.eval(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(const T& values) const { return m_arg0.eval(values) / m_arg1.eval(values); } protected: Arg0 m_arg0; Arg1 m_arg1; }; } // end namespace Symbolic namespace placeholders { namespace internal { struct symbolic_last_tag {}; } static const Symbolic::SymbolExpr last; static const Symbolic::AddExpr,Symbolic::ValueExpr> end(last+1); } // 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) //-------------------------------------------------------------------------------- template > class ArithemeticSequence { 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) {} 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; }; 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 > seqN(FirstType first, SizeType size, IncrType incr) { return ArithemeticSequence::type,typename cleanup_seq_type::type,typename cleanup_seq_type::type>(first,size,incr); } template ArithemeticSequence::type,typename cleanup_seq_type::type > 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+fix<1>()))) { return 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))) { 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 || Symbolic::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::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::AddExpr,Symbolic::ValueExpr> > >::type seq(FirstType f, const Symbolic::BaseExpr &l) { return seqN(f,(l.derived()-f+1)); } template 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 || Symbolic::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::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, ArithemeticSequence::type, Symbolic::QuotientExpr, Symbolic::ValueExpr>, Symbolic::ValueExpr>, typename cleanup_seq_type::type> >::type 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); } template ArithemeticSequence >, Symbolic::ValueExpr>, Symbolic::ValueExpr>, typename cleanup_seq_type::type> 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); } #endif namespace internal { template Index size(const T& x) { return x.size(); } template Index size(const T (&) [N]) { return N; } 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 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 Index symbolic2value(Index x, Index /* size */) { return x; } template fix_t symbolic2value(fix_t x, Index /*size*/) { return x; } template Index symbolic2value(const Symbolic::BaseExpr &x, Index size) { 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; }; template 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 // 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); } template struct get_compile_time_size { enum { value = XprSize }; }; template<> struct get_compile_time_incr { enum { value = 1 }; }; } // 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