31template <
class Mdspec, std::
size_t Rank>
36template <
class Mdspec, std::
size_t Rank>
56 std::size_t LhsRank, std::size_t RhsRank, std::size_t ContractedRank,
67 "contraction output extents do not match the surviving input axes");
71 if constexpr (axes_type::lhs_surviving_rank > 0)
73 for (std::size_t index = 0; index < axes.lhs_surviving.size(); ++index)
75 auto const lhs_axis = axes.lhs_surviving[index];
76 result.
m.emplace_back(lhs.extent(lhs_axis), lhs.stride(lhs_axis), output.stride(index));
79 if constexpr (axes_type::rhs_surviving_rank > 0)
81 for (std::size_t index = 0; index < axes.rhs_surviving.size(); ++index)
83 auto const rhs_axis = axes.rhs_surviving[index];
84 auto const output_axis = axes.lhs_surviving.size() + index;
85 result.
n.emplace_back(rhs.extent(rhs_axis), rhs.stride(rhs_axis), output.stride(output_axis));
88 if constexpr (ContractedRank > 0)
90 for (std::size_t index = 0; index < ContractedRank; ++index)
92 auto const lhs_axis = axes.lhs_contracted[index];
93 auto const rhs_axis = axes.rhs_contracted[index];
94 result.
k.emplace_back(lhs.extent(lhs_axis), lhs.stride(lhs_axis), rhs.stride(rhs_axis));
132namespace detail::contraction_strides
135struct GroupedDimension
138 std::array<uni20::index_type, 2>
strides{1, 1};
141template <std::
size_t Capacity>
144 if constexpr (Capacity == 0)
150 if (group.empty())
return {};
151 auto result = GroupedDimension{.extent = group[0].extent, .strides = group[0].strides};
152 if (result.extent <= 1) result.strides = {1, 1};
157[[nodiscard]]
inline auto grouped_dimension(extent_strides<2>
const& dimension) -> GroupedDimension
159 auto result = GroupedDimension{.extent = dimension.extent, .strides = dimension.strides};
160 if (result.extent <= 1) result.strides = {1, 1};
164[[nodiscard]]
inline bool projection_is_directly_strided(ContractionMatrixProjection
const& projection)
noexcept
173 for (std::size_t axis = 0; axis < 2; ++axis)
175 if (projection.extents[axis] < 0 || projection.strides[axis] <= 0)
return false;
177 return projection.strides[0] == 1 || projection.strides[1] == 1;
180[[nodiscard]]
inline auto try_make_direct_gemm_plan(GroupedDimension
const& m, GroupedDimension
const& n,
181 GroupedDimension
const& k)
182 -> std::optional<DirectContractionGemmPlan>
184 DirectContractionGemmPlan plan{.output = {.extents = {m.extent, n.extent}, .strides = {m.strides[1], n.strides[1]}},
185 .lhs = {.extents = {m.extent, k.extent}, .strides = {m.strides[0], k.strides[0]}},
186 .rhs = {.extents = {k.extent, n.extent}, .strides = {k.strides[1], n.strides[0]}}};
187 if (!projection_is_directly_strided(plan.output) || !projection_is_directly_strided(plan.lhs) ||
188 !projection_is_directly_strided(plan.rhs))
193template <
class Mdspec>
consteval bool can_offset_contraction_mdspec()
195 using span_type = std::remove_cvref_t<Mdspec>;
198 using accessor_type =
typename span_type::accessor_type;
199 using offset_accessor_type =
typename accessor_type::offset_policy;
200 return std::same_as<typename offset_accessor_type::element_type, typename span_type::element_type> &&
201 std::constructible_from<offset_accessor_type, accessor_type const&>&&
202 requires(span_type &
span, span_offset_t<accessor_type> offset)
204 {
span.accessor().offset(
span.data_handle(), offset)}
205 ->std::convertible_to<
typename offset_accessor_type::data_handle_type>;
210 using descriptor_type =
typename span_type::data_descriptor_type;
211 return requires(descriptor_type
const& descriptor, std::size_t offset) {
212 { descriptor.offset_by(offset) } -> std::same_as<descriptor_type>;
224 std::size_t LhsRank, std::size_t RhsRank, std::size_t ContractedRank,
225 MutableRankedContractionMdspecLike<ContractionAxes<LhsRank, RhsRank, ContractedRank>::output_rank> OutputMdspec,
226 RankedContractionMdspecLike<LhsRank> LhsMdspec, RankedContractionMdspecLike<RhsRank> RhsMdspec>
228 RhsMdspec
const& rhs,
230 -> std::optional<DirectContractionGemmPlan>
232 if (!output.mapping().is_unique() || !lhs.mapping().is_unique() || !rhs.mapping().is_unique())
return std::nullopt;
235 if (groups.m.size() > 1 || groups.n.size() > 1 || groups.k.size() > 1)
return std::nullopt;
237 auto const m = detail::contraction_strides::grouped_dimension(groups.m);
238 auto const n = detail::contraction_strides::grouped_dimension(groups.n);
239 auto const k = detail::contraction_strides::grouped_dimension(groups.k);
241 return detail::contraction_strides::try_make_direct_gemm_plan(m, n, k);
253 std::size_t LhsRank, std::size_t RhsRank, std::size_t ContractedRank,
254 MutableRankedContractionMdspecLike<ContractionAxes<LhsRank, RhsRank, ContractedRank>::output_rank> OutputMdspec,
255 RankedContractionMdspecLike<LhsRank> LhsMdspec, RankedContractionMdspecLike<RhsRank> RhsMdspec>
257 RhsMdspec
const& rhs,
259 -> std::optional<LoopedContractionGemmPlan>
261 if (!output.mapping().is_unique() || !lhs.mapping().is_unique() || !rhs.mapping().is_unique())
return std::nullopt;
264 if (groups.k.size() > 1)
return std::nullopt;
266 bool const loop_m = groups.m.size() == 2 && groups.n.size() <= 1;
267 bool const loop_n = groups.n.size() == 2 && groups.m.size() <= 1;
268 if (loop_m == loop_n)
return std::nullopt;
270 auto const k = detail::contraction_strides::grouped_dimension(groups.k);
271 std::optional<LoopedContractionGemmPlan> result;
272 for (std::size_t loop_index = 0; loop_index < 2; ++loop_index)
274 std::size_t
const matrix_index = 1 - loop_index;
275 auto const& loop = loop_m ? groups.m[loop_index] : groups.n[loop_index];
276 if (loop.extent < 0 || loop.strides[0] < 0 || loop.strides[1] < 0)
continue;
278 auto const m = loop_m ? detail::contraction_strides::grouped_dimension(groups.m[matrix_index])
279 : detail::contraction_strides::grouped_dimension(groups.m);
280 auto const n = loop_n ? detail::contraction_strides::grouped_dimension(groups.n[matrix_index])
281 : detail::contraction_strides::grouped_dimension(groups.n);
282 auto gemm = detail::contraction_strides::try_make_direct_gemm_plan(m, n, k);
287 .output_offset_stride = loop.strides[1],
288 .lhs_offset_stride = loop_m ? loop.strides[0] : 0,
289 .rhs_offset_stride = loop_n ? loop.strides[0] : 0,
292 if (!result || candidate.loop_extent < result->loop_extent) result = std::move(candidate);
298template <uni20::MdspanLike Mdspan>
300 stdex::mdspan<typename std::remove_cvref_t<Mdspan>::element_type,
301 stdex::dextents<typename std::remove_cvref_t<Mdspan>::index_type, 2>, stdex::layout_stride,
302 typename std::remove_cvref_t<Mdspan>::accessor_type>;
304namespace detail::contraction_strides
307template <
class Mdspec,
bool = uni20::MdspanLike<Mdspec>>
struct ContractionMatrixMdspec;
309template <
class Mdspec>
struct ContractionMatrixMdspec<Mdspec, true>
314template <
class Mdspec>
struct ContractionMatrixMdspec<Mdspec, false>
316 using span_type = std::remove_cvref_t<Mdspec>;
318 stdex::layout_stride,
typename span_type::accessor_type,
319 typename span_type::data_descriptor_type>;
322template <
class Mdspec,
bool = uni20::MdspanLike<Mdspec>>
struct OffsetContractionMatrixMdspec;
324template <
class Mdspec>
struct OffsetContractionMatrixMdspec<Mdspec, true>
326 using span_type = std::remove_cvref_t<Mdspec>;
327 using accessor_type =
typename span_type::accessor_type::offset_policy;
328 using type = stdex::mdspan<typename accessor_type::element_type, stdex::dextents<typename span_type::index_type, 2>,
329 stdex::layout_stride, accessor_type>;
332template <
class Mdspec>
struct OffsetContractionMatrixMdspec<Mdspec, false>
334 using type =
typename ContractionMatrixMdspec<Mdspec, false>::type;
340template <uni20::MdspecLike Mdspec>
342 typename detail::contraction_strides::ContractionMatrixMdspec<std::remove_cvref_t<Mdspec>>::type;
345template <uni20::MdspecLike Mdspec>
347 typename detail::contraction_strides::OffsetContractionMatrixMdspec<std::remove_cvref_t<Mdspec>>::type;
350template <uni20::MdspanLike Mdspan>
355 using extents_type =
typename result_type::extents_type;
356 using mapping_type =
typename result_type::mapping_type;
357 auto const extents = extents_type{projection.extents[0], projection.extents[1]};
358 auto const mapping = mapping_type{extents, projection.strides};
359 return result_type{
span.data_handle(), mapping,
span.accessor()};
366template <uni20::MdspecLike Mdspec>
371 using extents_type =
typename result_type::extents_type;
372 using mapping_type =
typename result_type::mapping_type;
373 auto const extents = extents_type{projection.extents[0], projection.extents[1]};
374 auto const mapping = mapping_type{extents, projection.strides};
376 return result_type{
span.data_handle(), mapping,
span.accessor()};
378 return result_type{
span.data_descriptor(), mapping,
span.accessor()};
388template <uni20::MdspecLike Mdspec>
389 requires(detail::contraction_strides::can_offset_contraction_mdspec<Mdspec>())
394 CHECK(element_offset >= 0);
396 using extents_type =
typename result_type::extents_type;
397 using mapping_type =
typename result_type::mapping_type;
398 auto const extents = extents_type{projection.
extents[0], projection.
extents[1]};
399 auto const mapping = mapping_type{extents, projection.
strides};
402 using source_accessor_type =
typename std::remove_cvref_t<Mdspec>::accessor_type;
403 using offset_accessor_type =
typename source_accessor_type::offset_policy;
405 return result_type{
span.accessor().offset(
span.data_handle(), offset), mapping,
406 offset_accessor_type{
span.accessor()}};
410 auto descriptor =
span.data_descriptor().offset_by(
static_cast<std::size_t
>(element_offset));
411 return result_type{std::move(descriptor), mapping,
span.accessor()};
A fixed-capacity vector with stack storage and std::vector-like API.
Definition static_vector.hpp:24
Store a data descriptor with the mapping and accessor for an eventual mdspan.
Definition mdspec.hpp:31
A readable type implementing the mdspan observers and multidimensional subscript contract.
Definition mdspan/concepts.hpp:291
Mutable mdspec-like type with a specified static rank.
Definition mdspan/concepts.hpp:487
Mutable mdspec-like type whose mapping is always strided.
Definition mdspan/concepts.hpp:440
An mdspec-like type with a specified static rank.
Definition mdspan/concepts.hpp:454
An mdspec-like type whose mapping exposes multidimensional strides.
Definition mdspan/concepts.hpp:427
Mutable ranked mdspec usable as a contraction output.
Definition contraction_strides.hpp:37
Ranked mdspec usable by contraction stride grouping.
Definition contraction_strides.hpp:32
Normalized axis metadata for fixed-rank pairwise tensor contractions.
auto strides(S const &s)
Retrieve the strides associated with a strided mdspec-like type.
Definition mdspan/concepts.hpp:558
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
typename span_offset_type< AP >::type span_offset_t
Convenience alias for accessor_offset_type<AP>::type.
Definition mdspan/concepts.hpp:48
Mdspan concept and accessor extensions for Uni20.
Configured gateway to Uni20's mdspan implementation.
Mdspan-shaped metadata for storage whose data handle requires acquisition.
Definition linalg/async.hpp:28
auto make_contraction_matrix_mdspec(Mdspec &span, ContractionMatrixProjection const &projection) -> contraction_matrix_mdspec_t< Mdspec >
Project an mdspec into one rank-two GEMM operand without acquiring its handle.
Definition contraction_strides.hpp:367
void gemm(BackendSelector selector, async::Async< OutputTensor > &output, Alpha &&alpha, async::Async< LhsTensor > const &lhs, async::Async< RhsTensor > const &rhs, Beta &&beta, std::optional< Precision > p={})
Schedule fixed-output GEMM with an explicit backend selector.
Definition async/matrix_product.hpp:162
auto contraction_output_extents(Lhs const &lhs, Rhs const &rhs, ContractionAxes< LhsRank, RhsRank, ContractedRank > const &axes) -> stdex::dextents< uni20::index_type, ContractionAxes< LhsRank, RhsRank, ContractedRank >::output_rank >
Validate paired extents and return the canonical contraction output shape.
Definition contraction_axes.hpp:141
auto make_contraction_stride_groups(OutputMdspec const &output, LhsMdspec const &lhs, RhsMdspec const &rhs, ContractionAxes< LhsRank, RhsRank, ContractedRank > const &axes) -> ContractionStrideGroups< LhsRank, RhsRank, ContractedRank >
Build jointly merged M, N, and K stride groups without acquiring data handles.
Definition contraction_strides.hpp:59
constexpr bool contraction_axes_are_valid(ContractionAxes< LhsRank, RhsRank, ContractedRank > const &axes) noexcept
Return whether contraction axes form canonical partitions of both inputs.
Definition contraction_axes.hpp:46
stdex::mdspan< typename std::remove_cvref_t< Mdspan >::element_type, stdex::dextents< typename std::remove_cvref_t< Mdspan >::index_type, 2 >, stdex::layout_stride, typename std::remove_cvref_t< Mdspan >::accessor_type > contraction_matrix_mdspan_t
Rank-two layout_stride mdspan type retaining a resolved operand accessor.
Definition contraction_strides.hpp:302
typename detail::contraction_strides::ContractionMatrixMdspec< std::remove_cvref_t< Mdspec > >::type contraction_matrix_mdspec_t
Rank-two strided metadata type retaining an operand descriptor or immediate handle.
Definition contraction_strides.hpp:342
auto try_make_looped_contraction_gemm_plan(OutputMdspec const &output, LhsMdspec const &lhs, RhsMdspec const &rhs, ContractionAxes< LhsRank, RhsRank, ContractedRank > const &axes) -> std::optional< LoopedContractionGemmPlan >
Try to leave one residual M or N dimension around a GEMM projection.
Definition contraction_strides.hpp:256
auto try_make_direct_contraction_gemm_plan(OutputMdspec const &output, LhsMdspec const &lhs, RhsMdspec const &rhs, ContractionAxes< LhsRank, RhsRank, ContractedRank > const &axes) -> std::optional< DirectContractionGemmPlan >
Try to collapse merged contraction groups to three rank-two GEMM operands.
Definition contraction_strides.hpp:227
auto make_offset_contraction_matrix_mdspec(Mdspec &span, ContractionMatrixProjection const &projection, uni20::index_type element_offset) -> offset_contraction_matrix_mdspec_t< Mdspec >
Project a rank-two mdspec slice at one nonnegative element offset.
Definition contraction_strides.hpp:390
typename detail::contraction_strides::OffsetContractionMatrixMdspec< std::remove_cvref_t< Mdspec > >::type offset_contraction_matrix_mdspec_t
Rank-two strided metadata type whose storage origin may be advanced.
Definition contraction_strides.hpp:347
auto make_contraction_matrix_mdspan(Mdspan &span, ContractionMatrixProjection const &projection) -> contraction_matrix_mdspan_t< Mdspan >
Project a resolved mdspan into one rank-two GEMM operand without changing storage.
Definition contraction_strides.hpp:351
std::ptrdiff_t index_type
Definition types.hpp:19
constexpr bool tensor_extents_equal(LhsExtents const &lhs, RhsExtents const &rhs) noexcept
Compare two tensor extent objects by rank and per-axis extent.
Definition tensor/output.hpp:31
std::size_t span
Definition presentation.cpp:2017
Defines static_vector, a fixed-capacity, stack-allocated vector with a std::vector-like API.
Stride utilities for mdspan-like tensors.
Structure to represent a common extent and an array of strides.
Definition strides.hpp:28
Canonical contracted and surviving axes for two fixed-rank operands.
Definition contraction_axes.hpp:26
static constexpr std::size_t lhs_surviving_rank
Definition contraction_axes.hpp:33
static constexpr std::size_t rhs_surviving_rank
Definition contraction_axes.hpp:34
static constexpr std::size_t contracted_rank
Definition contraction_axes.hpp:32
Extents and strides for one rank-two projection of a contraction operand.
Definition contraction_strides.hpp:106
std::array< uni20::index_type, 2 > strides
Definition contraction_strides.hpp:108
std::array< uni20::index_type, 2 > extents
Definition contraction_strides.hpp:107
M, N, and K stride groups for a normalized pairwise contraction.
Definition contraction_strides.hpp:46
static_vector< extent_strides< 2 >, axes_type::lhs_surviving_rank > m
Definition contraction_strides.hpp:49
static_vector< extent_strides< 2 >, axes_type::rhs_surviving_rank > n
Definition contraction_strides.hpp:50
static_vector< extent_strides< 2 >, axes_type::contracted_rank > k
Definition contraction_strides.hpp:51
Handle-independent projection of a contraction to one GEMM.
Definition contraction_strides.hpp:113
ContractionMatrixProjection rhs
Definition contraction_strides.hpp:116
ContractionMatrixProjection output
Definition contraction_strides.hpp:114
ContractionMatrixProjection lhs
Definition contraction_strides.hpp:115
One residual M or N loop around a rank-two GEMM projection.
Definition contraction_strides.hpp:124
uni20::index_type output_offset_stride
Definition contraction_strides.hpp:126
DirectContractionGemmPlan gemm
Definition contraction_strides.hpp:129
uni20::index_type rhs_offset_stride
Definition contraction_strides.hpp:128
uni20::index_type lhs_offset_stride
Definition contraction_strides.hpp:127
uni20::index_type loop_extent
Definition contraction_strides.hpp:125
#define CHECK(cond,...)
Definition trace.hpp:299