Draft: Return Padded Layouts From Dune::Std::submdspan

Summary

This merge request extends the Dune::Std::submdspan implementation so that it returns layout_left_padded or layout_right_padded for submatrix-like slices whenever the resulting mapping can be represented by a padded layout.

It builds on two independent merge requests:

  • !1639: adds the standard-shaped Dune::Std::submdspan utility.
  • !1641: adds Dune::Std::layout_left_padded and Dune::Std::layout_right_padded.

This MR combines both pieces in the way described by the padded-layout proposal P2642R0: subviews that are more specific than layout_stride, but not representable by plain layout_left or layout_right, should use a padded layout where possible.

Motivation

The important case is a contiguous submatrix of a matrix with standard dense storage.

For a row-major matrix, consecutive entries within one row are contiguous. If we take a submatrix by selecting a range of columns, consecutive entries inside each submatrix row are still contiguous. However, moving from one submatrix row to the next must use the stride of the original matrix row, not the smaller row length of the submatrix.

For a source matrix with row stride S, a row-major submatrix maps indices as:

(i,j) -> base + i*S + j

A plain layout_right mapping for the submatrix would use the submatrix extent as row stride. That is wrong when the submatrix does not include the full original row. layout_stride can represent the mapping, but it loses useful structure: the rightmost dimension is still contiguous and only the row stride is padded. layout_right_padded expresses exactly that. The layout_left_padded case is symmetric for column-major storage.

This matters for:

  • submatrices of row-major or column-major matrices,
  • slices of tensors where the relevant fast dimensions remain contiguous,
  • views into pitched or leading-dimension storage,
  • SIMD- or cache-aligned storage where row or column strides are deliberately larger than the logical extent,
  • downstream code that wants layout information more precise than layout_stride.

Dune has SIMD-related infrastructure, and preserving the fact that one dimension remains contiguous can be useful for vectorized kernels and data-layout-aware algorithms.

Behavior

The existing submdspan layout selection is extended as follows:

  • Keep returning layout_right for fixed leading indices followed by full dimensions.
  • Keep returning layout_left for the symmetric fixed trailing-index case.
  • Return layout_right_padded for row-major submatrix-like slices where the rightmost dimension remains contiguous and the row stride is inherited from the source mapping.
  • Return layout_left_padded for the corresponding column-major case.
  • Preserve the padded layout family when slicing an already padded layout, if the result is still representable by that padded layout.
  • Fall back to layout_stride for general slices, fixed middle indices, non-unit strides, or higher-rank slices whose resulting strides cannot be represented by the padded mapping.

The higher-rank case is handled conservatively. For rank greater than two, the dimension that contributes to outer strides must remain full. Otherwise the view is still regular, but no longer representable by the simple padded layout mapping and should remain layout_stride.

Examples

Row-Major Submatrix

#include <array>

#include <dune/common/std/mdspan.hh>
#include <dune/common/std/submdspan.hh>

std::array<double, 4*5> data{};
Dune::Std::mdspan matrix(data.data(), 4, 5);

// Rows [1,3), columns [1,4).
auto block = Dune::Std::submdspan(
  matrix,
  std::pair{1, 3},
  std::pair{1, 4});

// The view keeps contiguous columns, but the row stride is still 5.
static_assert(std::is_same_v<
  typename decltype(block)::layout_type,
  Dune::Std::layout_right_padded<5>>);

Column-Major Submatrix

#include <array>

#include <dune/common/std/layout_left.hh>
#include <dune/common/std/mdspan.hh>
#include <dune/common/std/submdspan.hh>

using Extents = Dune::Std::extents<int, 4, 5>;
using Mapping = Dune::Std::layout_left::mapping<Extents>;

std::array<double, 4*5> data{};
Dune::Std::mdspan<double, Extents, Dune::Std::layout_left> matrix(data.data(), Mapping{});

auto block = Dune::Std::submdspan(
  matrix,
  std::pair{1, 3},
  std::pair{1, 4});

// The first dimension remains contiguous, but the column stride is inherited.
static_assert(std::is_same_v<
  typename decltype(block)::layout_type,
  Dune::Std::layout_left_padded<4>>);

Slicing An Already Padded Layout

#include <vector>

#include <dune/common/std/extents.hh>
#include <dune/common/std/layout_right_padded.hh>
#include <dune/common/std/mdspan.hh>
#include <dune/common/std/submdspan.hh>

using Extents = Dune::Std::dextents<int, 2>;
using Layout = Dune::Std::layout_right_padded<>;
using Mapping = Layout::mapping<Extents>;

Mapping mapping(Extents{4, 5}, 8); // runtime row stride
std::vector<double> data(mapping.required_span_size());
Dune::Std::mdspan<double, Extents, Layout> matrix(data.data(), mapping);

auto block = Dune::Std::submdspan(
  matrix,
  std::pair{1, 3},
  std::pair{1, 4});

static_assert(std::is_same_v<
  typename decltype(block)::layout_type,
  Dune::Std::layout_right_padded<>>);

Tensor Slice

For tensors, padded layouts are returned only when the relevant fast dimensions remain representable by the padded mapping.

std::array<double, 2*4*5> data{};
Dune::Std::mdspan tensor(data.data(), 2, 4, 5);

// Keep leading dimension and the middle dimension full, slice the fastest one.
auto view = Dune::Std::submdspan(
  tensor,
  Dune::Std::full_extent,
  Dune::Std::full_extent,
  std::pair{1, 4});

static_assert(std::is_same_v<
  typename decltype(view)::layout_type,
  Dune::Std::layout_right_padded<5>>);

Relation To The Base MRs

This MR is intentionally small and depends on the APIs introduced in !1639 and !1641.

  • Without !1639, there is no submdspan entry point that needs layout selection.
  • Without !1641, representable submatrix views have to fall back to layout_stride.
  • With both pieces available, this MR teaches submdspan to return the more precise padded layout when that is valid.

Implementation Notes

The layout-selection code now checks for padded-representable cases before falling back to layout_stride.

For rank two:

  • row-major contiguous submatrices can return layout_right_padded,
  • column-major contiguous submatrices can return layout_left_padded.

For rank greater than two:

  • the fast dimensions must remain contiguous,
  • dimensions contributing to outer strides must remain full,
  • otherwise the result stays layout_stride.

The implementation also preserves static padding where it can be inferred from static source extents, and keeps dynamic padding for dynamically padded source layouts.

Tests

The submdspan tests cover:

  • row-major submatrices returning layout_right_padded,
  • column-major submatrices returning layout_left_padded,
  • slicing already padded layouts while preserving the padded layout family,
  • dynamic runtime padding,
  • rank-three cases where padded layout preservation is valid,
  • fallback to layout_stride for cases that are regular but not representable as padded layouts.
Edited by Simon Praetorius

Merge request reports

Loading