kokkos / mdspan

Reference implementation of mdspan targeting C++23
Other
404 stars 69 forks source link

Lack of begin() and end() #67

Closed Sebanisu closed 3 years ago

Sebanisu commented 3 years ago

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2374r1.html

I was thinking in cpp23 you could use views::cartesian_product to make mdspan into a range. You could convert the extents to a views::iota (0...extent(0) and pass those to views::cartesian_product. The result would be a tuple of coordinates. That we could use to read the value. Maybe we could have a function convert that tuple to a reference to the value. Could maybe wrap the views::cartesian_product with views::transform to get the references if you want that.

I'm not 100% sure on the syntax. I'm not a pro programmer.

mhoemmen commented 3 years ago

Such a thing is possible. However, there are a few issues.

  1. mdspan permits nonunique layouts. What does a "range" mean for those? Indices have no such ambiguity.
  2. Optimal iteration order depends on the layout and algorithm. cartesian_product has a fixed order.
  3. "Flattening" out multiple dimensions into a single dimension loses information that compilers and developers both use to optimize loops (e.g., for parallelization, and/or for tiling to improve locality). The resulting 1-D iterator would need to track extra state, and doing so would hinder or complicate compiler optimizations. (How would the compiler prove that there are no loop-carried dependencies, for example?)
  4. Idiomatic multidimensional array loops depend on being able to access "neighbors" of the current element in different dimensions, not just on iterating through all the elements in turn.

Solving these problems would amount to writing a high-level domain-specific language for multidimensional array loops. Many of us coauthors are at least somewhat familiar with that extensive field of research. I personally would consider that out of scope for P0009. It could be an interesting set of follow-on papers, though.

Sebanisu commented 3 years ago

Thanks for the reply. Those are definitely things I didn't think of.

I guess even if we don't have something built in the user can throw a function together. I would probably make something like this when cpp23 comes around.

[[nodiscard]] constexpr auto extent_range(auto &&stdex::mdspan m, size_t i) {
  return std::views::iota(i, m.extent(i));
}
[[nodiscard]] constexpr auto cartesian_product(auto &stdex::&mdspan m, std::unsigned_integral auto &&...i) {
  // assert to check if all possible extents are used?
  return std::views::cartesian_product(
      extent_range(std::forward<decltype(m)>(m), static_cast<size_t>(i))...);
}
mhoemmen commented 3 years ago

@Sebanisu you might like to look at existing solutions, such as Kokkos' MDRangePolicy. These address many of the concerns I pointed out above.

mhoemmen commented 3 years ago

I would probably make something like this when cpp23 comes around.

FYI, we're hopeful that mdspan will make C++23, but it hasn't been voted in yet.