ply.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. // -*- mode: c++; coding: utf-8 -*-
  2. // ra-ra/test - Traversal.
  3. // (c) Daniel Llorens - 2013-2023
  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 <numeric>
  9. #include <iostream>
  10. #include <iterator>
  11. #include "ra/test.hh"
  12. #include "ra/complex.hh"
  13. using std::cout, std::endl, std::flush, ra::TestRecorder;
  14. using real = double;
  15. struct Never
  16. {
  17. int a;
  18. Never(): a(0) {}
  19. void operator=(int b) { a = 99; }
  20. bool used() { return a==99 ? true : false; }
  21. };
  22. int main()
  23. {
  24. TestRecorder tr;
  25. tr.section("traversal - xpr types - Expr");
  26. {
  27. {
  28. real check[6] = {0-3, 1-3, 2-3, 3-3, 4-3, 5-3};
  29. ra::Unique<real, 2> a({3, 2}, ra::none);
  30. ra::Unique<real, 2> c({3, 2}, ra::none);
  31. std::iota(a.begin(), a.end(), 0);
  32. #define TEST(plier) \
  33. { \
  34. std::fill(c.begin(), c.end(), 0); \
  35. plier(ra::expr([](real & c, real a, real b) { c = a-b; }, \
  36. c.iter(), a.iter(), ra::scalar(3.0))); \
  37. tr.info(STRINGIZE(plier)).test(std::equal(check, check+6, c.begin())); \
  38. }
  39. TEST(ply_ravel);
  40. TEST(ply_fixed);
  41. #undef TEST
  42. }
  43. #define TEST(plier) \
  44. { \
  45. ra::Small<int, 3> A {1, 2, 3}; \
  46. ra::Small<int, 3> C {0, 0, 0}; \
  47. plier(ra::expr([](int a, int & c) { c = -a; }, A.iter(), C.iter())); \
  48. tr.test_eq(-1, C[0]); \
  49. tr.test_eq(-2, C[1]); \
  50. tr.test_eq(-3, C[2]); \
  51. ra::Small<int, 3> B {+1, -2, +3}; \
  52. plier(ra::expr([](int a, int b, int & c) { c = a*b; }, A.iter(), B.iter(), C.iter())); \
  53. tr.test_eq(+1, C[0]); \
  54. tr.test_eq(-4, C[1]); \
  55. tr.test_eq(+9, C[2]); \
  56. }
  57. TEST(ply_ravel);
  58. TEST(ply_fixed);
  59. #undef TEST
  60. {
  61. ra::Unique<int, 3> a(std::vector<ra::dim_t> {3, 2, 4}, ra::none);
  62. ra::Unique<int, 3> b(std::vector<ra::dim_t> {3, 2, 4}, ra::none);
  63. ra::Unique<int, 3> c(std::vector<ra::dim_t> {3, 2, 4}, ra::none);
  64. std::iota(a.begin(), a.end(), 0);
  65. std::iota(b.begin(), b.end(), 0);
  66. #define TEST(plier) \
  67. { \
  68. std::iota(c.begin(), c.end(), 99); \
  69. plier(ra::expr([](int a, int b, int & c) { c = a-b; }, a.iter(), b.iter(), c.iter())); \
  70. for (int ci: c) { tr.test_eq(0, ci); } \
  71. }
  72. TEST(ply_ravel);
  73. TEST(ply_fixed);
  74. #undef TEST
  75. }
  76. }
  77. tr.section("traversal - xpr types - Expr - rank 0");
  78. {
  79. {
  80. real check[1] = {4};
  81. #define TEST(plier) \
  82. [&tr, &check](auto && a, auto && c) \
  83. { \
  84. std::iota(a.begin(), a.end(), 7); \
  85. std::fill(c.begin(), c.end(), 0); \
  86. plier(ra::expr([](real & c, real a, real b) { c = a-b; }, \
  87. c.iter(), a.iter(), ra::scalar(3.0))); \
  88. tr.test(std::equal(check, check+1, c.begin())); \
  89. }
  90. #define TEST2(plier) \
  91. TEST(plier)(ra::Unique<real, 0>({}, ra::none), ra::Unique<real, 0>({}, ra::none)); \
  92. TEST(plier)(ra::Small<real> {}, ra::Small<real> {}); \
  93. TEST(plier)(ra::Small<real> {}, ra::Unique<real, 0>({}, ra::none));
  94. TEST2(ply_ravel);
  95. TEST2(ply_fixed);
  96. #undef TEST2
  97. #undef TEST
  98. }
  99. }
  100. tr.section("traversal - xpr types - Expr - empty");
  101. {
  102. {
  103. #define TEST(plier, id) \
  104. [&tr](auto && a, bool used) \
  105. { \
  106. tr.info(STRINGIZE(plier) "/" id) \
  107. .test((used || (a.begin()==a.end() && a.size()==0)) && STRINGIZE(plier) id " before"); \
  108. Never check; \
  109. plier(ra::expr([&check](int a) { check = a; }, a.iter())); \
  110. tr.info(STRINGIZE(plier) id " after") \
  111. .test(check.used()==used); \
  112. }
  113. #define TEST2(plier) \
  114. TEST(plier, "00")(ra::Small<int, 0> {}, false); \
  115. TEST(plier, "01")(ra::Unique<int, 1>({ 0 }, ra::none), false); \
  116. TEST(plier, "02")(ra::Unique<int, 2>({ 2, 0 }, ra::none), false); \
  117. TEST(plier, "03")(ra::Unique<int, 2>({ 0, 2 }, ra::none), false); \
  118. TEST(plier, "04")(ra::Small<int> {}, true); \
  119. TEST(plier, "05")(ra::Unique<int, 0>({}, ra::none), true);
  120. TEST2(ply_ravel);
  121. TEST2(ply_fixed);
  122. // this one cannot be done with ply_fixed.
  123. TEST(ply_ravel, "06")(ra::Unique<int>({ 0 }, ra::none), false);
  124. #undef TEST2
  125. #undef TEST
  126. // With ra::expr, non-slices.
  127. #define TEST(plier, id) \
  128. [&tr](auto && a, bool used) \
  129. { \
  130. cout << STRINGIZE(plier) "/" id << endl; \
  131. tr.test((used || (a.len(0)==0 || a.len(1)==0)) && STRINGIZE(plier) id " before"); \
  132. Never check; \
  133. plier(ra::expr([&check](int a) { check = a; }, a)); \
  134. tr.test(check.used()==used && STRINGIZE(plier) id " after"); \
  135. }
  136. #define TEST2(plier) \
  137. TEST(plier, "10")(ra::Unique<int, 1>({ 0 }, ra::none)+ra::Small<int, 0>(), false); \
  138. TEST(plier, "11")(ra::Unique<int, 2>({ 2, 0 }, ra::none)+ra::Small<int, 2, 0>(), false); \
  139. TEST(plier, "12")(ra::Unique<int, 2>({ 0, 2 }, ra::none)+ra::Small<int, 0, 2>(), false); \
  140. TEST(plier, "13")(ra::Unique<int, 1>({ 0 }, ra::none)+ra::scalar(1), false); \
  141. TEST(plier, "14")(ra::Unique<int, 2>({ 2, 0 }, ra::none)+ra::scalar(1), false); \
  142. TEST(plier, "15")(ra::Unique<int, 2>({ 0, 2 }, ra::none)+ra::scalar(1), false);
  143. TEST2(ply_fixed);
  144. TEST2(ply_ravel);
  145. }
  146. #undef TEST2
  147. #undef TEST
  148. }
  149. tr.section("traversal - does it compile?");
  150. {
  151. // TODO Check.
  152. auto print = [](real a) { cout << a << " "; };
  153. {
  154. auto test = [&](auto && a)
  155. {
  156. ra::ply_ravel(ra::expr(print, a.iter())); cout << endl;
  157. ra::ply_fixed(ra::expr(print, a.iter())); cout << endl;
  158. };
  159. ra::Unique<real, 3> a(std::vector<ra::dim_t> {1, 2, 3}, ra::none);
  160. std::iota(a.begin(), a.end(), 0);
  161. test(a);
  162. test(a()); // also View.
  163. }
  164. // TODO See Expr::CAN_DRIVE in expr.hh. Doesn't generally work with Unique<ANY> because Expr needs to pick a driving argument statically. However, it does work when there's only one argument, since ply_ravel() is rank-dynamic.
  165. {
  166. auto test = [&](auto && a)
  167. {
  168. ra::ply_ravel(ra::expr(print, a.iter())); cout << endl;
  169. };
  170. ra::Unique<real> a(std::vector<ra::dim_t> {1, 2, 3}, ra::none);
  171. std::iota(a.begin(), a.end(), 0);
  172. test(a);
  173. test(a()); // also View.
  174. }
  175. }
  176. tr.section("[ra6] constructor cases with scalar or ANY arguments");
  177. {
  178. // TODO Move these to the constructor tests, and put assignment versions here.
  179. tr.section("construction of 0 rank <- scalar expr");
  180. {
  181. ra::Unique<real, 0> a ({}, ra::scalar(77));
  182. tr.test_eq(77, a());
  183. }
  184. tr.section("construction of var rank <- scalar expr");
  185. {
  186. ra::Unique<real> a ({3, 2}, ra::scalar(77));
  187. tr.test_eq(77, a(0, 0));
  188. tr.test_eq(77, a(0, 1));
  189. tr.test_eq(77, a(1, 0));
  190. tr.test_eq(77, a(1, 1));
  191. tr.test_eq(77, a(2, 0));
  192. tr.test_eq(77, a(2, 1));
  193. }
  194. tr.section("construction of var rank <- lower rank expr I");
  195. {
  196. ra::Unique<real, 1> b ({3}, {1, 2, 3});
  197. ra::Unique<real> a ({3, 2}, b.iter());
  198. tr.test_eq(1, a(0, 0));
  199. tr.test_eq(1, a(0, 1));
  200. tr.test_eq(2, a(1, 0));
  201. tr.test_eq(2, a(1, 1));
  202. tr.test_eq(3, a(2, 0));
  203. tr.test_eq(3, a(2, 1));
  204. }
  205. tr.section("construction of var rank <- lower rank expr II");
  206. {
  207. ra::Unique<real> b ({3, 2}, {1, 2, 3, 4, 5, 6});
  208. cout << "b: " << b << endl;
  209. ra::Unique<real> a ({3, 2, 4}, b.iter());
  210. cout << "a: " << a << endl;
  211. for (int i=0; i<3; ++i) {
  212. for (int j=0; j<2; ++j) {
  213. for (int k=0; k<4; ++k) {
  214. tr.test_eq(a(i, j, k), b(i, j));
  215. }
  216. }
  217. }
  218. }
  219. // this succeeds because of the two var ranks, the top rank comes first (and so it's selected as driver). TODO Have run time driver selection so this is safe.
  220. tr.section("construction of var rank <- lower rank expr III (var rank)");
  221. {
  222. ra::Unique<real> b ({3}, {1, 2, 3});
  223. ra::Unique<real> a ({3, 2}, b.iter());
  224. tr.test_eq(1, a(0, 0));
  225. tr.test_eq(1, a(0, 1));
  226. tr.test_eq(2, a(1, 0));
  227. tr.test_eq(2, a(1, 1));
  228. tr.test_eq(3, a(2, 0));
  229. tr.test_eq(3, a(2, 1));
  230. }
  231. // driver selection is done at compile time (see Expr::DRIVER). Here it'll be the var rank expr, which results in an error at run time. TODO Do run time driver selection to avoid this error.
  232. // tr.section("construction of var rank <- higher rank expr");
  233. // {
  234. // ra::Unique<real> b ({3, 2}, {1, 2, 3, 4, 5, 6});
  235. // cout << "b: " << b << endl;
  236. // ra::Unique<real> a ({4}, b.iter());
  237. // cout << "a: " << a << endl;
  238. // }
  239. }
  240. tr.section("cf plying with and without driver (error)");
  241. {
  242. ra::Unique<real, 1> a({3}, ra::none);
  243. ply_ravel(expr([](real & a, int b) { a = b; }, a.iter(), ra::scalar(7)));
  244. tr.test_eq(7, a[0]);
  245. tr.test_eq(7, a[1]);
  246. tr.test_eq(7, a[2]);
  247. ply(expr([](real & a, int b) { a = b; }, a.iter(), ra::iota<0>()));
  248. tr.test_eq(0, a[0]);
  249. tr.test_eq(1, a[1]);
  250. tr.test_eq(2, a[2]);
  251. // TODO Check that these give ct error. Not clear that the second one should...
  252. // ply(expr([](int b) { cout << b << endl; }, ra::iota<0>()));
  253. // ply(expr([](int b) { cout << b << endl; }, ra::scalar(3)));
  254. }
  255. tr.section("traversal - rank matching - Unique/Unique 1");
  256. {
  257. ra::Unique<real, 3> a({ 3, 2, 4 }, ra::none);
  258. ra::Unique<real, 2> b({ 3, 2 }, ra::none);
  259. ra::Unique<real, 3> c({ 3, 2, 4 }, ra::none);
  260. real check[24] = { 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9,
  261. 9, 10, 11, 12, 12, 13, 14, 15, 15, 16, 17, 18 };
  262. std::iota(a.begin(), a.end(), 1);
  263. std::iota(b.begin(), b.end(), 1);
  264. {
  265. ra::Unique<real, 3> c0(expr([](real a, real b) { return a-b; }, a.iter(), b.iter()));
  266. tr.test(std::equal(check, check+24, c0.begin()));
  267. ra::Unique<real, 3> c1(expr([](real a, real b) { return b-a; }, b.iter(), a.iter()));
  268. tr.test(std::equal(check, check+24, c1.begin()));
  269. }
  270. {
  271. #define TEST(plier) \
  272. std::fill(c.begin(), c.end(), 0); \
  273. plier(expr([&](real & c, real a, real b) { c=a-b; }, \
  274. c.iter(), a.iter(), b.iter())); \
  275. tr.info(STRINGIZE(plier) " a-b").test(std::equal(check, check+24, c.begin())); \
  276. std::fill(c.begin(), c.end(), 0); \
  277. plier(expr([](real & c, real a, real b) { c=b-a; }, \
  278. c.iter(), b.iter(), a.iter())); \
  279. tr.info(STRINGIZE(plier) " b-a").test(std::equal(check, check+24, c.begin()));
  280. TEST(ply_ravel);
  281. TEST(ply_fixed);
  282. #undef TEST
  283. }
  284. }
  285. tr.section("traversal - op uses from");
  286. {
  287. ra::Unique<int, 1> a({3}, ra::none);
  288. ra::Unique<int, 1> b({3}, ra::none);
  289. std::iota(a.begin(), a.end(), 1);
  290. #define TEST(plier) \
  291. tr.section(STRINGIZE(plier)); \
  292. { \
  293. std::fill(b.begin(), b.end(), 0); \
  294. real check[3] = { 2, 3, 1 }; \
  295. plier(expr([&a](int & b, int i) { b = a(i); }, b.iter(), ra::ptr(std::array {1, 2, 0}))); \
  296. tr.info(STRINGIZE(plier) " std::array").test(std::equal(check, check+3, b.begin())); \
  297. plier(expr([&a](int & b, int i) { b = a(i); }, b.iter(), ra::ptr(std::vector {1, 2, 0}))); \
  298. tr.info(STRINGIZE(plier) " std::vector").test(std::equal(check, check+3, b.begin())); \
  299. }
  300. TEST(ply_ravel);
  301. TEST(ply_fixed);
  302. #undef TEST
  303. }
  304. tr.section("helpers for ply - map, for_each");
  305. {
  306. // TODO Test need for map() -> decltype(...) in the declaration of map.
  307. ra::Unique<real, 1> b = map([](auto x) { return exp(x); }, ra::Unique<int, 1>({1, 2}));
  308. tr.test_eq(b, ra::Unique<real, 1>({exp(1), exp(2)}));
  309. real x = 0.;
  310. for_each([&x](auto y) { x += y; }, ra::Unique<int, 1>({13, 21}));
  311. tr.test_eq(34, x);
  312. }
  313. tr.section("the loop cannot be unrolled entirely and one of the outside dims is zero");
  314. {
  315. real aa = 100;
  316. ra::View<real, 3> a { {{0, 22}, {11, 2}, {2, 1}}, &aa };
  317. ra::View<real, 3> b { {{0, 1}, {11, 2}, {2, 1}}, &aa };
  318. #define TEST(plier) \
  319. { \
  320. real c = 99; \
  321. plier(ra::expr([&c](real a, real b) { c = 77; }, \
  322. a.iter(), b.iter())); \
  323. tr.info(STRINGIZE(plier)).test(c==99); \
  324. }
  325. TEST(ply_ravel);
  326. TEST(ply_fixed);
  327. #undef TEST
  328. }
  329. tr.section("more pliers on scalar");
  330. {
  331. tr.test_eq(-99, ra::map([](auto && x) { return -x; }, ra::scalar(99)));
  332. tr.test_eq(true, every(ra::expr([](auto && x) { return x>0; }, ra::start(99))));
  333. }
  334. return tr.summary();
  335. }