test-ra-1.C 13 KB

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