ra-1.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. // -*- mode: c++; coding: utf-8 -*-
  2. // ra-ra/test - Fundamental tests.
  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. using std::cout, std::endl, std::flush, ra::TestRecorder;
  13. using A2 = ra::Unique<int, 2>;
  14. using A1 = ra::Unique<int, 1>;
  15. using int3 = ra::Small<int, 3>;
  16. using int2 = ra::Small<int, 2>;
  17. using std_int3 = std::array<int, 3>;
  18. using std_int2 = std::array<int, 2>;
  19. using ra::mp::int_list;
  20. template <class AA>
  21. void CheckPlyReverse1(TestRecorder & tr, AA && a)
  22. {
  23. std::iota(a.begin(), a.end(), 1);
  24. auto invert = [](int & a) { a = -a; return a; };
  25. ply_ravel(ra::expr(invert, a.iter()));
  26. for (int i=0; i<6; ++i) {
  27. tr.test_eq(-(i+1), a(i));
  28. }
  29. auto b = reverse(a, 0);
  30. ply_ravel(ra::expr(invert, b.iter()));
  31. for (int i=0; i<6; ++i) {
  32. tr.test_eq(6-i, b(i));
  33. tr.test_eq(i+1, a(i));
  34. }
  35. }
  36. template <class CC, class AA, class BB>
  37. void CheckPly(TestRecorder & tr, char const * tag, AA && A, BB && B)
  38. {
  39. // need to slice because B may be Unique (!) and I have left own-type constructors as default on purpose. Here, I need C's contents to be a fresh copy of B's.
  40. CC C(B());
  41. auto sub = [](int & b, int const a) -> int { return b -= a; };
  42. ra::ply_ravel(ra::expr(sub, B.iter(), A.iter()));
  43. for (int i=0; i!=A.len(0); ++i) {
  44. for (int j=0; j!=A.len(1); ++j) {
  45. tr.info(tag, " ravel").test_eq(C(i, j)-A(i, j), B(i, j));
  46. }
  47. }
  48. auto add = [](int & b, int const a) -> int { return b += a; };
  49. ra::ply_ravel(ra::expr(add, B.iter(), A.iter()));
  50. ra::ply(ra::expr(sub, B.iter(), A.iter()));
  51. for (int i=0; i!=A.len(0); ++i) {
  52. for (int j=0; j!=A.len(1); ++j) {
  53. tr.info(tag, " index").test_eq(C(i, j)-A(i, j), B(i, j));
  54. }
  55. }
  56. }
  57. using complex = std::complex<double>;
  58. int main()
  59. {
  60. TestRecorder tr(std::cout);
  61. tr.section("nested, with references, ply or ply_ravel");
  62. {
  63. int check[3] = {0, 2, 4};
  64. ra::Small<int, 3> A {1, 0, -1};
  65. ra::Small<int, 3> B {1, 2, 3};
  66. #define TEST(plier) \
  67. [&tr, &A, &B, check](auto && C) \
  68. { \
  69. std::fill(C.begin(), C.end(), -99); \
  70. plier(ra::expr([](int & k, int const i) { k = -i; }, \
  71. C.iter(), \
  72. ra::expr([](int const i, int const j) { return i-j; }, \
  73. A.iter(), B.iter()))); \
  74. tr.test(std::equal(check, check+3, C.begin())); \
  75. }
  76. #define TEST2(plier) \
  77. TEST(plier)(ra::Small<int, 3> {}); \
  78. TEST(plier)(ra::Unique<int, 1>({3}, ra::none));
  79. TEST2(ply_ravel)
  80. TEST2(ply_fixed)
  81. #undef TEST2
  82. #undef TEST
  83. }
  84. tr.section("with ref terms only");
  85. {
  86. #define TEST(plier, Biter, Citer) \
  87. [&tr](auto && B, auto && C) \
  88. { \
  89. plier(ra::expr([](int & k, int const i, int const j) { k = i+j; return k; }, \
  90. Citer, Biter, Biter)); \
  91. tr.test_eq(2, C[0]); \
  92. tr.test_eq(4, C[1]); \
  93. tr.test_eq(6, C[2]); \
  94. }
  95. #define TEST2(plier) \
  96. TEST(plier, B.iter(), C.iter())(int3 { 1, 2, 3 }, int3 { 77, 88, 99 }); \
  97. TEST(plier, ra::ptr(B), ra::ptr(C))(std_int3 {{ 1, 2, 3 }}, std_int3 {{ 77, 88, 99 }});
  98. TEST2(ply_ravel)
  99. TEST2(ply_fixed)
  100. #undef TEST2
  101. #undef TEST
  102. }
  103. tr.section("with ref & value terms");
  104. {
  105. #define TEST(plier, Biter, Citer, Btemp) \
  106. [&tr](auto && B, auto && C) \
  107. { \
  108. plier(ra::expr([](int & k, int const i, int const j) { k = i*j; return k; }, \
  109. Citer, Btemp, Biter)); \
  110. tr.test_eq(1, C[0]); \
  111. tr.test_eq(4, C[1]); \
  112. tr.test_eq(9, C[2]); \
  113. }
  114. TEST(ply_ravel, B.iter(), C.iter(), (int3 {1, 2, 3}.iter()))(int3 { 1, 2, 3 }, int3 { 77, 88, 99 });
  115. TEST(ply_ravel, ra::ptr(B), ra::ptr(C), ra::ptr(std_int3 {{1, 2, 3}}))
  116. (std_int3 {{ 1, 2, 3 }}, std_int3 {{ 77, 88, 99 }});
  117. #undef TEST
  118. }
  119. tr.section("complex or nested types");
  120. {
  121. using A2of2 = ra::Unique<int2, 2>;
  122. auto sum2 = [](int2 const i, int2 const j, int2 & x) { x = { i[0]+j[0], i[1]+j[1] }; };
  123. A2of2 A({2, 3}, { int2{1,1}, int2{2,2}, int2{3,3}, int2{4,4}, int2{5,5}, int2{6,6} });
  124. ply(ra::expr([](int2 & a, int i, int j) { int k = i*3+j; a = {k, k}; },
  125. A.iter(), ra::iota<0>(), ra::iota<1>()));
  126. A2of2 B({2, 3}, ra::scalar(int2 {0, 0}));
  127. cout << "A: " << A << endl;
  128. cout << "B: " << B << endl;
  129. cout << "\ntraverse_index..." << endl;
  130. ply_ravel(ra::expr([](int2 & b) { b = {0, 0}; }, B.iter()));
  131. ply(ra::expr(sum2, A.iter(), ra::scalar(int2{2, 2}), B.iter()));
  132. cout << B << endl;
  133. for (int i=2; int2 & b: B) { tr.test_eq(i, b[0]); tr.test_eq(i, b[1]); ++i; }
  134. ply_ravel(ra::expr([](int2 & b) { b = {0, 0}; }, B.iter()));
  135. ply(ra::expr(sum2, ra::scalar(int2{3, 3}), A.iter(), B.iter()));
  136. cout << B << endl;
  137. for (int i=3; int2 & b: B) { tr.test_eq(i, b[0]); tr.test_eq(i, b[1]); ++i; }
  138. cout << "\ntraverse..." << endl;
  139. ply_ravel(ra::expr([](int2 & b) { b = {0, 0}; }, B.iter()));
  140. ply_ravel(ra::expr(sum2, A.iter(), ra::scalar(int2{4, 5}), B.iter()));
  141. cout << B << endl;
  142. for (int i=4; int2 & b: B) { tr.test_eq(i, b[0]); tr.test_eq(i+1, b[1]); ++i; }
  143. ply_ravel(ra::expr([](int2 & b) { b = {0, 0}; }, B.iter()));
  144. ply_ravel(ra::expr(sum2, ra::scalar(int2{5, 5}), A.iter(), B.iter()));
  145. cout << B << endl;
  146. for (int i=5; int2 & b: B) { tr.test_eq(i, b[0]); tr.test_eq(i, b[1]); ++i; }
  147. }
  148. tr.section("reversed arrays");
  149. {
  150. ra::Unique<int, 1> A({ 6 }, ra::none);
  151. std::iota(A.begin(), A.end(), 1);
  152. ra::Unique<int, 1> B { {6}, ra::scalar(99) };
  153. auto copy = [](int & b, int const a) { b = a; return b; };
  154. ply(ra::expr(copy, B.iter(), A.iter()));
  155. for (int i=0; i<6; ++i) {
  156. tr.test_eq(i+1, B(i));
  157. }
  158. ply(ra::expr(copy, B.iter(), reverse(A, 0).iter()));
  159. for (int i=0; i<6; ++i) {
  160. tr.test_eq(6-i, B(i));
  161. }
  162. }
  163. tr.section("reversed arrays, traverse, only one");
  164. {
  165. CheckPlyReverse1(tr, ra::Unique<int, 1>({ 6 }, ra::none));
  166. CheckPlyReverse1(tr, ra::Unique<int>({ 6 }, ra::none));
  167. }
  168. tr.section("mismatched steps");
  169. {
  170. auto sum2 = [](int a, int b, int & c) { return c = a-b; };
  171. A2 a = A2({2, 3}, ra::none); std::iota(a.begin(), a.end(), 1);
  172. A2 b = A2({3, 2}, ra::none); std::iota(b.begin(), b.end(), 1);
  173. A2 c = A2({2, 3}, ra::none);
  174. int check[6] = {0, -1, -2, 2, 1, 0};
  175. #define TEST(plier) \
  176. { \
  177. std::fill(c.begin(), c.end(), 0); \
  178. plier(ra::expr(sum2, a.iter(), transpose<1, 0>(b).iter(), c.iter())); \
  179. tr.info(STRINGIZE(plier)).test(std::equal(check, check+6, c.begin())); \
  180. } \
  181. { \
  182. std::fill(c.begin(), c.end(), 0); \
  183. plier(ra::expr(sum2, transpose<1, 0>(a).iter(), b.iter(), transpose<1, 0>(c).iter())); \
  184. tr.info(STRINGIZE(plier)).test(std::equal(check, check+6, c.begin())); \
  185. }
  186. TEST(ply_ravel);
  187. TEST(ply_fixed);
  188. #undef TEST
  189. }
  190. tr.section("reverse 1/1 axis, traverse");
  191. #define TEST(plier) \
  192. { \
  193. A1 a({ 6 }, ra::none); \
  194. std::iota(a.begin(), a.end(), 1); \
  195. A1 b { {6}, ra::scalar(99) }; \
  196. auto copy = [](int & b, int const a) { b = a; }; \
  197. plier(ra::expr(copy, b.iter(), a.iter())); \
  198. cout << flush; \
  199. for (int i=0; i<6; ++i) { \
  200. tr.test_eq(i+1, b[i]); \
  201. } \
  202. plier(ra::expr(copy, b.iter(), reverse(a, 0).iter())); \
  203. for (int i=0; i<6; ++i) { \
  204. tr.test_eq(6-i, b(i)); \
  205. } \
  206. }
  207. TEST(ply_ravel)
  208. TEST(ply_fixed)
  209. #undef TEST
  210. tr.section("reverse (ref & non ref), traverse");
  211. {
  212. A2 A({2, 3}, { 1, 2, 3, 4, 5, 6 });
  213. A2 B({2, 3}, { 1, 2, 3, 4, 5, 6 });
  214. CheckPly<A2>(tr, "(a)", A, B);
  215. CheckPly<A2>(tr, "(b)", reverse(A, 0), B);
  216. CheckPly<A2>(tr, "(c)", A, reverse(B, 0));
  217. CheckPly<A2>(tr, "(d)", reverse(A, 0), reverse(B, 0));
  218. CheckPly<A2>(tr, "(e)", reverse(A, 1), B);
  219. CheckPly<A2>(tr, "(f)", A, reverse(B, 1));
  220. CheckPly<A2>(tr, "(g)", reverse(A, 1), reverse(B, 1));
  221. // When BOTH steps are negative, B is still compact and this can be reduced to a single loop.
  222. // TODO Enforce that the loop is linearized over both dimensions.
  223. CheckPly<A2>(tr, "(h)", A, reverse(reverse(B, 0), 1));
  224. CheckPly<A2>(tr, "(i)", reverse(reverse(A, 0), 1), B);
  225. CheckPly<A2>(tr, "(j)", reverse(reverse(A, 0), 1), reverse(reverse(B, 0), 1));
  226. }
  227. tr.section("reverse & transpose (ref & non ref), traverse");
  228. {
  229. using A2 = ra::Unique<int, 2>;
  230. A2 A({2, 2}, { 1, 2, 3, 4 });
  231. A2 B({2, 2}, { 1, 2, 3, 4 });
  232. CheckPly<A2>(tr, "(a)", transpose({1, 0}, A), B);
  233. CheckPly<A2>(tr, "(b)", A, transpose({1, 0}, B));
  234. CheckPly<A2>(tr, "(c)", reverse(reverse(transpose({1, 0}, A), 1), 0), B);
  235. CheckPly<A2>(tr, "(d)", A, reverse(reverse(transpose({1, 0}, B), 1), 0));
  236. CheckPly<A2>(tr, "(e)", transpose<1, 0>(A), B);
  237. CheckPly<A2>(tr, "(f)", A, transpose<1, 0>(B));
  238. CheckPly<A2>(tr, "(g)", reverse(reverse(transpose<1, 0>(A), 1), 0), B);
  239. CheckPly<A2>(tr, "(h)", A, reverse(reverse(transpose<1, 0>(B), 1), 0));
  240. CheckPly<A2>(tr, "(i)", transpose(int_list<1, 0>(), A), B);
  241. CheckPly<A2>(tr, "(j)", A, transpose(int_list<1, 0>(), B));
  242. CheckPly<A2>(tr, "(k)", reverse(reverse(transpose(int_list<1, 0>(), A), 1), 0), B);
  243. CheckPly<A2>(tr, "(l)", A, reverse(reverse(transpose(int_list<1, 0>(), B), 1), 0));
  244. }
  245. return tr.summary();
  246. }