operators.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  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. using ra::xI;
  14. int main()
  15. {
  16. TestRecorder tr;
  17. tr.section("[ra8]");
  18. {
  19. constexpr int z = 1 + ra::scalar(2);
  20. tr.test_eq(3, z);
  21. }
  22. tr.section("unary ops");
  23. {
  24. #define DEF_TEST_UNARY_OP(OP) \
  25. auto test = [&tr](auto token, auto x, auto y, auto && vx, auto && vy, real err) \
  26. { \
  27. using T = decltype(token); \
  28. using TY = decltype(OP(std::declval<T>())); \
  29. tr.info("scalar-scalar").test_abs(OP(T(x)), TY(y), err); \
  30. tr.info("array(0)-scalar").test_abs(OP(ra::Unique<T, 0>(x)), TY(y), err); \
  31. tr.info("array(var)-scalar").test_abs(OP(ra::Unique<T>(x)), TY(y), err); \
  32. tr.info("array(1)-array(1)").test_abs(OP(vx), vy, err); \
  33. };
  34. {
  35. DEF_TEST_UNARY_OP(abs);
  36. test(int(), -3, 3, ra::Unique<int, 1>{1, -3, -2}, ra::Unique<int, 1>{1, 3, 2}, 0.);
  37. test(real(), -3, 3, ra::Unique<real, 1>{1, -3, -2}, ra::Unique<real, 1>{1, 3, 2}, 0.);
  38. test(float(), -3, 3, ra::Unique<float, 1>{1, -3, -2}, ra::Unique<float, 1>{1, 3, 2}, 0.);
  39. test(complex(), -3, 3, ra::Unique<complex, 1>{1, -3, -2}, ra::Unique<complex, 1>{1, 3, 2}, 0.);
  40. }
  41. #define TEST_UNARY_OP_CR(OP, ri, ro, ci, co, err) \
  42. { \
  43. DEF_TEST_UNARY_OP(OP); \
  44. test(real(), ri, ro, ra::Unique<real, 1>{ri, ri, ri}, ra::Unique<complex, 1>{ro, ro, ro}, err); \
  45. test(complex(), ci, co, ra::Unique<complex, 1>{ci, ci}, ra::Unique<complex, 1>{co, co}, err); \
  46. }
  47. TEST_UNARY_OP_CR(conj, 1., 1., complex(1., 2.), complex(1., -2), 0.);
  48. TEST_UNARY_OP_CR(cos, 0., 1., complex(0, 0), complex(1., 0.), 0.);
  49. TEST_UNARY_OP_CR(sin, 1.57079632679489661, 1., complex(1.57079632679489661, 0), complex(1., 0.), 0.);
  50. TEST_UNARY_OP_CR(exp, 0., 1., complex(0, 0), complex(1., 0.), 0.);
  51. TEST_UNARY_OP_CR(sqrt, 4., 2., complex(-1, 0), complex(0., 1.), 1e-16);
  52. TEST_UNARY_OP_CR(xI, 4., complex(0, 4.), complex(1., -2.), complex(2., 1.), 0.);
  53. #undef TEST_UNARY_OP_CR
  54. #undef DEF_TEST_UNARY_OP
  55. // TODO merge with DEF_TEST_UNARY_OP
  56. tr.info("odd").test_eq(ra::Unique<bool, 1> {true, false, true, true}, odd(ra::Unique<int, 1> {1, 2, 3, -1}));
  57. }
  58. tr.section("binary ops");
  59. {
  60. // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96278
  61. #pragma GCC diagnostic push
  62. #pragma GCC diagnostic warning "-Wzero-as-null-pointer-constant"
  63. tr.info("<=> a").test_eq(true, (2<=>1)>0);
  64. tr.info("<=> b").test_eq(ra::ptr((char const *)"+0-"),
  65. map([](auto z) { return z>0 ? '+' : z<0 ? '-' : '0'; },
  66. ra::Small<int, 3>{3, 4, 5} <=> ra::Small<double, 3>{2., 4., 6.}));
  67. #pragma GCC diagnostic pop
  68. }
  69. tr.section("check decay of rank 0 Containers/Slices w/ operators");
  70. {
  71. {
  72. auto test = [&tr](auto && a)
  73. {
  74. tr.test_eq(12, a*4.);
  75. auto b = a();
  76. static_assert(std::is_same_v<int, decltype(b)>, "unexpected b non-decay to real");
  77. static_assert(std::is_same_v<real, decltype(b*4.)>, "expected b decay to real");
  78. static_assert(std::is_same_v<real, decltype(4.*b)>, "expected b decay to real");
  79. tr.test_eq(12., b*4.);
  80. tr.test_eq(12., 4.*b);
  81. static_assert(std::is_same_v<real, decltype(a*4.)>, "expected a decay to real");
  82. static_assert(std::is_same_v<real, decltype(4.*a)>, "expected a decay to real");
  83. tr.test_eq(12., a*4.);
  84. tr.test_eq(12., 4.*a);
  85. };
  86. test(ra::Small<int>(3));
  87. test(ra::Unique<int, 0>({}, 3));
  88. }
  89. {
  90. ra::Small<int, 3> a { 1, 2, 3 };
  91. ra::Small<int> b { 5 };
  92. a *= b;
  93. tr.test_eq(a[0], 5);
  94. tr.test_eq(a[1], 10);
  95. tr.test_eq(a[2], 15);
  96. }
  97. {
  98. ra::Small<int> a { 3 };
  99. ra::Small<int> b { 2 };
  100. auto c = a*b;
  101. static_assert(std::is_same_v<int, decltype(a*b)>, "expected a, b decay to real"); \
  102. tr.test_eq(c, 6);
  103. }
  104. }
  105. tr.section("lvalue-rvalue operators I");
  106. {
  107. ra::Unique<complex, 1> a({3}, 0.);
  108. imag_part(a) = ra::Unique<real, 1> { 7., 2., 3. }; // TODO operator=(initializer_list) ?
  109. real_part(a) = -imag_part(ra::Unique<complex, 1> { xI(7.), xI(2.), xI(3.) })+1;
  110. tr.test_eq(ra::Unique<complex, 1> {{-6., 7.}, {-1., 2.}, {-2., 3.}}, a);
  111. }
  112. tr.section("lvalue-rvalue operators II [ma115]");
  113. {
  114. ra::Small<std::complex<double>, 2, 2> A = {{1., 2.}, {3., 4.}};
  115. imag_part(A) = -2*real_part(A);
  116. cout << A << endl;
  117. tr.test_eq(ra::Small<std::complex<double>, 2, 2> {{{1., -2.}, {2., -4.}}, {{3., -6.}, {4, -8.}}}, A);
  118. }
  119. tr.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. tr.section("operators with View");
  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. tr.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. tr.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)
  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::_0-ra::_1));
  185. tr.test_eq(ra::Small<int, 3, 2> {0, -1, 1, 0, 2, 1}, a);
  186. }
  187. }
  188. tr.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. tr.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::_0-ra::_1)));
  211. test(ra::Small<int, 3, 2>(ra::cast<int>(ra::_0-ra::_1)));
  212. }
  213. tr.section("assignment ops with ra::scalar [ra21]");
  214. {
  215. ra::Small<real, 2> a { 0, 0 };
  216. ra::Big<ra::Small<real, 2>, 1> b { {1, 10}, {2, 20}, {3, 30} };
  217. // use scalar to match 1 (a) vs 3 (b) instead of 2 vs 3.
  218. ra::scalar(a) += b;
  219. tr.test_eq(ra::Small<real, 2> { 6, 60 }, a);
  220. }
  221. tr.section("pack operator");
  222. {
  223. ra::Small<real, 6> a = { 0, -1, 1, 0, 2, 1 };
  224. ra::Small<int, 6> b = { 4, 3, 5, 4, 6, 5 };
  225. ra::Big<std::tuple<real, int>, 1> x = ra::pack<std::tuple<real, int>>(a, b); // TODO kinda redundant...
  226. tr.test_eq(a, map([](auto && x) -> decltype(auto) { return std::get<0>(x); }, x));
  227. tr.test_eq(b, map([](auto && x) -> decltype(auto) { return std::get<1>(x); }, x));
  228. }
  229. tr.section("pack operator as ref");
  230. {
  231. using T = std::tuple<real, int>;
  232. ra::Big<T> x { T(0., 1), T(2., 3), T(4., 5) };
  233. ra::Small<real, 3> a = -99.;
  234. ra::Small<int, 3> b = -77;
  235. ra::pack<std::tuple<real &, int &>>(a, b) = x;
  236. tr.test_eq(ra::Small<real, 3> {0., 2., 4.}, a);
  237. tr.test_eq(ra::Small<int, 3> {1, 3, 5}, b);
  238. }
  239. tr.section("operator= for View, Container. Cf test/ownership.cc");
  240. {
  241. real check5[6] = { 5, 5, 5, 5, 5, 5 };
  242. real check9[6] = { 9, 9, 9, 9, 9, 9 };
  243. ra::Unique<int, 2> a({3, 2}, 7);
  244. ra::Unique<int, 2> b({3, 2}, 5);
  245. ra::View<int, 2> c = a();
  246. ra::View<int, 2> d = b();
  247. c = d;
  248. tr.test(std::equal(a.begin(), a.end(), check5));
  249. ra::Unique<int, 2> t({2, 3}, 9);
  250. c = transpose({1, 0}, t);
  251. tr.test(std::equal(a.begin(), a.end(), check9));
  252. a = d;
  253. tr.test(std::equal(a.begin(), a.end(), check5));
  254. ra::Unique<int, 2> e = d;
  255. tr.test(std::equal(e.begin(), e.end(), check5));
  256. }
  257. tr.section("operator= for Dynamic");
  258. {
  259. ra::Unique<int, 1> a({7}, 7);
  260. ra::Small<ra::dim_t, 3> i { 2, 3, 5 };
  261. ra::Small<int, 3> b { 22, 33, 55 };
  262. ra::expr([&a](ra::dim_t i) -> decltype(auto) { return a(i); }, ra::start(i)) = b;
  263. int checka[] = { 7, 7, 22, 33, 7, 55, 7 };
  264. tr.test(std::equal(checka, checka+7, a.begin()));
  265. }
  266. tr.section("wedge");
  267. {
  268. {
  269. ra::Small<real, 3> a {1, 2, 3};
  270. ra::Small<real, 3> b {4, 5, 7};
  271. ra::Small<real, 3> c;
  272. ra::mp::Wedge<3, 1, 1>::product(a, b, c);
  273. tr.test_eq(ra::Small<real, 3> {-1, 5, -3}, c);
  274. }
  275. {
  276. ra::Small<real, 1> a {2};
  277. ra::Small<real, 1> b {3};
  278. ra::Small<real, 1> r;
  279. ra::mp::Wedge<1, 0, 0>::product(a, b, r);
  280. tr.test_eq(6, r[0]);
  281. tr.test_eq(6, ra::wedge<1, 0, 0>(ra::Small<real, 1>{2}, ra::Small<real, 1>{3}));
  282. tr.test_eq(6, ra::wedge<1, 0, 0>(ra::Small<real, 1>{2}, 3.));
  283. tr.test_eq(6, ra::wedge<1, 0, 0>(2., ra::Small<real, 1>{3}));
  284. tr.test_eq(6, ra::wedge<1, 0, 0>(2., 3));
  285. }
  286. }
  287. tr.section("hodge / hodgex");
  288. {
  289. ra::Small<real, 3> a {1, 2, 3};
  290. ra::Small<real, 3> c;
  291. ra::mp::hodgex<3, 1>(a, c);
  292. tr.test_eq(a, c);
  293. auto d = ra::hodge<3, 1>(a);
  294. tr.test_eq(a, d);
  295. }
  296. tr.section("index");
  297. {
  298. {
  299. ra::Big<real, 1> a {1, 2, 3, -4, 9, 9, 8};
  300. tr.test_eq(3, index(a<0));
  301. tr.test_eq(-1, index(a>100));
  302. }
  303. {
  304. ra::Big<real> a {1, 2, 3, -4, 9, 9, 8};
  305. tr.test_eq(4, index(abs(a)>4));
  306. }
  307. }
  308. tr.section("lexicographical_compare");
  309. {
  310. 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});
  311. ra::Big<int, 1> i = ra::iota(a.len(0));
  312. std::sort(i.data(), i.data()+i.size(),
  313. [&a](int i, int j)
  314. {
  315. return lexicographical_compare(a(i), a(j));
  316. });
  317. tr.test_eq(ra::start({0, 8, 1, 2, 5, 4, 7, 6, 9, 3}), i);
  318. }
  319. return tr.summary();
  320. }