Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
var_toys.hpp
Go to the documentation of this file.
1#pragma once
2
8#include "async_toys.hpp"
9#include "var.hpp"
10#include <uni20/core/math.hpp>
11
12namespace uni20::async
13{
14
15namespace detail
16{
17
18// Reverse tasks must observe absence before touching any other dependency. An
19// unseeded result gradient prunes the task; a stored exception still propagates.
20template <typename T, typename Transform>
21AsyncTask accumulate_transformed_gradient(ReadBuffer<T> input_gradient, WriteBuffer<T> output_gradient,
22 Transform transform)
23{
24 auto gradient = co_await input_gradient.transfer().or_cancel();
25 T const value = gradient.get();
26 gradient.release();
27 co_await output_gradient += transform(value);
28}
29
30template <typename T, typename Transform>
31AsyncTask accumulate_transformed_gradient(ReadBuffer<T> input_gradient, ReadBuffer<T> forward_value,
32 WriteBuffer<T> output_gradient, Transform transform)
33{
34 auto gradient = co_await input_gradient.transfer().or_cancel();
35 T const gradient_value = gradient.get();
36 gradient.release();
37
38 auto value = co_await forward_value.transfer();
39 T const input_value = value.get();
40 value.release();
41 co_await output_gradient += transform(gradient_value, input_value);
42}
43
44} // namespace detail
45
50template <typename T> Var<T> sin(Var<T> x)
51{
52 Var<T> Result;
53
54 schedule(co_sin(x.value.read(), Result.value.write()));
55
56 // TRACE("Var Sin", Result.grad.value().queue().latest().get());
57 schedule([](ReadBuffer<T> in, ReadBuffer<T> in_grad, WriteBuffer<T> out_grad) static -> AsyncTask {
58 using std::cos;
59 // GCC 13 workaround for `(co_await ...).get()`: use an explicit owning proxy.
60 // GCC 14+ supports the one-liner form, e.g.
61 // auto const in_g = (co_await in_grad.transfer().or_cancel()).get();
62 auto in_grad_buffer = co_await in_grad.transfer().or_cancel();
63 auto const in_g = in_grad_buffer.get();
64 in_grad_buffer.release();
65
66 auto in_buffer = co_await in.transfer();
67 auto const cos_x = cos(in_buffer.get());
68 in_buffer.release();
69 co_await out_grad += uni20::conj(cos_x) * in_g;
70 }(x.value.read(), Result.grad.input(), x.grad.output()));
71
72 return Result;
73}
74
79template <typename T> Var<T> cos(Var<T> x)
80{
81 Var<T> Result;
82 schedule(co_cos(x.value.read(), Result.value.write()));
83 schedule(detail::accumulate_transformed_gradient(Result.grad.input(), x.value.read(), x.grad.output(),
84 [](T const& gradient, T const& input) {
85 using std::sin;
86 return -uni20::conj(sin(input)) * gradient;
87 }));
88 return Result;
89}
90
96template <typename T> Var<T> operator-(Var<T> x, T y)
97{
98 Var<T> Result;
99 Result.value = x.value - y;
100 x.grad += Result.grad;
101 return Result;
102}
103
109template <typename T> Var<T> operator-(T x, Var<T> y)
110{
111 Var<T> Result;
112 Result.value = x - y.value;
113 y.grad -= Result.grad;
114 return Result;
115}
116
122template <typename T> Var<T> operator-(Var<T> x, Var<T> y)
123{
124 Var<T> Result;
125 Result.value = x.value - y.value;
126 x.grad += Result.grad;
127 y.grad -= Result.grad;
128 return Result;
129}
130
136template <typename T> Var<T> operator+(Var<T> x, T y)
137{
138 Var<T> Result;
139 Result.value = x.value + y;
140 x.grad += Result.grad;
141 return Result;
142}
143
149template <typename T> Var<T> operator+(T x, Var<T> y)
150{
151 Var<T> Result;
152 Result.value = x + y.value;
153 y.grad += Result.grad;
154 return Result;
155}
156
162template <typename T> Var<T> operator+(Var<T> x, Var<T> y)
163{
164 Var<T> Result;
165 Result.value = x.value + y.value;
166 x.grad += Result.grad;
167 y.grad += Result.grad;
168 return Result;
169}
170
176template <typename T> Var<T> operator*(T x, Var<T> y)
177{
178 Var<T> Result;
179 Result.value = x * y.value;
180 schedule(detail::accumulate_transformed_gradient(
181 Result.grad.input(), y.grad.output(),
182 [factor = uni20::herm(x)](T const& gradient) { return factor * gradient; }));
183 return Result;
184}
185
191template <typename T> Var<T> operator*(Var<T> x, T y)
192{
193 Var<T> Result;
194 Result.value = x.value * y;
195 schedule(detail::accumulate_transformed_gradient(
196 Result.grad.input(), x.grad.output(),
197 [factor = uni20::herm(y)](T const& gradient) { return gradient * factor; }));
198 return Result;
199}
200
206template <typename T> Var<T> operator*(Var<T> x, Var<T> y)
207{
208 Var<T> Result;
209 Result.value = x.value * y.value;
210 schedule(detail::accumulate_transformed_gradient(
211 Result.grad.input(), y.value.read(), x.grad.output(),
212 [](T const& gradient, T const& value) { return gradient * uni20::herm(value); }));
213 schedule(detail::accumulate_transformed_gradient(
214 Result.grad.input(), x.value.read(), y.grad.output(),
215 [](T const& gradient, T const& value) { return uni20::herm(value) * gradient; }));
216 return Result;
217}
218
223template <typename T> Var<uni20::make_real_t<T>> real(Var<T> z)
224{
225 using uni20::real;
226 using r_type = uni20::make_real_t<T>;
227 Var<r_type> Result;
228 Result.value = real(z.value);
229 schedule([](ReadBuffer<r_type> in_grad, WriteBuffer<T> out_grad) static -> AsyncTask {
230 auto in_grad_buffer = co_await in_grad.transfer().or_cancel();
231 auto const grad = in_grad_buffer.get();
232 in_grad_buffer.release();
233 co_await out_grad += grad;
234 }(Result.grad.input(), z.grad.output()));
235 return Result;
236}
237
242template <typename T> Var<uni20::make_real_t<T>> imag(Var<T> z)
243{
244 using uni20::imag;
245 using r_type = uni20::make_real_t<T>;
246 Var<r_type> Result;
247 Result.value = imag(z.value);
248 schedule([](ReadBuffer<r_type> in_grad, WriteBuffer<T> out_grad) static -> AsyncTask {
249 auto in_grad_buffer = co_await in_grad.transfer().or_cancel();
250 auto const grad = in_grad_buffer.get();
251 in_grad_buffer.release();
252 T value{};
253 imag(value) = grad;
254 co_await out_grad += std::move(value);
255 }(Result.grad.input(), z.grad.output()));
256 return Result;
257}
258
259} // namespace uni20::async
Small async helper operations used in tests and examples.
Canonical host-oriented coroutine task type.
Definition async_task.hpp:196
RAII handle for reading the value from an Async container at a given epoch.
Definition buffers.hpp:53
void release() noexcept
Manually release the epoch reader before awaitable destruction.
Definition buffers.hpp:143
ReadBuffer && transfer() &noexcept
Transfer this read buffer into the owning-await path.
Definition buffers.hpp:147
Definition var.hpp:45
ReverseValue< T > grad
Definition var.hpp:88
Async< T > value
Definition var.hpp:87
Exclusive mutable-access buffer for one Async<T> epoch.
Definition buffers.hpp:859
locale_t value
Definition data_table.cpp:49
auto operator-(Async< T > const &x)
Unary negation overload for Async values.
Definition async_ops.hpp:477
uni20::complex< T > conj(detail::standard_complex< T > x)
Returns the complex conjugate for complex-valued scalars.
Definition math.hpp:70
constexpr T & imag(detail::standard_complex< T > &z) noexcept
Provides mutable access to the imaginary component of a uni20::complex value.
Definition math.hpp:184
constexpr auto herm(S x)
Computes the Hermitian adjoint of a scalar value.
Definition math.hpp:98
typename make_real< T >::type make_real_t
Alias for the underlying real-valued type of T.
Definition scalar_traits.hpp:168
constexpr T & real(detail::standard_complex< T > &z) noexcept
Provides mutable access to the real component of a uni20::complex value.
Definition math.hpp:173
Scalar math helper utilities.
This represents the reverse-mode adjoint for functions of complex variables, assuming a real-valued s...
Definition async/async.hpp:26
void schedule(AsyncTask &&task)
Schedule a task on the currently configured global scheduler.
Definition debug_scheduler.hpp:237
Var< T > operator*(T x, Var< T > y)
Computes x * y with reverse-mode gradient propagation.
Definition var_toys.hpp:176
AsyncTask co_cos(ReadBuffer< T > in, WriteBuffer< T > out)
Coroutine implementation of cos over async buffers.
Definition async_toys.hpp:60
Async< T > sin(Async< T > const &x)
Schedules asynchronous sine evaluation.
Definition async_toys.hpp:49
Var< T > operator+(Var< T > x, T y)
Computes x + y with reverse-mode gradient propagation.
Definition var_toys.hpp:136
Async< T > cos(Async< T > const &x)
Schedules asynchronous cosine evaluation.
Definition async_toys.hpp:73
AsyncTask co_sin(ReadBuffer< T > in, WriteBuffer< T > out)
Coroutine implementation of sin over async buffers.
Definition async_toys.hpp:22