frame-new.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. // -*- mode: c++; coding: utf-8 -*-
  2. /// @file frame-new.cc
  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.hh"
  12. // -------------------------------------
  13. // bit from example/throw.cc which FIXME should be easier. Maybe an option in ra/macros.hh.
  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.hh"
  30. #include "ra/ra.hh"
  31. using std::cout, std::endl, std::flush, ra::TestRecorder;
  32. template <int i> using UU = decltype(std::declval<ra::Unique<double, i>>().iter());
  33. using mp::int_t;
  34. void f2(ra::Big<int, 2> const & a)
  35. {
  36. cout << ra::start(shape(a)) << endl;
  37. }
  38. int main()
  39. {
  40. TestRecorder tr(std::cout);
  41. tr.section("view");
  42. {
  43. ra::Big<int, 3> a({2, 3, 4}, (ra::_0+1)*100 + (ra::_1+1)*10 + (ra::_2+1));
  44. ra::Big<int, 4> b({2, 2, 3, 4}, (ra::_0+1)*1000 + (ra::_1+1)*100 + (ra::_2+1)*10 + (ra::_3+1));
  45. cout << a << endl;
  46. }
  47. tr.section("II");
  48. {
  49. std::tuple<int_t<6>, int_t<3>, int_t<-4>> x;
  50. constexpr int ma = mp::fold_tuple(-99, x, [](auto && k, auto && a) { return max(k, std::decay_t<decltype(a)>::value); });
  51. constexpr int mi = mp::fold_tuple(+99, x, [](auto && k, auto && a) { return min(k, std::decay_t<decltype(a)>::value); });
  52. constexpr int su = mp::fold_tuple(0, x, [](auto && k, auto && a) { return k + std::decay_t<decltype(a)>::value; });
  53. cout << ma << endl;
  54. cout << mi << endl;
  55. cout << su << endl;
  56. }
  57. tr.section("static size - like Expr");
  58. {
  59. ra::Small<int, 2, 3, 4> a = (ra::_0+1)*100 + (ra::_1+1)*10 + (ra::_2+1);
  60. ra::Small<int, 2, 3, 4, 5> b = (ra::_0+1)*1000 + (ra::_1+1)*100 + (ra::_2+1)*10 + (ra::_3+1);
  61. #define EXPR expr([](auto && a, auto && b) { return a+b; }, start(a), start(b))
  62. tr.test_eq(4, EXPR.rank());
  63. tr.test_eq(b.size(0), EXPR.size(0));
  64. tr.test_eq(b.size(1), EXPR.size(1));
  65. tr.test_eq(b.size(2), EXPR.size(2));
  66. tr.test_eq(b.size(3), EXPR.size(3));
  67. tr.test_eq(2*3*4*5, size(EXPR));
  68. static_assert(4==EXPR.rank_s());
  69. static_assert(b.size_s(0)==EXPR.size_s(0));
  70. static_assert(b.size_s(1)==EXPR.size_s(1));
  71. static_assert(b.size_s(2)==EXPR.size_s(2));
  72. static_assert(b.size_s(3)==EXPR.size_s(3));
  73. static_assert(2*3*4*5 == size_s(EXPR));
  74. #undef EXPR
  75. }
  76. // properly fails to compile, which we cannot check at present [ra42]
  77. // tr.section("check mismatches - static");
  78. // {
  79. // ra::Small<int, 2, 3, 4> a = (ra::_0+1)*100 + (ra::_1+1)*10 + (ra::_2+1);
  80. // ra::Small<int, 2, 4, 4, 5> b = (ra::_0+1)*1000 + (ra::_1+1)*100 + (ra::_2+1)*10 + (ra::_3+1);
  81. // #define EXPR expr([](auto && a, auto && b) { return a+b; }, start(a), start(b))
  82. // tr.test_eq(2*3*4*5, size_s(EXPR));
  83. // tr.test_eq(3, EXPR.size_s(1));
  84. // #undef EXPR
  85. // }
  86. tr.section("static rank, dynamic size - like Expr");
  87. {
  88. ra::Big<int, 3> a({2, 3, 4}, (ra::_0+1)*100 + (ra::_1+1)*10 + (ra::_2+1));
  89. ra::Big<int, 4> b({2, 3, 4, 5}, (ra::_0+1)*1000 + (ra::_1+1)*100 + (ra::_2+1)*10 + (ra::_3+1));
  90. #define EXPR expr([](auto && a, auto && b) { return a+b; }, start(a), start(b))
  91. tr.test_eq(4, EXPR.rank());
  92. tr.test_eq(b.size(0), EXPR.size(0));
  93. tr.test_eq(b.size(1), EXPR.size(1));
  94. tr.test_eq(b.size(2), EXPR.size(2));
  95. tr.test_eq(b.size(3), EXPR.size(3));
  96. tr.test_eq(2*3*4*5, size(EXPR));
  97. // could check all statically through decltype, although Big cannot be constexpr yet.
  98. static_assert(4==ra::rank_s<decltype(EXPR)>());
  99. tr.test_eq(4, EXPR.rank_s());
  100. tr.test_eq(ra::DIM_ANY, EXPR.size_s(0));
  101. tr.test_eq(ra::DIM_ANY, EXPR.size_s(1));
  102. tr.test_eq(ra::DIM_ANY, EXPR.size_s(2));
  103. tr.test_eq(ra::DIM_ANY, EXPR.size_s(3));
  104. tr.test_eq(ra::DIM_ANY, size_s(EXPR));
  105. cout << EXPR << endl;
  106. #undef EXPR
  107. }
  108. tr.section("check mismatches - dynamic");
  109. {
  110. ra::Big<int, 3> a({2, 3, 4}, (ra::_0+1)*100 + (ra::_1+1)*10 + (ra::_2+1));
  111. ra::Big<int, 4> b({2, 4, 4, 5}, (ra::_0+1)*1000 + (ra::_1+1)*100 + (ra::_2+1)*10 + (ra::_3+1));
  112. #define EXPR expr([](auto && a, auto && b) { return a+b; }, start(a), start(b))
  113. int x = 0;
  114. try {
  115. tr.test_eq(ra::DIM_ANY, EXPR.size_s(1));
  116. x = 1;
  117. } catch (ra_error & e) {
  118. }
  119. tr.info("caught error").test_eq(0, x);
  120. #undef EXPR
  121. }
  122. tr.section("dynamic rank - Expr driver selection is broken in this case.");
  123. {
  124. ra::Big<int, 3> as({2, 3, 4}, (ra::_0+1)*100 + (ra::_1+1)*10 + (ra::_2+1));
  125. ra::Big<int> ad({2, 3, 4}, (ra::_0+1)*100 + (ra::_1+1)*10 + (ra::_2+1));
  126. ra::Big<int, 4> bs({2, 3, 4, 5}, (ra::_0+1)*1000 + (ra::_1+1)*100 + (ra::_2+1)*10 + (ra::_3+1));
  127. ra::Big<int> bd({2, 3, 4, 5}, (ra::_0+1)*1000 + (ra::_1+1)*100 + (ra::_2+1)*10 + (ra::_3+1));
  128. #define EXPR(a, b) expr([](auto && a, auto && b) { return a+b; }, start(a), start(b))
  129. auto test = [&tr](auto tag, auto && a, auto && b)
  130. {
  131. tr.section(tag);
  132. tr.test_eq(4, EXPR(a, b).rank());
  133. tr.info("0d").test_eq(b.size(0), EXPR(a, b).size(0));
  134. tr.test_eq(b.size(1), EXPR(a, b).size(1));
  135. tr.test_eq(b.size(2), EXPR(a, b).size(2));
  136. tr.test_eq(b.size(3), EXPR(a, b).size(3));
  137. tr.info("0-size()").test_eq(2*3*4*5, size(EXPR(a, b)));
  138. tr.test_eq(ra::RANK_ANY, EXPR(a, b).rank_s());
  139. tr.test_eq(ra::DIM_ANY, size_s(EXPR(a, b)));
  140. tr.test_eq(ra::DIM_ANY, EXPR(a, b).size_s(0));
  141. tr.test_eq(ra::DIM_ANY, EXPR(a, b).size_s(1));
  142. tr.test_eq(ra::DIM_ANY, EXPR(a, b).size_s(2));
  143. tr.test_eq(ra::DIM_ANY, EXPR(a, b).size_s(3));
  144. tr.info("0-size_s()").test_eq(ra::DIM_ANY, size_s(EXPR(a, b)));
  145. };
  146. test("sta-dyn", as, bd);
  147. test("dyn-sta", ad, bs);
  148. test("dyn-dyn", ad, bd);
  149. #undef EXPR
  150. }
  151. tr.section("cases with periodic axes - dynamic (broken with Expr)");
  152. {
  153. ra::Big<int, 3> a({2, 3, 4}, (ra::_0+1)*100 + (ra::_1+1)*10 + (ra::_2+1));
  154. auto b = a(ra::all, ra::insert<1>, ra::iota(4, 0, 0));
  155. #define EXPR(a, b) expr([](auto && a, auto && b) { return a+b; }, start(a), start(b))
  156. tr.test_eq(4, EXPR(a, b).rank());
  157. tr.test_eq(b.size(0), EXPR(a, b).size(0));
  158. tr.test_eq(a.size(1), EXPR(a, b).size(1));
  159. tr.test_eq(b.size(2), EXPR(a, b).size(2));
  160. tr.test_eq(b.size(3), EXPR(a, b).size(3));
  161. tr.test_eq(2*3*4*4, size(EXPR(a, b)));
  162. // could check all statically through decltype, although Big cannot be constexpr yet.
  163. static_assert(4==ra::rank_s<decltype(EXPR(a, b))>());
  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.cc");
  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); // FIXME [ra28]
  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. // If the size of an expr is static, dynamic checks may still need to be run if any of the terms of the expr has dynamic size. This is checked in match.hh: check_expr_s().
  230. {
  231. int error = 0;
  232. std::string s;
  233. try {
  234. ra::Small<int, 2> a {2, 3};
  235. ra::Big<int, 1> b({1}, 77);
  236. tr.test_eq(1, ra::check_expr_s<decltype(a+b)>());
  237. a = b;
  238. } catch (ra_error & e) {
  239. error = 1;
  240. s = e.s;
  241. }
  242. tr.info("dynamic size checks on static size expr (", s, ")").test_eq(1, error);
  243. }
  244. {
  245. int error = 0;
  246. std::string s;
  247. try {
  248. ra::Big<int> a {};
  249. // flag the error when casting rank-0 to rank-2 array. FIXME check that copying is still possible.
  250. f2(a);
  251. error = 0;
  252. } catch (ra_error & e) {
  253. error = 1;
  254. s = e.s;
  255. }
  256. tr.info("dynamic size checks on static size expr (", s, ")").test_eq(1, error);
  257. }
  258. return tr.summary();
  259. }