Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
linalg/async/reductions.hpp
Go to the documentation of this file.
1#pragma once
2
15
16#include <concepts>
17#include <cstddef>
18#include <memory>
19#include <tuple>
20#include <utility>
21
22namespace uni20
23{
24namespace detail
25{
26
27template <class OutputTensor, class InputTensor>
28void validate_async_reduction_aliasing(async::Async<OutputTensor> const& output, async::Async<InputTensor> const& input)
29{
30 ERROR_IF(std::addressof(output.queue()) == std::addressof(input.queue()),
31 "async reduction output must not share an epoch queue with its input");
32}
33
34template <AsyncTensorOutput OutputTensor, TensorView InputTensor, std::size_t InputRank, std::size_t ReducedRank>
35[[nodiscard]] OutputTensor& prepare_async_sum_output(async::shared_storage<OutputTensor>& storage,
36 InputTensor const& input,
37 linalg::ReductionAxes<InputRank, ReducedRank> const& axes)
38{
39 auto const required = reduction_output_extents(input, axes);
40 if (storage.constructed())
41 {
42 prepare_output(*storage, required);
43 return *storage;
44 }
45
46 using extents_type = tensor_extents_t<OutputTensor>;
47 if constexpr (std::constructible_from<OutputTensor, extents_type const&>)
48 {
49 auto const extents = convert_tensor_extents<extents_type>(required);
50 if constexpr (std::constructible_from<OutputTensor, uninitialized_t, extents_type const&>)
51 return storage.emplace(uninitialized, extents);
52 else
53 return storage.emplace(extents);
54 }
55 else
56 {
58 }
59}
60
61template <class BackendSelector, AsyncTensorOutput OutputTensor, TensorView InputTensor, std::size_t InputRank,
62 std::size_t ReducedRank>
63async::AsyncTask co_sum(BackendSelector const selector, async::WriteBuffer<OutputTensor> output,
64 async::ReadBuffer<InputTensor> input, linalg::ReductionAxes<InputRank, ReducedRank> axes)
65{
66 if constexpr (async::is_async_alias_v<OutputTensor>)
67 {
68 AsyncAliasWriteDescriptorAwaiter output_descriptor_awaiter(output);
69 auto awaited = co_await async::all(output_descriptor_awaiter, input);
70 auto mutable_output = std::get<0>(awaited);
71 auto const& input_value = std::get<1>(awaited);
72 prepare_output(mutable_output, reduction_output_extents(input_value, axes));
73 auto output_descriptor = mdspec_of(mutable_output);
74 auto input_descriptor = mdspec_of(input_value);
75 dispatch_sum(selector, output_descriptor, input_descriptor, std::move(axes));
76 }
77 else
78 {
79 auto output_storage = output.storage();
80 auto awaited = co_await async::all(output_storage, input);
81 auto& storage = std::get<0>(awaited);
82 auto const& input_value = std::get<1>(awaited);
83 auto& output_value = prepare_async_sum_output(storage, input_value, axes);
84 auto output_descriptor = mdspec_of(output_value);
85 auto input_descriptor = mdspec_of(input_value);
86 dispatch_sum(selector, output_descriptor, input_descriptor, std::move(axes));
87 }
88 co_return;
89}
90
91template <class BackendSelector, TensorView InputTensor>
92async::AsyncTask co_sum_host(BackendSelector const selector, async::WriteBuffer<tensor_element_t<InputTensor>> output,
94{
95 auto output_storage = output.storage();
96 auto awaited = co_await async::all(output_storage, input);
97 auto& storage = std::get<0>(awaited);
98 auto const& input_value = std::get<1>(awaited);
99 auto result = uni20::sum_host(selector, input_value);
100 storage.emplace(std::move(result));
101 co_return;
102}
103
104template <class BackendSelector, class ResultTensor, TensorView LhsTensor, TensorView RhsTensor>
105async::AsyncTask co_inner_product(BackendSelector const selector, async::WriteBuffer<ResultTensor> output,
107{
108 auto output_storage = output.storage();
109 auto awaited = co_await async::all(output_storage, lhs, rhs);
110 auto& storage = std::get<0>(awaited);
111 auto const& lhs_value = std::get<1>(awaited);
112 auto const& rhs_value = std::get<2>(awaited);
113
114 auto result = uni20::inner_product(selector, lhs_value, rhs_value);
115 storage.emplace(std::move(result));
116 co_return;
117}
118
119template <class BackendSelector, TensorView LhsTensor, TensorView RhsTensor>
120async::AsyncTask co_inner_product_host(BackendSelector const selector,
121 async::WriteBuffer<tensor_element_t<LhsTensor>> output,
123{
124 auto output_storage = output.storage();
125 auto awaited = co_await async::all(output_storage, lhs, rhs);
126 auto& storage = std::get<0>(awaited);
127 auto const& lhs_value = std::get<1>(awaited);
128 auto const& rhs_value = std::get<2>(awaited);
129
130 auto result = uni20::inner_product_host(selector, lhs_value, rhs_value);
131 storage.emplace(std::move(result));
132 co_return;
133}
134
135template <class BackendSelector, class ResultTensor, TensorView InputTensor>
136async::AsyncTask co_norm(BackendSelector const selector, async::WriteBuffer<ResultTensor> output,
138{
139 auto output_storage = output.storage();
140 auto awaited = co_await async::all(output_storage, input);
141 auto& storage = std::get<0>(awaited);
142 auto const& input_value = std::get<1>(awaited);
143
144 auto result = uni20::norm(selector, input_value);
145 storage.emplace(std::move(result));
146 co_return;
147}
148
149template <class BackendSelector, TensorView InputTensor>
150async::AsyncTask co_norm_host(BackendSelector const selector,
151 async::WriteBuffer<make_real_t<tensor_element_t<InputTensor>>> output,
153{
154 auto output_storage = output.storage();
155 auto awaited = co_await async::all(output_storage, input);
156 auto& storage = std::get<0>(awaited);
157 auto const& input_value = std::get<1>(awaited);
158
159 auto result = uni20::norm_host(selector, input_value);
160 storage.emplace(std::move(result));
161 co_return;
162}
163
164template <class BackendSelector, AsyncTensorOutput OutputTensor, TensorView LhsTensor, TensorView RhsTensor>
165async::AsyncTask co_inner_product_output(BackendSelector const selector, async::WriteBuffer<OutputTensor> output,
167{
168 if constexpr (async::is_async_alias_v<OutputTensor>)
169 {
170 AsyncAliasWriteDescriptorAwaiter output_descriptor_awaiter(output);
171 auto awaited = co_await async::all(output_descriptor_awaiter, lhs, rhs);
172 auto output_value = std::get<0>(awaited);
173 uni20::inner_product(selector, output_value, std::get<1>(awaited), std::get<2>(awaited));
174 }
175 else
176 {
177 auto output_storage = output.storage();
178 auto awaited = co_await async::all(output_storage, lhs, rhs);
179 auto& output_value = prepare_async_scalar_output<OutputTensor>(std::get<0>(awaited));
180 uni20::inner_product(selector, output_value, std::get<1>(awaited), std::get<2>(awaited));
181 }
182 co_return;
183}
184
185template <class BackendSelector, AsyncTensorOutput OutputTensor, TensorView InputTensor>
186async::AsyncTask co_norm_output(BackendSelector const selector, async::WriteBuffer<OutputTensor> output,
188{
189 if constexpr (async::is_async_alias_v<OutputTensor>)
190 {
191 AsyncAliasWriteDescriptorAwaiter output_descriptor_awaiter(output);
192 auto awaited = co_await async::all(output_descriptor_awaiter, input);
193 auto output_value = std::get<0>(awaited);
194 uni20::norm(selector, output_value, std::get<1>(awaited));
195 }
196 else
197 {
198 auto output_storage = output.storage();
199 auto awaited = co_await async::all(output_storage, input);
200 auto& output_value = prepare_async_scalar_output<OutputTensor>(std::get<0>(awaited));
201 uni20::norm(selector, output_value, std::get<1>(awaited));
202 }
203 co_return;
204}
205
206template <class BackendSelector, AsyncTensorOutput OutputTensor, TensorView InputTensor, std::size_t InputRank,
207 std::size_t ReducedRank>
208void schedule_async_sum(BackendSelector selector, async::Async<OutputTensor>& output,
209 async::Async<InputTensor> const& input, linalg::ReductionAxes<InputRank, ReducedRank> axes)
210{
211 validate_async_reduction_aliasing(output, input);
212 auto task = co_sum(std::move(selector), output.write(), input.read(), std::move(axes));
213 task.debug_name("sum");
214 async::schedule(std::move(task));
215}
216
217template <class BackendSelector, TensorView InputTensor>
218[[nodiscard]] auto schedule_async_sum_host(BackendSelector selector, async::Async<InputTensor> const& input)
219{
221 output.debug_name("sum_host.result");
222 auto task = co_sum_host(std::move(selector), output.write(), input.read());
223 task.debug_name("sum_host");
224 async::schedule(std::move(task));
225 return output;
226}
227
228template <class BackendSelector, TensorView LhsTensor, TensorView RhsTensor>
229[[nodiscard]] auto schedule_async_inner_product(BackendSelector selector, async::Async<LhsTensor> const& lhs,
230 async::Async<RhsTensor> const& rhs)
231{
232 using result_type = std::remove_cvref_t<decltype(uni20::inner_product(std::declval<LhsTensor const&>(),
233 std::declval<RhsTensor const&>()))>;
235 output.debug_name("inner_product.result");
236 auto task = co_inner_product(std::move(selector), output.write(), lhs.read(), rhs.read());
237 task.debug_name("inner_product");
238 async::schedule(std::move(task));
239 return output;
240}
241
242template <class BackendSelector, TensorView LhsTensor, TensorView RhsTensor>
243[[nodiscard]] auto schedule_async_inner_product_host(BackendSelector selector, async::Async<LhsTensor> const& lhs,
244 async::Async<RhsTensor> const& rhs)
245{
247 output.debug_name("inner_product_host.result");
248 auto task = co_inner_product_host(std::move(selector), output.write(), lhs.read(), rhs.read());
249 task.debug_name("inner_product_host");
250 async::schedule(std::move(task));
251 return output;
252}
253
254template <class BackendSelector, TensorView InputTensor>
255[[nodiscard]] auto schedule_async_norm(BackendSelector selector, async::Async<InputTensor> const& input)
256{
257 using result_type = std::remove_cvref_t<decltype(uni20::norm(std::declval<InputTensor const&>()))>;
259 output.debug_name("norm.result");
260 auto task = co_norm(std::move(selector), output.write(), input.read());
261 task.debug_name("norm");
262 async::schedule(std::move(task));
263 return output;
264}
265
266template <class BackendSelector, TensorView InputTensor>
267[[nodiscard]] auto schedule_async_norm_host(BackendSelector selector, async::Async<InputTensor> const& input)
268{
269 using result_type = make_real_t<tensor_element_t<InputTensor>>;
271 output.debug_name("norm_host.result");
272 auto task = co_norm_host(std::move(selector), output.write(), input.read());
273 task.debug_name("norm_host");
274 async::schedule(std::move(task));
275 return output;
276}
277
278template <class BackendSelector, AsyncTensorOutput OutputTensor, TensorView LhsTensor, TensorView RhsTensor>
279void schedule_async_inner_product_output(BackendSelector selector, async::Async<OutputTensor>& output,
281{
282 auto const* const output_queue = std::addressof(output.queue());
283 ERROR_IF(output_queue == std::addressof(lhs.queue()) || output_queue == std::addressof(rhs.queue()),
284 "async inner-product output must not share an epoch queue with an input");
285 auto task = co_inner_product_output(std::move(selector), output.write(), lhs.read(), rhs.read());
286 task.debug_name("inner_product");
287 async::schedule(std::move(task));
288}
289
290template <class BackendSelector, AsyncTensorOutput OutputTensor, TensorView InputTensor>
291void schedule_async_norm_output(BackendSelector selector, async::Async<OutputTensor>& output,
292 async::Async<InputTensor> const& input)
293{
294 validate_async_reduction_aliasing(output, input);
295 auto task = co_norm_output(std::move(selector), output.write(), input.read());
296 task.debug_name("norm");
297 async::schedule(std::move(task));
298}
299
300} // namespace detail
301
306template <linalg::KernelBackendSelector BackendSelector, AsyncTensorOutput OutputTensor, TensorView InputTensor>
307 requires MutableScalarTensorView<OutputTensor> && RealOrComplex<tensor_element_t<InputTensor>> &&
308 std::same_as<tensor_element_t<OutputTensor>, tensor_element_t<InputTensor>>
309void sum(BackendSelector selector, async::Async<OutputTensor>& output, async::Async<InputTensor> const& input)
310{
311 constexpr std::size_t input_rank = tensor_mdspec_t<InputTensor>::rank();
312 detail::schedule_async_sum(std::move(selector), output, input, linalg::all_reduction_axes<input_rank>());
313}
314
317template <AsyncTensorOutput OutputTensor, TensorView InputTensor>
318 requires MutableScalarTensorView<OutputTensor> && RealOrComplex<tensor_element_t<InputTensor>> &&
319 std::same_as<tensor_element_t<OutputTensor>, tensor_element_t<InputTensor>>
321{
322 constexpr std::size_t input_rank = tensor_mdspec_t<InputTensor>::rank();
323 auto axes = linalg::all_reduction_axes<input_rank>();
325 auto selector = linalg::select_backend_for<OutputTensor, InputTensor>(operation);
326 detail::schedule_async_sum(std::move(selector), output, input, std::move(axes));
327}
328
333template <linalg::KernelBackendSelector BackendSelector, AsyncTensorOutput OutputTensor, TensorView InputTensor,
334 linalg::ReductionAxis FirstAxis, linalg::ReductionAxis... RestAxes>
335 requires RealOrComplex<tensor_element_t<InputTensor>> &&
336 std::same_as<tensor_element_t<OutputTensor>, tensor_element_t<InputTensor>> &&
337 (1 + sizeof...(RestAxes) <= tensor_mdspec_t<InputTensor>::rank()) &&
338 (mutable_tensor_mdspec_t<OutputTensor>::rank() + 1 + sizeof...(RestAxes) ==
339 tensor_mdspec_t<InputTensor>::rank())
340void sum(BackendSelector selector, async::Async<OutputTensor>& output, async::Async<InputTensor> const& input,
341 FirstAxis first_axis, RestAxes... rest_axes)
342{
343 constexpr std::size_t input_rank = tensor_mdspec_t<InputTensor>::rank();
344 auto axes = linalg::make_reduction_axes<input_rank>(first_axis, rest_axes...);
345 detail::schedule_async_sum(std::move(selector), output, input, std::move(axes));
346}
347
350template <AsyncTensorOutput OutputTensor, TensorView InputTensor, linalg::ReductionAxis FirstAxis,
351 linalg::ReductionAxis... RestAxes>
352 requires RealOrComplex<tensor_element_t<InputTensor>> &&
353 std::same_as<tensor_element_t<OutputTensor>, tensor_element_t<InputTensor>> &&
354 (1 + sizeof...(RestAxes) <= tensor_mdspec_t<InputTensor>::rank()) &&
355 (mutable_tensor_mdspec_t<OutputTensor>::rank() + 1 + sizeof...(RestAxes) ==
356 tensor_mdspec_t<InputTensor>::rank())
357void sum(async::Async<OutputTensor>& output, async::Async<InputTensor> const& input, FirstAxis first_axis,
358 RestAxes... rest_axes)
359{
360 constexpr std::size_t input_rank = tensor_mdspec_t<InputTensor>::rank();
361 constexpr std::size_t reduced_rank = 1 + sizeof...(RestAxes);
362 auto axes = linalg::make_reduction_axes<input_rank>(first_axis, rest_axes...);
364 auto selector = linalg::select_backend_for<OutputTensor, InputTensor>(operation);
365 detail::schedule_async_sum(std::move(selector), output, input, std::move(axes));
366}
367
369template <linalg::KernelBackendSelector BackendSelector, TensorView InputTensor>
370 requires RealOrComplex<tensor_element_t<InputTensor>> &&
371 detail::ReductionResultAvailable<tensor_element_t<InputTensor>, InputTensor>
372[[nodiscard]] auto sum(BackendSelector selector, async::Async<InputTensor> const& input)
373{
374 constexpr std::size_t input_rank = tensor_mdspec_t<InputTensor>::rank();
377 output.debug_name("sum.result");
378 detail::schedule_async_sum(std::move(selector), output, input, linalg::all_reduction_axes<input_rank>());
379 return output;
380}
381
383template <TensorView InputTensor>
384 requires RealOrComplex<tensor_element_t<InputTensor>> &&
385 detail::ReductionResultAvailable<tensor_element_t<InputTensor>, InputTensor>
386[[nodiscard]] auto sum(async::Async<InputTensor> const& input)
387{
388 constexpr std::size_t input_rank = tensor_mdspec_t<InputTensor>::rank();
389 auto axes = linalg::all_reduction_axes<input_rank>();
391 auto selector = linalg::select_backend_for<InputTensor>(operation);
392 return sum(std::move(selector), input);
393}
394
397template <linalg::KernelBackendSelector BackendSelector, TensorView InputTensor, linalg::ReductionAxis FirstAxis,
398 linalg::ReductionAxis... RestAxes>
399 requires RealOrComplex<tensor_element_t<InputTensor>> &&
400 (1 + sizeof...(RestAxes) <= tensor_mdspec_t<InputTensor>::rank()) &&
401 detail::ReductionResultAvailable<tensor_element_t<InputTensor>, InputTensor>
402[[nodiscard]] auto sum(BackendSelector selector, async::Async<InputTensor> const& input, FirstAxis first_axis,
403 RestAxes... rest_axes)
404{
405 constexpr std::size_t input_rank = tensor_mdspec_t<InputTensor>::rank();
406 constexpr std::size_t reduced_rank = 1 + sizeof...(RestAxes);
407 auto axes = linalg::make_reduction_axes<input_rank>(first_axis, rest_axes...);
410 output.debug_name("sum.result");
411 detail::schedule_async_sum(std::move(selector), output, input, std::move(axes));
412 return output;
413}
414
416template <TensorView InputTensor, linalg::ReductionAxis FirstAxis, linalg::ReductionAxis... RestAxes>
417 requires RealOrComplex<tensor_element_t<InputTensor>> &&
418 (1 + sizeof...(RestAxes) <= tensor_mdspec_t<InputTensor>::rank()) &&
419 detail::ReductionResultAvailable<tensor_element_t<InputTensor>, InputTensor>
420[[nodiscard]] auto sum(async::Async<InputTensor> const& input, FirstAxis first_axis, RestAxes... rest_axes)
421{
422 constexpr std::size_t input_rank = tensor_mdspec_t<InputTensor>::rank();
423 constexpr std::size_t reduced_rank = 1 + sizeof...(RestAxes);
424 auto axes = linalg::make_reduction_axes<input_rank>(first_axis, rest_axes...);
426 auto selector = linalg::select_backend_for<InputTensor>(operation);
427 return sum(std::move(selector), input, first_axis, rest_axes...);
428}
429
431template <linalg::KernelBackendSelector BackendSelector, TensorView InputTensor>
432 requires RealOrComplex<tensor_element_t<InputTensor>>
433[[nodiscard]] auto sum_host(BackendSelector selector, async::Async<InputTensor> const& input)
434{
435 return detail::schedule_async_sum_host(std::move(selector), input);
436}
437
439template <TensorView InputTensor>
440 requires RealOrComplex<tensor_element_t<InputTensor>>
441[[nodiscard]] auto sum_host(async::Async<InputTensor> const& input)
442{
443 constexpr std::size_t input_rank = tensor_mdspec_t<InputTensor>::rank();
444 auto operation = linalg::sum_reduction_op<input_rank, input_rank>{.axes = linalg::all_reduction_axes<input_rank>()};
445 auto selector = linalg::select_backend_for<InputTensor>(operation);
446 return detail::schedule_async_sum_host(std::move(selector), input);
447}
448
451template <linalg::KernelBackendSelector BackendSelector, AsyncTensorOutput OutputTensor, TensorView LhsTensor,
452 TensorView RhsTensor>
453 requires MutableScalarTensorView<OutputTensor> && detail::CompatibleInnerProductTensors<LhsTensor, RhsTensor> &&
454 std::same_as<tensor_element_t<OutputTensor>, tensor_element_t<LhsTensor>>
455void inner_product(BackendSelector selector, async::Async<OutputTensor>& output, async::Async<LhsTensor> const& lhs,
456 async::Async<RhsTensor> const& rhs)
457{
458 detail::schedule_async_inner_product_output(std::move(selector), output, lhs, rhs);
459}
460
463template <AsyncTensorOutput OutputTensor, TensorView LhsTensor, TensorView RhsTensor>
464 requires MutableScalarTensorView<OutputTensor> && detail::CompatibleInnerProductTensors<LhsTensor, RhsTensor> &&
465 std::same_as<tensor_element_t<OutputTensor>, tensor_element_t<LhsTensor>>
467 async::Async<RhsTensor> const& rhs)
468{
469 auto selector = linalg::select_backend_for<OutputTensor, LhsTensor, RhsTensor>(linalg::inner_product_op{});
470 detail::schedule_async_inner_product_output(std::move(selector), output, lhs, rhs);
471}
472
474template <linalg::KernelBackendSelector BackendSelector, TensorView LhsTensor, TensorView RhsTensor>
475 requires detail::CompatibleInnerProductTensors<LhsTensor, RhsTensor> &&
476 detail::ReductionResultAvailable<tensor_element_t<LhsTensor>, LhsTensor, RhsTensor>
477[[nodiscard]] auto inner_product(BackendSelector selector, async::Async<LhsTensor> const& lhs,
478 async::Async<RhsTensor> const& rhs)
479{
480 return detail::schedule_async_inner_product(std::move(selector), lhs, rhs);
481}
482
484template <TensorView LhsTensor, TensorView RhsTensor>
485 requires detail::CompatibleInnerProductTensors<LhsTensor, RhsTensor> &&
486 detail::ReductionResultAvailable<tensor_element_t<LhsTensor>, LhsTensor, RhsTensor>
487[[nodiscard]] auto inner_product(async::Async<LhsTensor> const& lhs, async::Async<RhsTensor> const& rhs)
488{
489 auto selector = linalg::select_backend_for<LhsTensor, RhsTensor>(linalg::inner_product_op{});
490 return detail::schedule_async_inner_product(std::move(selector), lhs, rhs);
491}
492
494template <linalg::KernelBackendSelector BackendSelector, TensorView LhsTensor, TensorView RhsTensor>
495 requires detail::CompatibleInnerProductTensors<LhsTensor, RhsTensor>
496[[nodiscard]] auto inner_product_host(BackendSelector selector, async::Async<LhsTensor> const& lhs,
497 async::Async<RhsTensor> const& rhs)
498{
499 return detail::schedule_async_inner_product_host(std::move(selector), lhs, rhs);
500}
501
503template <TensorView LhsTensor, TensorView RhsTensor>
504 requires detail::CompatibleInnerProductTensors<LhsTensor, RhsTensor>
506{
507 auto selector = linalg::select_backend_for<LhsTensor, RhsTensor>(linalg::inner_product_op{});
508 return detail::schedule_async_inner_product_host(std::move(selector), lhs, rhs);
509}
510
513template <linalg::KernelBackendSelector BackendSelector, AsyncTensorOutput OutputTensor, TensorView InputTensor>
514 requires MutableScalarTensorView<OutputTensor> && RealOrComplex<tensor_element_t<InputTensor>> &&
515 std::same_as<tensor_element_t<OutputTensor>, make_real_t<tensor_element_t<InputTensor>>>
516void norm(BackendSelector selector, async::Async<OutputTensor>& output, async::Async<InputTensor> const& input)
517{
518 detail::schedule_async_norm_output(std::move(selector), output, input);
519}
520
523template <AsyncTensorOutput OutputTensor, TensorView InputTensor>
524 requires MutableScalarTensorView<OutputTensor> && RealOrComplex<tensor_element_t<InputTensor>> &&
525 std::same_as<tensor_element_t<OutputTensor>, make_real_t<tensor_element_t<InputTensor>>>
527{
528 auto selector = linalg::select_backend_for<OutputTensor, InputTensor>(linalg::norm_op{});
529 detail::schedule_async_norm_output(std::move(selector), output, input);
530}
531
533template <linalg::KernelBackendSelector BackendSelector, TensorView InputTensor>
534 requires RealOrComplex<tensor_element_t<InputTensor>> &&
535 detail::ReductionResultAvailable<make_real_t<tensor_element_t<InputTensor>>, InputTensor>
536[[nodiscard]] auto norm(BackendSelector selector, async::Async<InputTensor> const& input)
537{
538 return detail::schedule_async_norm(std::move(selector), input);
539}
540
542template <TensorView InputTensor>
543 requires RealOrComplex<tensor_element_t<InputTensor>> &&
544 detail::ReductionResultAvailable<make_real_t<tensor_element_t<InputTensor>>, InputTensor>
545[[nodiscard]] auto norm(async::Async<InputTensor> const& input)
546{
547 auto selector = linalg::select_backend_for<InputTensor>(linalg::norm_op{});
548 return detail::schedule_async_norm(std::move(selector), input);
549}
550
552template <linalg::KernelBackendSelector BackendSelector, TensorView InputTensor>
553 requires RealOrComplex<tensor_element_t<InputTensor>>
554[[nodiscard]] auto norm_host(BackendSelector selector, async::Async<InputTensor> const& input)
555{
556 return detail::schedule_async_norm_host(std::move(selector), input);
557}
558
560template <TensorView InputTensor>
561 requires RealOrComplex<tensor_element_t<InputTensor>>
562[[nodiscard]] auto norm_host(async::Async<InputTensor> const& input)
563{
564 auto selector = linalg::select_backend_for<InputTensor>(linalg::norm_op{});
565 return detail::schedule_async_norm_host(std::move(selector), input);
566}
567
568} // namespace uni20
The Async<T> container: coroutine‐safe asynchronous read/write.
Utilities for awaiting on Async<T>: co_await overload, all(), try_await().
General-purpose owning tensor with immediate or deferred mdspan metadata.
Definition basic_tensor.hpp:109
Canonical host-oriented coroutine task type.
Definition async_task.hpp:196
Async<T> is a container for coroutine-safe asynchronous read/write.
Definition async/async.hpp:93
ReadBuffer< T > read() const
Begin an asynchronous read of the value.
Definition async/async.hpp:339
EpochQueue const & queue() const
Inspect the shared epoch queue.
Definition async/async.hpp:423
WriteBuffer< T > write()
Begin exclusive asynchronous access to the payload.
Definition async/async.hpp:346
Async & debug_name(std::string const &label)
Assign an optional debug label for task-registry graph output.
Definition async/async.hpp:212
RAII handle for reading the value from an Async container at a given epoch.
Definition buffers.hpp:53
Exclusive mutable-access buffer for one Async<T> epoch.
Definition buffers.hpp:859
auto storage() &
Awaiter yielding direct access to writer shared storage.
Definition buffers.hpp:1029
Raised when a writer requests a mutable reference before construction.
Definition async_errors.hpp:74
A lightweight, thread-safe, reference-counted storage for a single object.
Definition shared_storage.hpp:94
bool constructed() const noexcept
Reports whether a value is currently constructed.
Definition shared_storage.hpp:234
T & emplace(Args &&... args)
Destroy any existing value and construct a new one in place.
Definition shared_storage.hpp:270
Coroutine scheduler for AsyncTask.
typename make_real< T >::type make_real_t
Alias for the underlying real-valued type of T.
Definition scalar_traits.hpp:168
Shared output capabilities for Async Tensor operation wrappers.
void schedule(AsyncTask &&task)
Schedule a task on the currently configured global scheduler.
Definition debug_scheduler.hpp:237
auto all(Aw &&... aw) noexcept
Build an awaitable that waits for all of the provided awaitables.
Definition awaiters.hpp:200
Definition async/async.hpp:26
constexpr uninitialized_t uninitialized
Explicit allocation tag for overwrite outputs and scratch space.
Definition common/initialization.hpp:22
void sum(BackendSelector selector, async::Async< OutputTensor > &output, async::Async< InputTensor > const &input)
Schedule a full sum into an explicit async scalar tensor.
Definition linalg/async/reductions.hpp:309
auto sum_host(BackendSelector selector, async::Async< InputTensor > const &input)
Return a nonblocking async host C++ scalar sum through an explicit selector.
Definition linalg/async/reductions.hpp:433
void inner_product(BackendSelector selector, async::Async< OutputTensor > &output, async::Async< LhsTensor > const &lhs, async::Async< RhsTensor > const &rhs)
Schedule an inner product into an explicit async scalar Tensor.
Definition linalg/async/reductions.hpp:455
Output & prepare_output(Output &output, RequiredExtents const &required)
Prepare a mutable tensor output with the specified shape.
Definition tensor/output.hpp:104
mpreal norm(mpcomplex const &z)
Definition mpcomplex.hpp:494
auto inner_product_host(BackendSelector selector, async::Async< LhsTensor > const &lhs, async::Async< RhsTensor > const &rhs)
Return a nonblocking async host C++ scalar inner product through an explicit selector.
Definition linalg/async/reductions.hpp:496
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
auto norm_host(BackendSelector selector, async::Async< InputTensor > const &input)
Return a nonblocking async host C++ scalar norm through an explicit selector.
Definition linalg/async/reductions.hpp:554
std::remove_cvref_t< detail::normalized_const_mdspec_t< T > > tensor_mdspec_t
Normalized readable MdspecLike type exposed by a tensor-level object.
Definition tensor/concepts.hpp:123
Conjugate-linear-left tensor inner-product operation tag.
Definition operation_tags.hpp:105
Euclidean tensor norm operation tag.
Definition operation_tags.hpp:111
Sum reduction over one or more fixed-rank input axes.
Definition operation_tags.hpp:195
ReductionAxes< InputRank, ReducedRank > axes
Definition operation_tags.hpp:197
Tensor sums, inner products, and Euclidean norms with explicit result residency.
#define ERROR_IF(cond,...)
Definition trace.hpp:389