27template <
class OutputTensor,
class... InputTensors>
31 if constexpr (
sizeof...(InputTensors) > 0)
33 auto const*
const output_queue = std::addressof(output.
queue());
34 auto validate_input = [&](
auto const& input) {
35 ERROR_IF(output_queue == std::addressof(input.queue()),
36 "async elementwise transform output must not share an epoch queue with an input");
38 (validate_input(inputs), ...);
42template <AsyncTensorOutput OutputTensor, TensorView FirstInputTensor>
44 FirstInputTensor
const& first_input)
48 using extents_type = tensor_extents_t<OutputTensor>;
49 if constexpr (std::constructible_from<OutputTensor, uninitialized_t, extents_type const&>)
51 auto const extents = convert_tensor_extents<extents_type>(first_input.extents());
54 else if constexpr (std::constructible_from<OutputTensor, extents_type const&>)
56 auto const extents = convert_tensor_extents<extents_type>(first_input.extents());
57 return storage.
emplace(extents);
65template <
class BackendSelector,
class Function, AsyncTensorOutput OutputTensor,
class Awaited, std::size_t... Input>
66void invoke_async_assign_transform(BackendSelector
const& selector, linalg::transform_op<Function>& operation,
67 OutputTensor& output, Awaited& awaited, std::index_sequence<Input...>)
72template <
class BackendSelector,
class Function, AsyncTensorOutput OutputTensor,
class Awaited, std::size_t... Input>
73void invoke_async_transform_inplace(BackendSelector
const& selector, linalg::transform_inplace_op<Function>& operation,
74 OutputTensor& output, Awaited& awaited, std::index_sequence<Input...>)
79template <
class BackendSelector, AsyncTensorOutput OutputTensor,
class Function, TensorView... InputTensors>
81 linalg::transform_op<Function> operation,
84 if constexpr (async::is_async_alias_v<OutputTensor>)
86 AsyncAliasWriteDescriptorAwaiter output_descriptor(output);
87 auto awaited =
co_await async::all(output_descriptor, inputs...);
88 auto mutable_output = std::get<0>(awaited);
90 invoke_async_assign_transform(selector, operation, mutable_output, awaited,
91 std::index_sequence_for<InputTensors...>{});
95 auto output_storage = output.
storage();
96 auto awaited =
co_await async::all(output_storage, inputs...);
97 auto& storage = std::get<0>(awaited);
98 auto& output_value = prepare_async_assign_transform_output(storage, std::get<1>(awaited));
99 invoke_async_assign_transform(selector, operation, output_value, awaited,
100 std::index_sequence_for<InputTensors...>{});
105template <
class BackendSelector, AsyncTensorOutput OutputTensor,
class Function, TensorView... InputTensors>
107 linalg::transform_inplace_op<Function> operation,
110 if constexpr (async::is_async_alias_v<OutputTensor>)
112 AsyncAliasWriteDescriptorAwaiter output_descriptor(output);
113 auto awaited =
co_await async::all(output_descriptor, inputs...);
114 auto mutable_output = std::get<0>(awaited);
115 invoke_async_transform_inplace(selector, operation, mutable_output, awaited,
116 std::index_sequence_for<InputTensors...>{});
120 auto output_storage = output.
storage();
121 auto awaited =
co_await async::all(output_storage, inputs...);
122 auto& storage = std::get<0>(awaited);
124 invoke_async_transform_inplace(selector, operation, *storage, awaited, std::index_sequence_for<InputTensors...>{});
129template <
class BackendSelector, AsyncTensorOutput OutputTensor,
class Function>
131 linalg::transform_op<Function> operation)
133 if constexpr (async::is_async_alias_v<OutputTensor>)
135 AsyncAliasWriteDescriptorAwaiter output_descriptor(output);
136 auto awaited =
co_await async::all(output_descriptor);
137 auto mutable_output = std::get<0>(awaited);
142 auto output_storage = output.
storage();
143 auto awaited =
co_await async::all(output_storage);
144 auto& storage = std::get<0>(awaited);
151template <
class BackendSelector, AsyncTensorOutput OutputTensor,
class Function, TensorView... InputTensors>
153 linalg::transform_op<Function> operation,
156 validate_async_transform_aliasing(output, inputs...);
157 auto task = co_assign_transform(std::move(selector), output.
write(), std::move(operation), inputs.
read()...);
158 task.debug_name(
"assign_transform");
162template <
class BackendSelector, AsyncTensorOutput OutputTensor,
class Function, TensorView... InputTensors>
164 linalg::transform_inplace_op<Function> operation,
167 validate_async_transform_aliasing(output, inputs...);
168 auto task = co_transform_inplace(std::move(selector), output.
write(), std::move(operation), inputs.
read()...);
169 task.debug_name(
"transform_inplace");
173template <
class BackendSelector, AsyncTensorOutput OutputTensor,
class Function>
175 linalg::transform_op<Function> operation)
177 auto task = co_assign_transform_existing(std::move(selector), output.
write(), std::move(operation));
178 task.debug_name(
"assign_transform");
187template <
class BackendSelector, AsyncTensorOutput OutputTensor,
class Function>
191 detail::schedule_async_assign_transform_existing(std::move(selector), output, std::move(operation));
195template <AsyncTensorOutput OutputTensor,
class Function>
199 auto selector = linalg::select_backend_for<OutputTensor>(operation);
200 detail::schedule_async_assign_transform_existing(std::move(selector), output, std::move(operation));
204template <
class BackendSelector, AsyncTensorOutput OutputTensor,
class Value>
222template <
class BackendSelector, AsyncTensorOutput OutputTensor,
class Function, TensorView FirstInputTensor,
223 TensorView... RestInputTensors>
224 requires detail::OverwriteTransformTensors<OutputTensor, FirstInputTensor, RestInputTensors...>
230 detail::schedule_async_assign_transform(std::move(selector), output, std::move(operation), first_input,
239template <AsyncTensorOutput OutputTensor,
class Function, TensorView FirstInputTensor, TensorView... RestInputTensors>
240 requires detail::OverwriteTransformTensors<OutputTensor, FirstInputTensor, RestInputTensors...>
247 detail::schedule_async_assign_transform(std::move(selector), output, std::move(operation), first_input,
256template <
class BackendSelector, AsyncTensorOutput OutputTensor,
class Function, TensorView... InputTensors>
257 requires detail::UpdateTransformTensors<OutputTensor, InputTensors...>
262 detail::schedule_async_transform_inplace(std::move(selector), output, std::move(operation), inputs...);
269template <AsyncTensorOutput OutputTensor,
class Function, TensorView... InputTensors>
270 requires detail::UpdateTransformTensors<OutputTensor, InputTensors...>
276 detail::schedule_async_transform_inplace(std::move(selector), output, std::move(operation), inputs...);
The Async<T> container: coroutineāsafe asynchronous read/write.
Utilities for awaiting on Async<T>: co_await overload, all(), try_await().
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
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
locale_t value
Definition data_table.cpp:49
Coroutine scheduler for AsyncTask.
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
constexpr auto select_backend_for(Operation const &operation)
Resolve the immutable backend selector for Tensor operand types.
Definition backend_selector.hpp:201
Definition async/async.hpp:26
constexpr uninitialized_t uninitialized
Explicit allocation tag for overwrite outputs and scratch space.
Definition common/initialization.hpp:22
void require_output(Output const &output, RequiredExtents const &required)
Require an existing tensor output to have the specified shape.
Definition tensor/output.hpp:84
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
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
Nullary elementwise function that returns one retained value.
Definition elementwise_functions.hpp:20
Shape preparation contracts for tensor operation outputs.
#define ERROR_IF(cond,...)
Definition trace.hpp:389