123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271 |
- // -*- mode: c++; coding: utf-8 -*-
- /// @file frame-new.cc
- /// @brief Test abilities of post v10 driverless frame matching Expr
- // (c) Daniel Llorens - 2019
- // This library is free software; you can redistribute it and/or modify it under
- // the terms of the GNU Lesser General Public License as published by the Free
- // Software Foundation; either version 3 of the License, or (at your option) any
- // later version.
- #include <iostream>
- #include <iterator>
- #include "ra/format.hh"
- // -------------------------------------
- // bit from example/throw.cc which FIXME should be easier. Maybe an option in ra/macros.hh.
- struct ra_error: public std::exception
- {
- std::string s;
- template <class ... A> ra_error(A && ... a): s(ra::format(std::forward<A>(a) ...)) {}
- virtual char const * what() const throw ()
- {
- return s.c_str();
- }
- };
- #ifdef RA_ASSERT
- #error RA_ASSERT is already defined!
- #endif
- #define RA_ASSERT( cond, ... ) \
- { if (!( cond )) throw ra_error("ra:: assert [" STRINGIZE(cond) "]", ##__VA_ARGS__); }
- // -------------------------------------
- #include "ra/test.hh"
- #include "ra/ra.hh"
- using std::cout, std::endl, std::flush, ra::TestRecorder;
- template <int i> using UU = decltype(std::declval<ra::Unique<double, i>>().iter());
- using mp::int_t;
- void f2(ra::Big<int, 2> const & a)
- {
- cout << ra::start(shape(a)) << endl;
- }
- int main()
- {
- TestRecorder tr(std::cout);
- tr.section("view");
- {
- ra::Big<int, 3> a({2, 3, 4}, (ra::_0+1)*100 + (ra::_1+1)*10 + (ra::_2+1));
- ra::Big<int, 4> b({2, 2, 3, 4}, (ra::_0+1)*1000 + (ra::_1+1)*100 + (ra::_2+1)*10 + (ra::_3+1));
- cout << a << endl;
- }
- tr.section("II");
- {
- std::tuple<int_t<6>, int_t<3>, int_t<-4>> x;
- constexpr int ma = mp::fold_tuple(-99, x, [](auto && k, auto && a) { return max(k, std::decay_t<decltype(a)>::value); });
- constexpr int mi = mp::fold_tuple(+99, x, [](auto && k, auto && a) { return min(k, std::decay_t<decltype(a)>::value); });
- constexpr int su = mp::fold_tuple(0, x, [](auto && k, auto && a) { return k + std::decay_t<decltype(a)>::value; });
- cout << ma << endl;
- cout << mi << endl;
- cout << su << endl;
- }
- tr.section("static size - like Expr");
- {
- ra::Small<int, 2, 3, 4> a = (ra::_0+1)*100 + (ra::_1+1)*10 + (ra::_2+1);
- ra::Small<int, 2, 3, 4, 5> b = (ra::_0+1)*1000 + (ra::_1+1)*100 + (ra::_2+1)*10 + (ra::_3+1);
- #define EXPR expr([](auto && a, auto && b) { return a+b; }, start(a), start(b))
- tr.test_eq(4, EXPR.rank());
- tr.test_eq(b.size(0), EXPR.size(0));
- tr.test_eq(b.size(1), EXPR.size(1));
- tr.test_eq(b.size(2), EXPR.size(2));
- tr.test_eq(b.size(3), EXPR.size(3));
- tr.test_eq(2*3*4*5, size(EXPR));
- static_assert(4==EXPR.rank_s());
- static_assert(b.size_s(0)==EXPR.size_s(0));
- static_assert(b.size_s(1)==EXPR.size_s(1));
- static_assert(b.size_s(2)==EXPR.size_s(2));
- static_assert(b.size_s(3)==EXPR.size_s(3));
- static_assert(2*3*4*5 == size_s(EXPR));
- #undef EXPR
- }
- // properly fails to compile, which we cannot check at present [ra42]
- // tr.section("check mismatches - static");
- // {
- // ra::Small<int, 2, 3, 4> a = (ra::_0+1)*100 + (ra::_1+1)*10 + (ra::_2+1);
- // ra::Small<int, 2, 4, 4, 5> b = (ra::_0+1)*1000 + (ra::_1+1)*100 + (ra::_2+1)*10 + (ra::_3+1);
- // #define EXPR expr([](auto && a, auto && b) { return a+b; }, start(a), start(b))
- // tr.test_eq(2*3*4*5, size_s(EXPR));
- // tr.test_eq(3, EXPR.size_s(1));
- // #undef EXPR
- // }
- tr.section("static rank, dynamic size - like Expr");
- {
- ra::Big<int, 3> a({2, 3, 4}, (ra::_0+1)*100 + (ra::_1+1)*10 + (ra::_2+1));
- ra::Big<int, 4> b({2, 3, 4, 5}, (ra::_0+1)*1000 + (ra::_1+1)*100 + (ra::_2+1)*10 + (ra::_3+1));
- #define EXPR expr([](auto && a, auto && b) { return a+b; }, start(a), start(b))
- tr.test_eq(4, EXPR.rank());
- tr.test_eq(b.size(0), EXPR.size(0));
- tr.test_eq(b.size(1), EXPR.size(1));
- tr.test_eq(b.size(2), EXPR.size(2));
- tr.test_eq(b.size(3), EXPR.size(3));
- tr.test_eq(2*3*4*5, size(EXPR));
- // could check all statically through decltype, although Big cannot be constexpr yet.
- static_assert(4==ra::rank_s<decltype(EXPR)>());
- tr.test_eq(4, EXPR.rank_s());
- tr.test_eq(ra::DIM_ANY, EXPR.size_s(0));
- tr.test_eq(ra::DIM_ANY, EXPR.size_s(1));
- tr.test_eq(ra::DIM_ANY, EXPR.size_s(2));
- tr.test_eq(ra::DIM_ANY, EXPR.size_s(3));
- tr.test_eq(ra::DIM_ANY, size_s(EXPR));
- cout << EXPR << endl;
- #undef EXPR
- }
- tr.section("check mismatches - dynamic");
- {
- ra::Big<int, 3> a({2, 3, 4}, (ra::_0+1)*100 + (ra::_1+1)*10 + (ra::_2+1));
- ra::Big<int, 4> b({2, 4, 4, 5}, (ra::_0+1)*1000 + (ra::_1+1)*100 + (ra::_2+1)*10 + (ra::_3+1));
- #define EXPR expr([](auto && a, auto && b) { return a+b; }, start(a), start(b))
- int x = 0;
- try {
- tr.test_eq(ra::DIM_ANY, EXPR.size_s(1));
- x = 1;
- } catch (ra_error & e) {
- }
- tr.info("caught error").test_eq(0, x);
- #undef EXPR
- }
- tr.section("dynamic rank - Expr driver selection is broken in this case.");
- {
- ra::Big<int, 3> as({2, 3, 4}, (ra::_0+1)*100 + (ra::_1+1)*10 + (ra::_2+1));
- ra::Big<int> ad({2, 3, 4}, (ra::_0+1)*100 + (ra::_1+1)*10 + (ra::_2+1));
- ra::Big<int, 4> bs({2, 3, 4, 5}, (ra::_0+1)*1000 + (ra::_1+1)*100 + (ra::_2+1)*10 + (ra::_3+1));
- ra::Big<int> bd({2, 3, 4, 5}, (ra::_0+1)*1000 + (ra::_1+1)*100 + (ra::_2+1)*10 + (ra::_3+1));
- #define EXPR(a, b) expr([](auto && a, auto && b) { return a+b; }, start(a), start(b))
- auto test = [&tr](auto tag, auto && a, auto && b)
- {
- tr.section(tag);
- tr.test_eq(4, EXPR(a, b).rank());
- tr.info("0d").test_eq(b.size(0), EXPR(a, b).size(0));
- tr.test_eq(b.size(1), EXPR(a, b).size(1));
- tr.test_eq(b.size(2), EXPR(a, b).size(2));
- tr.test_eq(b.size(3), EXPR(a, b).size(3));
- tr.info("0-size()").test_eq(2*3*4*5, size(EXPR(a, b)));
- tr.test_eq(ra::RANK_ANY, EXPR(a, b).rank_s());
- tr.test_eq(ra::DIM_ANY, size_s(EXPR(a, b)));
- tr.test_eq(ra::DIM_ANY, EXPR(a, b).size_s(0));
- tr.test_eq(ra::DIM_ANY, EXPR(a, b).size_s(1));
- tr.test_eq(ra::DIM_ANY, EXPR(a, b).size_s(2));
- tr.test_eq(ra::DIM_ANY, EXPR(a, b).size_s(3));
- tr.info("0-size_s()").test_eq(ra::DIM_ANY, size_s(EXPR(a, b)));
- };
- test("sta-dyn", as, bd);
- test("dyn-sta", ad, bs);
- test("dyn-dyn", ad, bd);
- #undef EXPR
- }
- tr.section("cases with periodic axes - dynamic (broken with Expr)");
- {
- ra::Big<int, 3> a({2, 3, 4}, (ra::_0+1)*100 + (ra::_1+1)*10 + (ra::_2+1));
- auto b = a(ra::all, ra::insert<1>, ra::iota(4, 0, 0));
- #define EXPR(a, b) expr([](auto && a, auto && b) { return a+b; }, start(a), start(b))
- tr.test_eq(4, EXPR(a, b).rank());
- tr.test_eq(b.size(0), EXPR(a, b).size(0));
- tr.test_eq(a.size(1), EXPR(a, b).size(1));
- tr.test_eq(b.size(2), EXPR(a, b).size(2));
- tr.test_eq(b.size(3), EXPR(a, b).size(3));
- tr.test_eq(2*3*4*4, size(EXPR(a, b)));
- // could check all statically through decltype, although Big cannot be constexpr yet.
- static_assert(4==ra::rank_s<decltype(EXPR(a, b))>());
- tr.test_eq(4, EXPR(a, b).rank_s());
- tr.test_eq(ra::DIM_ANY, EXPR(a, b).size_s(0));
- tr.test_eq(ra::DIM_ANY, EXPR(a, b).size_s(1));
- tr.test_eq(ra::DIM_ANY, EXPR(a, b).size_s(2));
- tr.test_eq(ra::DIM_ANY, EXPR(a, b).size_s(3));
- tr.test_eq(ra::DIM_ANY, size_s(EXPR(a, b)));
- cout << EXPR(a, b) << endl;
- // value test.
- ra::Big<int, 4> c({2, 3, 4, 4}, 0);
- c(ra::all, 0) = a(ra::all, ra::iota(4, 0, 0));
- c(ra::all, 1) = a(ra::all, ra::iota(4, 0, 0));
- c(ra::all, 2) = a(ra::all, ra::iota(4, 0, 0));
- tr.test_eq((a+c), EXPR(a, b));
- // order doesn't affect prefix matching with Expr
- tr.test_eq((a+c), EXPR(b, a));
- #undef EXPR
- }
- tr.section("broadcasting - like outer product");
- {
- ra::Big<int, 2> a({4, 3}, 10*ra::_1+100*ra::_0);
- ra::Big<int, 1> b({5}, ra::_0);
- cout << ra::start(ra::shape(from([](auto && a, auto && b) { return a-b; }, a, b))) << endl;
- #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>)))
- tr.test_eq(3, EXPR(a, b).rank_s());
- tr.test_eq(ra::DIM_ANY, EXPR(a, b).size_s(0));
- tr.test_eq(ra::DIM_ANY, EXPR(a, b).size_s(1));
- tr.test_eq(ra::DIM_ANY, EXPR(a, b).size_s(2));
- tr.test_eq(3, EXPR(a, b).rank());
- tr.test_eq(4, EXPR(a, b).size(0));
- tr.test_eq(3, EXPR(a, b).size(1));
- tr.test_eq(5, EXPR(a, b).size(2));
- tr.test_eq(from([](auto && a, auto && b) { return a-b; }, a, b), EXPR(a, b));
- #undef EXPR
- }
- tr.section("Expr has operatorX=");
- {
- ra::Big<int, 2> a({4, 3}, 10*ra::_1+100*ra::_0);
- expr([](auto & a) -> decltype(auto) { return a; }, start(a)) += 1;
- tr.test_eq(10*ra::_1 + 100*ra::_0 + 1, a);
- }
- tr.section("Compat with old Expr, from ra-0.cc");
- {
- int p[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
- int * pp = &p[0]; // force pointer decay in case we ever enforce p's shape
- 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]
- #define EXPR expr([](auto && a, auto && b) { return a==b; }, ra::_0*1 + ra::_1*0 + ra::_2*5 + 1, start(d))
- tr.test(every(EXPR));
- auto x = EXPR;
- static_assert(ra::DIM_ANY==size_s(x));
- static_assert(ra::DIM_ANY==ra::size_s(x));
- tr.test_eq(10, size(EXPR));
- }
- tr.section("DIM_BAD on any size_s(k) means size_s() is DIM_BAD");
- {
- using order = std::tuple<mp::int_t<0>, mp::int_t<1>>;
- using T0 = ra::Expr<ra::times, std::tuple<ra::TensorIndex<0>, ra::Scalar<int>>, order>;
- ra::dim_t s0 = ra::size_s<T0>();
- using T1 = ra::Expr<ra::times, std::tuple<ra::TensorIndex<1>, ra::Scalar<int>>, order>;
- ra::dim_t s1 = ra::size_s<T1>();
- using T2 = ra::Expr<ra::times, std::tuple<ra::TensorIndex<2>, ra::Scalar<int>>, order>;
- ra::dim_t s2 = ra::size_s<T2>();
- tr.test_eq(ra::DIM_BAD, s0);
- tr.test_eq(ra::DIM_BAD, s1);
- tr.test_eq(ra::DIM_BAD, s2);
- }
- // 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().
- {
- int error = 0;
- std::string s;
- try {
- ra::Small<int, 2> a {2, 3};
- ra::Big<int, 1> b({1}, 77);
- tr.test_eq(1, ra::check_expr_s<decltype(a+b)>());
- a = b;
- } catch (ra_error & e) {
- error = 1;
- s = e.s;
- }
- tr.info("dynamic size checks on static size expr (", s, ")").test_eq(1, error);
- }
- {
- int error = 0;
- std::string s;
- try {
- ra::Big<int> a {};
- // flag the error when casting rank-0 to rank-2 array. FIXME check that copying is still possible.
- f2(a);
- error = 0;
- } catch (ra_error & e) {
- error = 1;
- s = e.s;
- }
- tr.info("dynamic size checks on static size expr (", s, ")").test_eq(1, error);
- }
- return tr.summary();
- }
|