DiFfRG
Loading...
Searching...
No Matches
complex_math.hh
Go to the documentation of this file.
1#pragma once
2
3// DiFfRG
5
6// external libraries
7#include <autodiff/common/numbertraits.hpp>
8
9#ifdef USE_CUDA
10
11#include <cuda/std/complex>
12
13namespace DiFfRG
14{
15 using ::cuda::std::atan2;
16 using ::cuda::std::complex;
17 using ::cuda::std::cos;
18 using ::cuda::std::cosh;
19 using ::cuda::std::imag;
20 using ::cuda::std::log;
21 using ::cuda::std::pow;
22 using ::cuda::std::real;
23 using ::cuda::std::sin;
24 using ::cuda::std::sinh;
25 using ::cuda::std::sqrt;
26 using ::cuda::std::tan;
27 using ::cuda::std::tanh;
28 template <typename NT> constexpr auto cot(const NT x) { return NT(1) / tan(x); }
29
30} // namespace DiFfRG
31
32#else
33
34#include <complex>
35namespace DiFfRG
36{
37 using ::std::atan2;
38 using ::std::complex;
39 using ::std::cos;
40 using ::std::cosh;
41 using ::std::imag;
42 using ::std::log;
43 using ::std::pow;
44 using ::std::real;
45 using ::std::sin;
46 using ::std::sinh;
47 using ::std::sqrt;
48 using ::std::tan;
49 using ::std::tanh;
50 template <typename NT> constexpr auto cot(const NT x) { return NT(1) / tan(x); }
51} // namespace DiFfRG
52
53#endif
54
55#ifdef USE_CUDA
56
57// Specialize isArithmetic for complex to make it compatible with real
59{
60 using ::cuda::std::complex;
61 template <typename T> struct ArithmeticTraits<::cuda::std::__4::complex<T>> : ArithmeticTraits<T> {
62 };
63} // namespace autodiff::detail
64
65#else
66
67// Specialize isArithmetic for complex to make it compatible with real
68namespace autodiff::detail
69{
70 using ::std::complex;
71 template <typename T> struct ArithmeticTraits<::std::complex<T>> : ArithmeticTraits<T> {
72 };
73} // namespace autodiff::detail
74
75#endif
76
77namespace autodiff::detail
78{
79 // operators for multiplication of float and complex
80 template <typename T1, typename T2>
81 requires(!std::is_same_v<T1, T2>) && std::is_arithmetic_v<T1> && std::is_arithmetic_v<T2>
82 __host__ __device__ auto operator*(const T1 x, const complex<T2> y)
83 {
84 return complex<decltype(T1(1.) * T2(1.))>(x * y.real(), x * y.imag());
85 }
86 template <typename T1, typename T2>
87 requires(!std::is_same_v<T1, T2>) && std::is_arithmetic_v<T1> && std::is_arithmetic_v<T2>
88 __host__ __device__ auto operator*(const complex<T1> &x, const T2 &y)
89 {
90 return complex<decltype(T1(1.) * T2(1.))>(y * x.real(), y * x.imag());
91 }
92 // operators for addition of real and complex
93 template <typename T1, typename T2>
94 requires(!std::is_same_v<T1, T2>) && std::is_arithmetic_v<T1> && std::is_arithmetic_v<T2>
95 __host__ __device__ auto operator+(const T1 &x, const complex<T2> &y)
96 {
97 return complex<decltype(T1(1.) + T2(1.))>(x + y.real(), y.imag());
98 }
99 template <typename T1, typename T2>
100 requires(!std::is_same_v<T1, T2>) && std::is_arithmetic_v<T1> && std::is_arithmetic_v<T2>
101 __host__ __device__ auto operator+(const complex<T1> &x, const T2 &y)
102 {
103 return complex<decltype(T1(1.) + T2(1.))>(x.real() + y, x.imag());
104 }
105 // operators for subtraction of real and complex
106 template <typename T1, typename T2>
107 requires(!std::is_same_v<T1, T2>) && std::is_arithmetic_v<T1> && std::is_arithmetic_v<T2>
108 __host__ __device__ auto operator-(const T1 &x, const complex<T2> &y)
109 {
110 return complex<decltype(T1(1.) - T2(1.))>(x - y.real(), -y.imag());
111 }
112 template <typename T1, typename T2>
113 requires(!std::is_same_v<T1, T2>) && std::is_arithmetic_v<T1> && std::is_arithmetic_v<T2>
114 __host__ __device__ auto operator-(const complex<T1> &x, const T2 &y)
115 {
116 return complex<decltype(T1(1.) - T2(1.))>(x.real() - y, x.imag());
117 }
118 // operators for division of real and complex
119 template <typename T1, typename T2>
120 requires(!std::is_same_v<T1, T2>) && std::is_arithmetic_v<T1> && std::is_arithmetic_v<T2>
121 __host__ __device__ auto operator/(const T1 &x, const complex<T2> &y)
122 {
123 return complex<decltype(T1(1.) / T2(1.))>(x * y.real(), -x * y.imag()) / (powr<2>(y.real()) + powr<2>(y.imag()));
124 }
125 template <typename T1, typename T2>
126 requires(!std::is_same_v<T1, T2>) && std::is_arithmetic_v<T1> && std::is_arithmetic_v<T2>
127 __host__ __device__ auto operator/(const complex<T1> x, const T2 &y)
128 {
129 return complex<decltype(T1(1.) / T2(1.))>(x.real() / y, x.imag() / y);
130 }
131} // namespace autodiff::detail
132
133// external libraries
134#include <autodiff/forward/real.hpp>
135
136namespace DiFfRG
137{
138 template <size_t N, typename T> using cxreal = autodiff::Real<N, complex<T>>;
139 using cxReal = autodiff::Real<1, complex<double>>;
140
141 template <typename T> struct is_complex : public std::false_type {
142 };
143 template <typename T> struct is_complex<complex<T>> : public std::true_type {
144 };
145 template <size_t N, typename T> struct is_complex<cxreal<N, T>> : public std::true_type {
146 };
147
148 template <size_t N, typename T> AUTODIFF_DEVICE_FUNC auto real(const autodiff::Real<N, T> &a) { return a; }
149 template <size_t N, typename T> constexpr AUTODIFF_DEVICE_FUNC auto imag(const autodiff::Real<N, T> &) { return 0.; }
150
151 template <size_t N, typename T> AUTODIFF_DEVICE_FUNC auto real(const cxreal<N, T> &x)
152 {
153 autodiff::Real<N, T> res;
154 autodiff::detail::For<0, N + 1>([&](auto i) constexpr { res[i] = real(x[i]); });
155 return res;
156 }
157 template <size_t N, typename T> AUTODIFF_DEVICE_FUNC auto imag(const cxreal<N, T> &x)
158 {
159 autodiff::Real<N, T> res;
160 autodiff::detail::For<0, N + 1>([&](auto i) constexpr { res[i] = imag(x[i]); });
161 return res;
162 }
163
164 // operators for multiplication of real and complex
165 template <size_t N, typename T>
166 AUTODIFF_DEVICE_FUNC auto operator*(const autodiff::Real<N, T> &x, const complex<double> &y)
167 {
168 cxreal<N, T> res;
169 autodiff::detail::For<0, N + 1>([&](auto i) constexpr { res[i] = x[i] * y; });
170 return res;
171 }
172 template <size_t N, typename T>
173 AUTODIFF_DEVICE_FUNC auto operator*(const complex<double> x, const autodiff::Real<N, T> y)
174 {
175 cxreal<N, T> res;
176 autodiff::detail::For<0, N + 1>([&](auto i) constexpr { res[i] = x * y[i]; });
177 return res;
178 }
179 // operators for addition of real and complex
180 template <size_t N, typename T>
181 AUTODIFF_DEVICE_FUNC auto operator+(const autodiff::Real<N, T> &x, const complex<double> &y)
182 {
183 cxreal<N, T> res;
184 res[0] = x[0] + y;
185 autodiff::detail::For<1, N + 1>([&](auto i) constexpr { res[i] = x[i]; });
186 return res;
187 }
188 template <size_t N, typename T>
189 AUTODIFF_DEVICE_FUNC auto operator+(const complex<double> x, const autodiff::Real<N, T> y)
190 {
191 cxreal<N, T> res;
192 res[0] = x + y[0];
193 autodiff::detail::For<1, N + 1>([&](auto i) constexpr { res[i] = y[i]; });
194 return res;
195 }
196 // operators for subtraction of real and complex
197 template <size_t N, typename T>
198 AUTODIFF_DEVICE_FUNC auto operator-(const autodiff::Real<N, T> &x, const complex<double> &y)
199 {
200 cxreal<N, T> res;
201 res[0] = x[0] - y;
202 autodiff::detail::For<1, N + 1>([&](auto i) constexpr { res[i] = x[i]; });
203 return res;
204 }
205 template <size_t N, typename T>
206 AUTODIFF_DEVICE_FUNC auto operator-(const complex<double> x, const autodiff::Real<N, T> y)
207 {
208 cxreal<N, T> res;
209 res[0] = x - y[0];
210 autodiff::detail::For<1, N + 1>([&](auto i) constexpr { res[i] = -y[i]; });
211 return res;
212 }
213 // operators for division of real and complex
214 template <size_t N, typename T>
215 AUTODIFF_DEVICE_FUNC auto operator/(const autodiff::Real<N, T> &x, const complex<double> &y)
216 {
217 cxreal<N, T> res;
218 autodiff::detail::For<0, N + 1>([&](auto i) constexpr { res[i] = x[i] / y; });
219 return res;
220 }
221 template <size_t N, typename T>
222 AUTODIFF_DEVICE_FUNC auto operator/(const complex<double> x, const autodiff::Real<N, T> y)
223 {
224 cxreal<N, T> ux(x);
225 cxreal<N, T> uy(y);
226 return ux /= uy;
227 }
228
229 // operators for multiplication of real and cxreal
230 template <size_t N, typename T>
231 AUTODIFF_DEVICE_FUNC auto operator*(const autodiff::Real<N, T> &x, const cxreal<N, T> &y)
232 {
233 cxreal<N, T> res(x);
234 return res *= y;
235 }
236 template <size_t N, typename T>
237 AUTODIFF_DEVICE_FUNC auto operator*(const cxreal<N, T> &x, const autodiff::Real<N, T> &y)
238 {
239 cxreal<N, T> res(y);
240 return res *= x;
241 }
242 // operators for addition of real and cxreal
243 template <size_t N, typename T>
244 AUTODIFF_DEVICE_FUNC auto operator+(const autodiff::Real<N, T> &x, const cxreal<N, T> &y)
245 {
246 cxreal<N, T> res(x);
247 return res += y;
248 }
249 template <size_t N, typename T>
250 AUTODIFF_DEVICE_FUNC auto operator+(const cxreal<N, T> &x, const autodiff::Real<N, T> &y)
251 {
252 cxreal<N, T> res(y);
253 return res += x;
254 }
255 // operators for subtraction of real and cxreal
256 template <size_t N, typename T>
257 AUTODIFF_DEVICE_FUNC auto operator-(const autodiff::Real<N, T> &x, const cxreal<N, T> &y)
258 {
259 cxreal<N, T> res(x);
260 return res -= y;
261 }
262 template <size_t N, typename T>
263 AUTODIFF_DEVICE_FUNC auto operator-(const cxreal<N, T> &x, const autodiff::Real<N, T> &y)
264 {
265 cxreal<N, T> ux(x);
266 cxreal<N, T> uy(y);
267 return ux -= uy;
268 }
269 // operators for division of real and cxreal
270 template <size_t N, typename T>
271 AUTODIFF_DEVICE_FUNC auto operator/(const autodiff::Real<N, T> &x, const cxreal<N, T> &y)
272 {
273 cxreal<N, T> ux(x);
274 return ux /= y;
275 }
276 template <size_t N, typename T>
277 AUTODIFF_DEVICE_FUNC auto operator/(const cxreal<N, T> &x, const autodiff::Real<N, T> &y)
278 {
279 cxreal<N, T> uy(y);
280 return x / uy;
281 }
282
283 // operators for multiplication of complex and cxreal
284 template <size_t N, typename T> AUTODIFF_DEVICE_FUNC auto operator*(const complex<double> &x, const cxreal<N, T> &y)
285 {
286 cxreal<N, T> res;
287 autodiff::detail::For<0, N + 1>([&](auto i) constexpr { res[i] = y[i] * x; });
288 return res;
289 }
290 template <size_t N, typename T> AUTODIFF_DEVICE_FUNC auto operator*(const cxreal<N, T> &x, const complex<double> &y)
291 {
292 cxreal<N, T> res;
293 autodiff::detail::For<0, N + 1>([&](auto i) constexpr { res[i] = x[i] * y; });
294 return res;
295 }
296 // operators for addition of complex and cxreal
297 template <size_t N, typename T> AUTODIFF_DEVICE_FUNC auto operator+(const complex<double> &x, const cxreal<N, T> &y)
298 {
299 cxreal<N, T> res(y);
300 res[0] += x;
301 return res;
302 }
303 template <size_t N, typename T> AUTODIFF_DEVICE_FUNC auto operator+(const cxreal<N, T> &x, const complex<double> &y)
304 {
305 cxreal<N, T> res(x);
306 res[0] += y;
307 return res;
308 }
309 // operators for subtraction of complex and cxreal
310 template <size_t N, typename T> AUTODIFF_DEVICE_FUNC auto operator-(const complex<double> &x, const cxreal<N, T> &y)
311 {
312 cxreal<N, T> ux(x);
313 return ux -= y;
314 }
315 template <size_t N, typename T> AUTODIFF_DEVICE_FUNC auto operator-(const cxreal<N, T> &x, const complex<double> &y)
316 {
317 cxreal<N, T> res(x);
318 res[0] -= y;
319 return res;
320 }
321 // operators for division of complex and cxreal
322 template <size_t N, typename T> AUTODIFF_DEVICE_FUNC auto operator/(const cxreal<N, T> &x, const complex<double> &y)
323 {
324 cxreal<N, T> res;
325 autodiff::detail::For<0, N + 1>([&](auto i) constexpr { res[i] = x[i] / y; });
326 return res;
327 }
328 template <size_t N, typename T> AUTODIFF_DEVICE_FUNC auto operator/(const complex<double> &x, const cxreal<N, T> &y)
329 {
330 cxreal<N, T> ux(x);
331 cxreal<N, T> uy(y);
332 return ux /= uy;
333 }
334
335 // operators for division of double and cxreal
336 template <size_t N, typename T> AUTODIFF_DEVICE_FUNC auto operator/(const double x, const cxreal<N, T> &y)
337 {
338 cxreal<N, T> res;
339 res[0] = x;
340 autodiff::detail::For<N + 1>([&](auto i) constexpr {
341 res[i] -= autodiff::detail::Sum<0, i>([&](auto j) constexpr {
342 constexpr auto c = autodiff::detail::BinomialCoefficient<i.index, j.index>;
343 return c * res[j] * y[i - j];
344 });
345 res[i] /= y[0];
346 });
347 return res;
348 }
349
350 // ------------------------------------------------------------------
351 // operators for complex<T1> and T2
352 // ------------------------------------------------------------------
353
354 // operators for multiplication of float and complex
355 template <typename T1, typename T2>
356 requires(!std::is_same_v<T1, T2>) && std::is_arithmetic_v<T1> && std::is_arithmetic_v<T2>
357 AUTODIFF_DEVICE_FUNC auto operator*(const T1 x, const complex<T2> y)
358 {
359 return complex<decltype(T1(1.) * T2(1.))>(x * y.real(), x * y.imag());
360 }
361 template <typename T1, typename T2>
362 requires(!std::is_same_v<T1, T2>) && std::is_arithmetic_v<T1> && std::is_arithmetic_v<T2>
363 AUTODIFF_DEVICE_FUNC auto operator*(const complex<T1> &x, const T2 &y)
364 {
365 return complex<decltype(T1(1.) * T2(1.))>(y * x.real(), y * x.imag());
366 }
367 // operators for addition of real and complex
368 template <typename T1, typename T2>
369 requires(!std::is_same_v<T1, T2>) && std::is_arithmetic_v<T1> && std::is_arithmetic_v<T2>
370 AUTODIFF_DEVICE_FUNC auto operator+(const T1 &x, const complex<T2> &y)
371 {
372 return complex<decltype(T1(1.) + T2(1.))>(x + y.real(), y.imag());
373 }
374 template <typename T1, typename T2>
375 requires(!std::is_same_v<T1, T2>) && std::is_arithmetic_v<T1> && std::is_arithmetic_v<T2>
376 AUTODIFF_DEVICE_FUNC auto operator+(const complex<T1> &x, const T2 &y)
377 {
378 return complex<decltype(T1(1.) + T2(1.))>(x.real() + y, x.imag());
379 }
380 // operators for subtraction of real and complex
381 template <typename T1, typename T2>
382 requires(!std::is_same_v<T1, T2>) && std::is_arithmetic_v<T1> && std::is_arithmetic_v<T2>
383 AUTODIFF_DEVICE_FUNC auto operator-(const T1 &x, const complex<T2> &y)
384 {
385 return complex<decltype(T1(1.) + T2(1.))>(x - y.real(), -y.imag());
386 }
387 template <typename T1, typename T2>
388 requires(!std::is_same_v<T1, T2>) && std::is_arithmetic_v<T1> && std::is_arithmetic_v<T2>
389 AUTODIFF_DEVICE_FUNC auto operator-(const complex<T1> &x, const T2 &y)
390 {
391 return complex<decltype(T1(1.) + T2(1.))>(x.real() - y, x.imag());
392 }
393 // operators for division of real and complex
394 template <typename T1, typename T2>
395 requires(!std::is_same_v<T1, T2>) && std::is_arithmetic_v<T1> && std::is_arithmetic_v<T2>
396 AUTODIFF_DEVICE_FUNC auto operator/(const T1 &x, const complex<T2> &y)
397 {
398 return complex<decltype(T1(1.) + T2(1.))>(x * y.real(), -x * y.imag()) / (powr<2>(y.real()) + powr<2>(y.imag()));
399 }
400 template <typename T1, typename T2>
401 requires(!std::is_same_v<T1, T2>) && std::is_arithmetic_v<T1> && std::is_arithmetic_v<T2>
402 AUTODIFF_DEVICE_FUNC auto operator/(const complex<T1> x, const T2 &y)
403 {
404 return complex<decltype(T1(1.) + T2(1.))>(x.real() / y, x.imag() / y);
405 }
406} // namespace DiFfRG
Definition complex_math.hh:14
AUTODIFF_DEVICE_FUNC auto operator/(const autodiff::Real< N, T > &x, const complex< double > &y)
Definition complex_math.hh:215
constexpr __forceinline__ __host__ __device__ NumberType powr(const NumberType x)
A compile-time evaluatable power function for whole number exponents.
Definition math.hh:45
constexpr auto cot(const NT x)
Definition complex_math.hh:28
AUTODIFF_DEVICE_FUNC auto operator+(const autodiff::Real< N, T > &x, const complex< double > &y)
Definition complex_math.hh:181
AUTODIFF_DEVICE_FUNC auto operator*(const autodiff::Real< N, T > &x, const complex< double > &y)
Definition complex_math.hh:166
AUTODIFF_DEVICE_FUNC auto real(const autodiff::Real< N, T > &a)
Definition complex_math.hh:148
autodiff::Real< 1, complex< double > > cxReal
Definition complex_math.hh:139
AUTODIFF_DEVICE_FUNC auto operator-(const autodiff::Real< N, T > &x, const complex< double > &y)
Definition complex_math.hh:198
autodiff::Real< N, complex< T > > cxreal
Definition complex_math.hh:138
constexpr AUTODIFF_DEVICE_FUNC auto imag(const autodiff::Real< N, T > &)
Definition complex_math.hh:149
Definition complex_math.hh:59
Definition complex_math.hh:141