27template <
class OutputTensor,
class InputTensor>
31 "async reduction output must not share an epoch queue with its input");
34template <AsyncTensorOutput OutputTensor, TensorView InputTensor, std::
size_t InputRank, std::
size_t ReducedRank>
36 InputTensor
const& input,
37 linalg::ReductionAxes<InputRank, ReducedRank>
const& axes)
39 auto const required = reduction_output_extents(input, axes);
46 using extents_type = tensor_extents_t<OutputTensor>;
47 if constexpr (std::constructible_from<OutputTensor, extents_type const&>)
49 auto const extents = convert_tensor_extents<extents_type>(required);
50 if constexpr (std::constructible_from<OutputTensor, uninitialized_t, extents_type const&>)
53 return storage.
emplace(extents);
61template <
class BackendSelector, AsyncTensorOutput OutputTensor, TensorView InputTensor, std::size_t InputRank,
62 std::size_t ReducedRank>
66 if constexpr (async::is_async_alias_v<OutputTensor>)
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));
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));
91template <
class BackendSelector, TensorView InputTensor>
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);
100 storage.
emplace(std::move(result));
104template <
class BackendSelector,
class ResultTensor, TensorView LhsTensor, TensorView RhsTensor>
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);
115 storage.
emplace(std::move(result));
119template <
class BackendSelector, TensorView LhsTensor, TensorView RhsTensor>
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);
131 storage.
emplace(std::move(result));
135template <
class BackendSelector,
class ResultTensor, TensorView InputTensor>
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);
145 storage.
emplace(std::move(result));
149template <
class BackendSelector, TensorView InputTensor>
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);
160 storage.
emplace(std::move(result));
164template <
class BackendSelector, AsyncTensorOutput OutputTensor, TensorView LhsTensor, TensorView RhsTensor>
168 if constexpr (async::is_async_alias_v<OutputTensor>)
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);
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));
185template <
class BackendSelector, AsyncTensorOutput OutputTensor, TensorView InputTensor>
189 if constexpr (async::is_async_alias_v<OutputTensor>)
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));
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));
206template <
class BackendSelector, AsyncTensorOutput OutputTensor, TensorView InputTensor, std::size_t InputRank,
207 std::size_t ReducedRank>
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");
217template <
class BackendSelector, TensorView InputTensor>
222 auto task = co_sum_host(std::move(selector), output.
write(), input.
read());
223 task.debug_name(
"sum_host");
228template <
class BackendSelector, TensorView LhsTensor, TensorView RhsTensor>
232 using result_type = std::remove_cvref_t<decltype(uni20::inner_product(std::declval<LhsTensor const&>(),
233 std::declval<RhsTensor const&>()))>;
236 auto task = co_inner_product(std::move(selector), output.
write(), lhs.
read(), rhs.
read());
237 task.debug_name(
"inner_product");
242template <
class BackendSelector, TensorView LhsTensor, TensorView RhsTensor>
243[[nodiscard]]
auto schedule_async_inner_product_host(BackendSelector selector,
async::Async<LhsTensor> const& lhs,
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");
254template <
class BackendSelector, TensorView InputTensor>
257 using result_type = std::remove_cvref_t<decltype(uni20::norm(std::declval<InputTensor const&>()))>;
260 auto task = co_norm(std::move(selector), output.
write(), input.
read());
261 task.debug_name(
"norm");
266template <
class BackendSelector, TensorView InputTensor>
269 using result_type = make_real_t<tensor_element_t<InputTensor>>;
272 auto task = co_norm_host(std::move(selector), output.
write(), input.
read());
273 task.debug_name(
"norm_host");
278template <
class BackendSelector, AsyncTensorOutput OutputTensor, TensorView LhsTensor, TensorView RhsTensor>
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");
290template <
class BackendSelector, AsyncTensorOutput OutputTensor, TensorView InputTensor>
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");
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>>
312 detail::schedule_async_sum(std::move(selector), output, input, linalg::all_reduction_axes<input_rank>());
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>>
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));
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())
341 FirstAxis first_axis, RestAxes... rest_axes)
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));
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())
358 RestAxes... rest_axes)
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));
369template <linalg::KernelBackendSelector BackendSelector, TensorView InputTensor>
370 requires RealOrComplex<tensor_element_t<InputTensor>> &&
371 detail::ReductionResultAvailable<tensor_element_t<InputTensor>, InputTensor>
378 detail::schedule_async_sum(std::move(selector), output, input, linalg::all_reduction_axes<input_rank>());
383template <TensorView InputTensor>
384 requires RealOrComplex<tensor_element_t<InputTensor>> &&
385 detail::ReductionResultAvailable<tensor_element_t<InputTensor>, InputTensor>
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);
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>
403 RestAxes... rest_axes)
406 constexpr std::size_t reduced_rank = 1 +
sizeof...(RestAxes);
407 auto axes = linalg::make_reduction_axes<input_rank>(first_axis, rest_axes...);
411 detail::schedule_async_sum(std::move(selector), output, input, std::move(axes));
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>
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...);
431template <linalg::KernelBackendSelector BackendSelector, TensorView InputTensor>
432 requires RealOrComplex<tensor_element_t<InputTensor>>
435 return detail::schedule_async_sum_host(std::move(selector), input);
439template <TensorView InputTensor>
440 requires RealOrComplex<tensor_element_t<InputTensor>>
445 auto selector = linalg::select_backend_for<InputTensor>(operation);
446 return detail::schedule_async_sum_host(std::move(selector), input);
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>>
458 detail::schedule_async_inner_product_output(std::move(selector), output, lhs, rhs);
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>>
470 detail::schedule_async_inner_product_output(std::move(selector), output, lhs, rhs);
474template <linalg::KernelBackendSelector BackendSelector, TensorView LhsTensor, TensorView RhsTensor>
475 requires detail::CompatibleInnerProductTensors<LhsTensor, RhsTensor> &&
476 detail::ReductionResultAvailable<tensor_element_t<LhsTensor>, LhsTensor, RhsTensor>
480 return detail::schedule_async_inner_product(std::move(selector), lhs, rhs);
484template <TensorView LhsTensor, TensorView RhsTensor>
485 requires detail::CompatibleInnerProductTensors<LhsTensor, RhsTensor> &&
486 detail::ReductionResultAvailable<tensor_element_t<LhsTensor>, LhsTensor, RhsTensor>
490 return detail::schedule_async_inner_product(std::move(selector), lhs, rhs);
494template <linalg::KernelBackendSelector BackendSelector, TensorView LhsTensor, TensorView RhsTensor>
495 requires detail::CompatibleInnerProductTensors<LhsTensor, RhsTensor>
499 return detail::schedule_async_inner_product_host(std::move(selector), lhs, rhs);
503template <TensorView LhsTensor, TensorView RhsTensor>
504 requires detail::CompatibleInnerProductTensors<LhsTensor, RhsTensor>
508 return detail::schedule_async_inner_product_host(std::move(selector), lhs, rhs);
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>>>
518 detail::schedule_async_norm_output(std::move(selector), output, input);
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>>>
528 auto selector = linalg::select_backend_for<OutputTensor, InputTensor>(
linalg::norm_op{});
529 detail::schedule_async_norm_output(std::move(selector), output, input);
533template <linalg::KernelBackendSelector BackendSelector, TensorView InputTensor>
534 requires RealOrComplex<tensor_element_t<InputTensor>> &&
535 detail::ReductionResultAvailable<make_real_t<tensor_element_t<InputTensor>>, InputTensor>
538 return detail::schedule_async_norm(std::move(selector), input);
542template <TensorView InputTensor>
543 requires RealOrComplex<tensor_element_t<InputTensor>> &&
544 detail::ReductionResultAvailable<make_real_t<tensor_element_t<InputTensor>>, InputTensor>
547 auto selector = linalg::select_backend_for<InputTensor>(
linalg::norm_op{});
548 return detail::schedule_async_norm(std::move(selector), input);
552template <linalg::KernelBackendSelector BackendSelector, TensorView InputTensor>
553 requires RealOrComplex<tensor_element_t<InputTensor>>
556 return detail::schedule_async_norm_host(std::move(selector), input);
560template <TensorView InputTensor>
561 requires RealOrComplex<tensor_element_t<InputTensor>>
564 auto selector = linalg::select_backend_for<InputTensor>(
linalg::norm_op{});
565 return detail::schedule_async_norm_host(std::move(selector), input);
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