// // Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // The authors gratefully acknowledge the support of // Fraunhofer IOSB, Ettlingen, Germany // /// \file strides.hpp Definition for the basic_strides template class #ifndef BOOST_UBLAS_TENSOR_STRIDES_HPP #define BOOST_UBLAS_TENSOR_STRIDES_HPP #include #include #include #include #include #include #include #include namespace boost { namespace numeric { namespace ublas { using first_order = column_major; using last_order = row_major; template class basic_extents; /** @brief Template class for storing tensor strides for iteration with runtime variable size. * * Proxy template class of std::vector. * */ template class basic_strides { public: using base_type = std::vector<__int_type>; static_assert( std::numeric_limits::is_integer, "Static error in boost::numeric::ublas::basic_strides: type must be of type integer."); static_assert(!std::numeric_limits::is_signed, "Static error in boost::numeric::ublas::basic_strides: type must be of type unsigned integer."); static_assert(std::is_same<__layout,first_order>::value || std::is_same<__layout,last_order>::value, "Static error in boost::numeric::ublas::basic_strides: layout type must either first or last order"); using layout_type = __layout; using value_type = typename base_type::value_type; using reference = typename base_type::reference; using const_reference = typename base_type::const_reference; using size_type = typename base_type::size_type; using const_pointer = typename base_type::const_pointer; using const_iterator = typename base_type::const_iterator; /** @brief Default constructs basic_strides * * @code auto ex = basic_strides{}; */ constexpr explicit basic_strides() : _base{} { } /** @brief Constructs basic_strides from basic_extents for the first- and last-order storage formats * * @code auto strides = basic_strides( basic_extents{2,3,4} ); * */ template basic_strides(basic_extents const& s) : _base(s.size(),1) { if(s.empty()) return; if(!s.valid()) throw std::runtime_error("Error in boost::numeric::ublas::basic_strides() : shape is not valid."); if(s.is_vector() || s.is_scalar()) return; if(this->size() < 2) throw std::runtime_error("Error in boost::numeric::ublas::basic_strides() : size of strides must be greater or equal 2."); if constexpr (std::is_same::value){ size_type k = 1ul, kend = this->size(); for(; k < kend; ++k) _base[k] = _base[k-1] * s[k-1]; } else { size_type k = this->size()-2, kend = 0ul; for(; k > kend; --k) _base[k] = _base[k+1] * s[k+1]; _base[0] = _base[1] * s[1]; } } basic_strides(basic_strides const& l) : _base(l._base) {} basic_strides(basic_strides && l ) : _base(std::move(l._base)) {} basic_strides(base_type const& l ) : _base(l) {} basic_strides(base_type && l ) : _base(std::move(l)) {} ~basic_strides() = default; basic_strides& operator=(basic_strides other) { swap (*this, other); return *this; } friend void swap(basic_strides& lhs, basic_strides& rhs) { std::swap(lhs._base , rhs._base); } const_reference operator[] (size_type p) const{ return _base[p]; } const_pointer data() const{ return _base.data(); } const_reference at (size_type p) const{ return _base.at(p); } bool empty() const{ return _base.empty(); } size_type size() const{ return _base.size(); } template bool operator == (basic_strides const& b) const{ return b.base() == this->base(); } template bool operator != (basic_strides const& b) const{ return b.base() != this->base(); } bool operator == (basic_strides const& b) const{ return b._base == _base; } bool operator != (basic_strides const& b) const{ return b._base != _base; } const_iterator begin() const{ return _base.begin(); } const_iterator end() const{ return _base.end(); } void clear() { this->_base.clear(); } base_type const& base() const{ return this->_base; } protected: base_type _base; }; template using strides = basic_strides; namespace detail { /** @brief Returns relative memory index with respect to a multi-index * * @code auto j = access(std::vector{3,4,5}, strides{shape{4,2,3},first_order}); @endcode * * @param[in] i multi-index of length p * @param[in] w stride vector of length p * @returns relative memory location depending on \c i and \c w */ BOOST_UBLAS_INLINE template auto access(std::vector const& i, basic_strides const& w) { const auto p = i.size(); size_type sum = 0u; for(auto r = 0u; r < p; ++r) sum += i[r]*w[r]; return sum; } /** @brief Returns relative memory index with respect to a multi-index * * @code auto j = access(0, strides{shape{4,2,3},first_order}, 2,3,4); @endcode * * @param[in] i first element of the partial multi-index * @param[in] is the following elements of the partial multi-index * @param[in] sum the current relative memory index * @returns relative memory location depending on \c i and \c w */ BOOST_UBLAS_INLINE template auto access(std::size_t sum, basic_strides const& w, std::size_t i, size_types ... is) { sum+=i*w[r]; if constexpr (sizeof...(is) == 0) return sum; else return detail::access(sum,w,std::forward(is)...); } } } } } #endif