• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 //  Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com
3 //
4 //  Distributed under the Boost Software License, Version 1.0. (See
5 //  accompanying file LICENSE_1_0.txt or copy at
6 //  http://www.boost.org/LICENSE_1_0.txt)
7 //
8 //  The authors gratefully acknowledge the support of
9 //  Fraunhofer IOSB, Ettlingen, Germany
10 //
11 /// \file strides.hpp Definition for the basic_strides template class
12 
13 
14 #ifndef BOOST_UBLAS_TENSOR_STRIDES_HPP
15 #define BOOST_UBLAS_TENSOR_STRIDES_HPP
16 
17 #include <vector>
18 #include <limits>
19 #include <numeric>
20 #include <stdexcept>
21 #include <initializer_list>
22 #include <algorithm>
23 #include <cassert>
24 
25 #include <boost/numeric/ublas/functional.hpp>
26 
27 namespace boost {
28 namespace numeric {
29 namespace ublas {
30 
31 using first_order = column_major;
32 using last_order = row_major;
33 
34 template<class T>
35 class basic_extents;
36 
37 
38 /** @brief Template class for storing tensor strides for iteration with runtime variable size.
39  *
40  * Proxy template class of std::vector<int_type>.
41  *
42  */
43 template<class __int_type, class __layout>
44 class basic_strides
45 {
46 public:
47 
48 	using base_type = std::vector<__int_type>;
49 
50 	static_assert( std::numeric_limits<typename base_type::value_type>::is_integer,
51 								 "Static error in boost::numeric::ublas::basic_strides: type must be of type integer.");
52 	static_assert(!std::numeric_limits<typename base_type::value_type>::is_signed,
53 								"Static error in boost::numeric::ublas::basic_strides: type must be of type unsigned integer.");
54 	static_assert(std::is_same<__layout,first_order>::value || std::is_same<__layout,last_order>::value,
55 								"Static error in boost::numeric::ublas::basic_strides: layout type must either first or last order");
56 
57 
58 	using layout_type = __layout;
59 	using value_type = typename base_type::value_type;
60 	using reference = typename base_type::reference;
61 	using const_reference = typename base_type::const_reference;
62 	using size_type = typename base_type::size_type;
63 	using const_pointer = typename base_type::const_pointer;
64 	using const_iterator = typename base_type::const_iterator;
65 
66 
67 	/** @brief Default constructs basic_strides
68 	 *
69 	 * @code auto ex = basic_strides<unsigned>{};
70 	 */
basic_strides()71 	constexpr explicit basic_strides()
72 		: _base{}
73 	{
74 	}
75 
76 	/** @brief Constructs basic_strides from basic_extents for the first- and last-order storage formats
77 	 *
78 	 * @code auto strides = basic_strides<unsigned>( basic_extents<std::size_t>{2,3,4} );
79 	 *
80 	 */
81 	template <class T>
basic_strides(basic_extents<T> const & s)82 	basic_strides(basic_extents<T> const& s)
83 			: _base(s.size(),1)
84 	{
85 		if(s.empty())
86 			return;
87 
88 		if(!s.valid())
89 			throw std::runtime_error("Error in boost::numeric::ublas::basic_strides() : shape is not valid.");
90 
91 		if(s.is_vector() || s.is_scalar())
92 			return;
93 
94 		if(this->size() < 2)
95 			throw std::runtime_error("Error in boost::numeric::ublas::basic_strides() : size of strides must be greater or equal 2.");
96 
97 
98 		if constexpr (std::is_same<layout_type,first_order>::value){
99 			size_type k = 1ul, kend = this->size();
100 			for(; k < kend; ++k)
101 				_base[k] = _base[k-1] * s[k-1];
102 		}
103 		else {
104 			size_type k = this->size()-2, kend = 0ul;
105 			for(; k > kend; --k)
106 				_base[k] = _base[k+1] * s[k+1];
107 			_base[0] = _base[1] * s[1];
108 		}
109 	}
110 
basic_strides(basic_strides const & l)111 	basic_strides(basic_strides const& l)
112 	    : _base(l._base)
113 	{}
114 
basic_strides(basic_strides && l)115 	basic_strides(basic_strides && l )
116 	    : _base(std::move(l._base))
117 	{}
118 
basic_strides(base_type const & l)119 	basic_strides(base_type const& l )
120 	    : _base(l)
121 	{}
122 
basic_strides(base_type && l)123 	basic_strides(base_type && l )
124 			: _base(std::move(l))
125 	{}
126 
127 	~basic_strides() = default;
128 
129 
operator =(basic_strides other)130 	basic_strides& operator=(basic_strides other)
131 	{
132 		swap (*this, other);
133 		return *this;
134 	}
135 
swap(basic_strides & lhs,basic_strides & rhs)136 	friend void swap(basic_strides& lhs, basic_strides& rhs) {
137 		std::swap(lhs._base   , rhs._base);
138 	}
139 
operator [](size_type p) const140 	const_reference operator[] (size_type p) const{
141 		return _base[p];
142 	}
143 
data() const144 	const_pointer data() const{
145 		return _base.data();
146 	}
147 
at(size_type p) const148 	const_reference at (size_type p) const{
149 		return _base.at(p);
150 	}
151 
152 
empty() const153 	bool empty() const{
154 		return _base.empty();
155 	}
156 
size() const157 	size_type size() const{
158 		return _base.size();
159 	}
160 
161 	template<class other_layout>
operator ==(basic_strides<value_type,other_layout> const & b) const162 	bool operator == (basic_strides<value_type, other_layout> const& b) const{
163 		return b.base() == this->base();
164 	}
165 
166 	template<class other_layout>
operator !=(basic_strides<value_type,other_layout> const & b) const167 	bool operator != (basic_strides<value_type, other_layout> const& b) const{
168 		return b.base() != this->base();
169 	}
170 
operator ==(basic_strides const & b) const171 	bool operator == (basic_strides const& b) const{
172 		return b._base == _base;
173 	}
174 
operator !=(basic_strides const & b) const175 	bool operator != (basic_strides const& b) const{
176 		return b._base != _base;
177 	}
178 
begin() const179 	const_iterator begin() const{
180 		return _base.begin();
181 	}
182 
end() const183 	const_iterator end() const{
184 		return _base.end();
185 	}
186 
clear()187 	void clear() {
188 		this->_base.clear();
189 	}
190 
base() const191 	base_type const& base() const{
192 		return this->_base;
193 	}
194 
195 
196 protected:
197 	base_type _base;
198 };
199 
200 template<class layout_type>
201 using strides = basic_strides<std::size_t, layout_type>;
202 
203 namespace detail {
204 
205 
206 /** @brief Returns relative memory index with respect to a multi-index
207  *
208  * @code auto j = access(std::vector{3,4,5}, strides{shape{4,2,3},first_order}); @endcode
209  *
210  * @param[in] i multi-index of length p
211  * @param[in] w stride vector of length p
212  * @returns relative memory location depending on \c i and \c w
213 */
214 BOOST_UBLAS_INLINE
215 template<class size_type, class layout_type>
access(std::vector<size_type> const & i,basic_strides<size_type,layout_type> const & w)216 auto access(std::vector<size_type> const& i, basic_strides<size_type,layout_type> const& w)
217 {
218 	const auto p = i.size();
219 	size_type sum = 0u;
220 	for(auto r = 0u; r < p; ++r)
221 		sum += i[r]*w[r];
222 	return sum;
223 }
224 
225 /** @brief Returns relative memory index with respect to a multi-index
226  *
227  * @code auto j = access(0, strides{shape{4,2,3},first_order}, 2,3,4); @endcode
228  *
229  * @param[in] i   first element of the partial multi-index
230  * @param[in] is  the following elements of the partial multi-index
231  * @param[in] sum the current relative memory index
232  * @returns relative memory location depending on \c i and \c w
233 */
234 BOOST_UBLAS_INLINE
235 template<std::size_t r, class layout_type, class ... size_types>
access(std::size_t sum,basic_strides<std::size_t,layout_type> const & w,std::size_t i,size_types...is)236 auto access(std::size_t sum, basic_strides<std::size_t, layout_type> const& w, std::size_t i, size_types ... is)
237 {
238 	sum+=i*w[r];
239 	if constexpr (sizeof...(is) == 0)
240 		return sum;
241 	else
242 		return detail::access<r+1>(sum,w,std::forward<size_types>(is)...);
243 }
244 
245 }
246 
247 }
248 }
249 }
250 
251 #endif
252