test-small.C 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. // (c) Daniel Llorens - 2014, 2016
  2. // This library is free software; you can redistribute it and/or modify it under
  3. // the terms of the GNU Lesser General Public License as published by the Free
  4. // Software Foundation; either version 3 of the License, or (at your option) any
  5. // later version.
  6. /// @file test-small.C
  7. /// @brief Making ra::Small and its iterator work with expressions/traversal.
  8. #include <iostream>
  9. #include <iterator>
  10. #include "ra/complex.H"
  11. #include "ra/small.H"
  12. #include "ra/iterator.H"
  13. #include "ra/operators.H"
  14. #include "ra/io.H"
  15. #include "ra/big.H"
  16. #include "ra/format.H"
  17. #include "ra/test.H"
  18. #include "ra/mpdebug.H"
  19. using std::cout; using std::endl; using std::flush;
  20. using complex = std::complex<double>;
  21. int main()
  22. {
  23. TestRecorder tr;
  24. tr.section("basic");
  25. {
  26. tr.test(std::is_standard_layout<ra::Small<float, 2>>::value);
  27. }
  28. tr.section("pieces of transpose(ra::Small)");
  29. {
  30. using sizes = mp::int_list<1, 2, 3, 4, 5>;
  31. using strides = mp::int_list<1, 10, 100, 1000, 10000>;
  32. using c0 = ra::axis_indices<mp::int_list<0, 1, 3, 2, 0>, mp::int_t<0> >::type;
  33. using e0 = mp::int_list<0, 4>;
  34. tr.info(mp::print_int_list<e0> {}, " vs ", mp::print_int_list<c0> {}).test(std::is_same<e0, c0>::value);
  35. using c1 = ra::axis_indices<mp::int_list<0, 1, 3, 2, 0>, mp::int_t<1> >::type;
  36. using e1 = mp::int_list<1>;
  37. tr.info(mp::print_int_list<e1> {}, " vs ", mp::print_int_list<c1> {}).test(std::is_same<e1, c1>::value);
  38. using call = ra::axes_list_indices<mp::int_list<0, 1, 3, 2, 0>, sizes, strides>::type;
  39. using eall = std::tuple<mp::int_list<0, 4>, mp::int_list<1>, mp::int_list<3>, mp::int_list<2> >;
  40. tr.info(mp::print_int_list<eall> {}, " vs ", mp::print_int_list<call> {}).test(std::is_same<eall, call>::value);
  41. }
  42. tr.section("transpose(ra::Small)");
  43. {
  44. ra::Small<double, 2, 3> const a(ra::_0 + 10*ra::_1);
  45. tr.info("<0 1>").test_eq(a, ra::transpose<0, 1>(a));
  46. tr.info("<1 0>").test_eq(ra::Small<double, 3, 2>(10*ra::_0 + ra::_1), ra::transpose<1, 0>(a));
  47. tr.info("<0 0>").test_eq(ra::Small<double, 2> {0, 11}, ra::transpose<0, 0>(a));
  48. ra::Small<double, 2, 3> b(ra::_0 + 10*ra::_1);
  49. tr.info("<0 1>").test_eq(a, ra::transpose<0, 1>(a));
  50. tr.info("<1 0>").test_eq(ra::Small<double, 3, 2>(10*ra::_0 + ra::_1), ra::transpose<1, 0>(a));
  51. ra::transpose<0, 0>(b) = {7, 9};
  52. tr.info("<0 0>").test_eq(ra::Small<double, 2, 3>{7, 10, 20, 1, 9, 21}, b);
  53. ra::Small<double> x {99};
  54. auto xt = transpose<>(x);
  55. tr.info("<> rank").test_eq(0, xt.rank());
  56. tr.info("<>").test_eq(99, xt);
  57. ra::Small<double, 3, 3> x3 = ra::_0 - ra::_1;
  58. ra::Small<double, 3, 3> y3 = transpose<1, 0>(x3);
  59. tr.info("transpose copy").test_eq(y3, ra::_1 - ra::_0);
  60. x3() = transpose<1, 0>(y3());
  61. tr.info("transpose copy").test_eq(x3, ra::_0 - ra::_1);
  62. }
  63. tr.section("constructors");
  64. {
  65. {
  66. ra::Small<int, 1> a(9);
  67. tr.test_eq(1, a.rank());
  68. tr.test_eq(1, a.size());
  69. tr.test_eq(9, a[0]);
  70. }
  71. {
  72. ra::Small<complex, 1> a = 9.;
  73. tr.test_eq(1, a.rank());
  74. tr.test_eq(1, a.size());
  75. tr.test_eq(9., a[0]);
  76. }
  77. }
  78. tr.section("operator=");
  79. {
  80. ra::Small<complex, 2> a { 3, 4 };
  81. a = complex(99.);
  82. tr.test_eq(99., a[0]);
  83. tr.test_eq(99., a[1]);
  84. a = 88.;
  85. tr.test_eq(88., a[0]);
  86. tr.test_eq(88., a[1]);
  87. a += 1.;
  88. tr.test_eq(89., a[0]);
  89. tr.test_eq(89., a[1]);
  90. }
  91. tr.section("sizeof");
  92. {
  93. // These all static, but show the numbers if there's an error.
  94. tr.info("sizeof(ra::Small<double>)")
  95. .test_eq(sizeof(double), sizeof(ra::Small<double>));
  96. tr.info("sizeof(ra::Small<double, 0>)")
  97. .test(sizeof(double)==sizeof(ra::Small<double, 0>) || 0==sizeof(ra::Small<double, 0>)); // don't rely on either.
  98. tr.info("sizeof(ra::Small<double, 1>)")
  99. .test_eq(sizeof(double), sizeof(ra::Small<double, 1>));
  100. tr.info("sizeof(ra::Small<double, 2>)")
  101. .test_eq(2*sizeof(double), sizeof(ra::Small<double, 2>));
  102. }
  103. tr.section("internal fields");
  104. {
  105. {
  106. using A = ra::Small<double, 10, 10>;
  107. alignas(A) double storage[sizeof(A)/sizeof(double)];
  108. A * a = new (&storage) A();
  109. std::fill(a->data(), a->data()+100, 0.);
  110. storage[99] = 1.3;
  111. std::cout << (*a) << std::endl;
  112. tr.test_eq(1.3, a->data()[99]);
  113. tr.test_eq(1.3, (*a)(9, 9));
  114. }
  115. {
  116. ra::Small<double, 2, 3> a {1, 2, 3, 4, 5, 6};
  117. tr.test_eq(2*3*sizeof(double), sizeof(a));
  118. tr.test_eq(1, a.data()[0]);
  119. }
  120. }
  121. tr.section("iterators' shape_type is not Small, so it can be used by Small");
  122. {
  123. auto z = ra::ra_traits<std::array<double, 3>>::make(3);
  124. tr.test_eq(3u, z.size());
  125. }
  126. tr.section("traits");
  127. {
  128. ra::Small<double, 2, 3> a {1, 2, 3, 4, 5, 6};
  129. tr.test_eq(ra::Small<ra::dim_t, 2> {2, 3}, ra::ra_traits<decltype(a)>::shape(a));
  130. }
  131. tr.section("static stride computation");
  132. {
  133. using d = mp::int_list<3, 4, 5>;
  134. using s = typename ra::default_strides<d>::type;
  135. tr.info("stride 0").test_eq(20, mp::Ref_<s, 0>::value);
  136. tr.info("stride 1").test_eq(5, mp::Ref_<s, 1>::value);
  137. tr.info("stride 2").test_eq(1, mp::Ref_<s, 2>::value);
  138. }
  139. tr.section("subscripts");
  140. {
  141. tr.section("with scalar indices");
  142. {
  143. ra::Small<double, 3, 2> s { 1, 4, 2, 5, 3, 6 };
  144. auto s0 = s();
  145. double check0[6] = { 1, 4, 2, 5, 3, 6 };
  146. tr.test(std::equal(s0.begin(), s0.end(), check0));
  147. auto s1 = s(1);
  148. double check1[3] = { 2, 5 };
  149. cout << "s1: " << s1(0) << ", " << s1(1) << endl;
  150. tr.test(s1(0)==2 && s1(1)==5);
  151. tr.test(std::equal(s1.begin(), s1.end(), check1));
  152. // only valid if operator() -> rank 0 returns rank 0 array and not scalar
  153. // auto s2 = s(1, 1);
  154. // double check2[1] = { 5 };
  155. // tr.test(std::equal(s2.begin(), s2.end(), check2));
  156. tr.test_eq(5, s(1, 1));
  157. }
  158. tr.section("using SmallView as rvalue");
  159. {
  160. ra::Small<double, 3, 2> s { 1, 4, 2, 5, 3, 6 };
  161. // use as rvalue.
  162. s(0) = { 3, 2 };
  163. s(1) = { 5, 4 };
  164. s(2) = { 7, 6 };
  165. cout << s << endl;
  166. tr.test_eq(ra::Small<double, 3, 2> { 3, 2, 5, 4, 7, 6 }, s);
  167. ra::Small<double, 3, 2> z = s;
  168. z *= -1;
  169. // check that SmallView = SmallView copies contents, just as View = View.
  170. s(0) = z(2);
  171. s(1) = z(1);
  172. s(2) = z(0);
  173. tr.test_eq(ra::Small<double, 3, 2> { -3, -2, -5, -4, -7, -6 }, z);
  174. tr.test_eq(ra::Small<double, 3, 2> { -7, -6, -5, -4, -3, -2 }, s);
  175. }
  176. tr.section("with tuples");
  177. {
  178. ra::Small<double, 3, 2> s { 1, 4, 2, 5, 3, 6 };
  179. ra::Small<int, 2> i2 { 1, 1 };
  180. ra::Small<int, 1> i1 { 1 };
  181. ra::Small<int, 0> i0 { };
  182. double check2[1] = { 5 };
  183. double check1[2] = { 2, 5 };
  184. double check0[6] = { 1, 4, 2, 5, 3, 6 };
  185. auto k2 = s.at(i2).begin(); tr.test(std::equal(check2, check2+1, k2));
  186. auto k1 = s.at(i1).begin(); tr.test(std::equal(check1, check1+2, k1));
  187. auto k0 = s.at(i0).begin(); tr.test(std::equal(check0, check0+6, k0));
  188. }
  189. tr.section("with rank 1 subscripts");
  190. {
  191. ra::Small<double, 3, 2> s { 1, 4, 2, 5, 3, 6 };
  192. tr.test_eq(ra::Small<int, 2> { 1, 4 }, s(0));
  193. tr.test_eq(ra::Small<int, 2> { 2, 5 }, s(1));
  194. tr.test_eq(ra::Small<int, 2> { 3, 6 }, s(2));
  195. tr.test_eq(ra::Small<int, 3> { 1, 2, 3 }, s(ra::all, 0));
  196. tr.test_eq(ra::Small<int, 3> { 4, 5, 6 }, s(ra::all, 1));
  197. tr.test_eq(1, s(ra::all, 1).rank());
  198. // check STL iterator.
  199. {
  200. int check0[] = { 1, 2, 3 };
  201. int check1[] = { 4, 5, 6 };
  202. tr.test(std::equal(check0, check0+3, s(ra::all, 0).begin()));
  203. tr.test(std::equal(check1, check1+3, s(ra::all, 1).begin()));
  204. tr.test(std::equal(s(ra::all, 0).begin(), s(ra::all, 0).end(), check0));
  205. tr.test(std::equal(s(ra::all, 1).begin(), s(ra::all, 1).end(), check1));
  206. }
  207. tr.test_eq(1, s(ra::all, 0)[0]);
  208. tr.test_eq(2, s(ra::all, 0)[1]);
  209. tr.test_eq(3, s(ra::all, 0)[2]);
  210. tr.test_eq(4, s(ra::all, 1)(0));
  211. tr.test_eq(5, s(ra::all, 1)(1));
  212. tr.test_eq(6, s(ra::all, 1)(2));
  213. using I0 = ra::Small<ra::dim_t, 1>;
  214. tr.test_eq(1, s(ra::all, 0).at(I0 {0}));
  215. tr.test_eq(2, s(ra::all, 0).at(I0 {1}));
  216. tr.test_eq(3, s(ra::all, 0).at(I0 {2}));
  217. tr.test_eq(4, s(ra::all, 1).at(I0 {0}));
  218. tr.test_eq(5, s(ra::all, 1).at(I0 {1}));
  219. tr.test_eq(6, s(ra::all, 1).at(I0 {2}));
  220. }
  221. tr.section("with rank 1 subscripts, result rank > 1");
  222. {
  223. ra::Small<double, 3, 2, 2> s = 100*ra::_0 + 10*ra::_1 + 1*ra::_2;
  224. cout << s << endl;
  225. auto t = s(ra::all, 1, ra::all);
  226. tr.test_eq(2, t.rank());
  227. tr.test_eq(3, t.size(0));
  228. tr.test_eq(2, t.size(1));
  229. tr.test_eq(10, t(0, 0));
  230. tr.test_eq(11, t(0, 1));
  231. tr.test_eq(110, t(1, 0));
  232. tr.test_eq(111, t(1, 1));
  233. tr.test_eq(210, t(2, 0));
  234. tr.test_eq(211, t(2, 1));
  235. tr.test_eq(ra::Small<int, 3, 2> { 10, 11, 110, 111, 210, 211 }, t);
  236. tr.test_eq(4, t.stride(0));
  237. tr.test_eq(1, t.stride(1));
  238. // check STL iterator.
  239. {
  240. int check[] = { 10, 11, 110, 111, 210, 211 };
  241. tr.test(std::equal(t.begin(), t.end(), check));
  242. tr.test(std::equal(check, check+6, t.begin()));
  243. }
  244. }
  245. }
  246. tr.section("Small<> can be constexpr");
  247. {
  248. constexpr ra::Small<int, 2, 2> a = {1, 2, 3, 4};
  249. using Va = mp::int_t<int(a(1, 0))>;
  250. tr.test_eq(3, Va::value);
  251. constexpr ra::Small<int> b = {9};
  252. using Vb = mp::int_t<int(b)>;
  253. tr.test_eq(9, Vb::value);
  254. // using Vc = mp::int_t<sum(a)>; // TODO waiting for N4487 / P0170R1 in gcc 7
  255. // tr.test_eq(10, Vb::value);
  256. }
  257. tr.section("custom strides. List init is always row-major.");
  258. {
  259. ra::SmallArray<double, mp::int_list<2, 3>, mp::int_list<1, 2>> a { 1, 2, 3, 4, 5, 6 };
  260. tr.test_eq(1, a(0, 0));
  261. tr.test_eq(2, a(0, 1));
  262. tr.test_eq(3, a(0, 2));
  263. tr.test_eq(4, a(1, 0));
  264. tr.test_eq(5, a(1, 1));
  265. tr.test_eq(6, a(1, 2));
  266. tr.test_eq(1, a(0)(0));
  267. tr.test_eq(2, a(0)(1));
  268. tr.test_eq(3, a(0)(2));
  269. tr.test_eq(4, a(1)(0));
  270. tr.test_eq(5, a(1)(1));
  271. tr.test_eq(6, a(1)(2));
  272. using dim1 = std::array<ra::dim_t, 1>;
  273. auto sizes = mp::tuple_copy<decltype(a(0))::sizes, dim1>::f();
  274. auto strides = mp::tuple_copy<decltype(a(0))::strides, dim1>::f();
  275. tr.test_eq(dim1 {3}, ra::start(sizes));
  276. tr.test_eq(dim1 {2}, ra::start(strides));
  277. }
  278. tr.section("SmallArray converted to SmallView");
  279. {
  280. ra::Small<double, 2, 3> a { 1, 2, 3, 4, 5, 6 };
  281. ra::SmallView<double, mp::int_list<2, 3>, mp::int_list<3, 1>> b = a();
  282. tr.test_eq(a, b);
  283. // non-default strides
  284. ra::SmallArray<double, mp::int_list<2, 3>, mp::int_list<1, 2>> ax { 1, 2, 3, 4, 5, 6 };
  285. ra::SmallView<double, mp::int_list<2, 3>, mp::int_list<1, 2>> bx = ax();
  286. tr.test_eq(a, ax);
  287. tr.test_eq(a, bx);
  288. bx = 77.;
  289. tr.test_eq(77., ax);
  290. b = 99.;
  291. tr.test_eq(99., a);
  292. }
  293. tr.section("using ra_iterator with SmallBase");
  294. {
  295. cout << "TODO" << endl;
  296. }
  297. tr.section("expr with Small, rank 1, ply_index");
  298. {
  299. ra::Small<double, 3> a { 1, 4, 2 };
  300. tr.test_eq(3, a.iter().size(0));
  301. #define TEST(plier) \
  302. { \
  303. double s = 0; \
  304. plier(ra::expr([&s](double & a) { s += a; }, a.iter())); \
  305. tr.test_eq(7, s); \
  306. }
  307. TEST(ply_ravel)
  308. TEST(ply_index)
  309. #undef TEST
  310. }
  311. tr.section("expr with Small, rank 2");
  312. {
  313. ra::Small<double, 3, 2> a { 1, 4, 2, 5, 3, 6 };
  314. tr.test_eq(3, a.iter().size(0));
  315. tr.test_eq(2, a.iter().size(1));
  316. #define TEST(plier) \
  317. { \
  318. double s = 0; \
  319. plier(ra::expr([&s](double & a) { s += a; }, a.iter())); \
  320. tr.test_eq(21, s); \
  321. }
  322. TEST(ply_ravel);
  323. TEST(ply_index);
  324. #undef TEST
  325. #define TEST(plier) \
  326. { \
  327. ra::Small<double, 3, 2> b; \
  328. plier(ra::expr([](double & a, double & b) { b = -a; }, a.iter(), b.iter())); \
  329. tr.test_eq(-1, b(0, 0)); \
  330. tr.test_eq(-4, b(0, 1)); \
  331. tr.test_eq(-2, b(1, 0)); \
  332. tr.test_eq(-5, b(1, 1)); \
  333. tr.test_eq(-3, b(2, 0)); \
  334. tr.test_eq(-6, b(2, 1)); \
  335. }
  336. TEST(ply_ravel);
  337. TEST(ply_index);
  338. #undef TEST
  339. }
  340. tr.section("Small as value type in var-size array");
  341. {
  342. {
  343. // This pain with rank 0 arrays and ra::scalar can be avoided with ply; see e.g. grid_interp_n() in src/grid.C.
  344. ra::Unique<ra::Small<double, 2>, 1> b({4}, ra::scalar(ra::Small<double, 2> { 3., 1. }));
  345. tr.test_eq(3., b(0)(0));
  346. tr.test_eq(1., b(0)(1));
  347. // if () returns rank 0 instead of scalar, otherwise ct error.
  348. // b(1) = ra::scalar(ra::Small<double, 2> { 7., 9. });
  349. // cout << b << endl;
  350. // if () returns scalar instead of rank 0, otherwise bug. (This is what happens).
  351. b(1) = ra::Small<double, 2> { 7., 9. };
  352. tr.test_eq(3., b(0)(0));
  353. tr.test_eq(1., b(0)(1));
  354. tr.test_eq(7., b(1)(0));
  355. tr.test_eq(9., b(1)(1));
  356. }
  357. {
  358. ra::Unique<double, 1> b({2}, { 3., 1. });
  359. tr.test_eq(3., b(0));
  360. tr.test_eq(1., b(1));
  361. b = ra::Small<double, 2> { 7., 9. };
  362. cout << b << endl;
  363. tr.test_eq(7., b(0));
  364. tr.test_eq(9., b(1));
  365. }
  366. {
  367. ra::Unique<double, 2> b({2, 2}, { 3., 1., 3., 1. });
  368. b(1) = ra::Small<double, 2> { 7., 9. };
  369. tr.test_eq(3., b(0, 0));
  370. tr.test_eq(1., b(0, 1));
  371. tr.test_eq(7., b(1, 0));
  372. tr.test_eq(9., b(1, 1));
  373. }
  374. {
  375. ra::Unique<ra::Small<double, 2>, 0> b(ra::scalar(ra::Small<double, 2>{3., 1.}));
  376. b = ra::scalar(ra::Small<double, 2> { 7., 9. });
  377. tr.test_eq(7., b()(0));
  378. tr.test_eq(9., b()(1));
  379. }
  380. {
  381. ra::Unique<ra::Small<double, 2>, 1> b({4}, ra::scalar(ra::Small<double, 2> { 3., 1. }));
  382. ra::Small<double, 2> u = b(1);
  383. tr.test_eq(3, u[0]);
  384. tr.test_eq(1, u[1]);
  385. ra::Small<double, 2> v(b(1));
  386. tr.test_eq(3, v[0]);
  387. tr.test_eq(1, v[1]);
  388. }
  389. }
  390. tr.section("transpose");
  391. {
  392. ra::Small<double, 2, 3> a { 1, 2, 3, 4, 5, 6 };
  393. tr.test_eq(ra::Small<double, 3, 2> { 1, 4, 2, 5, 3, 6 }, transpose<1, 0>(a));
  394. ra::transpose<1, 0>(a) = { 1, 2, 3, 4, 5, 6 };
  395. tr.test_eq(ra::Small<double, 2, 3> { 1, 3, 5, 2, 4, 6 }, a);
  396. }
  397. tr.section("diag");
  398. {
  399. ra::Small<double, 3, 3> a = ra::_0*3 + ra::_1;
  400. tr.test_eq(ra::Small<double, 3> { 0, 4, 8 }, diag(a));
  401. diag(a) = { 11, 22, 33 };
  402. tr.test_eq(ra::Small<double, 3, 3> { 11, 1, 2, 3, 22, 5, 6, 7, 33 }, a);
  403. }
  404. tr.section("renames");
  405. {
  406. ra::Small<double, 2, 2> a { 13, 8, 75, 19 };
  407. ra::mat_uv<double> b(a);
  408. assert(b.uu==13 && b.uv==8 && b.vu==75 && b.vv==19);
  409. ra::Small<double, 3> x { 13, 8, 75 };
  410. ra::vec_xyz<double> y(x);
  411. assert(y.x==13 && y.y==8 && y.z==75);
  412. }
  413. tr.section(".back()");
  414. {
  415. ra::Small<double, 3> a = ra::_0*3;
  416. tr.test_eq(0, a[0]);
  417. tr.test_eq(3, a[1]);
  418. tr.test_eq(6, a[2]);
  419. tr.test_eq(6, a.back());
  420. }
  421. // TODO Replace with uniform subscripting (ra::iota).
  422. tr.section("compile time subscripting of ra::Small (as)");
  423. {
  424. auto test_as = [&tr](auto && a, auto && b)
  425. {
  426. tr.test_eq(2, b.size());
  427. tr.test_eq(1, b[0]);
  428. tr.test_eq(2, b[1]);
  429. b = { 7, 8 };
  430. tr.test_eq(7, a[0]);
  431. tr.test_eq(8, a[1]);
  432. tr.test_eq(3, a[2]);
  433. };
  434. {
  435. ra::Small<double, 3> a = { 1, 2, 3 };
  436. test_as(a, a.as<2>());
  437. ra::Small<double, 6> b = { 1, 99, 2, 99, 3, 99 };
  438. ra::SmallView<double, mp::int_list<3>, mp::int_list<2> > c(b.data()); // TODO no syntax yet.
  439. test_as(c, c.as<2>());
  440. }
  441. auto test_fra = [&tr](auto && a, auto && b)
  442. {
  443. tr.test_eq(2, b.size());
  444. tr.test_eq(2, b[0]);
  445. tr.test_eq(3, b[1]);
  446. b = { 7, 8 };
  447. tr.test_eq(1, a[0]);
  448. tr.test_eq(7, a[1]);
  449. tr.test_eq(8, a[2]);
  450. };
  451. {
  452. ra::Small<double, 3> a = { 1, 2, 3 };
  453. test_fra(a, a.as<2, 1>());
  454. ra::Small<double, 6> b = { 1, 99, 2, 99, 3, 99 };
  455. ra::SmallView<double, mp::int_list<3>, mp::int_list<2> > c(b.data()); // TODO no syntax yet.
  456. test_fra(c, c.as<2, 1>());
  457. }
  458. auto test_fra_rank_2 = [&tr](auto && a, auto && b)
  459. {
  460. tr.test_eq(2, b.size(0));
  461. tr.test_eq(2, b.size(1));
  462. tr.test_eq(ra::Small<double, 2, 2> { 3, 4, 5, 6 }, b);
  463. b = ra::Small<double, 2, 2> { 13, 14, 15, 16 };
  464. tr.test_eq(ra::Small<double, 3, 2> { 1, 2, 13, 14, 15, 16 }, a);
  465. };
  466. {
  467. ra::Small<double, 3, 2> a = { 1, 2, 3, 4, 5, 6 };
  468. test_fra_rank_2(a, a.as<2, 1>());
  469. ra::Small<double, 6, 2> b = { 1, 2, 99, 99, 3, 4, 99, 99, 5, 6, 99, 99 };
  470. ra::SmallView<double, mp::int_list<3, 2>, mp::int_list<4, 1> > c(b.data()); // TODO no syntax yet.
  471. test_fra_rank_2(c, c.as<2, 1>());
  472. }
  473. }
  474. tr.section("cat");
  475. {
  476. tr.test_eq(ra::Small<int, 4> {1, 2, 3, 4}, cat(ra::Small<int, 3> {1, 2, 3}, 4));
  477. tr.test_eq(ra::Small<int, 4> {4, 1, 2, 3}, cat(4, ra::Small<int, 3> {1, 2, 3}));
  478. 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}));
  479. }
  480. tr.section("a demo on rank1of1 vs rank2 [ref01]");
  481. {
  482. // by prefix matching, first dim is 2 for both so they get matched. Then {1 2}
  483. // (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.
  484. ra::Small<ra::Small<double, 2>, 2> a = { {1, 2}, {3, 4} };
  485. ra::Small<double, 2, 2> b = { 10, 20, 30, 40 };
  486. cout << "a: " << a << endl;
  487. cout << "b: " << b << endl;
  488. // a = b; // TODO Check that this static fails
  489. cout << "a = b, a: " << a << endl;
  490. }
  491. // ASSIGNOPS for SmallBase.iter()
  492. {
  493. ra::Small<int, 3> s {1, 2, 3};
  494. s.iter() += 9;
  495. tr.test_eq(ra::start({10, 11, 12}), s);
  496. }
  497. return tr.summary();
  498. }