fromu.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. // -*- mode: c++; coding: utf-8 -*-
  2. // ra-ra/test - Checks for index selectors, esp. delayed. See fromb.cc.
  3. // (c) Daniel Llorens - 2014-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 <iostream>
  9. #include <iterator>
  10. #include "ra/test.hh"
  11. using std::cout, std::endl, std::flush, std::tuple, ra::TestRecorder;
  12. using real = double;
  13. template <int rank=ra::ANY> using Ureal = ra::Unique<real, rank>;
  14. using Vint = ra::Unique<int, 1>;
  15. int main()
  16. {
  17. TestRecorder tr(std::cout);
  18. tr.section("len in unbeatable subscript");
  19. {
  20. ra::Big<int, 1> a({10}, ra::_0);
  21. tr.test_eq(ra::start({9, 8, 7, 6}), a(ra::len - std::array {1, 2, 3, 4}));
  22. ra::Big<int, 2> b({10, 10}, ra::_0-ra::_1);
  23. b(ra::len - std::array {1, 3, 4}) += 100;
  24. tr.test_eq(9 - ra::_0 + 100, b(9));
  25. tr.test_eq(7 - ra::_0 + 100, b(7));
  26. tr.test_eq(6 - ra::_0 + 100, b(6));
  27. }
  28. tr.section("len in unbeatable subscript");
  29. {
  30. ra::Small<int, 10> a = ra::_0;
  31. tr.test_eq(ra::start({9, 8, 7, 6}), a(ra::len - std::array {1, 2, 3, 4}));
  32. ra::Small<int, 10, 10> b = ra::_0-ra::_1;
  33. b(ra::len - std::array {1, 3, 4}) += 100;
  34. tr.test_eq(9 - ra::_0 + 100, b(9));
  35. tr.test_eq(7 - ra::_0 + 100, b(7));
  36. tr.test_eq(6 - ra::_0 + 100, b(6));
  37. }
  38. tr.section("unbeatable, 1D");
  39. {
  40. auto check_selection_unbeatable_1 = [&tr](auto && a)
  41. {
  42. using CT = ra::Small<real, 4>;
  43. tr.info("a(i ...)").test_eq(CT {a[3], a[2], a[0], a[1]}, a(Vint {3, 2, 0, 1}));
  44. tr.info("a(i ...)").test_eq(CT {a[3], a[2], a[0], a[1]}, from(a, Vint {3, 2, 0, 1}));
  45. a = 0.;
  46. a(Vint {3, 2, 0, 1}) = CT {9, 7, 1, 4};
  47. tr.info("a(i ...) as lvalue").test_eq(CT {1, 4, 7, 9}, a);
  48. a = 0.;
  49. from(a, Vint {3, 2, 0, 1}) = CT {9, 7, 1, 4};
  50. tr.info("from(a i ...) as lvalue").test_eq(CT {1, 4, 7, 9}, a);
  51. a = 0.;
  52. from(a, Vint {3, 2, 0, 1}) = 77.;
  53. tr.info("from(a i ...) as lvalue, rank extend of right hand").test_eq(a, 77.);
  54. ra::Small<real, 2, 2> c = from(a, ra::Small<int, 2, 2> {3, 2, 0, 1});
  55. tr.info("a([x y; z w])").test_eq(ra::Small<real, 2, 2> {a[3], a[2], a[0], a[1]}, c);
  56. };
  57. check_selection_unbeatable_1(Ureal<1> {7, 9, 3, 4});
  58. check_selection_unbeatable_1(ra::Small<real, 4> {7, 9, 3, 4});
  59. check_selection_unbeatable_1(Ureal<>({4}, {7, 9, 3, 4}));
  60. }
  61. tr.section("unbeatable, 2D");
  62. {
  63. auto check_selection_unbeatable_2 = [&tr](auto && a)
  64. {
  65. using CT22 = ra::Small<real, 2, 2>;
  66. using CT2 = ra::Small<real, 2>;
  67. tr.info("a([0 1], [0 1])").test_eq(CT22 {a(0, 0), a(0, 1), a(1, 0), a(1, 1)},
  68. from(a, Vint {0, 1}, Vint {0, 1}));
  69. tr.info("a([0 1], [1 0])").test_eq(CT22 {a(0, 1), a(0, 0), a(1, 1), a(1, 0)},
  70. from(a, Vint {0, 1}, Vint {1, 0}));
  71. tr.info("a([1 0], [0 1])").test_eq(CT22 {a(1, 0), a(1, 1), a(0, 0), a(0, 1)},
  72. from(a, Vint {1, 0}, Vint {0, 1}));
  73. tr.info("a([1 0], [1 0])").test_eq(CT22 {a(1, 1), a(1, 0), a(0, 1), a(0, 0)},
  74. from(a, Vint {1, 0}, Vint {1, 0}));
  75. // TODO This is a nested array, which is a problem, we would use it just as from(a, [0 1], [0 1]).
  76. std::cout << "TODO [" << from(a, Vint {0, 1}) << "]" << std::endl;
  77. a = 0.;
  78. from(a, Vint {1, 0}, Vint {1, 0}) = CT22 {9, 7, 1, 4};
  79. tr.info("a([1 0], [1 0]) as lvalue").test_eq(CT22 {4, 1, 7, 9}, a);
  80. from(a, Vint {1, 0}, Vint {1, 0}) *= CT22 {9, 7, 1, 4};
  81. tr.info("a([1 0], [1 0]) as lvalue, *=").test_eq(CT22 {16, 1, 49, 81}, a);
  82. // Note the difference with J amend, which requires x in (x m} y) ~ (y[m] = x) to be a suffix of y[m]; but we apply the general mechanism which is prefix matching.
  83. from(a, Vint {1, 0}, Vint {1, 0}) = CT2 {9, 7};
  84. tr.info("a([1 0], [1 0]) as lvalue, rank extend of right hand").test_eq(CT22 {7, 7, 9, 9}, a);
  85. // TODO Test cases with rank!=1, starting with this couple which should work the same.
  86. std::cout << "-> " << from(a, Vint{1, 0}, 0) << std::endl;
  87. a = CT22 {4, 1, 7, 9};
  88. tr.info("a(rank1, rank0)").test_eq(ra::Small<real, 2>{9, 1}, from(a, Vint{1, 0}, ra::Small<int>(1).iter()));
  89. tr.info("a(rank0, rank1)").test_eq(ra::Small<real, 2>{9, 7}, from(a, ra::Small<int>(1).iter(), Vint{1, 0}));
  90. };
  91. check_selection_unbeatable_2(Ureal<2>({2, 2}, {1, 2, 3, 4}));
  92. check_selection_unbeatable_2(ra::Small<real, 2, 2>({1, 2, 3, 4}));
  93. check_selection_unbeatable_2(Ureal<>({2, 2}, {1, 2, 3, 4}));
  94. }
  95. tr.section("mixed scalar/unbeatable, 2D -> 1D");
  96. {
  97. auto check_selection_unbeatable_mixed = [&tr](auto && a)
  98. {
  99. using CT2 = ra::Small<real, 2>;
  100. tr.info("from(a [0 1], 1)").test_eq(CT2 {a(0, 1), a(1, 1)}, from(a, Vint {0, 1}, 1));
  101. tr.info("from(a [1 0], 1)").test_eq(CT2 {a(1, 1), a(0, 1)}, from(a, Vint {1, 0}, 1));
  102. tr.info("from(a 1, [0 1])").test_eq(CT2 {a(1, 0), a(1, 1)}, from(a, 1, Vint {0, 1}));
  103. tr.info("from(a 1, [1 0])").test_eq(CT2 {a(1, 1), a(1, 0)}, from(a, 1, Vint {1, 0}));
  104. tr.info("a([0 1], 1)").test_eq(CT2 {a(0, 1), a(1, 1)}, a(Vint {0, 1}, 1));
  105. tr.info("a([1 0], 1)").test_eq(CT2 {a(1, 1), a(0, 1)}, a(Vint {1, 0}, 1));
  106. tr.info("a(1, [0 1])").test_eq(CT2 {a(1, 0), a(1, 1)}, a(1, Vint {0, 1}));
  107. tr.info("a(1, [1 0])").test_eq(CT2 {a(1, 1), a(1, 0)}, a(1, Vint {1, 0}));
  108. };
  109. check_selection_unbeatable_mixed(Ureal<2>({2, 2}, {1, 2, 3, 4}));
  110. check_selection_unbeatable_mixed(ra::Small<real, 2, 2>({1, 2, 3, 4}));
  111. }
  112. tr.section("mixed unbeatable/dots, 2D -> 2D (TODO)");
  113. {
  114. // auto check_selection_unbeatable_dots = [&tr](auto && a)
  115. // {
  116. // using CT2 = ra::Small<real, 2>;
  117. // tr.info("a({0, 0}, ra::all)").test_eq(a(CT2 {0, 0}, ra::all), a(CT2 {0, 0}, CT2 {0, 1}));
  118. // tr.info("a({0, 1}, ra::all)").test_eq(a(CT2 {0, 1}, ra::all), a(CT2 {0, 1}, CT2 {0, 1}));
  119. // tr.info("a({1, 0}, ra::all)").test_eq(a(CT2 {1, 0}, ra::all), a(CT2 {1, 0}, CT2 {0, 1}));
  120. // tr.info("a({1, 1}, ra::all)").test_eq(a(CT2 {1, 1}, ra::all), a(CT2 {1, 1}, CT2 {0, 1}));
  121. // };
  122. // TODO doesn't work because dots_t<> can only be beaten on, not iterated on, and the beating cases are missing.
  123. // check_selection_unbeatable_dots(Ureal<2>({2, 2}, {1, 2, 3, 4}));
  124. // check_selection_unbeatable_dots(ra::Small<real, 2, 2>({1, 2, 3, 4}));
  125. }
  126. tr.section("unbeatable, 3D & higher");
  127. {
  128. // see src/test/bench-from.cc for examples of higher-D.
  129. }
  130. tr.section("undef-len-iota / where TODO elsewhere");
  131. {
  132. Ureal<2> a({4, 4}, 1.);
  133. a(3, 3) = 7.;
  134. tr.test(every(ra::map([](auto a, int i, int j)
  135. {
  136. return a==(i==3 && j==3 ? 7. : 1.);
  137. },
  138. a, ra::_0, ra::_1)));
  139. tr.test_eq(where(ra::_0==3 && ra::_1==3, 7., 1.), a);
  140. }
  141. // The implementation of from() uses FrameMatch / Reframe and can't handle this yet.
  142. tr.section("undef-len-iota<i> as subscript, using ra::Expr directly.");
  143. {
  144. auto i = ra::_0;
  145. auto j = ra::_1;
  146. Ureal<2> a({4, 3}, i-j);
  147. Ureal<2> b({3, 4}, 0.);
  148. b = map([&a](int i, int j) { return a(i, j); }, j, i);
  149. tr.test_eq(i-j, a);
  150. tr.test_eq(j-i, b);
  151. }
  152. tr.section("undef-len-iota<i> as subscripts, 1 subscript TODO elsewhere");
  153. {
  154. Ureal<1> a {1, 4, 2, 3};
  155. Ureal<1> b({4}, 0.);
  156. // these work bc there's another term to drive the expr.
  157. b = a(3-ra::_0);
  158. tr.test_eq(Ureal<1> {3, 2, 4, 1}, b);
  159. b(3-ra::_0) = a;
  160. tr.test_eq(Ureal<1> {3, 2, 4, 1}, b);
  161. }
  162. tr.section("TODO undef-len-iota<i> as subscripts, 2 subscript (case I)");
  163. {
  164. Ureal<2> a({4, 4}, ra::_0-ra::_1);
  165. Ureal<2> b({4, 4}, -99.);
  166. cout << a << endl;
  167. cout << b << endl;
  168. // b = a(ra::_0, ra::_0);
  169. }
  170. tr.section("TODO undef-len-iota<i> as subscripts, 2 subscript (case II)");
  171. {
  172. Ureal<2> a({4, 4}, ra::_0-ra::_1);
  173. Ureal<2> b({4, 4}, 0.);
  174. cout << a << endl;
  175. cout << b << endl;
  176. // TODO these used to instantiate flat() when they should not (FIXME was for old OldTensorIndex; recheck)
  177. // tr.info("by_index I").test(ra::by_index<decltype(a(ra::_1, ra::_0))>);
  178. // cout << ra::mp::ref<decltype(a(ra::_1, ra::_0))>::rank_s() << endl;
  179. // these don't work because a(j, i) has rank 3 = [(w=1)+1 + (w=0)+1] and so it drives, but undef len exprs shouldn't ever drive.
  180. // tr.info("by_index II").test(ra::by_index<decltype(b+a(ra::_1, ra::_0))>);
  181. // cout << ra::mp::ref<decltype(b+a(ra::_1, ra::_0))::T, 0>::rank_s() << endl;
  182. // cout << ra::mp::ref<decltype(b+a(ra::_1, ra::_0))::T, 1>::rank_s() << endl;
  183. cout << ra::rank_s<ra::mp::ref<decltype(ra::_1)>>() << endl;
  184. // b = a(ra::_1, ra::_0);
  185. }
  186. // Small(Iota) isn't beaten because the the output type cannot depend on argument values. So we treat it as a common expr.
  187. tr.section("ra::Small(Iota)");
  188. {
  189. ra::Small<real, 4> a = ra::_0;
  190. tr.test_eq(a(ra::iota(2, 1)), Ureal<1> { 1, 2 });
  191. }
  192. // Indirection operator using list of coordinates.
  193. tr.section("at() indirection");
  194. {
  195. ra::Big<int, 2> A({4, 4}, 0), B({4, 4}, 10*ra::_0 + ra::_1);
  196. using coord = ra::Small<int, 2>;
  197. ra::Big<coord, 1> I = { {1, 1}, {2, 2} };
  198. at(A, I) = at(B, I);
  199. tr.test_eq(ra::Big<int>({4, 4}, {0, 0, 0, 0, /**/ 0, 11, 0, 0, /**/ 0, 0, 22, 0, /**/ 0, 0, 0, 0}), A);
  200. // TODO this is why we need ops to have explicit rank.
  201. at(A, ra::scalar(coord{3, 2})) = 99.;
  202. tr.test_eq(ra::Big<int>({4, 4}, {0, 0, 0, 0, /**/ 0, 11, 0, 0, /**/ 0, 0, 22, 0, /**/ 0, 0, 99, 0}), A);
  203. }
  204. // From the manual [ra30]
  205. {
  206. ra::Big<int, 2> A = {{100, 101}, {110, 111}, {120, 121}};
  207. ra::Big<ra::Small<int, 2>, 2> i = {{{0, 1}, {2, 0}}, {{1, 0}, {2, 1}}};
  208. ra::Big<int, 2> B = at(A, i);
  209. tr.test_eq(ra::Big<int, 2> {{101, 120}, {110, 121}}, at(A, i));
  210. }
  211. return tr.summary();
  212. }