ply.cc 16 KB

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