14#include <initializer_list>
39 template <
typename Ext>
40 requires std::is_integral_v<Ext>
43 assert(s.size() == N);
44 std::copy(s.begin(), s.end(),
strides.begin());
53 template <
typename Ext,
typename Str>
54 requires std::is_integral_v<Ext> && std::is_integral_v<Str>
57 for (std::size_t i = 0; i < N; ++i)
59 strides[i] =
static_cast<std::ptrdiff_t
>(s[i]);
69 template <
typename Ext,
typename... Strides>
70 requires(std::is_integral_v<Ext> &&
sizeof...(Strides) == N)
83 if (
extent < 0 || inner.extent < 0)
return false;
84 if (
extent == 1 || inner.extent == 1)
return true;
86 auto const inner_extent =
static_cast<std::ptrdiff_t
>(inner.extent);
87 for (std::size_t i = 0; i < N; ++i)
89 auto const inner_stride = inner.strides[i];
90 if (inner_extent != 0 &&
91 ((inner_stride > 0 && inner_stride > std::numeric_limits<std::ptrdiff_t>::max() / inner_extent) ||
92 (inner_stride < 0 && inner_stride < std::numeric_limits<std::ptrdiff_t>::min() / inner_extent)))
94 if (
strides[i] != inner_stride * inner_extent)
return false;
109 if (inner.extent == 1)
115 if (inner.extent == 1)
return;
125template <std::
size_t N, std::
size_t R>
126void remove_singleton_dimensions(
static_vector<extent_strides<N>, R>& dimensions)
128 if (dimensions.empty())
return;
130 std::size_t write = 0;
131 for (std::size_t read = 0; read < dimensions.size(); ++read)
133 if (dimensions[read].extent != 1) dimensions[write++] = dimensions[read];
138 dimensions[0].extent = 1;
139 dimensions[0].strides.fill(1);
140 dimensions.resize(1);
143 dimensions.resize(write);
146template <std::
size_t N, std::
size_t R>
void sort_and_merge_left(
static_vector<extent_strides<N>, R>& out)
148 remove_singleton_dimensions(out);
149 if (
out.size() <= 1)
return;
151 std::sort(
out.begin(),
out.end(),
152 [](
auto const& lhs,
auto const& rhs) { return std::abs(lhs.strides[0]) < std::abs(rhs.strides[0]); });
154 extent_strides<N> current =
out[0];
155 std::size_t
write = 0;
156 for (std::size_t i = 1; i <
out.size(); ++i)
158 auto candidate =
out[i];
159 if (candidate.can_merge_with_inner(current))
161 candidate.merge_with_inner(current);
175template <std::
size_t N, std::
size_t R>
void sort_and_merge_right(
static_vector<extent_strides<N>, R>& out)
177 remove_singleton_dimensions(out);
178 if (
out.size() <= 1)
return;
180 std::sort(
out.begin(),
out.end(),
181 [](
auto const& lhs,
auto const& rhs) { return std::abs(lhs.strides[0]) > std::abs(rhs.strides[0]); });
183 extent_strides<N> current =
out[0];
184 std::size_t
write = 0;
185 for (std::size_t i = 1; i <
out.size(); ++i)
188 if (current.can_merge_with_inner(inner))
190 current.merge_with_inner(inner);
213template <
typename Extents, std::
size_t R>
214 requires(Extents::rank() == R)
216 std::array<std::ptrdiff_t, R>
const& Stride1,
217 std::array<std::ptrdiff_t, R>
const& Stride2)
220 for (std::size_t i = 0; i < R; ++i)
222 out.emplace_back({ext[i], {Stride1[i], Stride2[i]}});
225 detail::sort_and_merge_left(out);
238template <
typename Extents, std::
size_t R>
239 requires(Extents::rank() == R)
241 std::array<std::ptrdiff_t, R>
const& Stride1,
242 std::array<std::ptrdiff_t, R>
const& Stride2)
245 for (std::size_t i = 0; i < R; ++i)
247 out.emplace_back({ext[i], {Stride1[i], Stride2[i]}});
250 detail::sort_and_merge_right(out);
262 detail::sort_and_merge_left(out);
272 detail::sort_and_merge_right(out);
286template <Str
idedMdspanLike AType, Str
idedMdspanLike BType, Str
idedMdspanLike CType, std::
size_t N>
288 std::array<std::pair<std::size_t, std::size_t>, N>
const& contractDims, CType
const& C)
290 constexpr std::size_t MR = AType::rank() - N;
291 constexpr std::size_t NR = BType::rank() - N;
292 constexpr std::size_t KR = N;
299 std::array<bool, AType::rank()> AContracted{};
300 std::array<bool, BType::rank()> BContracted{};
301 for (std::size_t i = 0; i < N; ++i)
304 auto [ai, bi] = contractDims[i];
305 ERROR_IF(A.extent(ai) != B.extent(bi),
"Extent along tensor contraction dimension does not match", ai, bi);
306 AContracted[ai] =
true;
307 BContracted[bi] =
true;
308 Kgroup.
emplace_back(A.extent(ai), A.stride(ai), B.stride(bi));
312 for (std::size_t ai = 0; ai < AType::rank(); ++ai)
314 if (!AContracted[ai])
316 ERROR_IF(A.extent(ai) != C.extent(ci),
"Extent along uncontracted dimension does not match", ai, ci);
317 Mgroup.
emplace_back(A.extent(ai), A.stride(ai), C.stride(ci));
321 for (std::size_t bi = 0; bi < BType::rank(); ++bi)
323 if (!BContracted[bi])
325 ERROR_IF(B.extent(bi) != C.extent(ci),
"Extent along uncontracted dimension does not match", bi, ci);
326 Ngroup.
emplace_back(B.extent(bi), B.stride(bi), C.stride(ci));
335 return std::tuple{Mgroup, Ngroup, Kgroup};
A fixed-capacity vector with stack storage and std::vector-like API.
Definition static_vector.hpp:24
void emplace_back(Args &&... args)
Construct a new element in-place at the end.
Definition static_vector.hpp:242
auto extract_strides(AType const &A, BType const &B, std::array< std::pair< std::size_t, std::size_t >, N > const &contractDims, CType const &C)
Extract merged stride groups for a tensor contraction.
Definition strides.hpp:287
constexpr extent_strides(Ext e, std::array< Str, N > s)
Construct from an extent and an array of strides.
Definition strides.hpp:55
static_vector< extent_strides< 2 >, R > merge_strides_left(Extents const &ext, std::array< std::ptrdiff_t, R > const &Stride1, std::array< std::ptrdiff_t, R > const &Stride2)
Build and merge stride metadata from two stride arrays favouring column-major (left) order.
Definition strides.hpp:215
constexpr void merge_with_inner(extent_strides inner) noexcept
Merge an inner dimension into this one when merging is valid.
Definition strides.hpp:104
constexpr bool can_merge_with_inner(extent_strides inner) const noexcept
Returns true if the current (outer) dimension and the given inner dimension can be merged.
Definition strides.hpp:81
static_vector< extent_strides< 2 >, R > merge_strides_right(Extents const &ext, std::array< std::ptrdiff_t, R > const &Stride1, std::array< std::ptrdiff_t, R > const &Stride2)
Build and merge stride metadata from two stride arrays favouring row-major (right) order.
Definition strides.hpp:240
constexpr extent_strides(Ext e, std::initializer_list< std::ptrdiff_t > s)
Construct from an extent and initializer-list strides.
Definition strides.hpp:41
Configured gateway to Uni20's mdspan implementation.
WriteBuffer< T > write(Async< T > &a)
Convenience helper that forwards to Async<T>::write().
Definition async/async.hpp:545
Definition async/async.hpp:26
std::ptrdiff_t index_type
Definition types.hpp:19
Defines static_vector, a fixed-capacity, stack-allocated vector with a std::vector-like API.
Structure to represent a common extent and an array of strides.
Definition strides.hpp:28
constexpr extent_strides()=default
index_type extent
Definition strides.hpp:29
std::array< std::ptrdiff_t, N > strides
Definition strides.hpp:30
Concepts for tensor-level objects that resolve mdspan kernel operands.
#define ERROR_IF(cond,...)
Definition trace.hpp:389