Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
tensor/transform.hpp
Go to the documentation of this file.
1#pragma once
2
19
20#if UNI20_BACKEND_CUDA
22#endif
23
24#include <cstddef>
25#include <tuple>
26#include <type_traits>
27#include <utility>
28
29namespace uni20
30{
31namespace detail
32{
33
34template <class Output, class... Inputs>
35concept OverwriteTransformSpans =
36 MutableMdspanLike<Output> && (MdspanLike<Inputs> && ...) &&
37 ((std::remove_cvref_t<Output>::rank() == std::remove_cvref_t<Inputs>::rank()) && ...);
38
39template <class Output, class... Inputs>
40concept UpdateTransformSpans = MutableMdspanLike<Output> && (MdspanLike<Inputs> && ...) &&
41 ((std::remove_cvref_t<Output>::rank() == std::remove_cvref_t<Inputs>::rank()) && ...);
42
43template <class Output, class... Inputs>
44concept OverwriteTransformTensors =
45 MutableTensorView<Output> && (sizeof...(Inputs) >= 1) && (TensorView<Inputs> && ...) &&
46 ((tensor_mdspec_t<Output>::rank() == tensor_mdspec_t<Inputs>::rank()) && ...);
47
48template <class Output, class... Inputs>
49concept UpdateTransformTensors = MutableTensorView<Output> && (TensorView<Inputs> && ...) &&
50 ((tensor_mdspec_t<Output>::rank() == tensor_mdspec_t<Inputs>::rank()) && ...);
51
52template <class Reference, class... Others>
53void require_transform_extents(Reference const& reference, Others const&... others)
54{
55 if constexpr (sizeof...(Others) > 0)
56 {
57 constexpr std::size_t Rank = [] {
58 if constexpr (TensorView<Reference>)
59 return tensor_mdspec_t<Reference>::rank();
60 else
61 return std::remove_cvref_t<Reference>::rank();
62 }();
63 if constexpr (Rank > 0)
64 {
65 auto require_equal = [&](auto const& other) {
66 for (std::size_t axis = 0; axis < Rank; ++axis)
67 ERROR_IF(reference.extent(axis) != other.extent(axis),
68 "elementwise transform operands have different extents");
69 };
70 (require_equal(others), ...);
71 }
72 }
73}
74
75template <class BackendSelector, class Operation, class OutputMdspan, class... InputMdspans>
76void dispatch_transform(BackendSelector&& selector, Operation operation, OutputMdspan&& output,
77 InputMdspans&&... inputs)
78{
79 linalg::dispatch_kernel(std::forward<BackendSelector>(selector), std::move(operation),
80 std::forward<OutputMdspan>(output), std::forward<InputMdspans>(inputs)...);
81}
82
83} // namespace detail
84
89template <class BackendSelector, class OutputMdspan, class Function, class... InputMdspans>
90 requires detail::OverwriteTransformSpans<OutputMdspan, InputMdspans...>
91void assign_transform(BackendSelector&& selector, OutputMdspan&& output, Function&& function, InputMdspans&&... inputs)
92{
93 detail::require_transform_extents(output, inputs...);
94 auto operation = linalg::transform_op{std::forward<Function>(function)};
95 auto output_descriptor = std::forward<OutputMdspan>(output);
96 auto input_descriptors = std::tuple{make_const_mdspan(inputs)...};
97 std::apply(
98 [&](auto&... input_descriptor) {
99 detail::dispatch_transform(std::forward<BackendSelector>(selector), std::move(operation), output_descriptor,
100 input_descriptor...);
101 },
102 input_descriptors);
103}
104
109template <class BackendSelector, class OutputMdspan, class Function, class... InputMdspans>
110 requires detail::UpdateTransformSpans<OutputMdspan, InputMdspans...>
111void transform_inplace(BackendSelector&& selector, OutputMdspan&& output, Function&& function, InputMdspans&&... inputs)
112{
113 detail::require_transform_extents(output, inputs...);
114 auto operation = linalg::transform_inplace_op{std::forward<Function>(function)};
115 auto output_descriptor = std::forward<OutputMdspan>(output);
116 auto input_descriptors = std::tuple{make_const_mdspan(inputs)...};
117 std::apply(
118 [&](auto&... input_descriptor) {
119 detail::dispatch_transform(std::forward<BackendSelector>(selector), std::move(operation), output_descriptor,
120 input_descriptor...);
121 },
122 input_descriptors);
123}
124
127template <class BackendSelector, MutableTensorView OutputTensor, class Function>
128void assign_transform(BackendSelector&& selector, OutputTensor&& output, Function&& function)
129{
130 auto operation = linalg::transform_op{std::forward<Function>(function)};
131 auto output_descriptor = mdspec_of(output);
132 detail::dispatch_transform(std::forward<BackendSelector>(selector), std::move(operation), output_descriptor);
133}
134
136template <MutableTensorView OutputTensor, class Function>
137void assign_transform(OutputTensor&& output, Function&& function)
138{
139 auto operation = linalg::transform_op{std::forward<Function>(function)};
140 auto selector = linalg::select_backend(operation, output);
141 auto output_descriptor = mdspec_of(output);
142 detail::dispatch_transform(std::move(selector), std::move(operation), output_descriptor);
143}
144
146template <class BackendSelector, class Output, class Value>
147 requires(detail::OverwriteTransformSpans<Output> || MutableTensorView<Output>)
148void fill(BackendSelector&& selector, Output&& output, Value&& value)
149{
150 assign_transform(std::forward<BackendSelector>(selector), std::forward<Output>(output),
151 linalg::constant{std::forward<Value>(value)});
152}
153
155template <MutableTensorView Output, class Value> void fill(Output&& output, Value&& value)
156{
157 assign_transform(std::forward<Output>(output), linalg::constant{std::forward<Value>(value)});
158}
159
165template <class BackendSelector, class OutputTensor, class Function, class FirstInputTensor, class... RestInputTensors>
166 requires detail::OverwriteTransformTensors<OutputTensor, FirstInputTensor, RestInputTensors...>
167void assign_transform(BackendSelector&& selector, OutputTensor&& output, Function&& function,
168 FirstInputTensor const& first_input, RestInputTensors const&... rest_inputs)
169{
170 detail::require_transform_extents(first_input, rest_inputs...);
171 prepare_output(output, first_input.extents());
172 auto operation = linalg::transform_op{std::forward<Function>(function)};
173 auto output_descriptor = mdspec_of(output);
174 auto input_descriptors = std::tuple{mdspec_of(first_input), mdspec_of(rest_inputs)...};
175 std::apply(
176 [&](auto&... inputs) {
177 detail::dispatch_transform(std::forward<BackendSelector>(selector), std::move(operation), output_descriptor,
178 inputs...);
179 },
180 input_descriptors);
181}
182
184template <class OutputTensor, class Function, class FirstInputTensor, class... RestInputTensors>
185 requires detail::OverwriteTransformTensors<OutputTensor, FirstInputTensor, RestInputTensors...>
186void assign_transform(OutputTensor&& output, Function&& function, FirstInputTensor const& first_input,
187 RestInputTensors const&... rest_inputs)
188{
189 auto operation = linalg::transform_op{std::forward<Function>(function)};
190 auto selector = linalg::select_backend(operation, output, first_input, rest_inputs...);
191 detail::require_transform_extents(first_input, rest_inputs...);
192 prepare_output(output, first_input.extents());
193 auto output_descriptor = mdspec_of(output);
194 auto input_descriptors = std::tuple{mdspec_of(first_input), mdspec_of(rest_inputs)...};
195 std::apply(
196 [&](auto&... inputs) {
197 detail::dispatch_transform(selector, std::move(operation), output_descriptor, inputs...);
198 },
199 input_descriptors);
200}
201
206template <class BackendSelector, class OutputTensor, class Function, class... InputTensors>
207 requires detail::UpdateTransformTensors<OutputTensor, InputTensors...>
208void transform_inplace(BackendSelector&& selector, OutputTensor&& output, Function&& function,
209 InputTensors const&... inputs)
210{
211 detail::require_transform_extents(output, inputs...);
212 auto operation = linalg::transform_inplace_op{std::forward<Function>(function)};
213 auto output_descriptor = mdspec_of(output);
214 auto input_descriptors = std::tuple{mdspec_of(inputs)...};
215 std::apply(
216 [&](auto&... input_descriptors) {
217 detail::dispatch_transform(std::forward<BackendSelector>(selector), std::move(operation), output_descriptor,
218 input_descriptors...);
219 },
220 input_descriptors);
221}
222
224template <class OutputTensor, class Function, class... InputTensors>
225 requires detail::UpdateTransformTensors<OutputTensor, InputTensors...>
226void transform_inplace(OutputTensor&& output, Function&& function, InputTensors const&... inputs)
227{
228 auto operation = linalg::transform_inplace_op{std::forward<Function>(function)};
229 auto selector = linalg::select_backend(operation, output, inputs...);
230 detail::require_transform_extents(output, inputs...);
231 auto output_descriptor = mdspec_of(output);
232 auto input_descriptors = std::tuple{mdspec_of(inputs)...};
233 std::apply(
234 [&](auto&... input_descriptors) {
235 detail::dispatch_transform(selector, std::move(operation), output_descriptor, input_descriptors...);
236 },
237 input_descriptors);
238}
239
240} // namespace uni20
RAII leases that resolve device descriptors and tensor views to mdspans.
Ordered backend selector values shared by tensor storage and linalg dispatch.
locale_t value
Definition data_table.cpp:49
Operation-tag backend dispatch over tensor-view operands.
Named backend-neutral function objects for elementwise transforms.
Reference CPU backend for generic elementwise transforms.
CUDA reference backend for registered elementwise transforms.
Mdspan concept and accessor extensions for Uni20.
constexpr auto select_backend(Operation const &operation, FirstTensor const &, RestTensors const &...)
Select the default backend list for an operation on Tensor operands.
Definition backend_selector.hpp:252
void dispatch_kernel(BackendSelector &&selector, Op op, Args &&... args)
Normalize a selector and dispatch or report that every eligible backend declined.
Definition dispatch.hpp:374
Definition async/async.hpp:26
Output & prepare_output(Output &output, RequiredExtents const &required)
Prepare a mutable tensor output with the specified shape.
Definition tensor/output.hpp:104
constexpr decltype(auto) mdspec_of(Tensor &tensor) noexcept(noexcept(tensor.mdspec()))
Return a tensor's immediate or descriptor-backed multidimensional metadata.
Definition tensor/concepts.hpp:50
void fill(BackendSelector selector, async::Async< OutputTensor > &output, Value &&value)
Fill an existing async Tensor without reading its old values.
Definition linalg/async/transform.hpp:205
void transform_inplace(BackendSelector selector, async::Async< OutputTensor > &output, Function &&function, async::Async< InputTensors > const &... inputs)
Schedule a variadic elementwise update with an explicit backend selector.
Definition linalg/async/transform.hpp:258
constexpr auto make_const_mdspan(Span const &span)
Build a read-only mdspan descriptor over the same storage and mapping.
Definition mdspan/concepts.hpp:372
void assign_transform(BackendSelector selector, async::Async< OutputTensor > &output, Function &&function)
Schedule a nullary overwrite of an existing async Tensor.
Definition linalg/async/transform.hpp:188
Backend-independent operation values used with normalized kernel operands.
Nullary elementwise function that returns one retained value.
Definition elementwise_functions.hpp:20
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.
Shape preparation contracts for tensor operation outputs.
#define ERROR_IF(cond,...)
Definition trace.hpp:389