test-ra-operators.C 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. // (c) Daniel Llorens - 2014-2015
  2. // This library is free software; you can redistribute it and/or modify it under
  3. // the terms of the GNU Lesser General Public License as published by the Free
  4. // Software Foundation; either version 3 of the License, or (at your option) any
  5. // later version.
  6. /// @file test-ra-operators.C
  7. /// @brief Tests for operators on ra:: expr templates.
  8. #include "ra/complex.H"
  9. #include "ra/test.H"
  10. #include "ra/mpdebug.H"
  11. #include "ra/ra-operators.H"
  12. #include "ra/ra-large.H"
  13. #include "ra/wedge.H"
  14. using std::cout; using std::endl;
  15. int main()
  16. {
  17. TestRecorder tr;
  18. section("unary ops");
  19. {
  20. #define DEF_TEST_UNARY_OP(OP) \
  21. auto test = [&tr](auto token, auto x, auto y, auto && vx, auto && vy, real err) \
  22. { \
  23. using T = decltype(token); \
  24. using TY = decltype(OP(std::declval<T>())); \
  25. tr.info("scalar-scalar").test_abs_error(OP(T(x)), TY(y), err); \
  26. tr.info("array(0)-scalar").test_abs_error(OP(ra::Unique<T, 0>(x)), TY(y), err); \
  27. tr.info("array(var)-scalar").test_abs_error(OP(ra::Unique<T>(x)), TY(y), err); \
  28. tr.info("array(1)-array(1)").test_abs_error(OP(vx), vy, err); \
  29. };
  30. {
  31. DEF_TEST_UNARY_OP(abs);
  32. test(int(), -3, 3, ra::Unique<int, 1>{1, -3, -2}, ra::Unique<int, 1>{1, 3, 2}, 0.);
  33. test(real(), -3, 3, ra::Unique<real, 1>{1, -3, -2}, ra::Unique<real, 1>{1, 3, 2}, 0.);
  34. test(float(), -3, 3, ra::Unique<float, 1>{1, -3, -2}, ra::Unique<float, 1>{1, 3, 2}, 0.);
  35. test(complex(), -3, 3, ra::Unique<complex, 1>{1, -3, -2}, ra::Unique<complex, 1>{1, 3, 2}, 0.);
  36. }
  37. #define TEST_UNARY_OP_CR(OP, ri, ro, ci, co, err) \
  38. { \
  39. DEF_TEST_UNARY_OP(OP); \
  40. test(real(), ri, ro, ra::Unique<real, 1>{ri, ri, ri}, ra::Unique<complex, 1>{ro, ro, ro}, err); \
  41. test(complex(), ci, co, ra::Unique<complex, 1>{ci, ci}, ra::Unique<complex, 1>{co, co}, err); \
  42. }
  43. TEST_UNARY_OP_CR(conj, 1., 1., complex(1., 2.), complex(1., -2), 0.);
  44. TEST_UNARY_OP_CR(cos, 0., 1., complex(0, 0), complex(1., 0.), 0.);
  45. TEST_UNARY_OP_CR(sin, 1.57079632679489661, 1., complex(1.57079632679489661, 0), complex(1., 0.), 0.);
  46. TEST_UNARY_OP_CR(exp, 0., 1., complex(0, 0), complex(1., 0.), 0.);
  47. TEST_UNARY_OP_CR(sqrt, 4., 2., complex(-1, 0), complex(0., 1.), 1e-16);
  48. TEST_UNARY_OP_CR(xI, 4., complex(0, 4.), complex(1., -2.), complex(2., 1.), 0.);
  49. #undef TEST_UNARY_OP_CR
  50. #undef DEF_TEST_UNARY_OP
  51. }
  52. section("establish meaning of selectors");
  53. {
  54. // rank 0 containers/slices are not is_slice (and therefore not is_ra) so that their conversions to scalar are used instead.
  55. static_assert(ra::is_ra<ra::Small<int>>::value, "bad is_ra Small");
  56. static_assert(ra::is_ra<ra::SmallSlice<int, mp::nil, mp::nil>>::value, "bad is_ra SmallSlice");
  57. static_assert(ra::is_ra<ra::Unique<int, 0>>::value, "bad is_ra Unique");
  58. static_assert(ra::is_ra<ra::Raw<int, 0>>::value, "bad is_ra Raw");
  59. static_assert(ra::is_ra<ra::Small<int, 1>>::value, "bad is_ra Small");
  60. static_assert(ra::is_ra<ra::SmallSlice<int, mp::int_list<1>, mp::int_list<1>>>::value, "bad is_ra SmallSlice");
  61. static_assert(ra::is_ra<ra::Unique<int, 1>>::value, "bad is_ra Unique");
  62. static_assert(ra::is_ra<ra::Raw<int, 1>>::value, "bad is_ra Raw");
  63. static_assert(ra::is_ra<ra::Raw<int>>::value, "bad is_ra Raw");
  64. static_assert(ra::is_ra<decltype(ra::scalar(3))>::value, "bad is_ra Scalar");
  65. static_assert(ra::is_ra<decltype(ra::vector({1, 2, 3}))>::value, "bad is_ra Vector");
  66. static_assert(!ra::is_ra<int *>::value, "bad is_ra int *");
  67. static_assert(ra::is_scalar<real>::value, "bad is_scalar real");
  68. static_assert(ra::is_scalar<complex>::value, "bad is_scalar complex");
  69. static_assert(ra::is_scalar<int>::value, "bad is_scalar int");
  70. static_assert(!ra::is_scalar<decltype(ra::scalar(3))>::value, "bad is_scalar Scalar");
  71. static_assert(!ra::is_scalar<decltype(ra::vector({1, 2, 3}))>::value, "bad is_scalar Scalar");
  72. static_assert(!ra::is_scalar<decltype(ra::start(3))>::value, "bad is_scalar Scalar");
  73. int a = 3;
  74. static_assert(!ra::is_scalar<decltype(ra::start(a))>::value, "bad is_scalar Scalar");
  75. // a regression.
  76. static_assert(ra::is_ra_zero_rank<ra::Scalar<int>>::value, "bad");
  77. static_assert(!ra::is_ra_pos_rank<ra::Scalar<int>>::value, "bad");
  78. static_assert(!ra::is_ra_zero_rank<ra::TensorIndex<0>>::value, "bad");
  79. static_assert(ra::is_ra_pos_rank<ra::TensorIndex<0>>::value, "bad");
  80. static_assert(!ra::ra_zero<ra::TensorIndex<0>>::value, "bad");
  81. static_assert(ra::is_ra_pos_rank<ra::Expr<ra::plus, std::tuple<ra::TensorIndex<0, int>, ra::Scalar<int> > > >::value, "bad");
  82. }
  83. section("check decay of rank 0 Containers/Slices w/ operators");
  84. {
  85. {
  86. auto test = [&tr](auto && a)
  87. {
  88. tr.test_eq(12, a*4.);
  89. auto b = a();
  90. static_assert(std::is_same<int, decltype(b)>::value, "unexpected b non-decay to real");
  91. static_assert(std::is_same<decltype(b*4.), real>::value, "expected b decay to real");
  92. static_assert(std::is_same<decltype(4.*b), real>::value, "expected b decay to real");
  93. tr.test_eq(12., b*4.);
  94. tr.test_eq(12., 4.*b);
  95. static_assert(std::is_same<decltype(a*4.), real>::value, "expected a decay to real");
  96. static_assert(std::is_same<decltype(4.*a), real>::value, "expected a decay to real");
  97. tr.test_eq(12., a*4.);
  98. tr.test_eq(12., 4.*a);
  99. };
  100. test(ra::Small<int>(3));
  101. test(ra::Unique<int, 0>({}, 3));
  102. }
  103. {
  104. ra::Small<int, 3> a { 1, 2, 3 };
  105. ra::Small<int> b { 5 };
  106. a *= b;
  107. tr.test_eq(a[0], 5);
  108. tr.test_eq(a[1], 10);
  109. tr.test_eq(a[2], 15);
  110. }
  111. {
  112. ra::Small<int> a { 3 };
  113. ra::Small<int> b { 2 };
  114. auto c = a*b;
  115. static_assert(std::is_same<decltype(a*b), int>::value, "expected a, b decay to real"); \
  116. tr.test_eq(c, 6);
  117. }
  118. }
  119. section("operators with Unique");
  120. {
  121. ra::Unique<int, 2> a({3, 2}, { 1, 2, 3, 20, 5, 6 });
  122. ra::Unique<int, 1> b({3}, { 10, 20, 30 });
  123. #define TESTSUM(expr) \
  124. tr.test_eq(expr, ra::Small<int, 3, 2> {11, 12, 23, 40, 35, 36});
  125. TESTSUM(ra::expr([](int a, int b) { return a + b; }, a.iter(), b.iter()));
  126. TESTSUM(a.iter() + b.iter());
  127. TESTSUM(a+b);
  128. #undef TESTSUM
  129. #define TESTEQ(expr) \
  130. tr.test_eq(expr, ra::Small<bool, 3, 2> {false, false, false, true, false, false});
  131. TESTEQ(a==b);
  132. TESTEQ(!(a!=b));
  133. #undef TESTEQ
  134. }
  135. section("operators with Raw");
  136. {
  137. {
  138. ra::Unique<complex, 2> const a({2, 3}, {1, 2, 3, 4, 5, 6});
  139. {
  140. auto a0 = a(0);
  141. tr.test_eq(ra::Small<real, 3>{.5, 1., 1.5}, 0.5*a0);
  142. }
  143. {
  144. auto a0 = a.at(ra::Small<int, 1> { 0 }); // @BUG Not sure this is what I want
  145. tr.test_eq(ra::Small<real, 3>{.5, 1., 1.5}, 0.5*a0);
  146. }
  147. }
  148. {
  149. ra::Unique<complex, 1> const a({3}, {1, 2, 3});
  150. {
  151. auto a0 = a(0);
  152. tr.test_eq(0.5, 0.5*a0);
  153. }
  154. {
  155. auto a0 = a.at(ra::Small<int, 1> { 0 }); // @BUG Not sure this is what I want, see above
  156. tr.test_eq(2.1, 2.1*a0);
  157. tr.test_eq(0.5, 0.5*a0);
  158. tr.test_eq(0.5, complex(0.5)*a0);
  159. }
  160. }
  161. }
  162. section("operators with Small");
  163. {
  164. ra::Small<int, 3> a { 1, 2, 3 };
  165. ra::Small<int, 3> b { 1, 2, 4 };
  166. tr.test_eq(ra::Small<int, 3> {2, 4, 7}, ra::expr([](int a, int b) { return a + b; }, a.iter(), b.iter()));
  167. tr.test_eq(ra::Small<int, 3> {2, 4, 7}, (a.iter() + b.iter()));
  168. tr.test_eq(ra::Small<int, 3> {2, 4, 7}, a+b);
  169. }
  170. section("constructors from expr"); // @TODO For all other Container types.
  171. {
  172. {
  173. // @TODO Systematic init-from-expr tests (every expr type vs every container type) with ra-operators.H included.
  174. ra::Unique<int, 1> a({3}, { 1, 2, 3 });
  175. ra::Unique<int, 1> b({3}, { 10, 20, 30 });
  176. ra::Unique<int, 1> c(a.iter() + b.iter());
  177. tr.test_eq(ra::Small<int, 3> {11, 22, 33}, c);
  178. }
  179. {
  180. ra::Unique<int, 2> a({3, 2}, 77);
  181. tr.test_eq(a, ra::Small<int, 3, 2> {77, 77, 77, 77, 77, 77});
  182. }
  183. {
  184. ra::Unique<int, 2> a({3, 2}, ra::cast<int>(ra::TensorIndex<0>()-ra::TensorIndex<1>()));
  185. tr.test_eq(ra::Small<int, 3, 2> {0, -1, 1, 0, 2, 1}, a);
  186. }
  187. }
  188. section("mixed ra-type / foreign-scalar operations");
  189. {
  190. ra::Unique<int, 2> a({3, 2}, { 1, 2, 3, 20, 5, 6 });
  191. ra::Small<int, 3, 2> ref {4, 5, 6, 23, 8, 9};
  192. tr.test_eq(ref, ra::expr([](int a, int b) { return a + b; }, ra::start(a), ra::start(3)));
  193. tr.test_eq(ref, ra::start(a) + ra::start(3));
  194. tr.test_eq(ref, a+3);
  195. }
  196. // These are rather different because they have to be defined in-class.
  197. section("constructors & assignment operators with expr rhs"); // @TODO use TestRecorder::test_eq().
  198. {
  199. real check0[6] = { 0, -1, 1, 0, 2, 1 };
  200. real check1[6] = { 4, 3, 5, 4, 6, 5 };
  201. real check2[6] = { 8, 6, 10, 8, 12, 10 };
  202. auto test = [&](auto && a)
  203. {
  204. tr.test(std::equal(a.begin(), a.end(), check0));
  205. a += 4;
  206. tr.test(std::equal(a.begin(), a.end(), check1));
  207. a += a;
  208. tr.test(std::equal(a.begin(), a.end(), check2));
  209. };
  210. test(ra::Unique<int, 2>({3, 2}, ra::cast<int>(ra::TensorIndex<0>()-ra::TensorIndex<1>())));
  211. test(ra::Small<int, 3, 2>(ra::cast<int>(ra::TensorIndex<0>()-ra::TensorIndex<1>())));
  212. }
  213. section("operator= for Raw, WithStorage. Also see test-ra-ownership.C"); // @TODO use TestRecorder::test_eq().
  214. {
  215. real check5[6] = { 5, 5, 5, 5, 5, 5 };
  216. real check9[6] = { 9, 9, 9, 9, 9, 9 };
  217. ra::Unique<int, 2> a({3, 2}, 7);
  218. ra::Unique<int, 2> b({3, 2}, 5);
  219. ra::Raw<int, 2> c = a();
  220. ra::Raw<int, 2> d = b();
  221. c = d;
  222. tr.test(std::equal(a.begin(), a.end(), check5));
  223. ra::Unique<int, 2> t({2, 3}, 9);
  224. c = transpose(t, {1, 0});
  225. tr.test(std::equal(a.begin(), a.end(), check9));
  226. a = d;
  227. tr.test(std::equal(a.begin(), a.end(), check5));
  228. {
  229. ra::Unique<int, 2> e = d;
  230. tr.test(std::equal(e.begin(), e.end(), check5));
  231. }
  232. }
  233. section("operator= for Dynamic");
  234. {
  235. ra::Unique<int, 1> a({7}, 7);
  236. ra::Small<ra::dim_t, 3> i { 2, 3, 5 };
  237. ra::Small<int, 3> b { 22, 33, 55 };
  238. ra::expr([&a](ra::dim_t i) -> decltype(auto) { return a(i); }, ra::start(i)) = b;
  239. int checka[] = { 7, 7, 22, 33, 7, 55, 7 };
  240. tr.test(std::equal(checka, checka+7, a.begin()));
  241. }
  242. section("wedge");
  243. {
  244. {
  245. ra::Small<real, 3> a {1, 2, 3};
  246. ra::Small<real, 3> b {4, 5, 7};
  247. ra::Small<real, 3> c;
  248. fun::Wedge<3, 1, 1>::product(a, b, c);
  249. tr.test_eq(ra::Small<real, 3> {-1, 5, -3}, c);
  250. }
  251. {
  252. ra::Small<real, 1> a {2};
  253. ra::Small<real, 1> b {3};
  254. ra::Small<real, 1> r;
  255. fun::Wedge<1, 0, 0>::product(a, b, r);
  256. tr.test_eq(6, r[0]);
  257. tr.test_eq(6, wedge<1, 0, 0>(ra::Small<real, 1>{2}, ra::Small<real, 1>{3}));
  258. tr.test_eq(6, wedge<1, 0, 0>(ra::Small<real, 1>{2}, 3.));
  259. tr.test_eq(6, wedge<1, 0, 0>(2., ra::Small<real, 1>{3}));
  260. tr.test_eq(6, wedge<1, 0, 0>(2., 3));
  261. }
  262. }
  263. section("hodge / hodgex");
  264. {
  265. ra::Small<real, 3> a {1, 2, 3};
  266. ra::Small<real, 3> c;
  267. fun::hodgex<3, 1>(a, c);
  268. tr.test_eq(a, c);
  269. auto d = fun::hodge<3, 1>(a);
  270. tr.test_eq(a, d);
  271. }
  272. return tr.summary();
  273. }