// 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 // IWYU pragma: private #include "../InternalHeaderCheck.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"; * * \endcode * * It is currently only used internally to define and manipulate the * Eigen::placeholders::last and Eigen::placeholders::lastp1 symbols in * Eigen::seq and Eigen::seqN. * */ namespace symbolic { template class Symbol; template class SymbolValue; template class NegateExpr; template class AddExpr; template class ProductExpr; template class QuotientExpr; template class ValueExpr; /** \class BaseExpr * \ingroup Core_Module * Common base class of any symbolic expressions */ template class BaseExpr { public: using Derived = Derived_; constexpr 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, as constructed by SymbolExpr::operator= operator. * */ template constexpr Index eval(const SymbolValue&... values) const { return derived().eval_impl(values...); } /** Evaluate the expression at compile time given the \a values of the symbols. * * If a value is not known at compile-time, returns Eigen::Undefined. * */ template static constexpr Index eval_at_compile_time(const SymbolValue&...) { return Derived::eval_at_compile_time_impl(SymbolValue{}...); } constexpr NegateExpr operator-() const { return NegateExpr(derived()); } constexpr AddExpr> operator+(Index b) const { return AddExpr>(derived(), b); } constexpr AddExpr> operator-(Index a) const { return AddExpr>(derived(), -a); } constexpr ProductExpr> operator*(Index a) const { return ProductExpr>(derived(), a); } constexpr QuotientExpr> operator/(Index a) const { return QuotientExpr>(derived(), a); } friend constexpr AddExpr> operator+(Index a, const BaseExpr& b) { return AddExpr>(b.derived(), a); } friend constexpr AddExpr, ValueExpr<>> operator-(Index a, const BaseExpr& b) { return AddExpr, ValueExpr<>>(-b.derived(), a); } friend constexpr ProductExpr, Derived> operator*(Index a, const BaseExpr& b) { return ProductExpr, Derived>(a, b.derived()); } friend constexpr QuotientExpr, Derived> operator/(Index a, const BaseExpr& b) { return QuotientExpr, Derived>(a, b.derived()); } template constexpr AddExpr>> operator+(internal::FixedInt) const { return AddExpr>>(derived(), ValueExpr>()); } template constexpr AddExpr>> operator-(internal::FixedInt) const { return AddExpr>>(derived(), ValueExpr>()); } template constexpr ProductExpr>> operator*(internal::FixedInt) const { return ProductExpr>>(derived(), ValueExpr>()); } template constexpr QuotientExpr>> operator/(internal::FixedInt) const { return QuotientExpr>>(derived(), ValueExpr>()); } template friend constexpr AddExpr>> operator+(internal::FixedInt, const BaseExpr& b) { return AddExpr>>(b.derived(), ValueExpr>()); } template friend constexpr AddExpr, ValueExpr>> operator-(internal::FixedInt, const BaseExpr& b) { return AddExpr, ValueExpr>>(-b.derived(), ValueExpr>()); } template friend constexpr ProductExpr>, Derived> operator*(internal::FixedInt, const BaseExpr& b) { return ProductExpr>, Derived>(ValueExpr>(), b.derived()); } template friend constexpr QuotientExpr>, Derived> operator/(internal::FixedInt, const BaseExpr& b) { return QuotientExpr>, Derived>(ValueExpr>(), b.derived()); } template constexpr AddExpr operator+(const BaseExpr& b) const { return AddExpr(derived(), b.derived()); } template constexpr AddExpr> operator-(const BaseExpr& b) const { return AddExpr>(derived(), -b.derived()); } template constexpr ProductExpr operator*(const BaseExpr& b) const { return ProductExpr(derived(), b.derived()); } template constexpr 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 statically cast to its base class // BaseExpr. enum { value = internal::is_convertible>::value }; }; // A simple wrapper around an integral value to provide the eval method. // We could also use a free-function symbolic_eval... template class ValueExpr : BaseExpr> { public: constexpr ValueExpr() = default; constexpr ValueExpr(IndexType val) : value_(val) {} template constexpr IndexType eval_impl(const SymbolValue&...) const { return value_; } template static constexpr IndexType eval_at_compile_time_impl(const SymbolValue&...) { return IndexType(Undefined); } protected: IndexType value_; }; // Specialization for compile-time value, // It is similar to ValueExpr(N) but this version helps the compiler to generate better code. template class ValueExpr> : public BaseExpr>> { public: constexpr ValueExpr() = default; constexpr ValueExpr(internal::FixedInt) {} template constexpr Index eval_impl(const SymbolValue&...) const { return Index(N); } template static constexpr Index eval_at_compile_time_impl(const SymbolValue&...) { return Index(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. */ template class SymbolValue : public BaseExpr> {}; template class SymbolValue : public BaseExpr> { public: constexpr SymbolValue() = default; /** Default constructor from the value \a val */ constexpr SymbolValue(Index val) : value_(val) {} /** \returns the stored value of the symbol */ constexpr Index value() const { return value_; } /** \returns the stored value of the symbol at compile time, or Undefined if not known. */ static constexpr Index value_at_compile_time() { return Index(Undefined); } template constexpr Index eval_impl(const SymbolValue&...) const { return value(); } template static constexpr Index eval_at_compile_time_impl(const SymbolValue&...) { return value_at_compile_time(); } protected: Index value_; }; template class SymbolValue> : public BaseExpr>> { public: constexpr SymbolValue() = default; /** Default constructor from the value \a val */ constexpr SymbolValue(internal::FixedInt) {} /** \returns the stored value of the symbol */ constexpr Index value() const { return static_cast(N); } /** \returns the stored value of the symbol at compile time, or Undefined if not known. */ static constexpr Index value_at_compile_time() { return static_cast(N); } template constexpr Index eval_impl(const SymbolValue&...) const { return value(); } template static constexpr Index eval_at_compile_time_impl(const SymbolValue&...) { return value_at_compile_time(); } }; // Find and return a symbol value based on the tag. template struct EvalSymbolValueHelper; // Empty base case, symbol not found. template struct EvalSymbolValueHelper { static constexpr Index eval_impl() { eigen_assert(false && "Symbol not found."); return Index(Undefined); } static constexpr Index eval_at_compile_time_impl() { return Index(Undefined); } }; // We found a symbol value matching the provided Tag! template struct EvalSymbolValueHelper, OtherTypes...> { static constexpr Index eval_impl(const SymbolValue& symbol, const OtherTypes&...) { return symbol.value(); } static constexpr Index eval_at_compile_time_impl(const SymbolValue& symbol, const OtherTypes&...) { return symbol.value_at_compile_time(); } }; // No symbol value in first value, recursive search starting with next. template struct EvalSymbolValueHelper { static constexpr Index eval_impl(const T1&, const OtherTypes&... values) { return EvalSymbolValueHelper::eval_impl(values...); } static constexpr Index eval_at_compile_time_impl(const T1&, const OtherTypes&...) { return EvalSymbolValueHelper::eval_at_compile_time_impl(OtherTypes{}...); } }; /** 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; constexpr SymbolExpr() = default; /** 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. */ constexpr SymbolValue operator=(Index val) const { return SymbolValue(val); } template constexpr SymbolValue> operator=(internal::FixedInt) const { return SymbolValue>{internal::FixedInt{}}; } template constexpr Index eval_impl(const SymbolValue&... values) const { return EvalSymbolValueHelper...>::eval_impl(values...); } template static constexpr Index eval_at_compile_time_impl(const SymbolValue&...) { return EvalSymbolValueHelper...>::eval_at_compile_time_impl( SymbolValue{}...); } }; template class NegateExpr : public BaseExpr> { public: constexpr NegateExpr() = default; constexpr NegateExpr(const Arg0& arg0) : m_arg0(arg0) {} template constexpr Index eval_impl(const SymbolValue&... values) const { return -m_arg0.eval_impl(values...); } template static constexpr Index eval_at_compile_time_impl(const SymbolValue&...) { constexpr Index v = Arg0::eval_at_compile_time_impl(SymbolValue{}...); return (v == Undefined) ? Undefined : -v; } protected: Arg0 m_arg0; }; template class AddExpr : public BaseExpr> { public: constexpr AddExpr() = default; constexpr AddExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} template constexpr Index eval_impl(const SymbolValue&... values) const { return m_arg0.eval_impl(values...) + m_arg1.eval_impl(values...); } template static constexpr Index eval_at_compile_time_impl(const SymbolValue&...) { constexpr Index v0 = Arg0::eval_at_compile_time_impl(SymbolValue{}...); constexpr Index v1 = Arg1::eval_at_compile_time_impl(SymbolValue{}...); return (v0 == Undefined || v1 == Undefined) ? Undefined : v0 + v1; } protected: Arg0 m_arg0; Arg1 m_arg1; }; template class ProductExpr : public BaseExpr> { public: constexpr ProductExpr() = default; constexpr ProductExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} template constexpr Index eval_impl(const SymbolValue&... values) const { return m_arg0.eval_impl(values...) * m_arg1.eval_impl(values...); } template static constexpr Index eval_at_compile_time_impl(const SymbolValue&...) { constexpr Index v0 = Arg0::eval_at_compile_time_impl(SymbolValue{}...); constexpr Index v1 = Arg1::eval_at_compile_time_impl(SymbolValue{}...); return (v0 == Undefined || v1 == Undefined) ? Undefined : v0 * v1; } protected: Arg0 m_arg0; Arg1 m_arg1; }; template class QuotientExpr : public BaseExpr> { public: constexpr QuotientExpr() = default; constexpr QuotientExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} template constexpr Index eval_impl(const SymbolValue&... values) const { return m_arg0.eval_impl(values...) / m_arg1.eval_impl(values...); } template static constexpr Index eval_at_compile_time_impl(const SymbolValue&...) { constexpr Index v0 = Arg0::eval_at_compile_time_impl(SymbolValue{}...); constexpr Index v1 = Arg1::eval_at_compile_time_impl(SymbolValue{}...); return (v0 == Undefined || v1 == Undefined) ? Undefined : v0 / v1; } protected: Arg0 m_arg0; Arg1 m_arg1; }; } // end namespace symbolic } // end namespace Eigen #endif // EIGEN_SYMBOLIC_INDEX_H