1 // Copyright (c) 2018-2019 Cem Bassoy
2 //
3 // Distributed under the Boost Software License, Version 1.0. (See
4 // accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // The authors gratefully acknowledge the support of
8 // Fraunhofer and Google in producing this work
9 // which started as a Google Summer of Code project.
10 //
11
12
13 #include <iostream>
14 #include <algorithm>
15 #include <vector>
16 #include <boost/numeric/ublas/tensor/algorithms.hpp>
17 #include <boost/numeric/ublas/tensor/extents.hpp>
18 #include <boost/numeric/ublas/tensor/strides.hpp>
19 #include "utility.hpp"
20
21 #include <boost/test/unit_test.hpp>
22
23
24 BOOST_AUTO_TEST_SUITE ( test_tensor_algorithms,
25 * boost::unit_test::depends_on("test_extents")
26 * boost::unit_test::depends_on("test_strides"))
27
28
29 using test_types = zip<int,long,float,double,std::complex<float>>::with_t<boost::numeric::ublas::first_order, boost::numeric::ublas::last_order>;
30 using test_types2 = std::tuple<int,long,float,double,std::complex<float>>;
31
32 struct fixture
33 {
34 using extents_type = boost::numeric::ublas::shape;
fixturefixture35 fixture()
36 : extents {
37 extents_type{1,1}, // 1
38 extents_type{1,2}, // 2
39 extents_type{2,1}, // 3
40 extents_type{2,3}, // 4
41 extents_type{2,3,1}, // 5
42 extents_type{4,1,3}, // 6
43 extents_type{1,2,3}, // 7
44 extents_type{4,2,3}, // 8
45 extents_type{4,2,3,5} } // 9
46 {
47 }
48 std::vector<extents_type> extents;
49 };
50
51
52
53
BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_algorithms_copy,value,test_types2,fixture)54 BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_copy, value, test_types2, fixture )
55 {
56 using namespace boost::numeric;
57 using value_type = value;
58 using vector_type = std::vector<value_type>;
59
60
61 for(auto const& n : extents) {
62
63 auto a = vector_type(n.product());
64 auto b = vector_type(n.product());
65 auto c = vector_type(n.product());
66
67 auto wa = ublas::strides<ublas::first_order>(n);
68 auto wb = ublas::strides<ublas::last_order> (n);
69 auto wc = ublas::strides<ublas::first_order>(n);
70
71 auto v = value_type{};
72 for(auto i = 0ul; i < a.size(); ++i, v+=1){
73 a[i]=v;
74 }
75
76 ublas::copy( n.size(), n.data(), b.data(), wb.data(), a.data(), wa.data() );
77 ublas::copy( n.size(), n.data(), c.data(), wc.data(), b.data(), wb.data() );
78
79 for(auto i = 1ul; i < c.size(); ++i)
80 BOOST_CHECK_EQUAL( c[i], a[i] );
81
82 using size_type = typename ublas::strides<ublas::first_order>::value_type;
83 size_type const*const p0 = nullptr;
84 BOOST_CHECK_THROW( ublas::copy( n.size(), p0, c.data(), wc.data(), b.data(), wb.data() ), std::length_error );
85 BOOST_CHECK_THROW( ublas::copy( n.size(), n.data(), c.data(), p0, b.data(), wb.data() ), std::length_error );
86 BOOST_CHECK_THROW( ublas::copy( n.size(), n.data(), c.data(), wc.data(), b.data(), p0 ), std::length_error );
87
88 value_type* c0 = nullptr;
89 BOOST_CHECK_THROW( ublas::copy( n.size(), n.data(), c0, wc.data(), b.data(), wb.data() ), std::length_error );
90 }
91
92 // special case rank == 0
93 {
94 auto n = ublas::shape{};
95
96 auto a = vector_type(n.product());
97 auto b = vector_type(n.product());
98 auto c = vector_type(n.product());
99
100
101 auto wa = ublas::strides<ublas::first_order>(n);
102 auto wb = ublas::strides<ublas::last_order> (n);
103 auto wc = ublas::strides<ublas::first_order>(n);
104
105 ublas::copy( n.size(), n.data(), b.data(), wb.data(), a.data(), wa.data() );
106 ublas::copy( n.size(), n.data(), c.data(), wc.data(), b.data(), wb.data() );
107
108
109
110 BOOST_CHECK_NO_THROW( ublas::copy( n.size(), n.data(), c.data(), wc.data(), b.data(), wb.data() ) );
111
112 }
113
114
115
116
117
118 }
119
120
121
BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_algorithms_transform,value,test_types2,fixture)122 BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_transform, value, test_types2, fixture )
123 {
124 using namespace boost::numeric;
125 using value_type = value;
126 using vector_type = std::vector<value_type>;
127
128
129 for(auto const& n : extents) {
130
131 auto a = vector_type(n.product());
132 auto b = vector_type(n.product());
133 auto c = vector_type(n.product());
134
135 auto wa = ublas::strides<ublas::first_order>(n);
136 auto wb = ublas::strides<ublas::last_order> (n);
137 auto wc = ublas::strides<ublas::first_order>(n);
138
139 auto v = value_type{};
140 for(auto i = 0ul; i < a.size(); ++i, v+=1){
141 a[i]=v;
142 }
143
144 ublas::transform( n.size(), n.data(), b.data(), wb.data(), a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} );
145 ublas::transform( n.size(), n.data(), c.data(), wc.data(), b.data(), wb.data(), [](value_type const& a){ return a - value_type(1);} );
146
147 for(auto i = 1ul; i < c.size(); ++i)
148 BOOST_CHECK_EQUAL( c[i], a[i] );
149
150 }
151 }
152
153
154
BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_algorithms_accumulate,value,test_types2,fixture)155 BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_accumulate, value, test_types2, fixture )
156 {
157 using namespace boost::numeric;
158 using value_type = value;
159 using vector_type = std::vector<value_type>;
160
161
162 for(auto const& n : extents) {
163
164 auto const s = n.product();
165
166 auto a = vector_type(n.product());
167 // auto b = vector_type(n.product());
168 // auto c = vector_type(n.product());
169
170 auto wa = ublas::strides<ublas::first_order>(n);
171 // auto wb = ublas::strides<ublas::last_order> (n);
172 // auto wc = ublas::strides<ublas::first_order>(n);
173
174 auto v = value_type{};
175 for(auto i = 0ul; i < a.size(); ++i, v+=value_type(1)){
176 a[i]=v;
177 }
178
179 auto acc = ublas::accumulate( n.size(), n.data(), a.data(), wa.data(), v);
180
181 BOOST_CHECK_EQUAL( acc, value_type( s*(s+1) / 2 ) );
182
183
184 auto acc2 = ublas::accumulate( n.size(), n.data(), a.data(), wa.data(), v,
185 [](auto const& l, auto const& r){return l + r; });
186
187 BOOST_CHECK_EQUAL( acc2, value_type( s*(s+1) / 2 ) );
188
189 }
190 }
191
192
193
194
195 template<class V>
init(std::vector<V> & a)196 void init(std::vector<V>& a)
197 {
198 auto v = V(1);
199 for(auto i = 0u; i < a.size(); ++i, ++v){
200 a[i] = v;
201 }
202 }
203
204 template<class V>
init(std::vector<std::complex<V>> & a)205 void init(std::vector<std::complex<V>>& a)
206 {
207 auto v = std::complex<V>(1,1);
208 for(auto i = 0u; i < a.size(); ++i){
209 a[i] = v;
210 v.real(v.real()+1);
211 v.imag(v.imag()+1);
212 }
213 }
214
215
BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_algorithms_trans,value,test_types,fixture)216 BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_trans, value, test_types, fixture )
217 {
218 using namespace boost::numeric;
219 using value_type = typename value::first_type;
220 using layout_type = typename value::second_type;
221 using vector_type = std::vector<value_type>;
222 using strides_type = ublas::strides<layout_type>;
223 using extents_type = ublas::shape;
224 using size_type = typename extents_type::value_type;
225 using permutation_type = std::vector<size_type>;
226
227
228 for(auto const& n : extents) {
229
230 auto p = n.size();
231 auto s = n.product();
232
233 auto pi = permutation_type(p);
234 auto a = vector_type(s);
235 auto b1 = vector_type(s);
236 auto b2 = vector_type(s);
237 auto c1 = vector_type(s);
238 auto c2 = vector_type(s);
239
240 auto wa = strides_type(n);
241
242 init(a);
243
244 // so wie last-order.
245 for(auto i = size_type(0), j = p; i < n.size(); ++i, --j)
246 pi[i] = j;
247
248 auto nc = typename extents_type::base_type (p);
249 for(auto i = 0u; i < p; ++i)
250 nc[pi[i]-1] = n[i];
251
252 auto wc = strides_type(extents_type(nc));
253 auto wc_pi = typename strides_type::base_type (p);
254 for(auto i = 0u; i < p; ++i)
255 wc_pi[pi[i]-1] = wc[i];
256
257 ublas::copy ( p, n.data(), c1.data(), wc_pi.data(), a.data(), wa.data());
258 ublas::trans( p, n.data(), pi.data(), c2.data(), wc.data(), a.data(), wa.data() );
259
260 if(!std::is_compound_v<value_type>)
261 for(auto i = 0ul; i < s; ++i)
262 BOOST_CHECK_EQUAL( c1[i], c2[i] );
263
264
265 auto nb = typename extents_type::base_type (p);
266 for(auto i = 0u; i < p; ++i)
267 nb[pi[i]-1] = nc[i];
268
269 auto wb = strides_type (extents_type(nb));
270 auto wb_pi = typename strides_type::base_type (p);
271 for(auto i = 0u; i < p; ++i)
272 wb_pi[pi[i]-1] = wb[i];
273
274 ublas::copy ( p, nc.data(), b1.data(), wb_pi.data(), c1.data(), wc.data());
275 ublas::trans( p, nc.data(), pi.data(), b2.data(), wb.data(), c2.data(), wc.data() );
276
277 if(!std::is_compound_v<value_type>)
278 for(auto i = 0ul; i < s; ++i)
279 BOOST_CHECK_EQUAL( b1[i], b2[i] );
280
281 for(auto i = 0ul; i < s; ++i)
282 BOOST_CHECK_EQUAL( a[i], b2[i] );
283
284 }
285 }
286
287
288 BOOST_AUTO_TEST_SUITE_END()
289