kokkos / mdspan

Reference implementation of mdspan targeting C++23
Other
412 stars 68 forks source link

Shortcut for dynamic multidimensional spans of size S. #32

Closed acdemiralp closed 3 years ago

acdemiralp commented 4 years ago

Hello,

I had the use case of pairing a linear container and a (dynamic) mdspan to create a basic grid like this:

template <typename type, std::size_t size>
class regular_grid
{
public:
  // Some methods, interpolate etc.

protected:
  thrust::device_vector<type> container_;
  std::experimental::mdspan<type, size> span_; // Bummer! Requires a variadic list of ptrdiff_ts unlike what one would expect.
}

Hence I created (excuse the naming):

template<std::size_t index>
class wrapper
{
  constexpr static auto value = std::experimental::dynamic_extent;
};

template<typename type, std::size_t size, typename = std::make_index_sequence<size>>
struct expander;
template<typename type, std::size_t size, std::size_t... indices>
struct expander<type, size, std::index_sequence<indices...>>
{
  using type = std::experimental::mdspan<type, wrapper<indices>::value...>;
};

template<typename type, std::size_t size>
using dynamic_mdspan_of_rank = typename expander<type, size>::type;

which allows e.g. dynamic_mdspan_of_rank<float, 3> instead of mdspan<float, std::dynamic_extent, std::dynamic_extent, std::dynamic_extent>. The code above is based on a bunch of stackoverflow template expansion posts and the naming is based on dsharlet/array (which I was using prior to mdspan).

Note how this was necessary for a multidimensional struct specified by a type and a number of dimensions to be able to contain a mdspan. I believe this is a common use case. Perhaps you consider a more generalized version into the library.

Edit: Obviously having the regular_grid accept a type and variadic extents is also possible without all this. It however doesn't feel conventional. Perhaps I used boost/multi_array too long.

dhollman commented 4 years ago

Hi! Thanks for the feedback. This implementation is based directly on what's proposed to the C++ standard in P0009, which doesn't include such a facility. I'd be happy to co-author a short paper proposing that an alias template that performs this expansion should be added to the C++ standard, but what you're doing here is more or less the way I do this also.

That said, the code you've written above is not all that complicated, and can actually be simplified a bit (you don't need wrapper after C++14 since you can just use a variable template, for instance). Adding something to the C++ standard is a lot of work, and we have to think carefully about priorities. I agree that it's not ideal, but it's what we've got for now.

acdemiralp commented 4 years ago

I'm glad multidimensional arrays are making their way into the standard in this form.

I would be more than happy to work on a separate paper together, but wonder what if we already talked about would be sufficient in terms of content. I have several more applications to data analysis and visualization which will be developed in the next days. Perhaps these support functionality could be summed up into a paper.

A common application of mdspan to scientific data analysis and visualization will be representing grids, specifically regular, rectilinear, curvilinear, Berger-Collela grids or more generally any grid with Cartesian topology. Some other ideas which might be of generic benefit in this sense:

Here is the revised version based on your suggestions. I think this is as concise as it gets:

template<std::size_t index>
constexpr std::ptrdiff_t dynamic_extent = std::experimental::dynamic_extent;
template<typename type, std::size_t size, typename = std::make_index_sequence<size>>
struct dynamic_extent_expander;
template<typename type, std::size_t size, std::size_t... indices>
struct dynamic_extent_expander<type, size, std::index_sequence<indices...>>
{
  using type = std::experimental::mdspan<type, dynamic_extent<indices>...>;
};
template<typename type, std::size_t size>
using dynamic_mdspan_of_rank = typename dynamic_extent_expander<type, size>::type;
dhollman commented 3 years ago

Stencil operations: Apply a callback according to a stencil e.g. [[0,1,0],[1,1,1],[0,1,0]] instead of for each element.

This sounds more or less like a pretty straightforward function template to write. What am I missing?

Selection view: A discontinuous iterator to an arbitrary subspan of an mdspan.

Slice view: A discontinuous iterator to an M<N dimensional subset cut from an N dimensional span.

If you mean subspan and not iterator, then std::experimental::subspan probably does what you want for both of these, depending on how "arbitrary" you actually mean.

Actual iterators are a much more complicated topic, since they are performance-dependent on layout but still need to present a consistent correctness semantic, so we've been designing mdspan iterators separately from P0009.

Multidimensional mutexes: Allow locking a subspan of an mdspan.

This seems like separable functionality from mdspan, and sounds like the kind of thing that would be a lot of work to get into the standard for not a lot of benefit (it's not extremely hard to write something like that, I don't know how the compiler or optimizer could benefit from something like that being standardized, and I'm not sure it's of wide enough applicability to standardize).

Anyway, thanks for your feedback! Let us know if you have more questions!