test-ply.C 17 KB

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