Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to "flip" mdspan using submdspan (or any other utility)? #352

Open
Sunday111 opened this issue Jun 30, 2024 · 4 comments
Open

How to "flip" mdspan using submdspan (or any other utility)? #352

Sunday111 opened this issue Jun 30, 2024 · 4 comments

Comments

@Sunday111
Copy link

I've been experimenting with mdspan for a few days, and one thing remains unclear to me: Is it possible to use submdspan to create an mdspan that "views" the original data in reverse order?

For example, consider a span with 9 rows and 10 columns:

constexpr int num_rows = 9;
constexpr int num_columns = 10;
auto data = std::views::iota(0, num_columns * num_rows) | std::ranges::to<std::vector>();
const exstd::mdspan<const int, exstd::extents<int, num_rows, num_columns>, exstd::layout_right> span{data.data()};

This represents the following table:

      0,   1,   2,   3,   4,   5,   6,   7,   8,   9
     10,  11,  12,  13,  14,  15,  16,  17,  18,  19
     20,  21,  22,  23,  24,  25,  26,  27,  28,  29
     30,  31,  32,  33,  34,  35,  36,  37,  38,  39
     40,  41,  42,  43,  44,  45,  46,  47,  48,  49
     50,  51,  52,  53,  54,  55,  56,  57,  58,  59
     60,  61,  62,  63,  64,  65,  66,  67,  68,  69
     70,  71,  72,  73,  74,  75,  76,  77,  78,  79
     80,  81,  82,  83,  84,  85,  86,  87,  88,  89

Is there a way to call the submdspan function to get the same data but with the rows flipped?

     80,  81,  82,  83,  84,  85,  86,  87,  88,  89
     70,  71,  72,  73,  74,  75,  76,  77,  78,  79
     60,  61,  62,  63,  64,  65,  66,  67,  68,  69
     50,  51,  52,  53,  54,  55,  56,  57,  58,  59
     40,  41,  42,  43,  44,  45,  46,  47,  48,  49
     30,  31,  32,  33,  34,  35,  36,  37,  38,  39
     20,  21,  22,  23,  24,  25,  26,  27,  28,  29
     10,  11,  12,  13,  14,  15,  16,  17,  18,  19
      0,   1,   2,   3,   4,   5,   6,   7,   8,   9

I tried to achieve this by passing a negative stride into strided_slice, but it returned incorrect results (with negative extents):

exstd::submdspan(span, exstd::strided_slice{.offset = 5, .extent = 5, .stride = -1}, exstd::full_extent)

At this point, I think I do not understand how this is supposed to be done. As far as I understand, the original intention of this proposal was to have a tool similar to indexing in NumPy, MATLAB, or Fortran, which can handle this task easily.

@crtrott
Copy link
Member

crtrott commented Sep 4, 2024

No this is not currently supported and was not brought up as a requirement in the last 9 years ...
mdspan itself can support this - though none of the standard layouts do. You could write one relatively easily though - in particular if you really are just interested in 2D. For submdspan to support this a proposal to the standard would be necessary. Basically, a negative stride right now would result in a negative extent which is invalid. One could however write a proposal to change how a negative stride is treated, more likely we would need a new slice specifier because the return type of the mdspan needs to change (since the current layouts do not support negative strides). If your "reverse layout" indeed is exactly going from the back in memory (which in 2D isn't 100% clear to me). You could go with a reverse accessor I think.

I.e. like the default accessor but just store the total offset, and then have an access function which does:

reference access(pointer_type ptr, size_t idx) const { return ptr[offset - idx]; }

@mhoemmen
Copy link
Contributor

mhoemmen commented Sep 9, 2024

As Christian explained, you can get the desired effect by defining a "reverse accessor."

As far as I understand, the original intention of this proposal was to have a tool similar to indexing in NumPy, MATLAB, or Fortran.

The front matter of the proposal explains the authors' design intent.

https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p0009r18.html

The authors considered and rejected Python-style "negative indices mean counting from the back." It complicates indexing math by adding branches and/or modular arithmetic, both of which may affect performance. One could wrap mdspan to get this effect.

@spinicist
Copy link

No this is not currently supported and was not brought up as a requirement in the last 9 years ...

Do you mean that flipping an mdspan in general has never come up, or specifically doing it via submdspan?

@burnpanck
Copy link
Contributor

The authors considered and rejected Python-style "negative indices mean counting from the back." It complicates indexing math by adding branches and/or modular arithmetic, both of which may affect performance. One could wrap mdspan to get this effect.

Indexing using a negative index is not the same as having a negative stride. Giving certain indexing values special meaning (like the python "index from the back") obviously adds a lot of potential runtime overhead. On the other hand, negative strides together with the exact same (mathematical) mapping rules of the mdspan/submdspan create no overhead during access of the span. The constructors of those types could become slightly more expensive, depending on their exact specification though.

In my experience (mostly with numpy), views with negative strides have come up as useful every once in a while. Thus, I would welcome additions to submdspan to make them compatible with negative strides. That is, if they really aren't; I actually have no experience with std::submdspan yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants