test_tensor.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  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. #include <random>
  12. #include <boost/numeric/ublas/tensor/tensor.hpp>
  13. #define BOOST_TEST_DYN_LINK
  14. #define BOOST_TEST_MODULE TestTensor
  15. #include <boost/test/unit_test.hpp>
  16. #include "utility.hpp"
  17. //BOOST_AUTO_TEST_SUITE ( test_tensor, * boost::unit_test::depends_on("test_extents") ) ;
  18. BOOST_AUTO_TEST_SUITE ( test_tensor )
  19. using test_types = zip<int,long,float,double,std::complex<float>>::with_t<boost::numeric::ublas::first_order, boost::numeric::ublas::last_order>;
  20. BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_ctor, value, test_types)
  21. {
  22. using namespace boost::numeric;
  23. using value_type = typename value::first_type;
  24. using layout_type = typename value::second_type;
  25. using tensor_type = ublas::tensor<value_type, layout_type>;
  26. auto a1 = tensor_type{};
  27. BOOST_CHECK_EQUAL( a1.size() , 0ul );
  28. BOOST_CHECK( a1.empty() );
  29. BOOST_CHECK_EQUAL( a1.data() , nullptr);
  30. auto a2 = tensor_type{1,1};
  31. BOOST_CHECK_EQUAL( a2.size() , 1 );
  32. BOOST_CHECK( !a2.empty() );
  33. BOOST_CHECK_NE( a2.data() , nullptr);
  34. auto a3 = tensor_type{2,1};
  35. BOOST_CHECK_EQUAL( a3.size() , 2 );
  36. BOOST_CHECK( !a3.empty() );
  37. BOOST_CHECK_NE( a3.data() , nullptr);
  38. auto a4 = tensor_type{1,2};
  39. BOOST_CHECK_EQUAL( a4.size() , 2 );
  40. BOOST_CHECK( !a4.empty() );
  41. BOOST_CHECK_NE( a4.data() , nullptr);
  42. auto a5 = tensor_type{2,1};
  43. BOOST_CHECK_EQUAL( a5.size() , 2 );
  44. BOOST_CHECK( !a5.empty() );
  45. BOOST_CHECK_NE( a5.data() , nullptr);
  46. auto a6 = tensor_type{4,3,2};
  47. BOOST_CHECK_EQUAL( a6.size() , 4*3*2 );
  48. BOOST_CHECK( !a6.empty() );
  49. BOOST_CHECK_NE( a6.data() , nullptr);
  50. auto a7 = tensor_type{4,1,2};
  51. BOOST_CHECK_EQUAL( a7.size() , 4*1*2 );
  52. BOOST_CHECK( !a7.empty() );
  53. BOOST_CHECK_NE( a7.data() , nullptr);
  54. }
  55. struct fixture
  56. {
  57. using extents_type = boost::numeric::ublas::basic_extents<std::size_t>;
  58. fixture()
  59. : extents {
  60. extents_type{}, // 0
  61. extents_type{1,1}, // 1
  62. extents_type{1,2}, // 2
  63. extents_type{2,1}, // 3
  64. extents_type{2,3}, // 4
  65. extents_type{2,3,1}, // 5
  66. extents_type{4,1,3}, // 6
  67. extents_type{1,2,3}, // 7
  68. extents_type{4,2,3}, // 8
  69. extents_type{4,2,3,5}} // 9
  70. {
  71. }
  72. std::vector<extents_type> extents;
  73. };
  74. BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ctor_extents, value, test_types, fixture )
  75. {
  76. using namespace boost::numeric;
  77. using value_type = typename value::first_type;
  78. using layout_type = typename value::second_type;
  79. using tensor_type = ublas::tensor<value_type, layout_type>;
  80. auto check = [](auto const& e) {
  81. auto t = tensor_type{e};
  82. BOOST_CHECK_EQUAL ( t.size() , e.product() );
  83. BOOST_CHECK_EQUAL ( t.rank() , e.size() );
  84. if(e.empty()) {
  85. BOOST_CHECK ( t.empty() );
  86. BOOST_CHECK_EQUAL ( t.data() , nullptr);
  87. }
  88. else{
  89. BOOST_CHECK ( !t.empty() );
  90. BOOST_CHECK_NE ( t.data() , nullptr);
  91. }
  92. };
  93. for(auto const& e : extents)
  94. check(e);
  95. }
  96. BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_copy_ctor, value, test_types, fixture )
  97. {
  98. using namespace boost::numeric;
  99. using value_type = typename value::first_type;
  100. using layout_type = typename value::second_type;
  101. using tensor_type = ublas::tensor<value_type, layout_type>;
  102. auto check = [](auto const& e)
  103. {
  104. auto r = tensor_type{e};
  105. auto t = r;
  106. BOOST_CHECK_EQUAL ( t.size() , r.size() );
  107. BOOST_CHECK_EQUAL ( t.rank() , r.rank() );
  108. BOOST_CHECK ( t.strides() == r.strides() );
  109. BOOST_CHECK ( t.extents() == r.extents() );
  110. if(e.empty()) {
  111. BOOST_CHECK ( t.empty() );
  112. BOOST_CHECK_EQUAL ( t.data() , nullptr);
  113. }
  114. else{
  115. BOOST_CHECK ( !t.empty() );
  116. BOOST_CHECK_NE ( t.data() , nullptr);
  117. }
  118. for(auto i = 0ul; i < t.size(); ++i)
  119. BOOST_CHECK_EQUAL( t[i], r[i] );
  120. };
  121. for(auto const& e : extents)
  122. check(e);
  123. }
  124. BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_copy_ctor_layout, value, test_types, fixture )
  125. {
  126. using namespace boost::numeric;
  127. using value_type = typename value::first_type;
  128. using layout_type = typename value::second_type;
  129. using tensor_type = ublas::tensor<value_type, layout_type>;
  130. using other_layout_type = std::conditional_t<std::is_same<ublas::first_order,layout_type>::value, ublas::last_order, ublas::first_order>;
  131. using other_tensor_type = ublas::tensor<value_type, other_layout_type>;
  132. for(auto const& e : extents)
  133. {
  134. auto r = tensor_type{e};
  135. other_tensor_type t = r;
  136. tensor_type q = t;
  137. BOOST_CHECK_EQUAL ( t.size() , r.size() );
  138. BOOST_CHECK_EQUAL ( t.rank() , r.rank() );
  139. BOOST_CHECK ( t.extents() == r.extents() );
  140. BOOST_CHECK_EQUAL ( q.size() , r.size() );
  141. BOOST_CHECK_EQUAL ( q.rank() , r.rank() );
  142. BOOST_CHECK ( q.strides() == r.strides() );
  143. BOOST_CHECK ( q.extents() == r.extents() );
  144. for(auto i = 0ul; i < t.size(); ++i)
  145. BOOST_CHECK_EQUAL( q[i], r[i] );
  146. }
  147. }
  148. BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_copy_move_ctor, value, test_types, fixture )
  149. {
  150. using namespace boost::numeric;
  151. using value_type = typename value::first_type;
  152. using layout_type = typename value::second_type;
  153. using tensor_type = ublas::tensor<value_type, layout_type>;
  154. auto check = [](auto const& e)
  155. {
  156. auto r = tensor_type{e};
  157. auto t = std::move(r);
  158. BOOST_CHECK_EQUAL ( t.size() , e.product() );
  159. BOOST_CHECK_EQUAL ( t.rank() , e.size() );
  160. if(e.empty()) {
  161. BOOST_CHECK ( t.empty() );
  162. BOOST_CHECK_EQUAL ( t.data() , nullptr);
  163. }
  164. else{
  165. BOOST_CHECK ( !t.empty() );
  166. BOOST_CHECK_NE ( t.data() , nullptr);
  167. }
  168. };
  169. for(auto const& e : extents)
  170. check(e);
  171. }
  172. BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ctor_extents_init, value, test_types, fixture )
  173. {
  174. using namespace boost::numeric;
  175. using value_type = typename value::first_type;
  176. using layout_type = typename value::second_type;
  177. using tensor_type = ublas::tensor<value_type, layout_type>;
  178. std::random_device device{};
  179. std::minstd_rand0 generator(device());
  180. using distribution_type = std::conditional_t<std::is_integral_v<value_type>, std::uniform_int_distribution<>, std::uniform_real_distribution<> >;
  181. auto distribution = distribution_type(1,6);
  182. for(auto const& e : extents){
  183. auto r = static_cast<value_type>(distribution(generator));
  184. auto t = tensor_type{e,r};
  185. for(auto i = 0ul; i < t.size(); ++i)
  186. BOOST_CHECK_EQUAL( t[i], r );
  187. }
  188. }
  189. BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ctor_extents_array, value, test_types, fixture)
  190. {
  191. using namespace boost::numeric;
  192. using value_type = typename value::first_type;
  193. using layout_type = typename value::second_type;
  194. using tensor_type = ublas::tensor<value_type, layout_type>;
  195. using array_type = typename tensor_type::array_type;
  196. for(auto const& e : extents) {
  197. auto a = array_type(e.product());
  198. auto v = value_type {};
  199. for(auto& aa : a){
  200. aa = v;
  201. v += value_type{1};
  202. }
  203. auto t = tensor_type{e, a};
  204. v = value_type{};
  205. for(auto i = 0ul; i < t.size(); ++i, v+=value_type{1})
  206. BOOST_CHECK_EQUAL( t[i], v);
  207. }
  208. }
  209. BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_single_index_access, value, test_types, fixture)
  210. {
  211. using namespace boost::numeric;
  212. using value_type = typename value::first_type;
  213. using layout_type = typename value::second_type;
  214. using tensor_type = ublas::tensor<value_type, layout_type>;
  215. for(auto const& e : extents) {
  216. auto t = tensor_type{e};
  217. auto v = value_type {};
  218. for(auto i = 0ul; i < t.size(); ++i, v+=value_type{1}){
  219. t[i] = v;
  220. BOOST_CHECK_EQUAL( t[i], v );
  221. t(i) = v;
  222. BOOST_CHECK_EQUAL( t(i), v );
  223. }
  224. }
  225. }
  226. BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_multi_index_access_at, value, test_types, fixture)
  227. {
  228. using namespace boost::numeric;
  229. using value_type = typename value::first_type;
  230. using layout_type = typename value::second_type;
  231. using tensor_type = ublas::tensor<value_type, layout_type>;
  232. auto check1 = [](const tensor_type& t)
  233. {
  234. auto v = value_type{};
  235. for(auto k = 0ul; k < t.size(); ++k){
  236. BOOST_CHECK_EQUAL(t[k], v);
  237. v+=value_type{1};
  238. }
  239. };
  240. auto check2 = [](const tensor_type& t)
  241. {
  242. std::array<unsigned,2> k;
  243. auto r = std::is_same_v<layout_type,ublas::first_order> ? 1 : 0;
  244. auto q = std::is_same_v<layout_type,ublas::last_order > ? 1 : 0;
  245. auto v = value_type{};
  246. for(k[r] = 0ul; k[r] < t.size(r); ++k[r]){
  247. for(k[q] = 0ul; k[q] < t.size(q); ++k[q]){
  248. BOOST_CHECK_EQUAL(t.at(k[0],k[1]), v);
  249. v+=value_type{1};
  250. }
  251. }
  252. };
  253. auto check3 = [](const tensor_type& t)
  254. {
  255. std::array<unsigned,3> k;
  256. using op_type = std::conditional_t<std::is_same_v<layout_type,ublas::first_order>, std::minus<>, std::plus<>>;
  257. auto r = std::is_same_v<layout_type,ublas::first_order> ? 2 : 0;
  258. auto o = op_type{};
  259. auto v = value_type{};
  260. for(k[r] = 0ul; k[r] < t.size(r); ++k[r]){
  261. for(k[o(r,1)] = 0ul; k[o(r,1)] < t.size(o(r,1)); ++k[o(r,1)]){
  262. for(k[o(r,2)] = 0ul; k[o(r,2)] < t.size(o(r,2)); ++k[o(r,2)]){
  263. BOOST_CHECK_EQUAL(t.at(k[0],k[1],k[2]), v);
  264. v+=value_type{1};
  265. }
  266. }
  267. }
  268. };
  269. auto check4 = [](const tensor_type& t)
  270. {
  271. std::array<unsigned,4> k;
  272. using op_type = std::conditional_t<std::is_same_v<layout_type,ublas::first_order>, std::minus<>, std::plus<>>;
  273. auto r = std::is_same_v<layout_type,ublas::first_order> ? 3 : 0;
  274. auto o = op_type{};
  275. auto v = value_type{};
  276. for(k[r] = 0ul; k[r] < t.size(r); ++k[r]){
  277. for(k[o(r,1)] = 0ul; k[o(r,1)] < t.size(o(r,1)); ++k[o(r,1)]){
  278. for(k[o(r,2)] = 0ul; k[o(r,2)] < t.size(o(r,2)); ++k[o(r,2)]){
  279. for(k[o(r,3)] = 0ul; k[o(r,3)] < t.size(o(r,3)); ++k[o(r,3)]){
  280. BOOST_CHECK_EQUAL(t.at(k[0],k[1],k[2],k[3]), v);
  281. v+=value_type{1};
  282. }
  283. }
  284. }
  285. }
  286. };
  287. auto check = [check1,check2,check3,check4](auto const& e) {
  288. auto t = tensor_type{e};
  289. auto v = value_type {};
  290. for(auto i = 0ul; i < t.size(); ++i){
  291. t[i] = v;
  292. v+=value_type{1};
  293. }
  294. if(t.rank() == 1) check1(t);
  295. else if(t.rank() == 2) check2(t);
  296. else if(t.rank() == 3) check3(t);
  297. else if(t.rank() == 4) check4(t);
  298. };
  299. for(auto const& e : extents)
  300. check(e);
  301. }
  302. BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_reshape, value, test_types, fixture)
  303. {
  304. using namespace boost::numeric;
  305. using value_type = typename value::first_type;
  306. using layout_type = typename value::second_type;
  307. using tensor_type = ublas::tensor<value_type, layout_type>;
  308. for(auto const& efrom : extents){
  309. for(auto const& eto : extents){
  310. auto v = value_type {};
  311. v+=value_type{1};
  312. auto t = tensor_type{efrom, v};
  313. for(auto i = 0ul; i < t.size(); ++i)
  314. BOOST_CHECK_EQUAL( t[i], v );
  315. t.reshape(eto);
  316. for(auto i = 0ul; i < std::min(efrom.product(),eto.product()); ++i)
  317. BOOST_CHECK_EQUAL( t[i], v );
  318. BOOST_CHECK_EQUAL ( t.size() , eto.product() );
  319. BOOST_CHECK_EQUAL ( t.rank() , eto.size() );
  320. BOOST_CHECK ( t.extents() == eto );
  321. if(efrom != eto){
  322. for(auto i = efrom.product(); i < t.size(); ++i)
  323. BOOST_CHECK_EQUAL( t[i], value_type{} );
  324. }
  325. }
  326. }
  327. }
  328. BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_swap, value, test_types, fixture)
  329. {
  330. using namespace boost::numeric;
  331. using value_type = typename value::first_type;
  332. using layout_type = typename value::second_type;
  333. using tensor_type = ublas::tensor<value_type, layout_type>;
  334. for(auto const& e_t : extents){
  335. for(auto const& e_r : extents) {
  336. auto v = value_type {} + value_type{1};
  337. auto w = value_type {} + value_type{2};
  338. auto t = tensor_type{e_t, v};
  339. auto r = tensor_type{e_r, w};
  340. std::swap( r, t );
  341. for(auto i = 0ul; i < t.size(); ++i)
  342. BOOST_CHECK_EQUAL( t[i], w );
  343. BOOST_CHECK_EQUAL ( t.size() , e_r.product() );
  344. BOOST_CHECK_EQUAL ( t.rank() , e_r.size() );
  345. BOOST_CHECK ( t.extents() == e_r );
  346. for(auto i = 0ul; i < r.size(); ++i)
  347. BOOST_CHECK_EQUAL( r[i], v );
  348. BOOST_CHECK_EQUAL ( r.size() , e_t.product() );
  349. BOOST_CHECK_EQUAL ( r.rank() , e_t.size() );
  350. BOOST_CHECK ( r.extents() == e_t );
  351. }
  352. }
  353. }
  354. BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_standard_iterator, value, test_types, fixture)
  355. {
  356. using namespace boost::numeric;
  357. using value_type = typename value::first_type;
  358. using layout_type = typename value::second_type;
  359. using tensor_type = ublas::tensor<value_type, layout_type>;
  360. for(auto const& e : extents)
  361. {
  362. auto v = value_type {} + value_type{1};
  363. auto t = tensor_type{e, v};
  364. BOOST_CHECK_EQUAL( std::distance(t.begin(), t.end ()), t.size() );
  365. BOOST_CHECK_EQUAL( std::distance(t.rbegin(), t.rend()), t.size() );
  366. BOOST_CHECK_EQUAL( std::distance(t.cbegin(), t.cend ()), t.size() );
  367. BOOST_CHECK_EQUAL( std::distance(t.crbegin(), t.crend()), t.size() );
  368. if(t.size() > 0) {
  369. BOOST_CHECK( t.data() == std::addressof( *t.begin () ) ) ;
  370. BOOST_CHECK( t.data() == std::addressof( *t.cbegin() ) ) ;
  371. }
  372. }
  373. }
  374. BOOST_AUTO_TEST_SUITE_END()