ply.cc 16 KB

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