small-1.cc 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. // -*- mode: c++; coding: utf-8 -*-
  2. // ra-ra/test - Making ra::Small and its iterator work with expressions/traversal.
  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. // See also small-0.cc.
  9. #include <iostream>
  10. #include <iterator>
  11. #include "ra/test.hh"
  12. #include "mpdebug.hh"
  13. using std::cout, std::endl, std::flush, ra::TestRecorder;
  14. using ra::ilist_t, ra::int_c, ra::mp::print_ilist_t, ra::mp::ref, ra::transpose;
  15. using int2 = ra::Small<int, 2>;
  16. int main()
  17. {
  18. TestRecorder tr;
  19. tr.section("transpose(ra::Small)");
  20. {
  21. ra::Small<double, 2, 3> const a(ra::_0 + 10*ra::_1);
  22. tr.info("<0 1>").test_eq(a, transpose(a, ilist_t<0, 1>{}));
  23. tr.info("<1 0>").test_eq(ra::Small<double, 3, 2>(10*ra::_0 + ra::_1), transpose(a, ilist_t<1, 0>{}));
  24. tr.info("<1 0> by default").test_eq(ra::Small<double, 3, 2>(10*ra::_0 + ra::_1), transpose(a));
  25. tr.info("<0 0>").test_eq(ra::Small<double, 2> {0, 11}, transpose(a, ilist_t<0, 0>{}));
  26. ra::Small<double, 2, 3> b(ra::_0 + 10*ra::_1);
  27. tr.info("<0 1>").test_eq(a, transpose(a, ilist_t<0, 1>{}));
  28. tr.info("<1 0>").test_eq(ra::Small<double, 3, 2>(10*ra::_0 + ra::_1), transpose(a, ilist_t<1, 0>{}));
  29. tr.info("<1 0> by default").test_eq(ra::Small<double, 3, 2>(10*ra::_0 + ra::_1), transpose(a));
  30. transpose(b, ilist_t<0, 0>{}) = {7, 9};
  31. tr.info("<0 0>").test_eq(ra::Small<double, 2, 3>{7, 10, 20, 1, 9, 21}, b);
  32. ra::Small<double> x {99};
  33. auto xt = transpose(x, ilist_t<>{});
  34. tr.info("<> rank").test_eq(0, xt.rank());
  35. tr.info("<>").test_eq(99, xt);
  36. ra::Small<double, 3, 3> x3 = ra::_0 - ra::_1;
  37. ra::Small<double, 3, 3> y3 = transpose(x3, ilist_t<1, 0>{});
  38. tr.info("transpose copy").test_eq(y3, ra::_1 - ra::_0);
  39. x3() = transpose(y3(), ilist_t<1, 0>{});
  40. tr.info("transpose copy").test_eq(x3, ra::_0 - ra::_1);
  41. }
  42. tr.section("sizeof");
  43. {
  44. // These all static, but show the numbers if there's an error.
  45. tr.info("sizeof(ra::Small<double>)")
  46. .test_eq(sizeof(double), sizeof(ra::Small<double>));
  47. tr.info("sizeof(ra::Small<double, 0>)")
  48. .test(sizeof(double)==sizeof(ra::Small<double, 0>) || 0==sizeof(ra::Small<double, 0>)); // don't rely on either.
  49. tr.info("sizeof(ra::Small<double, 1>)")
  50. .test_eq(sizeof(double), sizeof(ra::Small<double, 1>));
  51. tr.info("sizeof(ra::Small<double, 2>)")
  52. .test_eq(2*sizeof(double), sizeof(ra::Small<double, 2>));
  53. }
  54. tr.section("internal fields");
  55. {
  56. {
  57. using A = ra::Small<double, 10, 10>;
  58. alignas(A) double storage[sizeof(A)/sizeof(double)];
  59. A * a = new (&storage) A();
  60. std::fill(a->data(), a->data()+100, 0.);
  61. storage[99] = 1.3;
  62. std::cout << (*a) << std::endl;
  63. tr.test_eq(1.3, a->data()[99]);
  64. tr.test_eq(1.3, (*a)(9, 9));
  65. }
  66. {
  67. ra::Small<double, 2, 3> a {1, 2, 3, 4, 5, 6};
  68. tr.test_eq(2*3*sizeof(double), sizeof(a));
  69. tr.test_eq(1, a.data()[0]);
  70. }
  71. }
  72. tr.section("top level generics");
  73. {
  74. ra::Small<double, 2, 3> a {1, 2, 3, 4, 5, 6};
  75. tr.test_eq(ra::Small<ra::dim_t, 2> {2, 3}, shape(a));
  76. tr.test_eq(3u, ra::size(std::array<double, 3>()));
  77. }
  78. tr.section("static step computation");
  79. {
  80. using d = ilist_t<3, 4, 5>;
  81. using s = ra::default_steps<d>;
  82. tr.info("step 0").test_eq(20, ref<s, 0>::value);
  83. tr.info("step 1").test_eq(5, ref<s, 1>::value);
  84. tr.info("step 2").test_eq(1, ref<s, 2>::value);
  85. }
  86. tr.section("subscripts");
  87. {
  88. tr.section("with scalar indices");
  89. {
  90. ra::Small<double, 3, 2> s { 1, 4, 2, 5, 3, 6 };
  91. auto s0 = s();
  92. double check0[6] = { 1, 4, 2, 5, 3, 6 };
  93. tr.test(std::equal(s0.begin(), s0.end(), check0));
  94. auto s1 = s(1);
  95. double check1[3] = { 2, 5 };
  96. cout << "s1: " << s1(0) << ", " << s1(1) << endl;
  97. tr.test(s1(0)==2 && s1(1)==5);
  98. tr.test(std::equal(s1.begin(), s1.end(), check1));
  99. tr.test_eq(5, s(1, 1));
  100. }
  101. tr.section("using ViewSmall as rvalue");
  102. {
  103. ra::Small<double, 3, 2> s { 1, 4, 2, 5, 3, 6 };
  104. // use as rvalue.
  105. s(0) = { 3, 2 };
  106. s(1) = { 5, 4 };
  107. s(2) = { 7, 6 };
  108. cout << s << endl;
  109. tr.test_eq(ra::Small<double, 3, 2> { 3, 2, 5, 4, 7, 6 }, s);
  110. ra::Small<double, 3, 2> z = s;
  111. z *= -1;
  112. // check that ViewSmall = ViewSmall copies contents, just as View = View.
  113. s(0) = z(2);
  114. s(1) = z(1);
  115. s(2) = z(0);
  116. tr.test_eq(ra::Small<double, 3, 2> { -3, -2, -5, -4, -7, -6 }, z);
  117. tr.test_eq(ra::Small<double, 3, 2> { -7, -6, -5, -4, -3, -2 }, s);
  118. }
  119. tr.section("with tuples");
  120. {
  121. ra::Small<double, 3, 2> s { 1, 4, 2, 5, 3, 6 };
  122. ra::Small<int, 2> i2 { 1, 1 };
  123. ra::Small<int, 1> i1 { 1 };
  124. ra::Small<int, 0> i0 { };
  125. double check2[1] = { 5 };
  126. double check1[2] = { 2, 5 };
  127. double check0[6] = { 1, 4, 2, 5, 3, 6 };
  128. auto k2 = s.at(i2);
  129. tr.test_eq(0, ra::rank(k2));
  130. tr.test_eq(check2[0], k2);
  131. auto k1 = s.at(i1).begin(); tr.test(std::equal(check1, check1+2, k1));
  132. auto k0 = s.at(i0).begin(); tr.test(std::equal(check0, check0+6, k0));
  133. }
  134. tr.section("with rank 1 subscripts");
  135. {
  136. ra::Small<double, 3, 2> s { 1, 4, 2, 5, 3, 6 };
  137. tr.test_eq(ra::Small<int, 2> { 1, 4 }, s(0));
  138. tr.test_eq(ra::Small<int, 2> { 2, 5 }, s(1));
  139. tr.test_eq(ra::Small<int, 2> { 3, 6 }, s(2));
  140. tr.test_eq(ra::Small<int, 3> { 1, 2, 3 }, s(ra::all, 0));
  141. tr.test_eq(ra::Small<int, 3> { 4, 5, 6 }, s(ra::all, 1));
  142. tr.test_eq(1, s(ra::all, 1).rank());
  143. // check STL iterator.
  144. {
  145. int check0[] = { 1, 2, 3 };
  146. int check1[] = { 4, 5, 6 };
  147. tr.test(std::ranges::equal(check0, check0+3, s(ra::all, 0).begin(), s(ra::all, 0).end()));
  148. tr.test(std::ranges::equal(check1, check1+3, s(ra::all, 1).begin(), s(ra::all, 1).end()));
  149. tr.test(std::ranges::equal(s(ra::all, 0).begin(), s(ra::all, 0).end(), check0, check0+3));
  150. tr.test(std::ranges::equal(s(ra::all, 1).begin(), s(ra::all, 1).end(), check1, check1+3));
  151. }
  152. tr.test_eq(1, s(ra::all, 0)[0]);
  153. tr.test_eq(2, s(ra::all, 0)[1]);
  154. tr.test_eq(3, s(ra::all, 0)[2]);
  155. tr.test_eq(4, s(ra::all, 1)(0));
  156. tr.test_eq(5, s(ra::all, 1)(1));
  157. tr.test_eq(6, s(ra::all, 1)(2));
  158. using I0 = ra::Small<ra::dim_t, 1>;
  159. tr.test_eq(1, s(ra::all, 0).at(I0 {0}));
  160. tr.test_eq(2, s(ra::all, 0).at(I0 {1}));
  161. tr.test_eq(3, s(ra::all, 0).at(I0 {2}));
  162. tr.test_eq(4, s(ra::all, 1).at(I0 {0}));
  163. tr.test_eq(5, s(ra::all, 1).at(I0 {1}));
  164. tr.test_eq(6, s(ra::all, 1).at(I0 {2}));
  165. }
  166. tr.section("with rank 1 subscripts, result rank > 1");
  167. {
  168. ra::Small<double, 3, 2, 2> s = 100*ra::_0 + 10*ra::_1 + 1*ra::_2;
  169. cout << s << endl;
  170. auto t = s(ra::all, 1, ra::all);
  171. tr.test_eq(2, t.rank());
  172. tr.test_eq(3, t.len(0));
  173. tr.test_eq(2, t.len(1));
  174. tr.test_eq(10, t(0, 0));
  175. tr.test_eq(11, t(0, 1));
  176. tr.test_eq(110, t(1, 0));
  177. tr.test_eq(111, t(1, 1));
  178. tr.test_eq(210, t(2, 0));
  179. tr.test_eq(211, t(2, 1));
  180. tr.test_eq(ra::Small<int, 3, 2> { 10, 11, 110, 111, 210, 211 }, t);
  181. tr.test_eq(4, t.step(0));
  182. tr.test_eq(1, t.step(1));
  183. // check STL iterator.
  184. {
  185. int check[] = { 10, 11, 110, 111, 210, 211 };
  186. tr.test(std::ranges::equal(t.begin(), t.end(), check, check+6));
  187. tr.test(std::ranges::equal(check, check+6, t.begin(), t.end()));
  188. }
  189. }
  190. }
  191. tr.section("Small<> can be constexpr");
  192. {
  193. constexpr ra::Small<int, 2, 2> a = {1, 2, 3, 4};
  194. using Va = int_c<int(a(1, 0))>;
  195. tr.test_eq(3, Va::value);
  196. using Vc = int_c<sum(a)>; // constexpr reduction!
  197. tr.test_eq(10, Vc::value);
  198. constexpr ra::Small<int> b = { 9 }; // needs std::fill
  199. using Vb = int_c<int(b)>;
  200. tr.test_eq(9, Vb::value);
  201. }
  202. tr.section("custom steps. List init is row-major regardless.");
  203. {
  204. auto test = [&tr](auto && a)
  205. {
  206. tr.test_eq(1, a(0, 0));
  207. tr.test_eq(2, a(0, 1));
  208. tr.test_eq(3, a(0, 2));
  209. tr.test_eq(4, a(1, 0));
  210. tr.test_eq(5, a(1, 1));
  211. tr.test_eq(6, a(1, 2));
  212. tr.test_eq(1, a(0)(0));
  213. tr.test_eq(2, a(0)(1));
  214. tr.test_eq(3, a(0)(2));
  215. tr.test_eq(4, a(1)(0));
  216. tr.test_eq(5, a(1)(1));
  217. tr.test_eq(6, a(1)(2));
  218. using A = std::decay_t<decltype(a(0))>;
  219. using dim1 = std::array<ra::dim_t, 1>;
  220. auto lens = ra::mp::tuple2array<ra::dim_t, typename A::lens>();
  221. auto steps = ra::mp::tuple2array<ra::dim_t, typename A::steps>();
  222. tr.test_eq(dim1 {3}, ra::start(lens));
  223. tr.test_eq(dim1 {2}, ra::start(steps));
  224. };
  225. ra::SmallArray<double, ilist_t<2, 3>, ilist_t<1, 2>> a { 1, 2, 3, 4, 5, 6 };
  226. ra::SmallArray<double, ilist_t<2, 3>, ilist_t<1, 2>> b { {1, 2, 3}, {4, 5, 6} };
  227. test(a);
  228. test(b);
  229. }
  230. tr.section("SmallArray converted to ViewSmall");
  231. {
  232. ra::Small<double, 2, 3> a { 1, 2, 3, 4, 5, 6 };
  233. ra::ViewSmall<double, ilist_t<2, 3>, ilist_t<3, 1>> b = a();
  234. tr.test_eq(a, b);
  235. // non-default steps (fortran / column major order).
  236. ra::SmallArray<double, ilist_t<2, 3>, ilist_t<1, 2>> ax { 1, 2, 3, 4, 5, 6 };
  237. ra::ViewSmall<double, ilist_t<2, 3>, ilist_t<1, 2>> bx = ax();
  238. tr.test_eq(a, ax);
  239. tr.test_eq(a, bx);
  240. // check iterators.
  241. tr.test(std::ranges::equal(a.begin(), a.end(), ax.begin(), ax.end()));
  242. tr.test(std::ranges::equal(ax.begin(), ax.end(), a.begin(), a.end()));
  243. tr.test(std::ranges::equal(b.begin(), b.end(), bx.begin(), bx.end()));
  244. tr.test(std::ranges::equal(bx.begin(), bx.end(), b.begin(), b.end()));
  245. // check memory order.
  246. double fcheck[6] = { 1, 4, 2, 5, 3, 6 };
  247. tr.test(std::equal(fcheck, fcheck+6, ax.data()));
  248. tr.test(std::equal(fcheck, fcheck+6, bx.data()));
  249. // views work as views.
  250. bx = 77.;
  251. tr.test_eq(77., ax);
  252. b = 99.;
  253. tr.test_eq(99., a);
  254. }
  255. tr.section("map with Small, rank 1");
  256. {
  257. ra::Small<double, 3> a { 1, 4, 2 };
  258. tr.test_eq(3, a.iter().len(0));
  259. #define TEST(plier) \
  260. { \
  261. double s = 0; \
  262. plier(ra::map_([&s](double & a) { s += a; }, a.iter())); \
  263. tr.test_eq(7, s); \
  264. }
  265. TEST(ply_ravel);
  266. TEST(ply);
  267. #undef TEST
  268. }
  269. tr.section("map with Small, rank 2");
  270. {
  271. ra::Small<double, 3, 2> a { 1, 4, 2, 5, 3, 6 };
  272. tr.test_eq(3, a.iter().len(0));
  273. tr.test_eq(2, a.iter().len(1));
  274. #define TEST(plier) \
  275. { \
  276. double s = 0; \
  277. plier(ra::map_([&s](double & a) { s += a; }, a.iter())); \
  278. tr.test_eq(21, s); \
  279. }
  280. TEST(ply_ravel);
  281. TEST(ply);
  282. #undef TEST
  283. #define TEST(plier) \
  284. { \
  285. ra::Small<double, 3, 2> b; \
  286. plier(ra::map_([](double & a, double & b) { b = -a; }, a.iter(), b.iter())); \
  287. tr.test_eq(-1, b(0, 0)); \
  288. tr.test_eq(-4, b(0, 1)); \
  289. tr.test_eq(-2, b(1, 0)); \
  290. tr.test_eq(-5, b(1, 1)); \
  291. tr.test_eq(-3, b(2, 0)); \
  292. tr.test_eq(-6, b(2, 1)); \
  293. }
  294. TEST(ply_ravel);
  295. TEST(ply);
  296. #undef TEST
  297. }
  298. tr.section("Small as value type in var-size array");
  299. {
  300. {
  301. // This pain with rank 0 arrays and ra::scalar can be avoided with ply; see e.g. grid_interp_n() in src/grid.cc.
  302. ra::Unique<ra::Small<double, 2>, 1> b({4}, ra::scalar(ra::Small<double, 2> { 3., 1. }));
  303. tr.test_eq(3., b(0)(0));
  304. tr.test_eq(1., b(0)(1));
  305. // if () returns rank 0 instead of scalar, otherwise ct error.
  306. // b(1) = ra::scalar(ra::Small<double, 2> { 7., 9. });
  307. // cout << b << endl;
  308. // if () returns scalar instead of rank 0, otherwise bug. (This is what happens).
  309. b(1) = ra::Small<double, 2> { 7., 9. };
  310. tr.test_eq(3., b(0)(0));
  311. tr.test_eq(1., b(0)(1));
  312. tr.test_eq(7., b(1)(0));
  313. tr.test_eq(9., b(1)(1));
  314. }
  315. {
  316. ra::Unique<double, 1> b({2}, { 3., 1. });
  317. tr.test_eq(3., b(0));
  318. tr.test_eq(1., b(1));
  319. b = ra::Small<double, 2> { 7., 9. };
  320. cout << b << endl;
  321. tr.test_eq(7., b(0));
  322. tr.test_eq(9., b(1));
  323. }
  324. {
  325. ra::Unique<double, 2> b({2, 2}, { 3., 1., 3., 1. });
  326. b(1) = ra::Small<double, 2> { 7., 9. };
  327. tr.test_eq(3., b(0, 0));
  328. tr.test_eq(1., b(0, 1));
  329. tr.test_eq(7., b(1, 0));
  330. tr.test_eq(9., b(1, 1));
  331. }
  332. {
  333. ra::Unique<ra::Small<double, 2>, 0> b(ra::scalar(ra::Small<double, 2>{3., 1.}));
  334. b = ra::scalar(ra::Small<double, 2> { 7., 9. });
  335. tr.test_eq(7., b()(0));
  336. tr.test_eq(9., b()(1));
  337. }
  338. {
  339. ra::Unique<ra::Small<double, 2>, 1> b({4}, ra::scalar(ra::Small<double, 2> { 3., 1. }));
  340. ra::Small<double, 2> u = b(1);
  341. tr.test_eq(3, u[0]);
  342. tr.test_eq(1, u[1]);
  343. ra::Small<double, 2> v(b(1));
  344. tr.test_eq(3, v[0]);
  345. tr.test_eq(1, v[1]);
  346. }
  347. }
  348. tr.section("transpose");
  349. {
  350. ra::Small<double, 2, 3> a { 1, 2, 3, 4, 5, 6 };
  351. tr.test_eq(ra::Small<double, 3, 2> { 1, 4, 2, 5, 3, 6 }, transpose(a, ilist_t<1, 0>{}));
  352. transpose(a, ilist_t<1, 0>{}) = { 1, 2, 3, 4, 5, 6 };
  353. tr.test_eq(ra::Small<double, 2, 3> { 1, 3, 5, 2, 4, 6 }, a);
  354. }
  355. tr.section("diag");
  356. {
  357. ra::Small<double, 3, 3> a = ra::_0*3 + ra::_1;
  358. tr.test_eq(ra::Small<double, 3> { 0, 4, 8 }, diag(a));
  359. diag(a) = { 11, 22, 33 };
  360. tr.test_eq(ra::Small<double, 3, 3> { 11, 1, 2, 3, 22, 5, 6, 7, 33 }, a);
  361. }
  362. tr.section(".back()");
  363. {
  364. ra::Small<double, 3> a = ra::_0*3;
  365. tr.test_eq(0, a[0]);
  366. tr.test_eq(3, a[1]);
  367. tr.test_eq(6, a[2]);
  368. tr.test_eq(6, a.back());
  369. }
  370. tr.section(".back() is last element not last item");
  371. {
  372. ra::Small<int2> b(ra::scalar(int2 {1, 3})); // cf [ma116]
  373. tr.test_eq(int2 {1, 3}, b.back());
  374. }
  375. // TODO Replace with uniform subscripting (ra::iota).
  376. tr.section("compile time subscripting of ra::Small (as)");
  377. {
  378. auto test_as = [&tr](auto && a, auto && b)
  379. {
  380. tr.test_eq(2, b.size());
  381. tr.test_eq(1, b[0]);
  382. tr.test_eq(2, b[1]);
  383. b = { 7, 8 };
  384. tr.test_eq(7, a[0]);
  385. tr.test_eq(8, a[1]);
  386. tr.test_eq(3, a[2]);
  387. };
  388. {
  389. ra::Small<double, 3> a = { 1, 2, 3 };
  390. test_as(a, a.as<2>());
  391. ra::Small<double, 6> b = { 1, 99, 2, 99, 3, 99 };
  392. ra::ViewSmall<double, ilist_t<3>, ilist_t<2>> c(b.data()); // TODO no syntax yet.
  393. test_as(c, c.as<2>());
  394. }
  395. auto test_fra = [&tr](auto && a, auto && b)
  396. {
  397. tr.test_eq(2, b.size());
  398. tr.test_eq(2, b[0]);
  399. tr.test_eq(3, b[1]);
  400. b = { 7, 8 };
  401. tr.test_eq(1, a[0]);
  402. tr.test_eq(7, a[1]);
  403. tr.test_eq(8, a[2]);
  404. };
  405. {
  406. ra::Small<double, 3> a = { 1, 2, 3 };
  407. test_fra(a, a.as<2, 1>());
  408. ra::Small<double, 6> b = { 1, 99, 2, 99, 3, 99 };
  409. ra::ViewSmall<double, ilist_t<3>, ilist_t<2>> c(b.data()); // TODO no syntax yet.
  410. test_fra(c, c.as<2, 1>());
  411. }
  412. auto test_fra_rank_2 = [&tr](auto && a, auto && b)
  413. {
  414. tr.test_eq(2, b.len(0));
  415. tr.test_eq(2, b.len(1));
  416. tr.test_eq(ra::Small<double, 2, 2> { 3, 4, 5, 6 }, b);
  417. b = ra::Small<double, 2, 2> { 13, 14, 15, 16 };
  418. tr.test_eq(ra::Small<double, 3, 2> { 1, 2, 13, 14, 15, 16 }, a);
  419. };
  420. {
  421. ra::Small<double, 3, 2> a = { 1, 2, 3, 4, 5, 6 };
  422. test_fra_rank_2(a, a.as<2, 1>());
  423. ra::Small<double, 6, 2> b = { 1, 2, 99, 99, 3, 4, 99, 99, 5, 6, 99, 99 };
  424. ra::ViewSmall<double, ilist_t<3, 2>, ilist_t<4, 1>> c(b.data()); // TODO no syntax yet.
  425. test_fra_rank_2(c, c.as<2, 1>());
  426. }
  427. }
  428. tr.section("cat");
  429. {
  430. tr.test_eq(ra::Small<int, 4> {1, 2, 3, 4}, cat(ra::Small<int, 3> {1, 2, 3}, 4));
  431. tr.test_eq(ra::Small<int, 4> {4, 1, 2, 3}, cat(4, ra::Small<int, 3> {1, 2, 3}));
  432. tr.test_eq(ra::Small<int, 5> {1, 2, 3, 4, 5}, cat(ra::Small<int, 2> {1, 2}, ra::Small<int, 3> {3, 4, 5}));
  433. }
  434. tr.section("a demo on rank1of1 vs rank2");
  435. {
  436. // by prefix matching, first dim is 2 for both so they get matched. Then {1 2}
  437. // (a 'scalar') gets matched to 10 & 20 in succesion. This used to be forbidden in Small::Small(X && x), but now I value consistency more.
  438. ra::Small<ra::Small<double, 2>, 2> a = { {1, 2}, {3, 4} };
  439. ra::Small<double, 2, 2> b = { 10, 20, 30, 40 };
  440. cout << "a: " << a << endl;
  441. cout << "b: " << b << endl;
  442. // a = b; // TODO Check that this static fails
  443. cout << "a = b, a: " << a << endl;
  444. }
  445. // ASSIGNOPS for SmallBase.iter()
  446. {
  447. ra::Small<int, 3> s {1, 2, 3};
  448. s.iter() += 9;
  449. tr.test_eq(ra::start({10, 11, 12}), s);
  450. }
  451. tr.section("multidimensional []");
  452. {
  453. ra::Small<int, 3, 2, 4> a = ra::_0 + ra::_1 - ra::_2;
  454. tr.test_eq(a(ra::all, 0), a[ra::all, 0]);
  455. }
  456. tr.section("deduction guides");
  457. {
  458. ra::SmallArray a {1, 2, 3}; // FIXME the deduction guide can't work for ra::Small
  459. tr.test_eq(ra::start({1, 2, 3}), a);
  460. }
  461. return tr.summary();
  462. }