Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
linalg/backends/cpu/transform.hpp
Go to the documentation of this file.
1#pragma once
2
16
17#include <array>
18#include <concepts>
19#include <cstddef>
20#include <functional>
21#include <tuple>
22#include <type_traits>
23#include <utility>
24
25namespace uni20::linalg
26{
27namespace detail
28{
29
30template <class Mdspan> consteval bool transform_value_is_readable()
31{
32 using span_type = std::remove_cvref_t<Mdspan>;
33 return requires(typename span_type::reference element) { static_cast<typename span_type::value_type>(element); };
34}
35
36template <class OutputMdspan, class Function, class... InputMdspans> consteval bool overwrite_transform_is_supported()
37{
38 using output_type = std::remove_cvref_t<OutputMdspan>;
41 !((output_type::rank() == std::remove_cvref_t<InputMdspans>::rank()) && ...))
42 {
43 return false;
44 }
45 else
46 {
47 return (transform_value_is_readable<InputMdspans>() && ...) &&
48 std::invocable<Function const&, typename std::remove_cvref_t<InputMdspans>::value_type...>&&
49 requires(typename output_type::reference output, Function const& function)
50 {
51 output = std::invoke(function, std::declval<typename std::remove_cvref_t<InputMdspans>::value_type>()...);
52 };
53 }
54}
55
56template <class OutputMdspan, class Function, class... InputMdspans> consteval bool update_transform_is_supported()
57{
58 using output_type = std::remove_cvref_t<OutputMdspan>;
61 !((output_type::rank() == std::remove_cvref_t<InputMdspans>::rank()) && ...))
62 {
63 return false;
64 }
65 else
66 {
67 return transform_value_is_readable<OutputMdspan>() && (transform_value_is_readable<InputMdspans>() && ...) &&
68 std::invocable<Function const&, typename output_type::value_type,
69 typename std::remove_cvref_t<InputMdspans>::value_type...>&&
70 requires(typename output_type::reference output, Function const& function)
71 {
72 output = std::invoke(function, std::declval<typename output_type::value_type>(),
73 std::declval<typename std::remove_cvref_t<InputMdspans>::value_type>()...);
74 };
75 }
76}
77
78template <class OutputMdspan, class... InputMdspans>
79void check_transform_extents(OutputMdspan const& output, InputMdspans const&... inputs)
80{
81 if constexpr (sizeof...(InputMdspans) > 0)
82 {
83 constexpr std::size_t rank = std::remove_cvref_t<OutputMdspan>::rank();
84 if constexpr (rank > 0)
85 {
86 auto check_input = [&](auto const& input) {
87 for (std::size_t axis = 0; axis < rank; ++axis)
88 CHECK_EQUAL(output.extent(axis), input.extent(axis));
89 };
90 (check_input(inputs), ...);
91 }
92 }
93}
94
95template <class Mdspan, class Index, std::size_t... Axis>
96decltype(auto) transform_element(Mdspan&& span, Index const& index, std::index_sequence<Axis...>)
97{
98 using span_type = std::remove_cvref_t<Mdspan>;
99 using index_type = typename span_type::index_type;
100 return std::forward<Mdspan>(span)[static_cast<index_type>(index[Axis])...];
101}
102
103template <bool ReadsOutput, class Operation, class OutputMdspan, class Index, class... InputMdspans>
104void apply_transform_element(Operation const& operation, OutputMdspan& output, Index const& index,
105 InputMdspans&... inputs)
106{
107 constexpr auto axes = std::make_index_sequence<std::remove_cvref_t<OutputMdspan>::rank()>{};
108 auto&& output_element = transform_element(output, index, axes);
109 if constexpr (ReadsOutput)
110 {
111 using output_value = typename std::remove_cvref_t<OutputMdspan>::value_type;
112 output_element = std::invoke(
113 operation.function, static_cast<output_value>(output_element),
114 static_cast<typename std::remove_cvref_t<InputMdspans>::value_type>(transform_element(inputs, index, axes))...);
115 }
116 else
117 {
118 output_element = std::invoke(
119 operation.function,
120 static_cast<typename std::remove_cvref_t<InputMdspans>::value_type>(transform_element(inputs, index, axes))...);
121 }
122}
123
124template <std::size_t Axis, bool ReadsOutput, class Operation, class OutputMdspan, class Index, class... InputMdspans>
125void transform_elements(Operation const& operation, OutputMdspan& output, Index& index, InputMdspans&... inputs)
126{
127 if constexpr (Axis == std::remove_cvref_t<OutputMdspan>::rank())
128 {
129 apply_transform_element<ReadsOutput>(operation, output, index, inputs...);
130 }
131 else
132 {
133 using output_index = typename std::remove_cvref_t<OutputMdspan>::index_type;
134 for (output_index i = 0; i < static_cast<output_index>(output.extent(Axis)); ++i)
135 {
136 index[Axis] = i;
137 transform_elements<Axis + 1, ReadsOutput>(operation, output, index, inputs...);
138 }
139 }
140}
141
142template <bool ReadsOutput, class Operation, class OutputMdspan, class... InputMdspans>
143void reference_transform(Operation const& operation, OutputMdspan& output, InputMdspans&... inputs)
144{
145 using output_type = std::remove_cvref_t<OutputMdspan>;
148 {
149 if constexpr (ReadsOutput)
150 {
151 auto invoke_with_values = [&operation](auto&& output_value, auto&&... input_values) {
152 return std::invoke(operation.function, static_cast<typename output_type::value_type>(output_value),
153 static_cast<typename std::remove_cvref_t<InputMdspans>::value_type>(input_values)...);
154 };
155 cpu::detail::transform_strided<true>(output, std::cref(invoke_with_values), inputs...);
156 }
157 else
158 {
159 auto invoke_with_values = [&operation](auto&&... input_values) {
160 return std::invoke(operation.function,
161 static_cast<typename std::remove_cvref_t<InputMdspans>::value_type>(input_values)...);
162 };
163 cpu::detail::transform_strided<false>(output, std::cref(invoke_with_values), inputs...);
164 }
165 }
166 else
167 {
168 std::array<typename output_type::index_type, output_type::rank()> index{};
169 transform_elements<0, ReadsOutput>(operation, output, index, inputs...);
170 }
171}
172
173} // namespace detail
174
176template <class Function, uni20::MutableMdspecLike OutputMdspan, uni20::MdspecLike... InputMdspans>
178consteval auto kernel_accepts_types(CpuReferenceBackend const&, transform_op<Function> const&, OutputMdspan&,
179 InputMdspans&...)
180{
182 if constexpr (detail::overwrite_transform_is_supported<output_span, Function,
184 return kernel_types_yes;
185 else
186 return kernel_types_no;
187}
188
190template <class Function, uni20::MutableMdspecLike OutputMdspan, uni20::MdspecLike... InputMdspans>
192KernelAttempt try_kernel(CpuReferenceBackend, transform_op<Function> const& operation, OutputMdspan& output,
193 InputMdspans&... inputs)
194{
195 auto output_access = acquire_host_write_access_sync(output);
196 auto input_accesses = std::tuple{acquire_host_read_access_sync(inputs)...};
197 return std::apply(
198 [&](auto&... input_access) {
199 auto output_span = output_access.mdspan();
200 detail::check_transform_extents(output_span, input_access.mdspan()...);
201 detail::reference_transform<false>(operation, output_span, input_access.mdspan()...);
203 },
204 input_accesses);
205}
206
208template <class Function, uni20::MutableMdspecLike OutputMdspan, uni20::MdspecLike... InputMdspans>
210consteval auto kernel_accepts_types(CpuReferenceBackend const&, transform_inplace_op<Function> const&, OutputMdspan&,
211 InputMdspans&...)
212{
214 if constexpr (detail::update_transform_is_supported<output_span, Function,
216 return kernel_types_yes;
217 else
218 return kernel_types_no;
219}
220
222template <class Function, uni20::MutableMdspecLike OutputMdspan, uni20::MdspecLike... InputMdspans>
224KernelAttempt try_kernel(CpuReferenceBackend, transform_inplace_op<Function> const& operation, OutputMdspan& output,
225 InputMdspans&... inputs)
226{
227 auto output_access = acquire_host_write_access_sync(output);
228 auto input_accesses = std::tuple{acquire_host_read_access_sync(inputs)...};
229 return std::apply(
230 [&](auto&... input_access) {
231 auto output_span = output_access.mdspan();
232 detail::check_transform_extents(output_span, input_access.mdspan()...);
233 detail::reference_transform<true>(operation, output_span, input_access.mdspan()...);
235 },
236 input_accesses);
237}
238
239} // namespace uni20::linalg
RAII leases that resolve device descriptors and tensor views to mdspans.
Mdspec metadata supporting host read acquisition.
Definition access.hpp:688
Mutable mdspec metadata supporting host write acquisition.
Definition access.hpp:694
A readable type implementing the mdspan observers and multidimensional subscript contract.
Definition mdspan/concepts.hpp:291
Mdspan metadata whose data handle is immediate or available through a data descriptor.
Definition mdspan/concepts.hpp:304
MdspanLike types whose accessor supports indexed assignment.
Definition mdspan/concepts.hpp:387
MdspecLike types whose eventual storage supports writes.
Definition mdspan/concepts.hpp:398
Mutable mdspan-like types whose layout reports they are always strided.
Definition mdspan/concepts.hpp:421
An mdspan-like type whose mapping is always strided and exposes stride observers.
Definition mdspan/concepts.hpp:406
Operation-tag backend dispatch over tensor-view operands.
Mdspan concept and accessor extensions for Uni20.
Definition linalg/async.hpp:28
KernelAttempt try_kernel(BlasBackend, gemm_op const &, C &c, S const &alpha, A &a, B &b, S const &beta)
Pack logical host values and execute GEMM through value-preserving provider conversion.
Definition linalg/backends/blas/binary80.hpp:30
KernelAttempt
Result of one runtime kernel backend attempt.
Definition kernel_attempt.hpp:27
constexpr KernelAcceptance< KernelTypeAcceptance::no > kernel_types_no
Report that a backend rejects the argument types.
Definition dispatch_error.hpp:34
consteval auto kernel_accepts_types(BlasBackend, gemm_op const &, C &, S const &, A &, B &, S const &)
Accept host-readable native binary80 operands, including transforming accessors.
Definition linalg/backends/blas/binary80.hpp:19
constexpr KernelAcceptance< KernelTypeAcceptance::yes > kernel_types_yes
Report that a backend accepts every instance of the argument types.
Definition dispatch_error.hpp:40
std::remove_cvref_t< decltype(std::declval< detail::host_read_mdspan_lease_t< Mdspec > & >().mdspan())> host_read_mdspan_t
Read-only mdspan type resolved by host descriptor acquisition.
Definition access.hpp:679
auto acquire_host_read_access_sync(Mdspan const &mdspan)
Acquire a directly host-accessible read-only mdspan.
Definition access.hpp:616
std::remove_cvref_t< decltype(std::declval< detail::host_write_mdspan_lease_t< Mdspec > & >().mdspan())> host_write_mdspan_t
Writable mdspan type resolved by host descriptor acquisition.
Definition access.hpp:684
std::ptrdiff_t index_type
Definition types.hpp:19
auto acquire_host_write_access_sync(Mdspan &mdspan)
Acquire a directly host-accessible writable mdspan.
Definition access.hpp:626
Backend-independent operation values used with normalized kernel operands.
std::size_t span
Definition presentation.cpp:2017
CPU executor for compact strided elementwise iteration plans.
Backend value for the reference host CPU dense linalg oracle.
Definition backend_selector.hpp:55
Callable-carrying elementwise update operation.
Definition operation_tags.hpp:61
Callable-carrying elementwise overwrite operation.
Definition operation_tags.hpp:48
Concepts for tensor-level objects that resolve mdspan kernel operands.
#define CHECK_EQUAL(a, b,...)
Definition trace.hpp:309