test_algorithms.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  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 <algorithm>
  13. #include <vector>
  14. #include <boost/numeric/ublas/tensor/algorithms.hpp>
  15. #include <boost/numeric/ublas/tensor/extents.hpp>
  16. #include <boost/numeric/ublas/tensor/strides.hpp>
  17. #include "utility.hpp"
  18. #include <boost/test/unit_test.hpp>
  19. BOOST_AUTO_TEST_SUITE ( test_tensor_algorithms,
  20. * boost::unit_test::depends_on("test_extents")
  21. * boost::unit_test::depends_on("test_strides"))
  22. using test_types = zip<int,long,float,double,std::complex<float>>::with_t<boost::numeric::ublas::first_order, boost::numeric::ublas::last_order>;
  23. using test_types2 = std::tuple<int,long,float,double,std::complex<float>>;
  24. struct fixture
  25. {
  26. using extents_type = boost::numeric::ublas::shape;
  27. fixture()
  28. : extents {
  29. extents_type{1,1}, // 1
  30. extents_type{1,2}, // 2
  31. extents_type{2,1}, // 3
  32. extents_type{2,3}, // 4
  33. extents_type{2,3,1}, // 5
  34. extents_type{4,1,3}, // 6
  35. extents_type{1,2,3}, // 7
  36. extents_type{4,2,3}, // 8
  37. extents_type{4,2,3,5} } // 9
  38. {
  39. }
  40. std::vector<extents_type> extents;
  41. };
  42. BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_copy, value, test_types2, fixture )
  43. {
  44. using namespace boost::numeric;
  45. using value_type = value;
  46. using vector_type = std::vector<value_type>;
  47. for(auto const& n : extents) {
  48. auto a = vector_type(n.product());
  49. auto b = vector_type(n.product());
  50. auto c = vector_type(n.product());
  51. auto wa = ublas::strides<ublas::first_order>(n);
  52. auto wb = ublas::strides<ublas::last_order> (n);
  53. auto wc = ublas::strides<ublas::first_order>(n);
  54. auto v = value_type{};
  55. for(auto i = 0ul; i < a.size(); ++i, v+=1){
  56. a[i]=v;
  57. }
  58. ublas::copy( n.size(), n.data(), b.data(), wb.data(), a.data(), wa.data() );
  59. ublas::copy( n.size(), n.data(), c.data(), wc.data(), b.data(), wb.data() );
  60. for(auto i = 1ul; i < c.size(); ++i)
  61. BOOST_CHECK_EQUAL( c[i], a[i] );
  62. using size_type = typename ublas::strides<ublas::first_order>::value_type;
  63. size_type const*const p0 = nullptr;
  64. BOOST_CHECK_THROW( ublas::copy( n.size(), p0, c.data(), wc.data(), b.data(), wb.data() ), std::length_error );
  65. BOOST_CHECK_THROW( ublas::copy( n.size(), n.data(), c.data(), p0, b.data(), wb.data() ), std::length_error );
  66. BOOST_CHECK_THROW( ublas::copy( n.size(), n.data(), c.data(), wc.data(), b.data(), p0 ), std::length_error );
  67. value_type* c0 = nullptr;
  68. BOOST_CHECK_THROW( ublas::copy( n.size(), n.data(), c0, wc.data(), b.data(), wb.data() ), std::length_error );
  69. }
  70. // special case rank == 0
  71. {
  72. auto n = ublas::shape{};
  73. auto a = vector_type(n.product());
  74. auto b = vector_type(n.product());
  75. auto c = vector_type(n.product());
  76. auto wa = ublas::strides<ublas::first_order>(n);
  77. auto wb = ublas::strides<ublas::last_order> (n);
  78. auto wc = ublas::strides<ublas::first_order>(n);
  79. ublas::copy( n.size(), n.data(), b.data(), wb.data(), a.data(), wa.data() );
  80. ublas::copy( n.size(), n.data(), c.data(), wc.data(), b.data(), wb.data() );
  81. BOOST_CHECK_NO_THROW( ublas::copy( n.size(), n.data(), c.data(), wc.data(), b.data(), wb.data() ) );
  82. }
  83. }
  84. BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_transform, value, test_types2, fixture )
  85. {
  86. using namespace boost::numeric;
  87. using value_type = value;
  88. using vector_type = std::vector<value_type>;
  89. for(auto const& n : extents) {
  90. auto a = vector_type(n.product());
  91. auto b = vector_type(n.product());
  92. auto c = vector_type(n.product());
  93. auto wa = ublas::strides<ublas::first_order>(n);
  94. auto wb = ublas::strides<ublas::last_order> (n);
  95. auto wc = ublas::strides<ublas::first_order>(n);
  96. auto v = value_type{};
  97. for(auto i = 0ul; i < a.size(); ++i, v+=1){
  98. a[i]=v;
  99. }
  100. ublas::transform( n.size(), n.data(), b.data(), wb.data(), a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} );
  101. ublas::transform( n.size(), n.data(), c.data(), wc.data(), b.data(), wb.data(), [](value_type const& a){ return a - value_type(1);} );
  102. for(auto i = 1ul; i < c.size(); ++i)
  103. BOOST_CHECK_EQUAL( c[i], a[i] );
  104. }
  105. }
  106. BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_accumulate, value, test_types2, fixture )
  107. {
  108. using namespace boost::numeric;
  109. using value_type = value;
  110. using vector_type = std::vector<value_type>;
  111. for(auto const& n : extents) {
  112. auto const s = n.product();
  113. auto a = vector_type(n.product());
  114. // auto b = vector_type(n.product());
  115. // auto c = vector_type(n.product());
  116. auto wa = ublas::strides<ublas::first_order>(n);
  117. // auto wb = ublas::strides<ublas::last_order> (n);
  118. // auto wc = ublas::strides<ublas::first_order>(n);
  119. auto v = value_type{};
  120. for(auto i = 0ul; i < a.size(); ++i, v+=value_type(1)){
  121. a[i]=v;
  122. }
  123. auto acc = ublas::accumulate( n.size(), n.data(), a.data(), wa.data(), v);
  124. BOOST_CHECK_EQUAL( acc, value_type( s*(s+1) / 2 ) );
  125. auto acc2 = ublas::accumulate( n.size(), n.data(), a.data(), wa.data(), v,
  126. [](auto const& l, auto const& r){return l + r; });
  127. BOOST_CHECK_EQUAL( acc2, value_type( s*(s+1) / 2 ) );
  128. }
  129. }
  130. template<class V>
  131. void init(std::vector<V>& a)
  132. {
  133. auto v = V(1);
  134. for(auto i = 0u; i < a.size(); ++i, ++v){
  135. a[i] = v;
  136. }
  137. }
  138. template<class V>
  139. void init(std::vector<std::complex<V>>& a)
  140. {
  141. auto v = std::complex<V>(1,1);
  142. for(auto i = 0u; i < a.size(); ++i){
  143. a[i] = v;
  144. v.real(v.real()+1);
  145. v.imag(v.imag()+1);
  146. }
  147. }
  148. BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_trans, 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 vector_type = std::vector<value_type>;
  154. using strides_type = ublas::strides<layout_type>;
  155. using extents_type = ublas::shape;
  156. using size_type = typename extents_type::value_type;
  157. using permutation_type = std::vector<size_type>;
  158. for(auto const& n : extents) {
  159. auto p = n.size();
  160. auto s = n.product();
  161. auto pi = permutation_type(p);
  162. auto a = vector_type(s);
  163. auto b1 = vector_type(s);
  164. auto b2 = vector_type(s);
  165. auto c1 = vector_type(s);
  166. auto c2 = vector_type(s);
  167. auto wa = strides_type(n);
  168. init(a);
  169. // so wie last-order.
  170. for(auto i = size_type(0), j = p; i < n.size(); ++i, --j)
  171. pi[i] = j;
  172. auto nc = typename extents_type::base_type (p);
  173. for(auto i = 0u; i < p; ++i)
  174. nc[pi[i]-1] = n[i];
  175. auto wc = strides_type(extents_type(nc));
  176. auto wc_pi = typename strides_type::base_type (p);
  177. for(auto i = 0u; i < p; ++i)
  178. wc_pi[pi[i]-1] = wc[i];
  179. ublas::copy ( p, n.data(), c1.data(), wc_pi.data(), a.data(), wa.data());
  180. ublas::trans( p, n.data(), pi.data(), c2.data(), wc.data(), a.data(), wa.data() );
  181. if(!std::is_compound_v<value_type>)
  182. for(auto i = 0ul; i < s; ++i)
  183. BOOST_CHECK_EQUAL( c1[i], c2[i] );
  184. auto nb = typename extents_type::base_type (p);
  185. for(auto i = 0u; i < p; ++i)
  186. nb[pi[i]-1] = nc[i];
  187. auto wb = strides_type (extents_type(nb));
  188. auto wb_pi = typename strides_type::base_type (p);
  189. for(auto i = 0u; i < p; ++i)
  190. wb_pi[pi[i]-1] = wb[i];
  191. ublas::copy ( p, nc.data(), b1.data(), wb_pi.data(), c1.data(), wc.data());
  192. ublas::trans( p, nc.data(), pi.data(), b2.data(), wb.data(), c2.data(), wc.data() );
  193. if(!std::is_compound_v<value_type>)
  194. for(auto i = 0ul; i < s; ++i)
  195. BOOST_CHECK_EQUAL( b1[i], b2[i] );
  196. for(auto i = 0ul; i < s; ++i)
  197. BOOST_CHECK_EQUAL( a[i], b2[i] );
  198. }
  199. }
  200. BOOST_AUTO_TEST_SUITE_END()