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 <random>
15 #include <boost/numeric/ublas/tensor.hpp>
16 #include <boost/numeric/ublas/matrix.hpp>
17 #include <boost/test/unit_test.hpp>
18
19 #include "utility.hpp"
20
21 // BOOST_AUTO_TEST_SUITE ( test_tensor_matrix_interoperability, * boost::unit_test::depends_on("test_tensor") ) ;
22
23 BOOST_AUTO_TEST_SUITE ( test_tensor_matrix_interoperability )
24
25 using test_types = zip<int,long,float,double>::with_t<boost::numeric::ublas::first_order, boost::numeric::ublas::last_order>;
26
27
BOOST_AUTO_TEST_CASE_TEMPLATE(test_tensor_matrix_copy_ctor,value,test_types)28 BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_ctor, value, test_types)
29 {
30 using namespace boost::numeric;
31 using value_type = typename value::first_type;
32 using layout_type = typename value::second_type;
33 using tensor_type = ublas::tensor<value_type, layout_type>;
34 using matrix_type = typename tensor_type::matrix_type;
35
36 tensor_type a1 = matrix_type();
37 BOOST_CHECK_EQUAL( a1.size() , 0ul );
38 BOOST_CHECK( a1.empty() );
39 BOOST_CHECK_EQUAL( a1.data() , nullptr);
40
41 tensor_type a2 = matrix_type(1,1);
42 BOOST_CHECK_EQUAL( a2.size() , 1 );
43 BOOST_CHECK( !a2.empty() );
44 BOOST_CHECK_NE( a2.data() , nullptr);
45
46 tensor_type a3 = matrix_type(2,1);
47 BOOST_CHECK_EQUAL( a3.size() , 2 );
48 BOOST_CHECK( !a3.empty() );
49 BOOST_CHECK_NE( a3.data() , nullptr);
50
51 tensor_type a4 = matrix_type(1,2);
52 BOOST_CHECK_EQUAL( a4.size() , 2 );
53 BOOST_CHECK( !a4.empty() );
54 BOOST_CHECK_NE( a4.data() , nullptr);
55
56 tensor_type a5 = matrix_type(2,3);
57 BOOST_CHECK_EQUAL( a5.size() , 6 );
58 BOOST_CHECK( !a5.empty() );
59 BOOST_CHECK_NE( a5.data() , nullptr);
60 }
61
62
BOOST_AUTO_TEST_CASE_TEMPLATE(test_tensor_vector_copy_ctor,value,test_types)63 BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_vector_copy_ctor, value, test_types)
64 {
65 using namespace boost::numeric;
66 using value_type = typename value::first_type;
67 using layout_type = typename value::second_type;
68 using tensor_type = ublas::tensor<value_type, layout_type>;
69 using vector_type = typename tensor_type::vector_type;
70
71 tensor_type a1 = vector_type();
72 BOOST_CHECK_EQUAL( a1.size() , 0ul );
73 BOOST_CHECK( a1.empty() );
74 BOOST_CHECK_EQUAL( a1.data() , nullptr);
75
76 tensor_type a2 = vector_type(1);
77 BOOST_CHECK_EQUAL( a2.size() , 1 );
78 BOOST_CHECK( !a2.empty() );
79 BOOST_CHECK_NE( a2.data() , nullptr);
80
81 tensor_type a3 = vector_type(2);
82 BOOST_CHECK_EQUAL( a3.size() , 2 );
83 BOOST_CHECK( !a3.empty() );
84 BOOST_CHECK_NE( a3.data() , nullptr);
85
86 tensor_type a4 = vector_type(2);
87 BOOST_CHECK_EQUAL( a4.size() , 2 );
88 BOOST_CHECK( !a4.empty() );
89 BOOST_CHECK_NE( a4.data() , nullptr);
90
91 tensor_type a5 = vector_type(3);
92 BOOST_CHECK_EQUAL( a5.size() , 3 );
93 BOOST_CHECK( !a5.empty() );
94 BOOST_CHECK_NE( a5.data() , nullptr);
95 }
96
97
98 struct fixture
99 {
100 using extents_type = boost::numeric::ublas::basic_extents<std::size_t>;
fixturefixture101 fixture()
102 : extents{
103 extents_type{1,1}, // 1
104 extents_type{1,2}, // 2
105 extents_type{2,1}, // 3
106 extents_type{2,3}, // 4
107 extents_type{9,7}, // 5
108 extents_type{9,11}, // 6
109 extents_type{12,12}, // 7
110 extents_type{15,17}} // 8
111 {
112 }
113 std::vector<extents_type> extents;
114 };
115
116
117
118
BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_matrix_copy_ctor_extents,value,test_types,fixture)119 BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_ctor_extents, value, test_types, fixture )
120 {
121 using namespace boost::numeric;
122 using value_type = typename value::first_type;
123 using layout_type = typename value::second_type;
124 using tensor_type = ublas::tensor<value_type, layout_type>;
125 using matrix_type = typename tensor_type::matrix_type;
126
127 auto check = [](auto const& e) {
128 assert(e.size()==2);
129 tensor_type t = matrix_type{e[0],e[1]};
130 BOOST_CHECK_EQUAL ( t.size() , e.product() );
131 BOOST_CHECK_EQUAL ( t.rank() , e.size() );
132 BOOST_CHECK ( !t.empty() );
133 BOOST_CHECK_NE ( t.data() , nullptr);
134 };
135
136 for(auto const& e : extents)
137 check(e);
138 }
139
140
BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_vector_copy_ctor_extents,value,test_types,fixture)141 BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_copy_ctor_extents, value, test_types, fixture )
142 {
143 using namespace boost::numeric;
144 using value_type = typename value::first_type;
145 using layout_type = typename value::second_type;
146 using tensor_type = ublas::tensor<value_type, layout_type>;
147 using vector_type = typename tensor_type::vector_type;
148
149 auto check = [](auto const& e) {
150 assert(e.size()==2);
151 if(e.empty())
152 return;
153
154 tensor_type t = vector_type(e.product());
155 BOOST_CHECK_EQUAL ( t.size() , e.product() );
156 BOOST_CHECK_EQUAL ( t.rank() , e.size() );
157 BOOST_CHECK ( !t.empty() );
158 BOOST_CHECK_NE ( t.data() , nullptr);
159 };
160
161 for(auto const& e : extents)
162 check(e);
163 }
164
165
166
BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_matrix_copy_assignment,value,test_types,fixture)167 BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_assignment, value, test_types, fixture )
168 {
169 using namespace boost::numeric;
170 using value_type = typename value::first_type;
171 using layout_type = typename value::second_type;
172 using tensor_type = ublas::tensor<value_type, layout_type>;
173 using matrix_type = typename tensor_type::matrix_type;
174
175 auto check = [](auto const& e)
176 {
177 assert(e.size() == 2);
178 auto t = tensor_type{};
179 auto r = matrix_type(e[0],e[1]);
180 std::iota(r.data().begin(),r.data().end(), 1);
181 t = r;
182
183 BOOST_CHECK_EQUAL ( t.extents().at(0) , e.at(0) );
184 BOOST_CHECK_EQUAL ( t.extents().at(1) , e.at(1) );
185 BOOST_CHECK_EQUAL ( t.size() , e.product() );
186 BOOST_CHECK_EQUAL ( t.rank() , e.size() );
187 BOOST_CHECK ( !t.empty() );
188 BOOST_CHECK_NE ( t.data() , nullptr);
189
190 for(auto j = 0ul; j < t.size(1); ++j){
191 for(auto i = 0ul; i < t.size(0); ++i){
192 BOOST_CHECK_EQUAL( t.at(i,j), r(i,j) );
193 }
194 }
195 };
196
197 for(auto const& e : extents)
198 check(e);
199 }
200
201
BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_vector_copy_assignment,value,test_types,fixture)202 BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_copy_assignment, value, test_types, fixture )
203 {
204 using namespace boost::numeric;
205 using value_type = typename value::first_type;
206 using layout_type = typename value::second_type;
207 using tensor_type = ublas::tensor<value_type, layout_type>;
208 using vector_type = typename tensor_type::vector_type;
209
210 auto check = [](auto const& e)
211 {
212 assert(e.size() == 2);
213 auto t = tensor_type{};
214 auto r = vector_type(e[0]*e[1]);
215 std::iota(r.data().begin(),r.data().end(), 1);
216 t = r;
217
218 BOOST_CHECK_EQUAL ( t.extents().at(0) , e.at(0)*e.at(1) );
219 BOOST_CHECK_EQUAL ( t.extents().at(1) , 1);
220 BOOST_CHECK_EQUAL ( t.size() , e.product() );
221 BOOST_CHECK_EQUAL ( t.rank() , e.size() );
222 BOOST_CHECK ( !t.empty() );
223 BOOST_CHECK_NE ( t.data() , nullptr);
224
225 for(auto i = 0ul; i < t.size(); ++i){
226 BOOST_CHECK_EQUAL( t[i], r(i) );
227 }
228 };
229
230 for(auto const& e : extents)
231 check(e);
232 }
233
BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_matrix_move_assignment,value,test_types,fixture)234 BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_move_assignment, value, test_types, fixture )
235 {
236 using namespace boost::numeric;
237 using value_type = typename value::first_type;
238 using layout_type = typename value::second_type;
239 using tensor_type = ublas::tensor<value_type, layout_type>;
240 using matrix_type = typename tensor_type::matrix_type;
241
242 auto check = [](auto const& e)
243 {
244 assert(e.size() == 2);
245 auto t = tensor_type{};
246 auto r = matrix_type(e[0],e[1]);
247 std::iota(r.data().begin(),r.data().end(), 1);
248 auto q = r;
249 t = std::move(r);
250
251 BOOST_CHECK_EQUAL ( t.extents().at(0) , e.at(0) );
252 BOOST_CHECK_EQUAL ( t.extents().at(1) , e.at(1) );
253 BOOST_CHECK_EQUAL ( t.size() , e.product() );
254 BOOST_CHECK_EQUAL ( t.rank() , e.size() );
255 BOOST_CHECK ( !t.empty() );
256 BOOST_CHECK_NE ( t.data() , nullptr);
257
258 for(auto j = 0ul; j < t.size(1); ++j){
259 for(auto i = 0ul; i < t.size(0); ++i){
260 BOOST_CHECK_EQUAL( t.at(i,j), q(i,j) );
261 }
262 }
263 };
264
265 for(auto const& e : extents)
266 check(e);
267 }
268
269
270
271
BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_vector_move_assignment,value,test_types,fixture)272 BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_move_assignment, value, test_types, fixture )
273 {
274 using namespace boost::numeric;
275 using value_type = typename value::first_type;
276 using layout_type = typename value::second_type;
277 using tensor_type = ublas::tensor<value_type, layout_type>;
278 using vector_type = typename tensor_type::vector_type;
279
280 auto check = [](auto const& e)
281 {
282 assert(e.size() == 2);
283 auto t = tensor_type{};
284 auto r = vector_type(e[0]*e[1]);
285 std::iota(r.data().begin(),r.data().end(), 1);
286 auto q = r;
287 t = std::move(r);
288
289 BOOST_CHECK_EQUAL ( t.extents().at(0) , e.at(0) * e.at(1));
290 BOOST_CHECK_EQUAL ( t.extents().at(1) , 1);
291 BOOST_CHECK_EQUAL ( t.size() , e.product() );
292 BOOST_CHECK_EQUAL ( t.rank() , e.size() );
293 BOOST_CHECK ( !t.empty() );
294 BOOST_CHECK_NE ( t.data() , nullptr);
295
296 for(auto i = 0ul; i < t.size(); ++i){
297 BOOST_CHECK_EQUAL( t[i], q(i) );
298 }
299 };
300
301 for(auto const& e : extents)
302 check(e);
303 }
304
305
306
307
308
BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_matrix_expressions,value,test_types,fixture)309 BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_expressions, value, test_types, fixture )
310 {
311 using namespace boost::numeric;
312 using value_type = typename value::first_type;
313 using layout_type = typename value::second_type;
314 using tensor_type = ublas::tensor<value_type, layout_type>;
315 using matrix_type = typename tensor_type::matrix_type;
316
317 auto check = [](auto const& e)
318 {
319 assert(e.size() == 2);
320 auto t = tensor_type{};
321 auto r = matrix_type(e[0],e[1]);
322 std::iota(r.data().begin(),r.data().end(), 1);
323 t = r + 3*r;
324 tensor_type s = r + 3*r;
325 tensor_type q = s + r + 3*r + s; // + 3*r
326
327
328 BOOST_CHECK_EQUAL ( t.extents().at(0) , e.at(0) );
329 BOOST_CHECK_EQUAL ( t.extents().at(1) , e.at(1) );
330 BOOST_CHECK_EQUAL ( t.size() , e.product() );
331 BOOST_CHECK_EQUAL ( t.rank() , e.size() );
332 BOOST_CHECK ( !t.empty() );
333 BOOST_CHECK_NE ( t.data() , nullptr);
334
335 BOOST_CHECK_EQUAL ( s.extents().at(0) , e.at(0) );
336 BOOST_CHECK_EQUAL ( s.extents().at(1) , e.at(1) );
337 BOOST_CHECK_EQUAL ( s.size() , e.product() );
338 BOOST_CHECK_EQUAL ( s.rank() , e.size() );
339 BOOST_CHECK ( !s.empty() );
340 BOOST_CHECK_NE ( s.data() , nullptr);
341
342 BOOST_CHECK_EQUAL ( q.extents().at(0) , e.at(0) );
343 BOOST_CHECK_EQUAL ( q.extents().at(1) , e.at(1) );
344 BOOST_CHECK_EQUAL ( q.size() , e.product() );
345 BOOST_CHECK_EQUAL ( q.rank() , e.size() );
346 BOOST_CHECK ( !q.empty() );
347 BOOST_CHECK_NE ( q.data() , nullptr);
348
349
350 for(auto j = 0ul; j < t.size(1); ++j){
351 for(auto i = 0ul; i < t.size(0); ++i){
352 BOOST_CHECK_EQUAL( t.at(i,j), 4*r(i,j) );
353 BOOST_CHECK_EQUAL( s.at(i,j), t.at(i,j) );
354 BOOST_CHECK_EQUAL( q.at(i,j), 3*s.at(i,j) );
355 }
356 }
357 };
358
359 for(auto const& e : extents)
360 check(e);
361 }
362
363
364
365
366
367
BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_vector_expressions,value,test_types,fixture)368 BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_expressions, value, test_types, fixture )
369 {
370 using namespace boost::numeric;
371 using value_type = typename value::first_type;
372 using layout_type = typename value::second_type;
373 using tensor_type = ublas::tensor<value_type, layout_type>;
374 using vector_type = typename tensor_type::vector_type;
375
376 auto check = [](auto const& e)
377 {
378 assert(e.size() == 2);
379 auto t = tensor_type{};
380 auto r = vector_type(e[0]*e[1]);
381 std::iota(r.data().begin(),r.data().end(), 1);
382 t = r + 3*r;
383 tensor_type s = r + 3*r;
384 tensor_type q = s + r + 3*r + s; // + 3*r
385
386
387 BOOST_CHECK_EQUAL ( t.extents().at(0) , e.at(0)*e.at(1) );
388 BOOST_CHECK_EQUAL ( t.extents().at(1) , 1);
389 BOOST_CHECK_EQUAL ( t.size() , e.product() );
390 BOOST_CHECK_EQUAL ( t.rank() , e.size() );
391 BOOST_CHECK ( !t.empty() );
392 BOOST_CHECK_NE ( t.data() , nullptr);
393
394 BOOST_CHECK_EQUAL ( s.extents().at(0) , e.at(0)*e.at(1) );
395 BOOST_CHECK_EQUAL ( s.extents().at(1) , 1);
396 BOOST_CHECK_EQUAL ( s.size() , e.product() );
397 BOOST_CHECK_EQUAL ( s.rank() , e.size() );
398 BOOST_CHECK ( !s.empty() );
399 BOOST_CHECK_NE ( s.data() , nullptr);
400
401 BOOST_CHECK_EQUAL ( q.extents().at(0) , e.at(0)*e.at(1) );
402 BOOST_CHECK_EQUAL ( q.extents().at(1) , 1);
403 BOOST_CHECK_EQUAL ( q.size() , e.product() );
404 BOOST_CHECK_EQUAL ( q.rank() , e.size() );
405 BOOST_CHECK ( !q.empty() );
406 BOOST_CHECK_NE ( q.data() , nullptr);
407
408
409
410 for(auto i = 0ul; i < t.size(); ++i){
411 BOOST_CHECK_EQUAL( t.at(i), 4*r(i) );
412 BOOST_CHECK_EQUAL( s.at(i), t.at(i) );
413 BOOST_CHECK_EQUAL( q.at(i), 3*s.at(i) );
414 }
415 };
416
417 for(auto const& e : extents)
418 check(e);
419 }
420
421
422
BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_matrix_vector_expressions,value,test_types,fixture)423 BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_vector_expressions, value, test_types, fixture )
424 {
425 using namespace boost::numeric;
426 using value_type = typename value::first_type;
427 using layout_type = typename value::second_type;
428 using tensor_type = ublas::tensor<value_type, layout_type>;
429 using matrix_type = typename tensor_type::matrix_type;
430 using vector_type = typename tensor_type::vector_type;
431
432 auto check = [](auto const& e)
433 {
434 if(e.product() <= 2)
435 return;
436 assert(e.size() == 2);
437 auto Q = tensor_type{e[0],1};
438 auto A = matrix_type(e[0],e[1]);
439 auto b = vector_type(e[1]);
440 auto c = vector_type(e[0]);
441 std::iota(b.data().begin(),b.data().end(), 1);
442 std::fill(A.data().begin(),A.data().end(), 1);
443 std::fill(c.data().begin(),c.data().end(), 2);
444 std::fill(Q.begin(),Q.end(), 2);
445
446 tensor_type T = Q + (ublas::prod(A , b) + 2*c) + 3*Q;
447
448 BOOST_CHECK_EQUAL ( T.extents().at(0) , Q.extents().at(0) );
449 BOOST_CHECK_EQUAL ( T.extents().at(1) , Q.extents().at(1));
450 BOOST_CHECK_EQUAL ( T.size() , Q.size() );
451 BOOST_CHECK_EQUAL ( T.size() , c.size() );
452 BOOST_CHECK_EQUAL ( T.rank() , Q.rank() );
453 BOOST_CHECK ( !T.empty() );
454 BOOST_CHECK_NE ( T.data() , nullptr);
455
456 for(auto i = 0ul; i < T.size(); ++i){
457 auto n = e[1];
458 auto ab = n * (n+1) / 2;
459 BOOST_CHECK_EQUAL( T(i), ab+4*Q(0)+2*c(0) );
460 }
461
462 };
463
464
465
466 for(auto const& e : extents)
467 check(e);
468 }
469
470
471 BOOST_AUTO_TEST_SUITE_END()
472
473