ply.cc 16 KB

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