// 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_DIMENSIONS_H #define EIGEN_CXX11_TENSOR_TENSOR_DIMENSIONS_H namespace Eigen { /** \internal * * \class TensorDimensions * \ingroup CXX11_Tensor_Module * * \brief Set of classes used to encode and store the dimensions of a Tensor. * * The Sizes class encodes as part of the type the number of dimensions and the * sizes corresponding to each dimension. It uses no storage space since it is * entirely known at compile time. * The DSizes class is its dynamic sibling: the number of dimensions is known * at compile time but the sizes are set during execution. * * \sa Tensor */ // Can't use std::pair on cuda devices template struct IndexPair { EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE IndexPair() : first(0), second(0) { } EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE IndexPair(Index f, Index s) : first(f), second(s) { } Index first; Index second; }; // Boilerplate code namespace internal { template struct dget { static const std::size_t value = get::value; }; template struct fixed_size_tensor_index_linearization_helper { template EIGEN_DEVICE_FUNC static inline Index run(array const& indices, const Dimensions& dimensions) { return array_get(indices) + dget::value * fixed_size_tensor_index_linearization_helper::run(indices, dimensions); } }; template struct fixed_size_tensor_index_linearization_helper { template EIGEN_DEVICE_FUNC static inline Index run(array const& indices, const Dimensions&) { return array_get(indices); } }; } // end namespace internal // Fixed size #ifndef EIGEN_EMULATE_CXX11_META_H template struct Sizes : internal::numeric_list { typedef internal::numeric_list Base; static const std::size_t total_size = internal::arg_prod(Indices...); EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE size_t rank() const { return Base::count; } static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::size_t TotalSize() { return internal::arg_prod(Indices...); } Sizes() { } template explicit Sizes(const array& /*indices*/) { // todo: add assertion } #ifdef EIGEN_HAS_VARIADIC_TEMPLATES template Sizes(DenseIndex...) { } explicit Sizes(std::initializer_list /*l*/) { // todo: add assertion } #endif template Sizes& operator = (const T& /*other*/) { // add assertion failure if the size of other is different return *this; } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE size_t IndexOfColMajor(const array& indices) const { return internal::fixed_size_tensor_index_linearization_helper::run(indices, *static_cast(this)); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE size_t IndexOfRowMajor(const array& indices) const { return internal::fixed_size_tensor_index_linearization_helper::run(indices, *static_cast(this)); } }; template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::size_t array_prod(const Sizes&) { return Sizes::total_size; } #else template struct non_zero_size { typedef internal::type2val type; }; template <> struct non_zero_size<0> { typedef internal::null_type type; }; template struct Sizes { typedef typename internal::make_type_list::type, typename non_zero_size::type, typename non_zero_size::type, typename non_zero_size::type, typename non_zero_size::type >::type Base; static const size_t count = Base::count; static const std::size_t total_size = internal::arg_prod::value; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE size_t rank() const { return count; } static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE size_t TotalSize() { return internal::arg_prod::value; } Sizes() { } template explicit Sizes(const array& indices) { // todo: add assertion } #ifdef EIGEN_HAS_VARIADIC_TEMPLATES template Sizes(DenseIndex... indices) { } explicit Sizes(std::initializer_list l) { // todo: add assertion } #else EIGEN_DEVICE_FUNC explicit Sizes(const DenseIndex i0) { } EIGEN_DEVICE_FUNC explicit Sizes(const DenseIndex i0, const DenseIndex i1) { } EIGEN_DEVICE_FUNC explicit Sizes(const DenseIndex i0, const DenseIndex i1, const DenseIndex i2) { } EIGEN_DEVICE_FUNC explicit Sizes(const DenseIndex i0, const DenseIndex i1, const DenseIndex i2, const DenseIndex i3) { } EIGEN_DEVICE_FUNC explicit Sizes(const DenseIndex i0, const DenseIndex i1, const DenseIndex i2, const DenseIndex i3, const DenseIndex i4) { } #endif template Sizes& operator = (const T& other) { // to do: check the size of other return *this; } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE size_t IndexOfColMajor(const array& indices) const { return internal::fixed_size_tensor_index_linearization_helper::run(indices, *static_cast(this); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE size_t IndexOfRowMajor(const array& indices) const { return internal::fixed_size_tensor_index_linearization_helper::run(indices, *static_cast(this); } }; template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::size_t array_prod(const Sizes&) { return Sizes::total_size; }; #endif // Boilerplate namespace internal { template struct tensor_index_linearization_helper { static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index run(array const& indices, array const& dimensions) { return array_get(indices) + array_get(dimensions) * tensor_index_linearization_helper::run(indices, dimensions); } }; template struct tensor_index_linearization_helper { static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index run(array const& indices, array const&) { return array_get(indices); } }; } // end namespace internal // Dynamic size template struct DSizes : array { typedef array Base; static const std::size_t count = NumDims; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE size_t rank() const { return NumDims; } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE size_t TotalSize() const { return internal::array_prod(*static_cast(this)); } EIGEN_DEVICE_FUNC DSizes() { for (int i = 0 ; i < NumDims; ++i) { (*this)[i] = 0; } } EIGEN_DEVICE_FUNC explicit DSizes(const array& a) : Base(a) { } #ifdef EIGEN_HAS_VARIADIC_TEMPLATES template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit DSizes(DenseIndex firstDimension, IndexTypes... otherDimensions) { EIGEN_STATIC_ASSERT(sizeof...(otherDimensions) + 1 == NumDims, YOU_MADE_A_PROGRAMMING_MISTAKE) (*this) = array{{firstDimension, otherDimensions...}}; } #else EIGEN_DEVICE_FUNC explicit DSizes(const DenseIndex i0) { eigen_assert(NumDims == 1); (*this)[0] = i0; } EIGEN_DEVICE_FUNC explicit DSizes(const DenseIndex i0, const DenseIndex i1) { eigen_assert(NumDims == 2); (*this)[0] = i0; (*this)[1] = i1; } EIGEN_DEVICE_FUNC explicit DSizes(const DenseIndex i0, const DenseIndex i1, const DenseIndex i2) { eigen_assert(NumDims == 3); (*this)[0] = i0; (*this)[1] = i1; (*this)[2] = i2; } EIGEN_DEVICE_FUNC explicit DSizes(const DenseIndex i0, const DenseIndex i1, const DenseIndex i2, const DenseIndex i3) { eigen_assert(NumDims == 4); (*this)[0] = i0; (*this)[1] = i1; (*this)[2] = i2; (*this)[3] = i3; } EIGEN_DEVICE_FUNC explicit DSizes(const DenseIndex i0, const DenseIndex i1, const DenseIndex i2, const DenseIndex i3, const DenseIndex i4) { eigen_assert(NumDims == 5); (*this)[0] = i0; (*this)[1] = i1; (*this)[2] = i2; (*this)[3] = i3; (*this)[4] = i4; } #endif EIGEN_DEVICE_FUNC DSizes& operator = (const array& other) { *static_cast(this) = other; return *this; } // A constexpr would be so much better here EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE size_t IndexOfColMajor(const array& indices) const { return internal::tensor_index_linearization_helper::run(indices, *static_cast(this)); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE size_t IndexOfRowMajor(const array& indices) const { return internal::tensor_index_linearization_helper::run(indices, *static_cast(this)); } }; // Boilerplate namespace internal { template struct tensor_vsize_index_linearization_helper { static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index run(array const& indices, std::vector const& dimensions) { return array_get(indices) + array_get(dimensions) * tensor_vsize_index_linearization_helper::run(indices, dimensions); } }; template struct tensor_vsize_index_linearization_helper { static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index run(array const& indices, std::vector const&) { return array_get(indices); } }; } // end namespace internal namespace internal { template struct array_size > { static const size_t value = NumDims; }; template struct array_size > { static const size_t value = NumDims; }; #ifndef EIGEN_EMULATE_CXX11_META_H template struct array_size > { static const size_t value = Sizes::count; }; template struct array_size > { static const size_t value = Sizes::count; }; template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::size_t array_get(const Sizes&) { return get >::value; } #else template struct array_size > { static const size_t value = Sizes::count; }; template struct array_size > { static const size_t value = Sizes::count; }; template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::size_t array_get(const Sizes& a) { return get::Base>::value; }; #endif template struct sizes_match_up_to_dim { static inline bool run(Dims1& dims1, Dims2& dims2) { return (array_get(dims1) == array_get(dims2)) & sizes_match_up_to_dim::run(dims1, dims2); } }; template struct sizes_match_up_to_dim { static inline bool run(Dims1& dims1, Dims2& dims2) { return (array_get<0>(dims1) == array_get<0>(dims2)); } }; } // end namespace internal template bool dimensions_match(Dims1& dims1, Dims2& dims2) { if (internal::array_size::value != internal::array_size::value) { return false; } return internal::sizes_match_up_to_dim::value-1>::run(dims1, dims2); } } // end namespace Eigen #endif // EIGEN_CXX11_TENSOR_TENSOR_DIMENSIONS_H