test_tensor_matrix_vector.cpp 13 KB

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