Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
mdspan_matrix.hpp
Go to the documentation of this file.
1#pragma once
2
14
15#include <optional>
16#include <type_traits>
17#include <utility>
18
19namespace uni20::linalg::blas
20{
21
24{
25 blas_int extent0 = 0;
26 blas_int extent1 = 0;
28 blas_int nonunit_stride = 0;
30 bool needs_conjugation = false;
31};
32
34template <class Scalar, class Handle> struct MdspanMatrixStage
35{
36 Handle data{};
37 blas_int extent0 = 0;
38 blas_int extent1 = 0;
40 blas_int nonunit_stride = 0;
42 bool needs_conjugation = false;
43};
44
45namespace detail
46{
47template <class Span, class = void> struct SpanData
48{
49 using type = typename std::remove_cvref_t<Span>::data_handle_type;
50
51 [[nodiscard]] static constexpr auto get(Span const& span) -> type { return span.data_handle(); }
52};
53
54template <class Span> struct SpanData<Span, std::void_t<typename std::remove_cvref_t<Span>::data_descriptor_type>>
55{
56 using type = typename std::remove_cvref_t<Span>::data_descriptor_type;
57
58 [[nodiscard]] static constexpr auto get(Span const& span) -> type { return span.data_descriptor(); }
59};
60
61template <class Span> using span_data_t = typename SpanData<Span>::type;
62
63template <class Span> [[nodiscard]] constexpr auto span_data(Span const& span) -> span_data_t<Span>
64{
65 return SpanData<Span>::get(span);
66}
67
68inline blas_int minimum_leading_dimension(blas_int rows) { return rows > 1 ? rows : 1; }
69
70inline std::optional<blas_int> normalized_nonunit_stride(blas_int nonunit_stride, blas_int provider_rows,
71 blas_int provider_cols)
72{
73 blas_int const minimum = minimum_leading_dimension(provider_rows);
74 if (nonunit_stride >= minimum)
75 {
76 return nonunit_stride;
77 }
78
79 // If there are no provider rows or at most one provider column, the stride
80 // between columns does not address two logical elements. Choose the
81 // BLAS-compatible representative.
82 if (provider_rows == 0 || provider_cols <= 1)
83 {
84 return minimum;
85 }
86
87 return std::nullopt;
88}
89
90template <class Mdspan>
91concept lapack_writable_mdspan =
95} // namespace detail
96
98template <uni20::RankedStridedMdspecLike<2> Mdspan>
99auto try_mdspan_matrix_metadata(Mdspan const& span) -> std::optional<MdspanMatrixMetadata>
100{
101 auto const& mapping = span.mapping();
102 if (!mapping.is_unique())
103 {
104 return std::nullopt;
105 }
106
107 auto const extent0 = uni20::blas::try_blas_int(span.extent(0));
108 auto const extent1 = uni20::blas::try_blas_int(span.extent(1));
110 {
111 return std::nullopt;
112 }
113
114 // Empty and singleton axes do not observe their stride. Canonicalize them
115 // before checking the provider integer range or selecting a unit-stride axis.
116 blas_int stride0 = 1;
117 if (extent0 > 1)
118 {
119 stride0 = uni20::blas::try_blas_int(mapping.stride(0));
120 if (!uni20::blas::is_valid_blas_int(stride0)) return std::nullopt;
121 }
122 blas_int stride1 = 1;
123 if (extent1 > 1)
124 {
125 stride1 = uni20::blas::try_blas_int(mapping.stride(1));
126 if (!uni20::blas::is_valid_blas_int(stride1)) return std::nullopt;
127 }
128
129 int unit_stride_axis = -1;
130 blas_int nonunit_stride = 0;
131 blas_int provider_rows = 0;
132 blas_int provider_cols = 0;
133
134 // Prefer a genuinely unit-stride non-singleton axis. This preserves the
135 // natural provider orientation before using a singleton as the unit axis.
136 if (extent0 > 1 && stride0 == 1)
137 {
138 unit_stride_axis = 0;
139 nonunit_stride = stride1;
140 provider_rows = extent0;
141 provider_cols = extent1;
142 }
143 else if (extent1 > 1 && stride1 == 1)
144 {
145 unit_stride_axis = 1;
146 nonunit_stride = stride0;
147 provider_rows = extent1;
148 provider_cols = extent0;
149 }
150 else if (extent0 <= 1)
151 {
152 unit_stride_axis = 0;
153 nonunit_stride = stride1;
154 provider_rows = extent0;
155 provider_cols = extent1;
156 }
157 else if (extent1 <= 1)
158 {
159 unit_stride_axis = 1;
160 nonunit_stride = stride0;
161 provider_rows = extent1;
162 provider_cols = extent0;
163 }
164 else
165 {
166 return std::nullopt;
167 }
168
169 auto const normalized_stride = detail::normalized_nonunit_stride(nonunit_stride, provider_rows, provider_cols);
170 if (!normalized_stride)
171 {
172 return std::nullopt;
173 }
174
175 return MdspanMatrixMetadata{.extent0 = extent0,
176 .extent1 = extent1,
177 .nonunit_stride = *normalized_stride,
178 .unit_stride_axis = unit_stride_axis,
179 .needs_conjugation = mdspan_needs_conjugation_v<Mdspan>};
180}
181
182namespace detail
183{
185template <uni20::RankedStridedMdspecLike<2> Mdspan>
186auto make_mdspan_matrix_stage(Mdspan const& span, MdspanMatrixMetadata const& metadata)
187 -> MdspanMatrixStage<std::remove_cv_t<typename Mdspan::element_type>, detail::span_data_t<Mdspan>>
188{
189 using scalar_type = std::remove_cv_t<typename Mdspan::element_type>;
190 using handle_type = detail::span_data_t<Mdspan>;
191 return MdspanMatrixStage<scalar_type, handle_type>{.data = detail::span_data(span),
192 .extent0 = metadata.extent0,
193 .extent1 = metadata.extent1,
194 .nonunit_stride = metadata.nonunit_stride,
195 .unit_stride_axis = metadata.unit_stride_axis,
196 .needs_conjugation = metadata.needs_conjugation};
197}
198} // namespace detail
199
201template <uni20::RankedStridedMdspecLike<2> Mdspan>
202auto try_mdspan_matrix_stage(Mdspan const& span)
203 -> std::optional<MdspanMatrixStage<std::remove_cv_t<typename Mdspan::element_type>, detail::span_data_t<Mdspan>>>
204{
205 auto metadata = try_mdspan_matrix_metadata(span);
206 if (!metadata) return std::nullopt;
207 return detail::make_mdspan_matrix_stage(span, *metadata);
208}
209
215
217template <class Scalar, class Handle>
222
224template <class Scalar, class Handle>
227{
228 if (stage.unit_stride_axis == 0)
229 {
230 return {
231 .data = stage.data, .rows = stage.extent0, .cols = stage.extent1, .leading_dimension = stage.nonunit_stride};
232 }
233 return {.data = stage.data, .rows = stage.extent1, .cols = stage.extent0, .leading_dimension = stage.nonunit_stride};
234}
235
237template <class Scalar, class Handle>
240{
241 MatrixTransform transform = storage_transform(stage);
242 if (stage.needs_conjugation)
243 {
244 transform = compose(MatrixTransform::conjugate, transform);
245 }
246
247 auto writable = blas_writable_matrix(stage);
248 return {.data = writable.data,
249 .rows = writable.rows,
250 .cols = writable.cols,
251 .leading_dimension = writable.leading_dimension,
252 .transform = transform};
253}
254
256template <class Mdspan>
257 requires detail::blas_writable_mdspan<Mdspan, 2>
258auto try_blas_writable_matrix(Mdspan const& span) -> std::optional<
260{
261 auto stage = try_mdspan_matrix_stage(span);
262 if (!stage)
263 {
264 return std::nullopt;
265 }
266 return blas_writable_matrix(*stage);
267}
268
270template <class Mdspan>
271 requires detail::blas_readable_mdspan<Mdspan, 2>
272auto try_blas_readable_matrix(Mdspan const& span) -> std::optional<
274{
275 auto stage = try_mdspan_matrix_stage(span);
276 if (!stage)
277 {
278 return std::nullopt;
279 }
280 return blas_readable_matrix(*stage);
281}
282
284template <detail::lapack_writable_mdspan Mdspan>
285auto try_lapack_writable_matrix(Mdspan const& span) -> std::optional<
287{
288 auto stage = try_mdspan_matrix_stage(span);
289 if (!stage || stage->needs_conjugation)
290 {
291 return std::nullopt;
292 }
293 // A 1 x N matrix with unit stride between columns is both row- and
294 // column-major. Generic BLAS staging prefers its non-singleton axis, but
295 // LAPACK may use the equivalent logical column-major representation.
296 if (stage->unit_stride_axis != 0)
297 {
298 if (stage->extent0 > 1) return std::nullopt;
299 stage->unit_stride_axis = 0;
300 stage->nonunit_stride = detail::minimum_leading_dimension(stage->extent0);
301 }
302 return blas_writable_matrix(*stage);
303}
304
305} // namespace uni20::linalg::blas
Safe conversion helpers for the configured signed BLAS integer ABI.
Provider-ready BLAS matrix operands and transform helpers.
An mdspan-like type whose accessor is stdex::default_accessor.
Definition mdspan/concepts.hpp:501
Concept for scalar types with a configured dense LAPACK backend.
Definition scalar_concepts.hpp:147
A mutable strided mdspan-like type with a specified static rank.
Definition mdspan/concepts.hpp:532
Direct BLAS accessor eligibility for ranked mdspan operands.
Definition qnum.hpp:403
int rows(std::FILE *stream)
Return the terminal row count associated with a C stream.
Definition terminal.cpp:482
constexpr blas_int try_blas_int(Value value) noexcept
Convert a non-negative integer to blas_int, or return the negative invalid sentinel.
Definition blas_int.hpp:28
constexpr bool is_valid_blas_int(blas_int value) noexcept
Return whether a non-throwing BLAS integer conversion succeeded.
Definition blas_int.hpp:25
Definition blas.hpp:18
constexpr MatrixTransform storage_transform(MdspanMatrixMetadata const &metadata)
Transform from the provider matrix shape to the logical mdspan shape.
Definition mdspan_matrix.hpp:211
MatrixTransform
Logical matrix transform independent of a provider-specific opcode, although it happens to coincide w...
Definition blas_matrix.hpp:23
constexpr auto blas_writable_matrix(MdspanMatrixStage< Scalar, Handle > const &stage) -> BlasWritableMatrix< Scalar, Handle >
Return the provider-ready writable operand for a staged mdspan matrix.
Definition mdspan_matrix.hpp:225
auto try_mdspan_matrix_metadata(Mdspan const &span) -> std::optional< MdspanMatrixMetadata >
Inspect matrix layout and accessor semantics without resolving a data handle.
Definition mdspan_matrix.hpp:99
auto try_blas_writable_matrix(Mdspan const &span) -> std::optional< BlasWritableMatrix< std::remove_cv_t< typename Mdspan::element_type >, typename Mdspan::data_handle_type > >
Try to lower a mutable mdspan directly to a writable provider operand.
Definition mdspan_matrix.hpp:258
auto try_mdspan_matrix_stage(Mdspan const &span) -> std::optional< MdspanMatrixStage< std::remove_cv_t< typename Mdspan::element_type >, detail::span_data_t< Mdspan > > >
Build a matrix staging descriptor when direct provider lowering is possible.
Definition mdspan_matrix.hpp:202
constexpr auto blas_readable_matrix(MdspanMatrixStage< Scalar, Handle > const &stage) -> BlasReadableMatrix< Scalar, Handle >
Return the provider-ready readable operand for a staged mdspan matrix.
Definition mdspan_matrix.hpp:238
auto try_blas_readable_matrix(Mdspan const &span) -> std::optional< BlasReadableMatrix< std::remove_cv_t< typename Mdspan::element_type >, typename Mdspan::data_handle_type > >
Try to lower an mdspan directly to a readable provider operand.
Definition mdspan_matrix.hpp:272
auto try_lapack_writable_matrix(Mdspan const &span) -> std::optional< BlasWritableMatrix< std::remove_cv_t< typename Mdspan::element_type >, typename Mdspan::data_handle_type > >
Try to lower an mdspan to the strict column-major shape expected by LAPACK.
Definition mdspan_matrix.hpp:285
constexpr MatrixTransform compose(MatrixTransform outer, MatrixTransform inner)
Compose two matrix transforms as outer(inner(A)).
Definition blas_matrix.hpp:58
std::size_t span
Definition presentation.cpp:2017
Readable matrix shape plus transform as seen by a BLAS provider.
Definition blas_matrix.hpp:130
Writable matrix shape as seen by a BLAS/LAPACK provider.
Definition blas_matrix.hpp:119
Handle data
Definition blas_matrix.hpp:120
Handle-independent matrix metadata used for BLAS eligibility checks.
Definition mdspan_matrix.hpp:24
bool needs_conjugation
Definition mdspan_matrix.hpp:30
blas_int extent0
Definition mdspan_matrix.hpp:25
int unit_stride_axis
Definition mdspan_matrix.hpp:29
blas_int nonunit_stride
Mdspan stride orthogonal to the unit-stride axis.
Definition mdspan_matrix.hpp:28
blas_int extent1
Definition mdspan_matrix.hpp:26
Logical mdspan matrix layout before provider-specific BLAS lowering.
Definition mdspan_matrix.hpp:35
bool needs_conjugation
Definition mdspan_matrix.hpp:42
blas_int nonunit_stride
Mdspan stride orthogonal to the unit-stride axis.
Definition mdspan_matrix.hpp:40
blas_int extent1
Definition mdspan_matrix.hpp:38
int unit_stride_axis
Definition mdspan_matrix.hpp:41
blas_int extent0
Definition mdspan_matrix.hpp:37
Handle data
Definition mdspan_matrix.hpp:36
Trait to extract the scalar type from a type T.
Definition scalar_traits.hpp:93