Skip to content

Commit 19a3afa

Browse files
committed
Support reverse(small)
* ra/small.hh (reverse): As stated. * test/ra-1.cc, test/view-ops.cc: Test.
1 parent b8e7e3e commit 19a3afa

File tree

8 files changed

+100
-46
lines changed

8 files changed

+100
-46
lines changed

docs/index.html

Lines changed: 8 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/ra-ra.texi

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2507,11 +2507,20 @@ See also @ref{x-imag_part,@code{imag_part}}.
25072507
@end defun
25082508

25092509
@cindex @code{reverse}
2510-
@anchor{x-reverse} @defun reverse view axis
2510+
@anchor{x-reverse} @defun reverse view k
25112511
Create a new view by reversing axis @var{k} of @var{view}.
25122512

25132513
This is equivalent to @code{view(ra::dots<k>, ra::iota(ra::len, ra::len-1, -1))}.
25142514

2515+
If @var{view} has static dimensions, then @var{k} must be a static constant, e.g.
2516+
@example
2517+
@verbatim
2518+
ra::Small<int, 3, 2> a = {{1, 2, 3}, {4, 5, 6}};
2519+
auto z = reverse(a, ra::ic<0>); // z has static dimensions
2520+
@end verbatim
2521+
@result{} z = @{@{3, 2, 1@}, @{6, 5, 4@}@}
2522+
@end example
2523+
25152524
This operation does not work on arbitrary array expressions yet. @c TODO FILL
25162525

25172526
@end defun

ra/base.hh

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -391,8 +391,7 @@ template <class ... A> constexpr bool tomap = ((is_ra_pos<A> || is_special<A>) |
391391

392392
// Sometimes we can't do shape(std::declval<V>()) even for static shape :-/ FIXME
393393
template <class VV>
394-
constexpr auto shape_s = []
395-
{
394+
constexpr auto shape_s = []{
396395
using V = std::remove_cvref_t<VV>;
397396
if constexpr (constexpr rank_t rs=rank_s<V>(); 0==rs) {
398397
return std::array<dim_t, 0> {};

ra/big.hh

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -524,15 +524,14 @@ with_shape(std::initializer_list<S> && s, X && x) { return with_shape<E>(start(s
524524
// --------------------
525525

526526
template <class P, rank_t RANK>
527-
constexpr ViewBig<P, RANK>
527+
constexpr auto
528528
reverse(ViewBig<P, RANK> const & view, int k=0)
529529
{
530530
RA_CHECK(inside(k, view.rank()), "Bad axis ", k, " for rank ", view.rank(), ".");
531531
ViewBig<P, RANK> r = view;
532-
if (auto & dim=r.dimv[k]; dim.len!=0) {
533-
r.cp += dim.step*(dim.len-1);
534-
dim.step *= -1;
535-
}
532+
auto & dim = r.dimv[k];
533+
dim.step *= -1;
534+
if (dim.len!=0) { r.cp += dim.step*(1-dim.len); }
536535
return r;
537536
}
538537

ra/small.hh

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@ inline std::ostream &
2424
operator<<(std::ostream & o, Dim const & dim) { return (o << "[Dim " << dim.len << " " << dim.step << "]"); }
2525

2626
template <auto v, int n>
27-
constexpr auto vdrop = []
28-
{
27+
constexpr auto vdrop = []{
2928
std::array<Dim, ssize(v)-n> r;
3029
for (int i=0; i<int(r.size()); ++i) { r[i] = v[n+i]; }
3130
return r;
@@ -314,8 +313,7 @@ struct filterdims<prev, I0, I ...>
314313
constexpr static int dst = stretch ? (ssize(prev) - (0 + ... + beatable<I>.src)) : beatable<I0>.dst;
315314
constexpr static int src = stretch ? (ssize(prev) - (0 + ... + beatable<I>.src)) : beatable<I0>.src;
316315
constexpr static auto next = filterdims<vdrop<prev, src>, I ...>::dimv;
317-
constexpr static auto dimv = []
318-
{
316+
constexpr static auto dimv = []{
319317
std::array<Dim, dst+ssize(next)> r;
320318
for (int i=0; i<dst; ++i) { r[i] = prev[i]; }
321319
for (int i=0; i<ssize(next); ++i) { r[dst+i] = next[i]; }
@@ -328,8 +326,7 @@ struct filterdims<prev, I0, I ...>
328326
{
329327
constexpr static int src = beatable<I0>.src;
330328
constexpr static auto next = filterdims<vdrop<prev, src>, I ...>::dimv;
331-
constexpr static auto dimv = []
332-
{
329+
constexpr static auto dimv = []{
333330
std::array<Dim, 1+ssize(next)> r;
334331
r[0] = Dim { I0::nn, prev[0].step * I0::gets() };
335332
for (int i=0; i<ssize(next); ++i) { r[1+i] = next[i]; }
@@ -373,25 +370,13 @@ struct ViewSmall
373370
consteval static dim_t size() { return std::apply([](auto ... i) { return (i.len * ... * 1); }, dimv); }
374371

375372
P cp;
373+
constexpr ViewSmall const & view() const { return *this; }
374+
constexpr P data() const { return cp; }
375+
constexpr explicit ViewSmall(P cp_): cp(cp_) {}
376376
// exclude all T and sub constructors by making T & sub noarg
377377
constexpr static bool have_braces = std::is_reference_v<decltype(*cp)>;
378378
using T = std::conditional_t<have_braces, std::remove_reference_t<decltype(*cp)>, noarg>;
379379
using sub = typename nested_arg<T, Dimv>::sub;
380-
381-
constexpr ViewSmall const & view() const { return *this; }
382-
constexpr P data() const { return cp; }
383-
384-
constexpr explicit ViewSmall(P cp_): cp(cp_) {}
385-
// cf RA_ASSIGNOPS_SELF [ra38] [ra34]
386-
ViewSmall const & operator=(ViewSmall const & x) const { start(*this) = x; return *this; }
387-
constexpr ViewSmall(ViewSmall const & s) = default;
388-
389-
template <class X> requires (!std::is_same_v<std::decay_t<X>, T>)
390-
constexpr ViewSmall const & operator=(X && x) const { start(*this) = x; return *this; }
391-
#define ASSIGNOPS(OP) \
392-
constexpr ViewSmall const & operator OP(auto && x) const { start(*this) OP x; return *this; }
393-
FOR_EACH(ASSIGNOPS, *=, +=, -=, /=)
394-
#undef ASSIGNOPS
395380
// if T isn't is_scalar [ra44]
396381
constexpr ViewSmall const &
397382
operator=(T const & t) const
@@ -412,6 +397,15 @@ struct ViewSmall
412397
{
413398
ra::iter<-1>(*this) = x; return *this;
414399
}
400+
// cf RA_ASSIGNOPS_SELF [ra38] [ra34]
401+
ViewSmall const & operator=(ViewSmall const & x) const { start(*this) = x; return *this; }
402+
constexpr ViewSmall(ViewSmall const & s) = default;
403+
template <class X> requires (!std::is_same_v<std::decay_t<X>, T>)
404+
constexpr ViewSmall const & operator=(X && x) const { start(*this) = x; return *this; }
405+
#define ASSIGNOPS(OP) \
406+
constexpr ViewSmall const & operator OP(auto && x) const { start(*this) OP x; return *this; }
407+
FOR_EACH(ASSIGNOPS, *=, +=, -=, /=)
408+
#undef ASSIGNOPS
415409

416410
template <int k>
417411
constexpr static dim_t
@@ -597,6 +591,21 @@ transpose_dims(auto const & s, auto const & src, auto & dst)
597591

598592
RA_IS_DEF(cv_viewsmall, (std::is_convertible_v<A, ViewSmall<decltype(std::declval<A>().data()), ic_t<A::dimv>>>));
599593

594+
template <class K=ic_t<0>>
595+
constexpr auto
596+
reverse(cv_viewsmall auto && a_, K k = K {})
597+
{
598+
decltype(auto) a = a_.view();
599+
using A = std::decay_t<decltype(a)>;
600+
constexpr auto rdimv = [&]{
601+
std::remove_const_t<decltype(A::dimv)> rdimv = A::dimv;
602+
RA_CHECK(inside(k, ssize(rdimv)), "Bad axis ", K::value, " for rank ", ssize(rdimv), ".");
603+
rdimv[k].step *= -1;
604+
return rdimv;
605+
}();
606+
return ViewSmall<decltype(a.cp), ic_t<rdimv>>(0==rdimv[k].len ? a.cp : a.cp + rdimv[k].step*(1-rdimv[k].len));
607+
}
608+
600609
template <int ... Iarg>
601610
constexpr auto
602611
transpose(cv_viewsmall auto && a_, ilist_t<Iarg ...>)
@@ -607,7 +616,7 @@ transpose(cv_viewsmall auto && a_, ilist_t<Iarg ...>)
607616
constexpr static auto src = A::dimv;
608617
static_assert(ra::size(src)==ra::size(s), "Bad size for transposed axes list.");
609618
constexpr static rank_t dstrank = (0==ra::size(s)) ? 0 : 1 + std::ranges::max(s);
610-
constexpr static auto dst = [&]() { std::array<Dim, dstrank> dst; transpose_dims(s, src, dst); return dst; }();
619+
constexpr static auto dst = [&]{ std::array<Dim, dstrank> dst; transpose_dims(s, src, dst); return dst; }();
611620
return ViewSmall<decltype(a.cp), ic_t<dst>>(a.data());
612621
}
613622

@@ -641,8 +650,7 @@ constexpr auto
641650
explode(cv_viewsmall auto && a)
642651
{
643652
constexpr static rank_t ru = sizeof(value_t<sup_t>)==sizeof(value_t<decltype(a)>) ? 0 : 1;
644-
constexpr static auto bdimv = [&a]()
645-
{
653+
constexpr static auto bdimv = [&a]{
646654
std::array<Dim, ra::rank_s(a)-rank_s<sup_t>()-ru> bdimv;
647655
explode_dims<sup_t, value_t<decltype(a)>>(a.dimv, bdimv);
648656
return bdimv;

test/ra-1.cc

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ int main()
222222
TEST(ply_ravel)
223223
TEST(ply_fixed)
224224
#undef TEST
225-
tr.section("reverse (ref & non ref), traverse");
225+
tr.section("big reverse (ref & non ref), traverse");
226226
{
227227
A2 A({2, 3}, { 1, 2, 3, 4, 5, 6 });
228228
A2 B({2, 3}, { 1, 2, 3, 4, 5, 6 });
@@ -243,9 +243,8 @@ int main()
243243
CheckPly<A2>(tr, "(i)", reverse(reverse(A, 0), 1), B);
244244
CheckPly<A2>(tr, "(j)", reverse(reverse(A, 0), 1), reverse(reverse(B, 0), 1));
245245
}
246-
tr.section("reverse & transpose (ref & non ref), traverse");
246+
tr.section("big reverse & transpose (ref & non ref), traverse");
247247
{
248-
using A2 = ra::Unique<int, 2>;
249248
A2 A({2, 2}, { 1, 2, 3, 4 });
250249
A2 B({2, 2}, { 1, 2, 3, 4 });
251250

@@ -264,5 +263,26 @@ int main()
264263
CheckPly<A2>(tr, "(k)", reverse(reverse(transpose(A, ilist_t<1, 0>{}), 1), 0), B);
265264
CheckPly<A2>(tr, "(l)", A, reverse(reverse(transpose(B, ilist_t<1, 0>{}), 1), 0));
266265
}
266+
tr.section("small reverse (ref & non ref), traverse");
267+
{
268+
ra::Small<int, 2, 3> A = { 1, 2, 3, 4, 5, 6 };
269+
ra::Small<int, 2, 3> B = { 1, 2, 3, 4, 5, 6 };
270+
271+
CheckPly<A2>(tr, "(a)", A, B);
272+
CheckPly<A2>(tr, "(b)", reverse(A, ra::ic<0>), B);
273+
CheckPly<A2>(tr, "(c)", A, reverse(B, ra::ic<0>));
274+
CheckPly<A2>(tr, "(d)", reverse(A, ra::ic<0>), reverse(B, ra::ic<0>));
275+
276+
CheckPly<A2>(tr, "(e)", reverse(A, ra::ic<1>), B);
277+
CheckPly<A2>(tr, "(f)", A, reverse(B, ra::ic<1>));
278+
CheckPly<A2>(tr, "(g)", reverse(A, ra::ic<1>), reverse(B, ra::ic<1>));
279+
280+
// When BOTH steps are negative, B is still compact and this can be reduced to a single loop.
281+
// TODO Enforce that the loop is linearized over both dimensions.
282+
283+
CheckPly<A2>(tr, "(h)", A, reverse(reverse(B, ra::ic<0>), ra::ic<1>));
284+
CheckPly<A2>(tr, "(i)", reverse(reverse(A, ra::ic<0>), ra::ic<1>), B);
285+
CheckPly<A2>(tr, "(j)", reverse(reverse(A, ra::ic<0>), ra::ic<1>), reverse(reverse(B, ra::ic<0>), ra::ic<1>));
286+
}
267287
return tr.summary();
268288
}

test/small-1.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,7 @@ int main()
466466
tr.test_eq(a, 1+ra::Small<int, 3, 2> {{0, 1}, {2, 3}, {4, 5}});
467467
}
468468
tr.section("ViewSmall as iota<w>");
469+
// in order to replace Ptr<>, we must support Len both in P and in Dimv.
469470
{
470471
constexpr ra::ViewSmall<ra::Seq<ra::dim_t>, ra::ic_t<std::array {ra::Dim {ra::UNB, 1}}>>
471472
i0(ra::Seq<ra::dim_t> {0});

test/view-ops.cc

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,30 +19,40 @@ template <class A>
1919
void CheckReverse(TestRecorder & tr, A && a)
2020
{
2121
std::iota(a.begin(), a.end(), 1);
22-
cout << "a: " << a << endl;
23-
auto b0 = reverse(a, 0);
24-
auto c0 = a(ra::iota(ra::len, ra::len-1, -1));
22+
auto bd = reverse(a);
23+
auto b0 = reverse(a, ra::ic<0>);
2524
double check0[24] = { 17, 18, 19, 20, 21, 22, 23, 24,
2625
9, 10, 11, 12, 13, 14, 15, 16,
2726
1, 2, 3, 4, 5, 6, 7, 8 };
2827
tr.test(std::ranges::equal(check0, check0+24, b0.begin(), b0.end()));
29-
tr.test_eq(b0, c0);
28+
tr.test(std::ranges::equal(check0, check0+24, bd.begin(), bd.end()));
29+
// FIXME ViewSmall doesn't support these subscripts
30+
if constexpr (ra::ANY==size_s(a)) {
31+
auto c0 = a(ra::iota(ra::len, ra::len-1, -1));
32+
tr.test_eq(b0, c0);
33+
}
3034

31-
auto b1 = reverse(a, 1);
32-
auto c1 = a(ra::dots<1>, ra::iota(ra::len, ra::len-1, -1));
35+
auto b1 = reverse(a, ra::ic<1>);
3336
double check1[24] = { 5, 6, 7, 8, 1, 2, 3, 4,
3437
13, 14, 15, 16, 9, 10, 11, 12,
3538
21, 22, 23, 24, 17, 18, 19, 20 };
3639
tr.test(std::ranges::equal(check1, check1+24, b1.begin(), b1.end()));
37-
tr.test_eq(b1, c1);
40+
// FIXME ViewSmall doesn't support these subscripts
41+
if constexpr (ra::ANY==size_s(a)) {
42+
auto c1 = a(ra::dots<1>, ra::iota(ra::len, ra::len-1, -1));
43+
tr.test_eq(b1, c1);
44+
}
3845

39-
auto b2 = reverse(a, 2);
40-
auto c2 = a(ra::dots<2>, ra::iota(ra::len, ra::len-1, -1));
46+
auto b2 = reverse(a, ra::ic<2>);
4147
double check2[24] = { 4, 3, 2, 1, 8, 7, 6, 5,
4248
12, 11, 10, 9, 16, 15, 14, 13,
4349
20, 19, 18, 17, 24, 23, 22, 21 };
4450
tr.test(std::ranges::equal(check2, check2+24, b2.begin(), b2.end()));
45-
tr.test_eq(b2, c2);
51+
// FIXME ViewSmall doesn't support these subscripts
52+
if constexpr (ra::ANY==size_s(a)) {
53+
auto c2 = a(ra::dots<2>, ra::iota(ra::len, ra::len-1, -1));
54+
tr.test_eq(b2, c2);
55+
}
4656
}
4757

4858
template <class A>
@@ -75,6 +85,7 @@ int main()
7585
{
7686
CheckReverse(tr, ra::Unique<double>({ 3, 2, 4 }, ra::none));
7787
CheckReverse(tr, ra::Unique<double, 3>({ 3, 2, 4 }, ra::none));
88+
CheckReverse(tr, ra::Small<double, 3, 2, 4>(ra::none));
7889
}
7990
tr.section("transpose of 0 rank");
8091
{

0 commit comments

Comments
 (0)