operators.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. // -*- mode: c++; coding: utf-8 -*-
  2. // ra-ra/test - Tests for operators.
  3. // (c) Daniel Llorens - 2014-2015
  4. // This library is free software; you can redistribute it and/or modify it under
  5. // the terms of the GNU Lesser General Public License as published by the Free
  6. // Software Foundation; either version 3 of the License, or (at your option) any
  7. // later version.
  8. #include "ra/test.hh"
  9. #include "mpdebug.hh"
  10. using std::cout, std::endl, ra::TestRecorder;
  11. using real = double;
  12. using complex = std::complex<double>;
  13. int main()
  14. {
  15. TestRecorder tr;
  16. tr.section("[ra8]");
  17. {
  18. constexpr int z = 1 + ra::scalar(2);
  19. tr.test_eq(3, z);
  20. }
  21. tr.section("unary ops");
  22. {
  23. #define DEF_TEST_UNARY_OP(OP) \
  24. auto test = [&tr](auto token, auto x, auto y, auto && vx, auto && vy, real err) \
  25. { \
  26. using T = decltype(token); \
  27. using TY = decltype(OP(std::declval<T>())); \
  28. tr.info("scalar-scalar").test_abs(OP(T(x)), TY(y), err); \
  29. tr.info("array(0)-scalar").test_abs(OP(ra::Unique<T, 0>(x)), TY(y), err); \
  30. tr.info("array(var)-scalar").test_abs(OP(ra::Unique<T>(x)), TY(y), err); \
  31. tr.info("array(1)-array(1)").test_abs(OP(vx), vy, err); \
  32. };
  33. {
  34. DEF_TEST_UNARY_OP(abs);
  35. test(int(), -3, 3, ra::Unique<int, 1>{1, -3, -2}, ra::Unique<int, 1>{1, 3, 2}, 0.);
  36. test(real(), -3, 3, ra::Unique<real, 1>{1, -3, -2}, ra::Unique<real, 1>{1, 3, 2}, 0.);
  37. test(float(), -3, 3, ra::Unique<float, 1>{1, -3, -2}, ra::Unique<float, 1>{1, 3, 2}, 0.);
  38. test(complex(), -3, 3, ra::Unique<complex, 1>{1, -3, -2}, ra::Unique<complex, 1>{1, 3, 2}, 0.);
  39. }
  40. #define TEST_UNARY_OP_CR(OP, ri, ro, ci, co, err) \
  41. { \
  42. DEF_TEST_UNARY_OP(OP); \
  43. test(real(), ri, ro, ra::Unique<real, 1>{ri, ri, ri}, ra::Unique<complex, 1>{ro, ro, ro}, err); \
  44. test(complex(), ci, co, ra::Unique<complex, 1>{ci, ci}, ra::Unique<complex, 1>{co, co}, err); \
  45. }
  46. TEST_UNARY_OP_CR(conj, 1., 1., complex(1., 2.), complex(1., -2), 0.);
  47. TEST_UNARY_OP_CR(cos, 0., 1., complex(0, 0), complex(1., 0.), 0.);
  48. TEST_UNARY_OP_CR(sin, 1.57079632679489661, 1., complex(1.57079632679489661, 0), complex(1., 0.), 0.);
  49. TEST_UNARY_OP_CR(exp, 0., 1., complex(0, 0), complex(1., 0.), 0.);
  50. TEST_UNARY_OP_CR(sqrt, 4., 2., complex(-1, 0), complex(0., 1.), 1e-16);
  51. TEST_UNARY_OP_CR(ra::xi, 4., complex(0, 4.), complex(1., -2.), complex(2., 1.), 0.);
  52. #undef TEST_UNARY_OP_CR
  53. #undef DEF_TEST_UNARY_OP
  54. // TODO merge with DEF_TEST_UNARY_OP
  55. tr.info("odd").test_eq(ra::Unique<bool, 1> {true, false, true, true}, odd(ra::Unique<int, 1> {1, 2, 3, -1}));
  56. }
  57. tr.section("binary ops");
  58. {
  59. // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96278
  60. #pragma GCC diagnostic push
  61. #pragma GCC diagnostic warning "-Wzero-as-null-pointer-constant"
  62. tr.info("<=> a").test_eq(true, (2<=>1)>0);
  63. tr.info("<=> b").test_eq(ra::ptr((char const *)"+0-"),
  64. map([](auto z) { return z>0 ? '+' : z<0 ? '-' : '0'; },
  65. ra::Small<int, 3>{3, 4, 5} <=> ra::Small<double, 3>{2., 4., 6.}));
  66. #pragma GCC diagnostic pop
  67. }
  68. tr.section("check decay of rank 0 Containers/Slices w/ operators");
  69. {
  70. {
  71. auto test = [&tr](auto && a)
  72. {
  73. tr.test_eq(12, a*4.);
  74. auto b = a();
  75. static_assert(std::is_same_v<int, decltype(b)>, "unexpected b non-decay to real");
  76. static_assert(std::is_same_v<real, decltype(b*4.)>, "expected b decay to real");
  77. static_assert(std::is_same_v<real, decltype(4.*b)>, "expected b decay to real");
  78. tr.test_eq(12., b*4.);
  79. tr.test_eq(12., 4.*b);
  80. static_assert(std::is_same_v<real, decltype(a*4.)>, "expected a decay to real");
  81. static_assert(std::is_same_v<real, decltype(4.*a)>, "expected a decay to real");
  82. tr.test_eq(12., a*4.);
  83. tr.test_eq(12., 4.*a);
  84. };
  85. test(ra::Small<int>(3));
  86. test(ra::Unique<int, 0>({}, 3));
  87. }
  88. {
  89. ra::Small<int, 3> a { 1, 2, 3 };
  90. ra::Small<int> b { 5 };
  91. a *= b;
  92. tr.test_eq(a[0], 5);
  93. tr.test_eq(a[1], 10);
  94. tr.test_eq(a[2], 15);
  95. }
  96. {
  97. ra::Small<int> a { 3 };
  98. ra::Small<int> b { 2 };
  99. auto c = a*b;
  100. static_assert(std::is_same_v<int, decltype(a*b)>, "expected a, b decay to real"); \
  101. tr.test_eq(c, 6);
  102. }
  103. }
  104. tr.section("lvalue-rvalue operators I");
  105. {
  106. ra::Unique<complex, 1> a({3}, 0.);
  107. imag_part(a) = ra::Unique<real, 1> { 7., 2., 3. }; // TODO operator=(initializer_list) ?
  108. real_part(a) = -imag_part(ra::Unique<complex, 1> { ra::xi(7.), ra::xi(2.), ra::xi(3.) })+1;
  109. tr.test_eq(ra::Unique<complex, 1> {{-6., 7.}, {-1., 2.}, {-2., 3.}}, a);
  110. }
  111. tr.section("lvalue-rvalue operators II [ma115]");
  112. {
  113. ra::Small<std::complex<double>, 2, 2> A = {{1., 2.}, {3., 4.}};
  114. imag_part(A) = -2*real_part(A);
  115. cout << A << endl;
  116. tr.test_eq(ra::Small<std::complex<double>, 2, 2> {{{1., -2.}, {2., -4.}}, {{3., -6.}, {4, -8.}}}, A);
  117. }
  118. tr.section("operators with Unique");
  119. {
  120. ra::Unique<int, 2> a({3, 2}, { 1, 2, 3, 20, 5, 6 });
  121. ra::Unique<int, 1> b({3}, { 10, 20, 30 });
  122. #define TESTSUM(expr) \
  123. tr.test_eq(expr, ra::Small<int, 3, 2> {11, 12, 23, 40, 35, 36});
  124. TESTSUM(ra::expr([](int a, int b) { return a + b; }, a.iter(), b.iter()));
  125. TESTSUM(a.iter() + b.iter());
  126. TESTSUM(a+b);
  127. #undef TESTSUM
  128. #define TESTEQ(expr) \
  129. tr.test_eq(expr, ra::Small<bool, 3, 2> {false, false, false, true, false, false});
  130. TESTEQ(a==b);
  131. TESTEQ(!(a!=b));
  132. #undef TESTEQ
  133. }
  134. tr.section("operators with View");
  135. {
  136. {
  137. ra::Unique<complex, 2> const a({2, 3}, {1, 2, 3, 4, 5, 6});
  138. {
  139. auto a0 = a(0);
  140. tr.test_eq(ra::Small<real, 3>{.5, 1., 1.5}, 0.5*a0);
  141. }
  142. {
  143. auto a0 = a.at(ra::Small<int, 1> { 0 }); // BUG Not sure this is what I want
  144. tr.test_eq(ra::Small<real, 3>{.5, 1., 1.5}, 0.5*a0);
  145. }
  146. }
  147. {
  148. ra::Unique<complex, 1> const a({3}, {1, 2, 3});
  149. {
  150. auto a0 = a(0);
  151. tr.test_eq(0.5, 0.5*a0);
  152. }
  153. {
  154. auto a0 = a.at(ra::Small<int, 1> { 0 }); // BUG Not sure this is what I want, see above
  155. tr.test_eq(2.1, 2.1*a0);
  156. tr.test_eq(0.5, 0.5*a0);
  157. tr.test_eq(0.5, complex(0.5)*a0);
  158. }
  159. }
  160. }
  161. tr.section("operators with Small");
  162. {
  163. ra::Small<int, 3> a { 1, 2, 3 };
  164. ra::Small<int, 3> b { 1, 2, 4 };
  165. tr.test_eq(ra::Small<int, 3> {2, 4, 7}, ra::expr([](int a, int b) { return a + b; }, a.iter(), b.iter()));
  166. tr.test_eq(ra::Small<int, 3> {2, 4, 7}, (a.iter() + b.iter()));
  167. tr.test_eq(ra::Small<int, 3> {2, 4, 7}, a+b);
  168. }
  169. tr.section("constructors from expr"); // TODO For all other Container types.
  170. {
  171. {
  172. // TODO Systematic init-from-expr tests (every expr type vs every container type)
  173. ra::Unique<int, 1> a({3}, { 1, 2, 3 });
  174. ra::Unique<int, 1> b({3}, { 10, 20, 30 });
  175. ra::Unique<int, 1> c(a.iter() + b.iter());
  176. tr.test_eq(ra::Small<int, 3> {11, 22, 33}, c);
  177. }
  178. {
  179. ra::Unique<int, 2> a({3, 2}, 77);
  180. tr.test_eq(a, ra::Small<int, 3, 2> {77, 77, 77, 77, 77, 77});
  181. }
  182. {
  183. ra::Unique<int, 2> a({3, 2}, ra::cast<int>(ra::_0-ra::_1));
  184. tr.test_eq(ra::Small<int, 3, 2> {0, -1, 1, 0, 2, 1}, a);
  185. }
  186. }
  187. tr.section("mixed ra-type / foreign-scalar operations");
  188. {
  189. ra::Unique<int, 2> a({3, 2}, { 1, 2, 3, 20, 5, 6 });
  190. ra::Small<int, 3, 2> ref {4, 5, 6, 23, 8, 9};
  191. tr.test_eq(ref, ra::expr([](int a, int b) { return a + b; }, ra::start(a), ra::start(3)));
  192. tr.test_eq(ref, ra::start(a) + ra::start(3));
  193. tr.test_eq(ref, a+3);
  194. }
  195. // These are rather different because they have to be defined in-class.
  196. tr.section("constructors & assignment operators with expr rhs"); // TODO use TestRecorder::test_eq().
  197. {
  198. real check0[6] = { 0, -1, 1, 0, 2, 1 };
  199. real check1[6] = { 4, 3, 5, 4, 6, 5 };
  200. real check2[6] = { 8, 6, 10, 8, 12, 10 };
  201. auto test = [&](auto && a)
  202. {
  203. tr.test(std::equal(a.begin(), a.end(), check0));
  204. a += 4;
  205. tr.test(std::equal(a.begin(), a.end(), check1));
  206. a += a;
  207. tr.test(std::equal(a.begin(), a.end(), check2));
  208. };
  209. test(ra::Unique<int, 2>({3, 2}, ra::cast<int>(ra::_0-ra::_1)));
  210. test(ra::Small<int, 3, 2>(ra::cast<int>(ra::_0-ra::_1)));
  211. }
  212. tr.section("assignment ops with ra::scalar [ra21]");
  213. {
  214. ra::Small<real, 2> a { 0, 0 };
  215. ra::Big<ra::Small<real, 2>, 1> b { {1, 10}, {2, 20}, {3, 30} };
  216. // use scalar to match 1 (a) vs 3 (b) instead of 2 vs 3.
  217. ra::scalar(a) += b;
  218. tr.test_eq(ra::Small<real, 2> { 6, 60 }, a);
  219. }
  220. tr.section("pack operator");
  221. {
  222. ra::Small<real, 6> a = { 0, -1, 1, 0, 2, 1 };
  223. ra::Small<int, 6> b = { 4, 3, 5, 4, 6, 5 };
  224. ra::Big<std::tuple<real, int>, 1> x = ra::pack<std::tuple<real, int>>(a, b); // TODO kinda redundant...
  225. tr.test_eq(a, map([](auto && x) -> decltype(auto) { return std::get<0>(x); }, x));
  226. tr.test_eq(b, map([](auto && x) -> decltype(auto) { return std::get<1>(x); }, x));
  227. }
  228. tr.section("pack operator as ref");
  229. {
  230. using T = std::tuple<real, int>;
  231. ra::Big<T> x { T(0., 1), T(2., 3), T(4., 5) };
  232. ra::Small<real, 3> a = -99.;
  233. ra::Small<int, 3> b = -77;
  234. ra::pack<std::tuple<real &, int &>>(a, b) = x;
  235. tr.test_eq(ra::Small<real, 3> {0., 2., 4.}, a);
  236. tr.test_eq(ra::Small<int, 3> {1, 3, 5}, b);
  237. }
  238. tr.section("operator= for View, Container. Cf test/ownership.cc");
  239. {
  240. real check5[6] = { 5, 5, 5, 5, 5, 5 };
  241. real check9[6] = { 9, 9, 9, 9, 9, 9 };
  242. ra::Unique<int, 2> a({3, 2}, 7);
  243. ra::Unique<int, 2> b({3, 2}, 5);
  244. ra::ViewBig<int, 2> c = a();
  245. ra::ViewBig<int, 2> d = b();
  246. c = d;
  247. tr.test(std::equal(a.begin(), a.end(), check5));
  248. ra::Unique<int, 2> t({2, 3}, 9);
  249. c = transpose({1, 0}, t);
  250. tr.test(std::equal(a.begin(), a.end(), check9));
  251. a = d;
  252. tr.test(std::equal(a.begin(), a.end(), check5));
  253. ra::Unique<int, 2> e = d;
  254. tr.test(std::equal(e.begin(), e.end(), check5));
  255. }
  256. tr.section("operator= for Dynamic");
  257. {
  258. ra::Unique<int, 1> a({7}, 7);
  259. ra::Small<ra::dim_t, 3> i { 2, 3, 5 };
  260. ra::Small<int, 3> b { 22, 33, 55 };
  261. ra::expr([&a](ra::dim_t i) -> decltype(auto) { return a(i); }, ra::start(i)) = b;
  262. int checka[] = { 7, 7, 22, 33, 7, 55, 7 };
  263. tr.test(std::equal(checka, checka+7, a.begin()));
  264. }
  265. tr.section("wedge");
  266. {
  267. {
  268. ra::Small<real, 3> a {1, 2, 3};
  269. ra::Small<real, 3> b {4, 5, 7};
  270. ra::Small<real, 3> c;
  271. ra::mp::Wedge<3, 1, 1>::product(a, b, c);
  272. tr.test_eq(ra::Small<real, 3> {-1, 5, -3}, c);
  273. }
  274. {
  275. ra::Small<real, 1> a {2};
  276. ra::Small<real, 1> b {3};
  277. ra::Small<real, 1> r;
  278. ra::mp::Wedge<1, 0, 0>::product(a, b, r);
  279. tr.test_eq(6, r[0]);
  280. tr.test_eq(6, ra::wedge<1, 0, 0>(ra::Small<real, 1>{2}, ra::Small<real, 1>{3}));
  281. tr.test_eq(6, ra::wedge<1, 0, 0>(ra::Small<real, 1>{2}, 3.));
  282. tr.test_eq(6, ra::wedge<1, 0, 0>(2., ra::Small<real, 1>{3}));
  283. tr.test_eq(6, ra::wedge<1, 0, 0>(2., 3));
  284. }
  285. }
  286. tr.section("hodge / hodgex");
  287. {
  288. ra::Small<real, 3> a {1, 2, 3};
  289. ra::Small<real, 3> c;
  290. ra::mp::hodgex<3, 1>(a, c);
  291. tr.test_eq(a, c);
  292. auto d = ra::hodge<3, 1>(a);
  293. tr.test_eq(a, d);
  294. }
  295. tr.section("index");
  296. {
  297. {
  298. ra::Big<real, 1> a {1, 2, 3, -4, 9, 9, 8};
  299. tr.test_eq(3, index(a<0));
  300. tr.test_eq(-1, index(a>100));
  301. }
  302. {
  303. ra::Big<real> a {1, 2, 3, -4, 9, 9, 8};
  304. tr.test_eq(4, index(abs(a)>4));
  305. }
  306. }
  307. tr.section("lexicographical_compare");
  308. {
  309. ra::Big<int, 3> a({10, 2, 2}, {0, 0, 1, 3, 0, 1, 3, 3, 0, 2, 3, 0, 3, 1, 2, 1, 1, 1, 3, 1, 0, 3, 2, 2, 2, 3, 1, 2, 2, 0, 0, 1, 0, 1, 1, 1, 3, 0, 2, 1});
  310. ra::Big<int, 1> i = ra::iota(a.len(0));
  311. std::sort(i.data(), i.data()+i.size(),
  312. [&a](int i, int j)
  313. {
  314. return lexicographical_compare(a(i), a(j));
  315. });
  316. tr.test_eq(ra::start({0, 8, 1, 2, 5, 4, 7, 6, 9, 3}), i);
  317. }
  318. return tr.summary();
  319. }