// 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 //-------------------------------------------------------------------------------- /** 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; 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; }; /** \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 { 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 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; }; template class SymbolExpr : public BaseExpr > { public: typedef TagT Tag; SymbolExpr() {} Index eval(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(); } #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 > { 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 first() const { return m_first; } 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; }; 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 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); } 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); } #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 internal::cleanup_seq_type::type(incr)) / typename internal::cleanup_seq_type::type(incr),typename internal::cleanup_seq_type::type(incr))) { 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 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 internal::cleanup_seq_type::type> >::type seq(FirstType f, LastType l, IncrType incr) { typedef typename internal::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 internal::cleanup_seq_type::type> >::type seq(const Symbolic::BaseExpr &f, LastType l, IncrType incr) { 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, Symbolic::QuotientExpr, Symbolic::ValueExpr>, Symbolic::ValueExpr>, typename internal::cleanup_seq_type::type> >::type seq(FirstType f, const Symbolic::BaseExpr &l, IncrType incr) { typedef typename internal::cleanup_seq_type::type CleanedIncrType; return seqN(f,(l.derived()-f+CleanedIncrType(incr))/CleanedIncrType(incr), incr); } template ArithemeticSequence >, Symbolic::ValueExpr>, Symbolic::ValueExpr>, 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; 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 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; } 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(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>( 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 }; }; } // 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; 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 { 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 internal::cleanup_seq_type::type > seq(FirstType f, LastType l) { return ArithemeticSequenceProxyWithBounds::type,typename internal::cleanup_seq_type::type>(f,l); } template 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)); } } 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( eval_expr_given_size(ids.firstObject(),size),eval_expr_given_size(ids.lastObject(),size),ids.incrObject()); } } } // end namespace Eigen #endif // EIGEN_ARITHMETIC_SEQUENCE_H