// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2014 Benoit Steiner // // 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_CXX11_TENSOR_TENSOR_INDEX_LIST_H #define EIGEN_CXX11_TENSOR_TENSOR_INDEX_LIST_H #if EIGEN_HAS_CONSTEXPR && EIGEN_HAS_VARIADIC_TEMPLATES #define EIGEN_HAS_INDEX_LIST namespace Eigen { /** \internal * * \class TensorIndexList * \ingroup CXX11_Tensor_Module * * \brief Set of classes used to encode a set of Tensor dimensions/indices. * * The indices in the list can be known at compile time or at runtime. A mix * of static and dynamic indices can also be provided if needed. The tensor * code will attempt to take advantage of the indices that are known at * compile time to optimize the code it generates. * * This functionality requires a c++11 compliant compiler. If your compiler * is older you need to use arrays of indices instead. * * Several examples are provided in the cxx11_tensor_index_list.cpp file. * * \sa Tensor */ template struct type2index { static const DenseIndex value = n; EIGEN_DEVICE_FUNC constexpr operator DenseIndex() const { return n; } EIGEN_DEVICE_FUNC void set(DenseIndex val) { eigen_assert(val == n); } }; // This can be used with IndexPairList to get compile-time constant pairs, // such as IndexPairList, type2indexpair<3,4>>(). template struct type2indexpair { static const DenseIndex first = f; static const DenseIndex second = s; constexpr EIGEN_DEVICE_FUNC operator IndexPair() const { return IndexPair(f, s); } EIGEN_DEVICE_FUNC void set(const IndexPair& val) { eigen_assert(val.first == f); eigen_assert(val.second == s); } }; template struct NumTraits > { typedef DenseIndex Real; enum { IsComplex = 0, RequireInitialization = false, ReadCost = 1, AddCost = 1, MulCost = 1 }; EIGEN_DEVICE_FUNC static inline Real epsilon() { return 0; } EIGEN_DEVICE_FUNC static inline Real dummy_precision() { return 0; } EIGEN_DEVICE_FUNC static inline Real highest() { return n; } EIGEN_DEVICE_FUNC static inline Real lowest() { return n; } }; namespace internal { template EIGEN_DEVICE_FUNC void update_value(T& val, DenseIndex new_val) { val = new_val; } template EIGEN_DEVICE_FUNC void update_value(type2index& val, DenseIndex new_val) { val.set(new_val); } template EIGEN_DEVICE_FUNC void update_value(T& val, IndexPair new_val) { val = new_val; } template EIGEN_DEVICE_FUNC void update_value(type2indexpair& val, IndexPair new_val) { val.set(new_val); } template struct is_compile_time_constant { static constexpr bool value = false; }; template struct is_compile_time_constant > { static constexpr bool value = true; }; template struct is_compile_time_constant > { static constexpr bool value = true; }; template struct is_compile_time_constant& > { static constexpr bool value = true; }; template struct is_compile_time_constant& > { static constexpr bool value = true; }; template struct is_compile_time_constant > { static constexpr bool value = true; }; template struct is_compile_time_constant > { static constexpr bool value = true; }; template struct is_compile_time_constant& > { static constexpr bool value = true; }; template struct is_compile_time_constant& > { static constexpr bool value = true; }; template struct IndexTuple; template struct IndexTuple { EIGEN_DEVICE_FUNC constexpr IndexTuple() : head(), others() { } EIGEN_DEVICE_FUNC constexpr IndexTuple(const T& v, const O... o) : head(v), others(o...) { } constexpr static int count = 1 + sizeof...(O); T head; IndexTuple others; typedef T Head; typedef IndexTuple Other; }; template struct IndexTuple { EIGEN_DEVICE_FUNC constexpr IndexTuple() : head() { } EIGEN_DEVICE_FUNC constexpr IndexTuple(const T& v) : head(v) { } constexpr static int count = 1; T head; typedef T Head; }; template struct IndexTupleExtractor; template struct IndexTupleExtractor { typedef typename IndexTupleExtractor::ValType ValType; EIGEN_DEVICE_FUNC static constexpr ValType& get_val(IndexTuple& val) { return IndexTupleExtractor::get_val(val.others); } EIGEN_DEVICE_FUNC static constexpr const ValType& get_val(const IndexTuple& val) { return IndexTupleExtractor::get_val(val.others); } template EIGEN_DEVICE_FUNC static void set_val(IndexTuple& val, V& new_val) { IndexTupleExtractor::set_val(val.others, new_val); } }; template struct IndexTupleExtractor<0, T, O...> { typedef T ValType; EIGEN_DEVICE_FUNC static constexpr ValType& get_val(IndexTuple& val) { return val.head; } EIGEN_DEVICE_FUNC static constexpr const ValType& get_val(const IndexTuple& val) { return val.head; } template EIGEN_DEVICE_FUNC static void set_val(IndexTuple& val, V& new_val) { val.head = new_val; } }; template EIGEN_DEVICE_FUNC constexpr typename IndexTupleExtractor::ValType& array_get(IndexTuple& tuple) { return IndexTupleExtractor::get_val(tuple); } template EIGEN_DEVICE_FUNC constexpr const typename IndexTupleExtractor::ValType& array_get(const IndexTuple& tuple) { return IndexTupleExtractor::get_val(tuple); } template struct array_size > { static const size_t value = IndexTuple::count; }; template struct array_size > { static const size_t value = IndexTuple::count; }; template struct tuple_coeff { template EIGEN_DEVICE_FUNC static constexpr ValueT get(const DenseIndex i, const IndexTuple& t) { // return array_get(t) * (i == Idx) + tuple_coeff::get(i, t) * (i != Idx); return (i == Idx ? array_get(t) : tuple_coeff::get(i, t)); } template EIGEN_DEVICE_FUNC static void set(const DenseIndex i, IndexTuple& t, const ValueT& value) { if (i == Idx) { update_value(array_get(t), value); } else { tuple_coeff::set(i, t, value); } } template EIGEN_DEVICE_FUNC static constexpr bool value_known_statically(const DenseIndex i, const IndexTuple& t) { return ((i == Idx) & is_compile_time_constant::ValType>::value) || tuple_coeff::value_known_statically(i, t); } template EIGEN_DEVICE_FUNC static constexpr bool values_up_to_known_statically(const IndexTuple& t) { return is_compile_time_constant::ValType>::value && tuple_coeff::values_up_to_known_statically(t); } template EIGEN_DEVICE_FUNC static constexpr bool values_up_to_statically_known_to_increase(const IndexTuple& t) { return is_compile_time_constant::ValType>::value && is_compile_time_constant::ValType>::value && array_get(t) > array_get(t) && tuple_coeff::values_up_to_statically_known_to_increase(t); } }; template struct tuple_coeff<0, ValueT> { template EIGEN_DEVICE_FUNC static constexpr ValueT get(const DenseIndex /*i*/, const IndexTuple& t) { // eigen_assert (i == 0); // gcc fails to compile assertions in constexpr return array_get<0>(t)/* * (i == 0)*/; } template EIGEN_DEVICE_FUNC static void set(const DenseIndex i, IndexTuple& t, const ValueT value) { eigen_assert (i == 0); update_value(array_get<0>(t), value); } template EIGEN_DEVICE_FUNC static constexpr bool value_known_statically(const DenseIndex i, const IndexTuple&) { return is_compile_time_constant::ValType>::value & (i == 0); } template EIGEN_DEVICE_FUNC static constexpr bool values_up_to_known_statically(const IndexTuple&) { return is_compile_time_constant::ValType>::value; } template EIGEN_DEVICE_FUNC static constexpr bool values_up_to_statically_known_to_increase(const IndexTuple&) { return true; } }; } // namespace internal template struct IndexList : internal::IndexTuple { EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC constexpr DenseIndex operator[] (const DenseIndex i) const { return internal::tuple_coeff >::value-1, DenseIndex>::get(i, *this); } EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC constexpr DenseIndex get(const DenseIndex i) const { return internal::tuple_coeff >::value-1, DenseIndex>::get(i, *this); } EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC void set(const DenseIndex i, const DenseIndex value) { return internal::tuple_coeff >::value-1, DenseIndex>::set(i, *this, value); } EIGEN_DEVICE_FUNC constexpr IndexList(const internal::IndexTuple& other) : internal::IndexTuple(other) { } EIGEN_DEVICE_FUNC constexpr IndexList(FirstType& first, OtherTypes... other) : internal::IndexTuple(first, other...) { } EIGEN_DEVICE_FUNC constexpr IndexList() : internal::IndexTuple() { } EIGEN_DEVICE_FUNC constexpr bool value_known_statically(const DenseIndex i) const { return internal::tuple_coeff >::value-1, DenseIndex>::value_known_statically(i, *this); } EIGEN_DEVICE_FUNC constexpr bool all_values_known_statically() const { return internal::tuple_coeff >::value-1, DenseIndex>::values_up_to_known_statically(*this); } EIGEN_DEVICE_FUNC constexpr bool values_statically_known_to_increase() const { return internal::tuple_coeff >::value-1, DenseIndex>::values_up_to_statically_known_to_increase(*this); } }; template constexpr IndexList make_index_list(FirstType val1, OtherTypes... other_vals) { return IndexList(val1, other_vals...); } template struct IndexPairList : internal::IndexTuple { EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC constexpr IndexPair operator[] (const DenseIndex i) const { return internal::tuple_coeff >::value-1, IndexPair>::get(i, *this); } EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC void set(const DenseIndex i, const IndexPair value) { return internal::tuple_coeff>::value-1, IndexPair >::set(i, *this, value); } EIGEN_DEVICE_FUNC constexpr IndexPairList(const internal::IndexTuple& other) : internal::IndexTuple(other) { } EIGEN_DEVICE_FUNC constexpr IndexPairList() : internal::IndexTuple() { } EIGEN_DEVICE_FUNC constexpr bool value_known_statically(const DenseIndex i) const { return internal::tuple_coeff >::value-1, DenseIndex>::value_known_statically(i, *this); } }; namespace internal { template size_t array_prod(const IndexList& sizes) { size_t result = 1; for (int i = 0; i < array_size >::value; ++i) { result *= sizes[i]; } return result; } template struct array_size > { static const size_t value = array_size >::value; }; template struct array_size > { static const size_t value = array_size >::value; }; template struct array_size > { static const size_t value = std::tuple_size >::value; }; template struct array_size > { static const size_t value = std::tuple_size >::value; }; template EIGEN_DEVICE_FUNC constexpr DenseIndex array_get(IndexList& a) { return IndexTupleExtractor::get_val(a); } template EIGEN_DEVICE_FUNC constexpr DenseIndex array_get(const IndexList& a) { return IndexTupleExtractor::get_val(a); } template struct index_known_statically_impl { EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex) { return false; } }; template struct index_known_statically_impl > { EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex i) { return IndexList().value_known_statically(i); } }; template struct index_known_statically_impl > { EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex i) { return IndexList().value_known_statically(i); } }; template struct all_indices_known_statically_impl { static constexpr bool run() { return false; } }; template struct all_indices_known_statically_impl > { EIGEN_DEVICE_FUNC static constexpr bool run() { return IndexList().all_values_known_statically(); } }; template struct all_indices_known_statically_impl > { EIGEN_DEVICE_FUNC static constexpr bool run() { return IndexList().all_values_known_statically(); } }; template struct indices_statically_known_to_increase_impl { EIGEN_DEVICE_FUNC static constexpr bool run() { return false; } }; template struct indices_statically_known_to_increase_impl > { EIGEN_DEVICE_FUNC static constexpr bool run() { return Eigen::IndexList().values_statically_known_to_increase(); } }; template struct indices_statically_known_to_increase_impl > { EIGEN_DEVICE_FUNC static constexpr bool run() { return Eigen::IndexList().values_statically_known_to_increase(); } }; template struct index_statically_eq_impl { EIGEN_DEVICE_FUNC static constexpr bool run(DenseIndex, DenseIndex) { return false; } }; template struct index_statically_eq_impl > { EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex i, const DenseIndex value) { return IndexList().value_known_statically(i) & (IndexList().get(i) == value); } }; template struct index_statically_eq_impl > { EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex i, const DenseIndex value) { return IndexList().value_known_statically(i) & (IndexList().get(i) == value); } }; template struct index_statically_ne_impl { EIGEN_DEVICE_FUNC static constexpr bool run(DenseIndex, DenseIndex) { return false; } }; template struct index_statically_ne_impl > { EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex i, const DenseIndex value) { return IndexList().value_known_statically(i) & (IndexList().get(i) != value); } }; template struct index_statically_ne_impl > { EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex i, const DenseIndex value) { return IndexList().value_known_statically(i) & (IndexList().get(i) != value); } }; template struct index_statically_gt_impl { EIGEN_DEVICE_FUNC static constexpr bool run(DenseIndex, DenseIndex) { return false; } }; template struct index_statically_gt_impl > { EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex i, const DenseIndex value) { return IndexList().value_known_statically(i) & (IndexList().get(i) > value); } }; template struct index_statically_gt_impl > { EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex i, const DenseIndex value) { return IndexList().value_known_statically(i) & (IndexList().get(i) > value); } }; template struct index_statically_lt_impl { EIGEN_DEVICE_FUNC static constexpr bool run(DenseIndex, DenseIndex) { return false; } }; template struct index_statically_lt_impl > { EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex i, const DenseIndex value) { return IndexList().value_known_statically(i) & (IndexList().get(i) < value); } }; template struct index_statically_lt_impl > { EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex i, const DenseIndex value) { return IndexList().value_known_statically(i) & (IndexList().get(i) < value); } }; template struct index_pair_first_statically_eq_impl { EIGEN_DEVICE_FUNC static constexpr bool run(DenseIndex, DenseIndex) { return false; } }; template struct index_pair_first_statically_eq_impl > { EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex i, const DenseIndex value) { return IndexPairList().value_known_statically(i) & (IndexPairList().operator[](i).first == value); } }; template struct index_pair_first_statically_eq_impl > { EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex i, const DenseIndex value) { return IndexPairList().value_known_statically(i) & (IndexPairList().operator[](i).first == value); } }; template struct index_pair_second_statically_eq_impl { EIGEN_DEVICE_FUNC static constexpr bool run(DenseIndex, DenseIndex) { return false; } }; template struct index_pair_second_statically_eq_impl > { EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex i, const DenseIndex value) { return IndexPairList().value_known_statically(i) & (IndexPairList().operator[](i).second == value); } }; template struct index_pair_second_statically_eq_impl > { EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex i, const DenseIndex value) { return IndexPairList().value_known_statically(i) & (IndexPairList().operator[](i).second == value); } }; } // end namespace internal } // end namespace Eigen #else namespace Eigen { namespace internal { template struct index_known_statically_impl { static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool run(const DenseIndex) { return false; } }; template struct all_indices_known_statically_impl { static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool run() { return false; } }; template struct indices_statically_known_to_increase_impl { static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool run() { return false; } }; template struct index_statically_eq_impl { static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool run(DenseIndex, DenseIndex) { return false; } }; template struct index_statically_ne_impl { static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool run(DenseIndex, DenseIndex) { return false; } }; template struct index_statically_gt_impl { static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool run(DenseIndex, DenseIndex) { return false; } }; template struct index_statically_lt_impl { static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool run(DenseIndex, DenseIndex) { return false; } }; template struct index_pair_first_statically_eq_impl { static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool run(DenseIndex, DenseIndex) { return false; } }; template struct index_pair_second_statically_eq_impl { static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool run(DenseIndex, DenseIndex) { return false; } }; } // end namespace internal } // end namespace Eigen #endif namespace Eigen { namespace internal { template static EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR bool index_known_statically(DenseIndex i) { return index_known_statically_impl::run(i); } template static EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR bool all_indices_known_statically() { return all_indices_known_statically_impl::run(); } template static EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR bool indices_statically_known_to_increase() { return indices_statically_known_to_increase_impl::run(); } template static EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR bool index_statically_eq(DenseIndex i, DenseIndex value) { return index_statically_eq_impl::run(i, value); } template static EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR bool index_statically_ne(DenseIndex i, DenseIndex value) { return index_statically_ne_impl::run(i, value); } template static EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR bool index_statically_gt(DenseIndex i, DenseIndex value) { return index_statically_gt_impl::run(i, value); } template static EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR bool index_statically_lt(DenseIndex i, DenseIndex value) { return index_statically_lt_impl::run(i, value); } template static EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR bool index_pair_first_statically_eq(DenseIndex i, DenseIndex value) { return index_pair_first_statically_eq_impl::run(i, value); } template static EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR bool index_pair_second_statically_eq(DenseIndex i, DenseIndex value) { return index_pair_second_statically_eq_impl::run(i, value); } } // end namespace internal } // end namespace Eigen #endif // EIGEN_CXX11_TENSOR_TENSOR_INDEX_LIST_H