frame-new.C 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. // -*- mode: c++; coding: utf-8 -*-
  2. /// @file frame-new.C
  3. /// @brief Test abilities of post v10 driverless frame matching Expr
  4. // (c) Daniel Llorens - 2019
  5. // This library is free software; you can redistribute it and/or modify it under
  6. // the terms of the GNU Lesser General Public License as published by the Free
  7. // Software Foundation; either version 3 of the License, or (at your option) any
  8. // later version.
  9. #include <iostream>
  10. #include <iterator>
  11. #include "ra/format.H"
  12. // -------------------------------------
  13. // bit from example/throw.C which FIXME should be easier. Maybe an option in ra/macros.H.
  14. struct ra_error: public std::exception
  15. {
  16. std::string s;
  17. template <class ... A> ra_error(A && ... a): s(ra::format(std::forward<A>(a) ...)) {}
  18. virtual char const * what() const throw ()
  19. {
  20. return s.c_str();
  21. }
  22. };
  23. #ifdef RA_ASSERT
  24. #error RA_ASSERT is already defined!
  25. #endif
  26. #define RA_ASSERT( cond, ... ) \
  27. { if (!( cond )) throw ra_error("ra:: assert [" STRINGIZE(cond) "]", __VA_ARGS__); }
  28. // -------------------------------------
  29. #include "ra/test.H"
  30. #include "ra/operators.H"
  31. #include "ra/io.H"
  32. using std::cout, std::endl, std::flush;
  33. template <int i> using TI = ra::TensorIndex<i, int>;
  34. template <int i> using UU = decltype(std::declval<ra::Unique<double, i>>().iter());
  35. using mp::int_t;
  36. int main()
  37. {
  38. TestRecorder tr(std::cout);
  39. tr.section("view");
  40. {
  41. ra::Big<int, 3> a({2, 3, 4}, (ra::_0+1)*100 + (ra::_1+1)*10 + (ra::_2+1));
  42. ra::Big<int, 4> b({2, 2, 3, 4}, (ra::_0+1)*1000 + (ra::_1+1)*100 + (ra::_2+1)*10 + (ra::_3+1));
  43. cout << a << endl;
  44. }
  45. tr.section("II");
  46. {
  47. std::tuple<int_t<6>, int_t<3>, int_t<-4>> x;
  48. constexpr int ma = mp::fold_tuple(-99, x, [](auto && k, auto && a) { return max(k, std::decay_t<decltype(a)>::value); });
  49. constexpr int mi = mp::fold_tuple(+99, x, [](auto && k, auto && a) { return min(k, std::decay_t<decltype(a)>::value); });
  50. constexpr int su = mp::fold_tuple(0, x, [](auto && k, auto && a) { return k + std::decay_t<decltype(a)>::value; });
  51. cout << ma << endl;
  52. cout << mi << endl;
  53. cout << su << endl;
  54. }
  55. tr.section("static size - like Expr");
  56. {
  57. ra::Small<int, 2, 3, 4> a = (ra::_0+1)*100 + (ra::_1+1)*10 + (ra::_2+1);
  58. ra::Small<int, 2, 3, 4, 5> b = (ra::_0+1)*1000 + (ra::_1+1)*100 + (ra::_2+1)*10 + (ra::_3+1);
  59. #define EXPR expr([](auto && a, auto && b) { return a+b; }, start(a), start(b))
  60. tr.test_eq(4, EXPR.rank());
  61. tr.test_eq(b.size(0), EXPR.size(0));
  62. tr.test_eq(b.size(1), EXPR.size(1));
  63. tr.test_eq(b.size(2), EXPR.size(2));
  64. tr.test_eq(b.size(3), EXPR.size(3));
  65. tr.test_eq(2*3*4*5, size(EXPR));
  66. static_assert(4==EXPR.rank_s());
  67. static_assert(b.size_s(0)==EXPR.size_s(0));
  68. static_assert(b.size_s(1)==EXPR.size_s(1));
  69. static_assert(b.size_s(2)==EXPR.size_s(2));
  70. static_assert(b.size_s(3)==EXPR.size_s(3));
  71. static_assert(2*3*4*5 == size_s(EXPR));
  72. #undef EXPR
  73. }
  74. // properly fails to compile, which we cannot check at present [ra42]
  75. // tr.section("check mismatches - static");
  76. // {
  77. // ra::Small<int, 2, 3, 4> a = (ra::_0+1)*100 + (ra::_1+1)*10 + (ra::_2+1);
  78. // ra::Small<int, 2, 4, 4, 5> b = (ra::_0+1)*1000 + (ra::_1+1)*100 + (ra::_2+1)*10 + (ra::_3+1);
  79. // #define EXPR expr([](auto && a, auto && b) { return a+b; }, start(a), start(b))
  80. // tr.test_eq(2*3*4*5, size_s(EXPR));
  81. // tr.test_eq(3, EXPR.size_s(1));
  82. // #undef EXPR
  83. // }
  84. tr.section("static rank, dynamic size - like Expr");
  85. {
  86. ra::Big<int, 3> a({2, 3, 4}, (ra::_0+1)*100 + (ra::_1+1)*10 + (ra::_2+1));
  87. ra::Big<int, 4> b({2, 3, 4, 5}, (ra::_0+1)*1000 + (ra::_1+1)*100 + (ra::_2+1)*10 + (ra::_3+1));
  88. #define EXPR expr([](auto && a, auto && b) { return a+b; }, start(a), start(b))
  89. tr.test_eq(4, EXPR.rank());
  90. tr.test_eq(b.size(0), EXPR.size(0));
  91. tr.test_eq(b.size(1), EXPR.size(1));
  92. tr.test_eq(b.size(2), EXPR.size(2));
  93. tr.test_eq(b.size(3), EXPR.size(3));
  94. tr.test_eq(2*3*4*5, size(EXPR));
  95. // these _s are all static, but cannot Big cannot be constexpr yet.
  96. // also decltype(EXPR) fails until p0315r3 (c++20).
  97. // so check at runtime instead.
  98. tr.test_eq(4, EXPR.rank_s());
  99. tr.test_eq(ra::DIM_ANY, EXPR.size_s(0));
  100. tr.test_eq(ra::DIM_ANY, EXPR.size_s(1));
  101. tr.test_eq(ra::DIM_ANY, EXPR.size_s(2));
  102. tr.test_eq(ra::DIM_ANY, EXPR.size_s(3));
  103. tr.test_eq(ra::DIM_ANY, size_s(EXPR));
  104. cout << EXPR << endl;
  105. #undef EXPR
  106. }
  107. tr.section("check mismatches - dynamic");
  108. {
  109. ra::Big<int, 3> a({2, 3, 4}, (ra::_0+1)*100 + (ra::_1+1)*10 + (ra::_2+1));
  110. ra::Big<int, 4> b({2, 4, 4, 5}, (ra::_0+1)*1000 + (ra::_1+1)*100 + (ra::_2+1)*10 + (ra::_3+1));
  111. #define EXPR expr([](auto && a, auto && b) { return a+b; }, start(a), start(b))
  112. int x = 0;
  113. try {
  114. tr.test_eq(ra::DIM_ANY, EXPR.size_s(1));
  115. x = 1;
  116. } catch (ra_error & e) {
  117. }
  118. tr.info("caught error").test_eq(0, x);
  119. #undef EXPR
  120. }
  121. tr.section("dynamic rank - Expr driver selection is broken in this case.");
  122. {
  123. ra::Big<int, 3> as({2, 3, 4}, (ra::_0+1)*100 + (ra::_1+1)*10 + (ra::_2+1));
  124. ra::Big<int> ad({2, 3, 4}, (ra::_0+1)*100 + (ra::_1+1)*10 + (ra::_2+1));
  125. ra::Big<int, 4> bs({2, 3, 4, 5}, (ra::_0+1)*1000 + (ra::_1+1)*100 + (ra::_2+1)*10 + (ra::_3+1));
  126. ra::Big<int> bd({2, 3, 4, 5}, (ra::_0+1)*1000 + (ra::_1+1)*100 + (ra::_2+1)*10 + (ra::_3+1));
  127. #define EXPR(a, b) expr([](auto && a, auto && b) { return a+b; }, start(a), start(b))
  128. auto test = [&tr](auto tag, auto && a, auto && b)
  129. {
  130. tr.section(tag);
  131. tr.test_eq(4, EXPR(a, b).rank());
  132. tr.info("0d").test_eq(b.size(0), EXPR(a, b).size(0));
  133. tr.test_eq(b.size(1), EXPR(a, b).size(1));
  134. tr.test_eq(b.size(2), EXPR(a, b).size(2));
  135. tr.test_eq(b.size(3), EXPR(a, b).size(3));
  136. tr.info("0-size()").test_eq(2*3*4*5, size(EXPR(a, b)));
  137. tr.test_eq(ra::RANK_ANY, EXPR(a, b).rank_s());
  138. tr.test_eq(ra::DIM_ANY, size_s(EXPR(a, b)));
  139. tr.test_eq(ra::DIM_ANY, EXPR(a, b).size_s(0));
  140. tr.test_eq(ra::DIM_ANY, EXPR(a, b).size_s(1));
  141. tr.test_eq(ra::DIM_ANY, EXPR(a, b).size_s(2));
  142. tr.test_eq(ra::DIM_ANY, EXPR(a, b).size_s(3));
  143. tr.info("0-size_s()").test_eq(ra::DIM_ANY, size_s(EXPR(a, b)));
  144. };
  145. test("sta-dyn", as, bd);
  146. test("dyn-sta", ad, bs);
  147. test("dyn-dyn", ad, bd);
  148. #undef EXPR
  149. }
  150. tr.section("cases with periodic axes - dynamic (broken with Expr)");
  151. {
  152. ra::Big<int, 3> a({2, 3, 4}, (ra::_0+1)*100 + (ra::_1+1)*10 + (ra::_2+1));
  153. auto b = a(ra::all, ra::insert<1>, ra::iota(4, 0, 0));
  154. #define EXPR(a, b) expr([](auto && a, auto && b) { return a+b; }, start(a), start(b))
  155. tr.test_eq(4, EXPR(a, b).rank());
  156. tr.test_eq(b.size(0), EXPR(a, b).size(0));
  157. tr.test_eq(a.size(1), EXPR(a, b).size(1));
  158. tr.test_eq(b.size(2), EXPR(a, b).size(2));
  159. tr.test_eq(b.size(3), EXPR(a, b).size(3));
  160. tr.test_eq(2*3*4*4, size(EXPR(a, b)));
  161. // these _s are all static, but cannot Big cannot be constexpr yet.
  162. // also decltype(EXPR(a, b)) fails until p0315r3 (c++20).
  163. // so check at runtime instead.
  164. tr.test_eq(4, EXPR(a, b).rank_s());
  165. tr.test_eq(ra::DIM_ANY, EXPR(a, b).size_s(0));
  166. tr.test_eq(ra::DIM_ANY, EXPR(a, b).size_s(1));
  167. tr.test_eq(ra::DIM_ANY, EXPR(a, b).size_s(2));
  168. tr.test_eq(ra::DIM_ANY, EXPR(a, b).size_s(3));
  169. tr.test_eq(ra::DIM_ANY, size_s(EXPR(a, b)));
  170. cout << EXPR(a, b) << endl;
  171. // value test.
  172. ra::Big<int, 4> c({2, 3, 4, 4}, 0);
  173. c(ra::all, 0) = a(ra::all, ra::iota(4, 0, 0));
  174. c(ra::all, 1) = a(ra::all, ra::iota(4, 0, 0));
  175. c(ra::all, 2) = a(ra::all, ra::iota(4, 0, 0));
  176. tr.test_eq((a+c), EXPR(a, b));
  177. // order doesn't affect prefix matching with Expr
  178. tr.test_eq((a+c), EXPR(b, a));
  179. #undef EXPR
  180. }
  181. tr.section("broadcasting - like outer product");
  182. {
  183. ra::Big<int, 2> a({4, 3}, 10*ra::_1+100*ra::_0);
  184. ra::Big<int, 1> b({5}, ra::_0);
  185. cout << ra::start(ra::shape(from([](auto && a, auto && b) { return a-b; }, a, b))) << endl;
  186. #define EXPR(a, b) expr([](auto && a, auto && b) { return a-b; }, start(a(ra::dots<2>, ra::insert<1>)), start(b(ra::insert<2>, ra::dots<1>)))
  187. tr.test_eq(3, EXPR(a, b).rank_s());
  188. tr.test_eq(ra::DIM_ANY, EXPR(a, b).size_s(0));
  189. tr.test_eq(ra::DIM_ANY, EXPR(a, b).size_s(1));
  190. tr.test_eq(ra::DIM_ANY, EXPR(a, b).size_s(2));
  191. tr.test_eq(3, EXPR(a, b).rank());
  192. tr.test_eq(4, EXPR(a, b).size(0));
  193. tr.test_eq(3, EXPR(a, b).size(1));
  194. tr.test_eq(5, EXPR(a, b).size(2));
  195. tr.test_eq(from([](auto && a, auto && b) { return a-b; }, a, b), EXPR(a, b));
  196. #undef EXPR
  197. }
  198. tr.section("Expr has operatorX=");
  199. {
  200. ra::Big<int, 2> a({4, 3}, 10*ra::_1+100*ra::_0);
  201. expr([](auto & a) -> decltype(auto) { return a; }, start(a)) += 1;
  202. tr.test_eq(10*ra::_1 + 100*ra::_0 + 1, a);
  203. }
  204. tr.section("Compat with old Expr, from ra-0.C");
  205. {
  206. int p[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
  207. int * pp = &p[0]; // force pointer decay in case we ever enforce p's shape
  208. ra::View<int> d(ra::pack<ra::Dim>(ra::Small<int, 3> {5, 1, 2}, ra::Small<int, 3> {1, 0, 5}), pp);
  209. #define EXPR expr([](auto && a, auto && b) { return a==b; }, ra::_0*1 + ra::_1*0 + ra::_2*5 + 1, start(d))
  210. tr.test(every(EXPR));
  211. auto x = EXPR;
  212. static_assert(ra::DIM_ANY==size_s(x));
  213. static_assert(ra::DIM_ANY==ra::size_s(x));
  214. tr.test_eq(10, size(EXPR));
  215. }
  216. tr.section("DIM_BAD on any size_s(k) means size_s() is DIM_BAD");
  217. {
  218. using order = std::tuple<mp::int_t<0>, mp::int_t<1> >;
  219. using T0 = ra::Expr<ra::times, std::tuple<ra::TensorIndex<0>, ra::Scalar<int>>, order>;
  220. ra::dim_t s0 = ra::size_s<T0>();
  221. using T1 = ra::Expr<ra::times, std::tuple<ra::TensorIndex<1>, ra::Scalar<int>>, order>;
  222. ra::dim_t s1 = ra::size_s<T1>();
  223. using T2 = ra::Expr<ra::times, std::tuple<ra::TensorIndex<2>, ra::Scalar<int>>, order>;
  224. ra::dim_t s2 = ra::size_s<T2>();
  225. tr.test_eq(ra::DIM_BAD, s0);
  226. tr.test_eq(ra::DIM_BAD, s1);
  227. tr.test_eq(ra::DIM_BAD, s2);
  228. }
  229. return tr.summary();
  230. }