alpaka
Abstraction Library for Parallel Kernel Acceleration
Loading...
Searching...
No Matches
Complex.hpp
Go to the documentation of this file.
1/* Copyright 2024 Sergei Bastrakov, Aurora Perego
2 * SPDX-License-Identifier: MPL-2.0
3 */
4
5#pragma once
6
11
12#include <cmath>
13#include <complex>
14#include <iostream>
15#include <type_traits>
16
17namespace alpaka
18{
19 namespace internal
20 {
21 //! Implementation of a complex number useable on host and device.
22 //!
23 //! It follows the layout of std::complex and so array-oriented access.
24 //! The class template implements all methods and operators as std::complex<T>.
25 //! Additionally, it provides an implicit conversion to and from std::complex<T>.
26 //! All methods besides operators << and >> are host-device.
27 //! It does not provide non-member functions of std::complex besides the operators.
28 //! Those are provided the same way as alpaka math functions for real numbers.
29 //!
30 //! Note that unlike most of alpaka, this is a concrete type template, and not merely a concept.
31 //!
32 //! Naming and order of the methods match https://en.cppreference.com/w/cpp/numeric/complex in C++17.
33 //! Implementation chose to not extend it e.g. by adding constexpr to some places that would get it in C++20.
34 //! The motivation is that with internal conversion to std::complex<T> for CPU backends, it would define the
35 //! common interface for generic code anyways. So it is more clear to have alpaka's interface exactly matching
36 //! when possible, and not "improving".
37 //!
38 //! @tparam T type of the real and imaginary part: float, double, or long double.
39 template<typename T>
40 class Complex
41 {
42 public:
43 // Make sure the input type is floating-point
44 static_assert(std::is_floating_point_v<T>);
45
46 //! Type of the real and imaginary parts
47 using value_type = T;
48
49 //! Constructor from the given real and imaginary parts
50 constexpr ALPAKA_FN_HOST_ACC Complex(T const& real = T{}, T const& imag = T{}) : m_real(real), m_imag(imag)
51 {
52 }
53
54 //! Copy constructor
55 constexpr Complex(Complex const& other) = default;
56
57 //! Constructor from Complex of another type
58 template<typename U>
59 constexpr ALPAKA_FN_HOST_ACC Complex(Complex<U> const& other)
60 : m_real(static_cast<T>(other.real()))
61 , m_imag(static_cast<T>(other.imag()))
62 {
63 }
64
65 //! Constructor from std::complex
66 constexpr ALPAKA_FN_HOST_ACC Complex(std::complex<T> const& other)
67 : m_real(other.real())
68 , m_imag(other.imag())
69 {
70 }
71
72 //! Conversion to std::complex
73 constexpr ALPAKA_FN_HOST_ACC operator std::complex<T>() const
74 {
75 return std::complex<T>{m_real, m_imag};
76 }
77
78 //! Assignment
79 Complex& operator=(Complex const&) = default;
80
81 //! Get the real part
82 constexpr ALPAKA_FN_HOST_ACC T real() const
83 {
84 return m_real;
85 }
86
87 //! Set the real part
88 constexpr ALPAKA_FN_HOST_ACC void real(T value)
89 {
90 m_real = value;
91 }
92
93 //! Get the imaginary part
94 constexpr ALPAKA_FN_HOST_ACC T imag() const
95 {
96 return m_imag;
97 }
98
99 //! Set the imaginary part
100 constexpr ALPAKA_FN_HOST_ACC void imag(T value)
101 {
102 m_imag = value;
103 }
104
105 //! Addition assignment with a real number
107 {
108 m_real += other;
109 return *this;
110 }
111
112 //! Addition assignment with a complex number
113 template<typename U>
115 {
116 m_real += static_cast<T>(other.real());
117 m_imag += static_cast<T>(other.imag());
118 return *this;
119 }
120
121 //! Subtraction assignment with a real number
123 {
124 m_real -= other;
125 return *this;
126 }
127
128 //! Subtraction assignment with a complex number
129 template<typename U>
131 {
132 m_real -= static_cast<T>(other.real());
133 m_imag -= static_cast<T>(other.imag());
134 return *this;
135 }
136
137 //! Multiplication assignment with a real number
139 {
140 m_real *= other;
141 m_imag *= other;
142 return *this;
143 }
144
145 //! Multiplication assignment with a complex number
146 template<typename U>
148 {
149 auto const newReal = m_real * static_cast<T>(other.real()) - m_imag * static_cast<T>(other.imag());
150 auto const newImag = m_imag * static_cast<T>(other.real()) + m_real * static_cast<T>(other.imag());
151 m_real = newReal;
152 m_imag = newImag;
153 return *this;
154 }
155
156 //! Division assignment with a real number
158 {
159 m_real /= other;
160 m_imag /= other;
161 return *this;
162 }
163
164 //! Division assignment with a complex number
165 template<typename U>
167 {
168 return *this *= Complex{
169 static_cast<T>(other.real() / (other.real() * other.real() + other.imag() * other.imag())),
170 static_cast<T>(
171 -other.imag() / (other.real() * other.real() + other.imag() * other.imag()))};
172 }
173
174 private:
175 //! Real and imaginary parts, storage enables array-oriented access
176 T m_real, m_imag;
177 };
178
179 //! Host-device arithmetic operations matching std::complex<T>.
180 //!
181 //! They take and return alpaka::Complex.
182 //!
183 //! @{
184 //!
185
186 //! Unary plus (added for compatibility with std::complex)
187 template<typename T>
189 {
190 return val;
191 }
192
193 //! Unary minus
194 template<typename T>
196 {
197 return Complex<T>{-val.real(), -val.imag()};
198 }
199
200 //! Addition of two complex numbers
201 template<typename T>
203 {
204 return Complex<T>{lhs.real() + rhs.real(), lhs.imag() + rhs.imag()};
205 }
206
207 //! Addition of a complex and a real number
208 template<typename T>
210 {
211 return Complex<T>{lhs.real() + rhs, lhs.imag()};
212 }
213
214 //! Addition of a real and a complex number
215 template<typename T>
217 {
218 return Complex<T>{lhs + rhs.real(), rhs.imag()};
219 }
220
221 //! Subtraction of two complex numbers
222 template<typename T>
224 {
225 return Complex<T>{lhs.real() - rhs.real(), lhs.imag() - rhs.imag()};
226 }
227
228 //! Subtraction of a complex and a real number
229 template<typename T>
231 {
232 return Complex<T>{lhs.real() - rhs, lhs.imag()};
233 }
234
235 //! Subtraction of a real and a complex number
236 template<typename T>
238 {
239 return Complex<T>{lhs - rhs.real(), -rhs.imag()};
240 }
241
242 //! Muptiplication of two complex numbers
243 template<typename T>
245 {
246 return Complex<T>{
247 lhs.real() * rhs.real() - lhs.imag() * rhs.imag(),
248 lhs.imag() * rhs.real() + lhs.real() * rhs.imag()};
249 }
250
251 //! Muptiplication of a complex and a real number
252 template<typename T>
254 {
255 return Complex<T>{lhs.real() * rhs, lhs.imag() * rhs};
256 }
257
258 //! Muptiplication of a real and a complex number
259 template<typename T>
261 {
262 return Complex<T>{lhs * rhs.real(), lhs * rhs.imag()};
263 }
264
265 //! Division of two complex numbers
266 template<typename T>
268 {
269 return Complex<T>{
270 (lhs.real() * rhs.real() + lhs.imag() * rhs.imag())
271 / (rhs.real() * rhs.real() + rhs.imag() * rhs.imag()),
272 (lhs.imag() * rhs.real() - lhs.real() * rhs.imag())
273 / (rhs.real() * rhs.real() + rhs.imag() * rhs.imag())};
274 }
275
276 //! Division of complex and a real number
277 template<typename T>
279 {
280 return Complex<T>{lhs.real() / rhs, lhs.imag() / rhs};
281 }
282
283 //! Division of a real and a complex number
284 template<typename T>
286 {
287 return Complex<T>{
288 lhs * rhs.real() / (rhs.real() * rhs.real() + rhs.imag() * rhs.imag()),
289 -lhs * rhs.imag() / (rhs.real() * rhs.real() + rhs.imag() * rhs.imag())};
290 }
291
292 //! Equality of two complex numbers
293 template<typename T>
294 constexpr ALPAKA_FN_HOST_ACC bool operator==(Complex<T> const& lhs, Complex<T> const& rhs)
295 {
296 return math::floatEqualExactNoWarning(lhs.real(), rhs.real())
298 }
299
300 //! Equality of a complex and a real number
301 template<typename T>
302 constexpr ALPAKA_FN_HOST_ACC bool operator==(Complex<T> const& lhs, T const& rhs)
303 {
304 return math::floatEqualExactNoWarning(lhs.real(), rhs)
305 && math::floatEqualExactNoWarning(lhs.imag(), static_cast<T>(0));
306 }
307
308 //! Equality of a real and a complex number
309 template<typename T>
310 constexpr ALPAKA_FN_HOST_ACC bool operator==(T const& lhs, Complex<T> const& rhs)
311 {
312 return math::floatEqualExactNoWarning(lhs, rhs.real())
313 && math::floatEqualExactNoWarning(static_cast<T>(0), rhs.imag());
314 }
315
316 //! Inequality of two complex numbers.
317 //!
318 //! @note this and other versions of operator != should be removed since C++20, as so does std::complex
319 template<typename T>
320 constexpr ALPAKA_FN_HOST_ACC bool operator!=(Complex<T> const& lhs, Complex<T> const& rhs)
321 {
322 return !(lhs == rhs);
323 }
324
325 //! Inequality of a complex and a real number
326 template<typename T>
327 constexpr ALPAKA_FN_HOST_ACC bool operator!=(Complex<T> const& lhs, T const& rhs)
328 {
329 return !math::floatEqualExactNoWarning(lhs.real(), rhs)
330 || !math::floatEqualExactNoWarning(lhs.imag(), static_cast<T>(0));
331 }
332
333 //! Inequality of a real and a complex number
334 template<typename T>
335 constexpr ALPAKA_FN_HOST_ACC bool operator!=(T const& lhs, Complex<T> const& rhs)
336 {
337 return !math::floatEqualExactNoWarning(lhs, rhs.real())
338 || !math::floatEqualExactNoWarning(static_cast<T>(0), rhs.imag());
339 }
340
341 //! @}
342
343 //! Host-only output of a complex number
344 template<typename T, typename TChar, typename TTraits>
345 std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& os, Complex<T> const& x)
346 {
347 os << x.operator std::complex<T>();
348 return os;
349 }
350
351 //! Host-only input of a complex number
352 template<typename T, typename TChar, typename TTraits>
353 std::basic_istream<TChar, TTraits>& operator>>(std::basic_istream<TChar, TTraits>& is, Complex<T> const& x)
354 {
355 std::complex<T> z;
356 is >> z;
357 x = z;
358 return is;
359 }
360
361 //! Host-only math functions matching std::complex<T>.
362 //!
363 //! Due to issue #1688, these functions are technically marked host-device and suppress related warnings.
364 //! However, they must be called for host only.
365 //!
366 //! They take and return alpaka::Complex (or a real number when appropriate).
367 //! Internally cast, fall back to std::complex implementation and cast back.
368 //! These functions can be used directly on the host side.
369 //! They are also picked up by ADL in math traits for CPU backends.
370 //!
371 //! On the device side, alpaka math traits must be used instead.
372 //! Note that the set of the traits is currently a bit smaller.
373 //!
374 //! @{
375 //!
376
377 //! Absolute value
379 template<typename T>
380 constexpr ALPAKA_FN_HOST_ACC T abs(Complex<T> const& x)
381 {
382 return std::abs(std::complex<T>(x));
383 }
384
385 //! Arc cosine
387 template<typename T>
389 {
390 return std::acos(std::complex<T>(x));
391 }
392
393 //! Arc hyperbolic cosine
395 template<typename T>
397 {
398 return std::acosh(std::complex<T>(x));
399 }
400
401 //! Argument
403 template<typename T>
404 constexpr ALPAKA_FN_HOST_ACC T arg(Complex<T> const& x)
405 {
406 return std::arg(std::complex<T>(x));
407 }
408
409 //! Arc sine
411 template<typename T>
413 {
414 return std::asin(std::complex<T>(x));
415 }
416
417 //! Arc hyperbolic sine
419 template<typename T>
421 {
422 return std::asinh(std::complex<T>(x));
423 }
424
425 //! Arc tangent
427 template<typename T>
429 {
430 return std::atan(std::complex<T>(x));
431 }
432
433 //! Arc hyperbolic tangent
435 template<typename T>
437 {
438 return std::atanh(std::complex<T>(x));
439 }
440
441 //! Complex conjugate
443 template<typename T>
445 {
446 return std::conj(std::complex<T>(x));
447 }
448
449 //! Cosine
451 template<typename T>
453 {
454 return std::cos(std::complex<T>(x));
455 }
456
457 //! Hyperbolic cosine
459 template<typename T>
461 {
462 return std::cosh(std::complex<T>(x));
463 }
464
465 //! Exponential
467 template<typename T>
469 {
470 return std::exp(std::complex<T>(x));
471 }
472
473 //! Natural logarithm
475 template<typename T>
477 {
478 return std::log(std::complex<T>(x));
479 }
480
481 //! Base 10 logarithm
483 template<typename T>
485 {
486 return std::log10(std::complex<T>(x));
487 }
488
489 //! Squared magnitude
491 template<typename T>
492 constexpr ALPAKA_FN_HOST_ACC T norm(Complex<T> const& x)
493 {
494 return std::norm(std::complex<T>(x));
495 }
496
497 //! Get a complex number with given magnitude and phase angle
499 template<typename T>
500 constexpr ALPAKA_FN_HOST_ACC Complex<T> polar(T const& r, T const& theta = T())
501 {
502 return std::polar(r, theta);
503 }
504
505 //! Complex power of a complex number
507 template<typename T, typename U>
508 constexpr ALPAKA_FN_HOST_ACC auto pow(Complex<T> const& x, Complex<U> const& y)
509 {
510 // Use same type promotion as std::pow
511 auto const result = std::pow(std::complex<T>(x), std::complex<U>(y));
512 using ValueType = typename decltype(result)::value_type;
513 return Complex<ValueType>(result);
514 }
515
516 //! Real power of a complex number
518 template<typename T, typename U>
519 constexpr ALPAKA_FN_HOST_ACC auto pow(Complex<T> const& x, U const& y)
520 {
521 return pow(x, Complex<U>(y));
522 }
523
524 //! Complex power of a real number
526 template<typename T, typename U>
527 constexpr ALPAKA_FN_HOST_ACC auto pow(T const& x, Complex<U> const& y)
528 {
529 return pow(Complex<T>(x), y);
530 }
531
532 //! Projection onto the Riemann sphere
534 template<typename T>
536 {
537 return std::proj(std::complex<T>(x));
538 }
539
540 //! Sine
542 template<typename T>
544 {
545 return std::sin(std::complex<T>(x));
546 }
547
548 //! Hyperbolic sine
550 template<typename T>
552 {
553 return std::sinh(std::complex<T>(x));
554 }
555
556 //! Square root
558 template<typename T>
560 {
561 return std::sqrt(std::complex<T>(x));
562 }
563
564 //! Tangent
566 template<typename T>
568 {
569 return std::tan(std::complex<T>(x));
570 }
571
572 //! Hyperbolic tangent
574 template<typename T>
576 {
577 return std::tanh(std::complex<T>(x));
578 }
579
580 //! @}
581 } // namespace internal
582
583 using internal::Complex;
584
585#if defined(ALPAKA_ACC_SYCL_ENABLED) || defined(ALPAKA_ACC_GPU_CUDA_ENABLED) || defined(ALPAKA_ACC_GPU_HIP_ENABLED)
586
587 namespace math::trait
588 {
589
590 //! The abs trait specialization for complex types.
591 template<typename TAcc, typename T>
592 struct Abs<TAcc, Complex<T>>
593 {
594 //! Take context as original (accelerator) type, since we call other math functions
595 template<typename TCtx>
596 ALPAKA_FN_ACC auto operator()(TCtx const& ctx, Complex<T> const& arg)
597 {
598 return sqrt(ctx, arg.real() * arg.real() + arg.imag() * arg.imag());
599 }
600 };
601
602 //! The acos trait specialization for complex types.
603 template<typename TAcc, typename T>
604 struct Acos<TAcc, Complex<T>>
605 {
606 //! Take context as original (accelerator) type, since we call other math functions
607 template<typename TCtx>
608 ALPAKA_FN_ACC auto operator()(TCtx const& ctx, Complex<T> const& arg)
609 {
610 // This holds everywhere, including the branch cuts: acos(z) = -i * ln(z + i * sqrt(1 - z^2))
611 return Complex<T>{static_cast<T>(0.0), static_cast<T>(-1.0)}
612 * log(
613 ctx,
614 arg
615 + Complex<T>{static_cast<T>(0.0), static_cast<T>(1.0)}
616 * sqrt(ctx, static_cast<T>(1.0) - arg * arg));
617 }
618 };
619
620 //! The acosh trait specialization for complex types.
621 template<typename TAcc, typename T>
622 struct Acosh<TAcc, Complex<T>>
623 {
624 //! Take context as original (accelerator) type, since we call other math functions
625 template<typename TCtx>
626 ALPAKA_FN_ACC auto operator()(TCtx const& ctx, Complex<T> const& arg)
627 {
628 // acos(z) = ln(z + sqrt(z-1) * sqrt(z+1))
629 return log(ctx, arg + sqrt(ctx, arg - static_cast<T>(1.0)) * sqrt(ctx, arg + static_cast<T>(1.0)));
630 }
631 };
632
633 //! The arg Complex<T> specialization for complex types.
634 template<typename TAcc, typename T>
635 struct Arg<TAcc, Complex<T>>
636 {
637 //! Take context as original (accelerator) type, since we call other math functions
638 template<typename TCtx>
639 ALPAKA_FN_ACC auto operator()(TCtx const& ctx, Complex<T> const& argument)
640 {
641 return atan2(ctx, argument.imag(), argument.real());
642 }
643 };
644
645 //! The asin trait specialization for complex types.
646 template<typename TAcc, typename T>
647 struct Asin<TAcc, Complex<T>>
648 {
649 //! Take context as original (accelerator) type, since we call other math functions
650 template<typename TCtx>
651 ALPAKA_FN_ACC auto operator()(TCtx const& ctx, Complex<T> const& arg)
652 {
653 // This holds everywhere, including the branch cuts: asin(z) = i * ln(sqrt(1 - z^2) - i * z)
654 return Complex<T>{static_cast<T>(0.0), static_cast<T>(1.0)}
655 * log(
656 ctx,
657 sqrt(ctx, static_cast<T>(1.0) - arg * arg)
658 - Complex<T>{static_cast<T>(0.0), static_cast<T>(1.0)} * arg);
659 }
660 };
661
662 //! The asinh trait specialization for complex types.
663 template<typename TAcc, typename T>
664 struct Asinh<TAcc, Complex<T>>
665 {
666 //! Take context as original (accelerator) type, since we call other math functions
667 template<typename TCtx>
668 ALPAKA_FN_ACC auto operator()(TCtx const& ctx, Complex<T> const& arg)
669 {
670 // asinh(z) = ln(z + sqrt(z^2 + 1))
671 return log(ctx, arg + sqrt(ctx, arg * arg + static_cast<T>(1.0)));
672 }
673 };
674
675 //! The atan trait specialization for complex types.
676 template<typename TAcc, typename T>
677 struct Atan<TAcc, Complex<T>>
678 {
679 //! Take context as original (accelerator) type, since we call other math functions
680 template<typename TCtx>
681 ALPAKA_FN_ACC auto operator()(TCtx const& ctx, Complex<T> const& arg)
682 {
683 // This holds everywhere, including the branch cuts: atan(z) = -i/2 * ln((i - z) / (i + z))
684 return Complex<T>{static_cast<T>(0.0), static_cast<T>(-0.5)}
685 * log(
686 ctx,
687 (Complex<T>{static_cast<T>(0.0), static_cast<T>(1.0)} - arg)
688 / (Complex<T>{static_cast<T>(0.0), static_cast<T>(1.0)} + arg));
689 }
690 };
691
692 //! The atanh trait specialization for complex types.
693 template<typename TAcc, typename T>
694 struct Atanh<TAcc, Complex<T>>
695 {
696 //! Take context as original (accelerator) type, since we call other math functions
697 template<typename TCtx>
698 ALPAKA_FN_ACC auto operator()(TCtx const& ctx, Complex<T> const& arg)
699 {
700 // atanh(z) = 0.5 * (ln(1 + z) - ln(1 - z))
701 return static_cast<T>(0.5)
702 * (log(ctx, static_cast<T>(1.0) + arg) - log(ctx, static_cast<T>(1.0) - arg));
703 }
704 };
705
706 //! The conj specialization for complex types.
707 template<typename TAcc, typename T>
708 struct Conj<TAcc, Complex<T>>
709 {
710 ALPAKA_FN_ACC auto operator()(TAcc const& /* conj_ctx */, Complex<T> const& arg)
711 {
712 return Complex<T>{arg.real(), -arg.imag()};
713 }
714 };
715
716 //! The cos trait specialization for complex types.
717 template<typename TAcc, typename T>
718 struct Cos<TAcc, Complex<T>>
719 {
720 //! Take context as original (accelerator) type, since we call other math functions
721 template<typename TCtx>
722 ALPAKA_FN_ACC auto operator()(TCtx const& ctx, Complex<T> const& arg)
723 {
724 // cos(z) = 0.5 * (exp(i * z) + exp(-i * z))
725 return T(0.5)
726 * (exp(ctx, Complex<T>{static_cast<T>(0.0), static_cast<T>(1.0)} * arg)
727 + exp(ctx, Complex<T>{static_cast<T>(0.0), static_cast<T>(-1.0)} * arg));
728 }
729 };
730
731 //! The cosh trait specialization for complex types.
732 template<typename TAcc, typename T>
733 struct Cosh<TAcc, Complex<T>>
734 {
735 //! Take context as original (accelerator) type, since we call other math functions
736 template<typename TCtx>
737 ALPAKA_FN_ACC auto operator()(TCtx const& ctx, Complex<T> const& arg)
738 {
739 // cosh(z) = 0.5 * (exp(z) + exp(-z))
740 return T(0.5) * (exp(ctx, arg) + exp(ctx, static_cast<T>(-1.0) * arg));
741 }
742 };
743
744 //! The exp trait specialization for complex types.
745 template<typename TAcc, typename T>
746 struct Exp<TAcc, Complex<T>>
747 {
748 //! Take context as original (accelerator) type, since we call other math functions
749 template<typename TCtx>
750 ALPAKA_FN_ACC auto operator()(TCtx const& ctx, Complex<T> const& arg)
751 {
752 // exp(z) = exp(x + iy) = exp(x) * (cos(y) + i * sin(y))
753 auto re = T{}, im = T{};
754 sincos(ctx, arg.imag(), im, re);
755 return exp(ctx, arg.real()) * Complex<T>{re, im};
756 }
757 };
758
759 //! The log trait specialization for complex types.
760 template<typename TAcc, typename T>
761 struct Log<TAcc, Complex<T>>
762 {
763 //! Take context as original (accelerator) type, since we call other math functions
764 template<typename TCtx>
765 ALPAKA_FN_ACC auto operator()(TCtx const& ctx, Complex<T> const& argument)
766 {
767 // Branch cut along the negative real axis (same as for std::complex),
768 // principal value of ln(z) = ln(|z|) + i * arg(z)
769 return log(ctx, abs(ctx, argument))
770 + Complex<T>{static_cast<T>(0.0), static_cast<T>(1.0)} * arg(ctx, argument);
771 }
772 };
773
774 //! The log2 trait specialization for complex types.
775 template<typename TAcc, typename T>
776 struct Log2<TAcc, Complex<T>>
777 {
778 //! Take context as original (accelerator) type, since we call other math functions
779 template<typename TCtx>
780 ALPAKA_FN_ACC auto operator()(TCtx const& ctx, Complex<T> const& argument)
781 {
782 return log(ctx, argument) / log(ctx, static_cast<T>(2));
783 }
784 };
785
786 //! The log10 trait specialization for complex types.
787 template<typename TAcc, typename T>
788 struct Log10<TAcc, Complex<T>>
789 {
790 //! Take context as original (accelerator) type, since we call other math functions
791 template<typename TCtx>
792 ALPAKA_FN_ACC auto operator()(TCtx const& ctx, Complex<T> const& argument)
793 {
794 return log(ctx, argument) / log(ctx, static_cast<T>(10));
795 }
796 };
797
798 //! The pow trait specialization for complex types.
799 template<typename TAcc, typename T, typename U>
800 struct Pow<TAcc, Complex<T>, Complex<U>>
801 {
802 //! Take context as original (accelerator) type, since we call other math functions
803 template<typename TCtx>
804 ALPAKA_FN_ACC auto operator()(TCtx const& ctx, Complex<T> const& base, Complex<U> const& exponent)
805 {
806 // Type promotion matching rules of complex std::pow but simplified given our math only supports float
807 // and double, no long double.
808 using Promoted
809 = Complex<std::conditional_t<is_decayed_v<T, float> && is_decayed_v<U, float>, float, double>>;
810 // pow(z1, z2) = e^(z2 * log(z1))
811 return exp(ctx, Promoted{exponent} * log(ctx, Promoted{base}));
812 }
813 };
814
815 //! The pow trait specialization for complex and real types.
816 template<typename TAcc, typename T, typename U>
817 struct Pow<TAcc, Complex<T>, U>
818 {
819 //! Take context as original (accelerator) type, since we call other math functions
820 template<typename TCtx>
821 ALPAKA_FN_ACC auto operator()(TCtx const& ctx, Complex<T> const& base, U const& exponent)
822 {
823 return pow(ctx, base, Complex<U>{exponent});
824 }
825 };
826
827 //! The pow trait specialization for real and complex types.
828 template<typename TAcc, typename T, typename U>
829 struct Pow<TAcc, T, Complex<U>>
830 {
831 //! Take context as original (accelerator) type, since we call other math functions
832 template<typename TCtx>
833 ALPAKA_FN_ACC auto operator()(TCtx const& ctx, T const& base, Complex<U> const& exponent)
834 {
835 return pow(ctx, Complex<T>{base}, exponent);
836 }
837 };
838
839 //! The rsqrt trait specialization for complex types.
840 template<typename TAcc, typename T>
841 struct Rsqrt<TAcc, Complex<T>>
842 {
843 //! Take context as original (accelerator) type, since we call other math functions
844 template<typename TCtx>
845 ALPAKA_FN_ACC auto operator()(TCtx const& ctx, Complex<T> const& arg)
846 {
847 return static_cast<T>(1.0) / sqrt(ctx, arg);
848 }
849 };
850
851 //! The sin trait specialization for complex types.
852 template<typename TAcc, typename T>
853 struct Sin<TAcc, Complex<T>>
854 {
855 //! Take context as original (accelerator) type, since we call other math functions
856 template<typename TCtx>
857 ALPAKA_FN_ACC auto operator()(TCtx const& ctx, Complex<T> const& arg)
858 {
859 // sin(z) = (exp(i * z) - exp(-i * z)) / 2i
860 return (exp(ctx, Complex<T>{static_cast<T>(0.0), static_cast<T>(1.0)} * arg)
861 - exp(ctx, Complex<T>{static_cast<T>(0.0), static_cast<T>(-1.0)} * arg))
862 / Complex<T>{static_cast<T>(0.0), static_cast<T>(2.0)};
863 }
864 };
865
866 //! The sinh trait specialization for complex types.
867 template<typename TAcc, typename T>
868 struct Sinh<TAcc, Complex<T>>
869 {
870 //! Take context as original (accelerator) type, since we call other math functions
871 template<typename TCtx>
872 ALPAKA_FN_ACC auto operator()(TCtx const& ctx, Complex<T> const& arg)
873 {
874 // sinh(z) = (exp(z) - exp(-i * z)) / 2
875 return (exp(ctx, arg) - exp(ctx, static_cast<T>(-1.0) * arg)) / static_cast<T>(2.0);
876 }
877 };
878
879 //! The sincos trait specialization for complex types.
880 template<typename TAcc, typename T>
881 struct SinCos<TAcc, Complex<T>>
882 {
883 //! Take context as original (accelerator) type, since we call other math functions
884 template<typename TCtx>
886 TCtx const& ctx,
887 Complex<T> const& arg,
888 Complex<T>& result_sin,
889 Complex<T>& result_cos) -> void
890 {
891 result_sin = sin(ctx, arg);
892 result_cos = cos(ctx, arg);
893 }
894 };
895
896 //! The sqrt trait specialization for complex types.
897 template<typename TAcc, typename T>
898 struct Sqrt<TAcc, Complex<T>>
899 {
900 //! Take context as original (accelerator) type, since we call other math functions
901 template<typename TCtx>
902 ALPAKA_FN_ACC auto operator()(TCtx const& ctx, Complex<T> const& argument)
903 {
904 // Branch cut along the negative real axis (same as for std::complex),
905 // principal value of sqrt(z) = sqrt(|z|) * e^(i * arg(z) / 2)
906 auto const halfArg = T(0.5) * arg(ctx, argument);
907 auto re = T{}, im = T{};
908 sincos(ctx, halfArg, im, re);
909 return sqrt(ctx, abs(ctx, argument)) * Complex<T>(re, im);
910 }
911 };
912
913 //! The tan trait specialization for complex types.
914 template<typename TAcc, typename T>
915 struct Tan<TAcc, Complex<T>>
916 {
917 //! Take context as original (accelerator) type, since we call other math functions
918 template<typename TCtx>
919 ALPAKA_FN_ACC auto operator()(TCtx const& ctx, Complex<T> const& arg)
920 {
921 // tan(z) = i * (e^-iz - e^iz) / (e^-iz + e^iz) = i * (1 - e^2iz) / (1 + e^2iz)
922 // Warning: this straightforward implementation can easily result in NaN as 0/0 or inf/inf.
923 auto const expValue = exp(ctx, Complex<T>{static_cast<T>(0.0), static_cast<T>(2.0)} * arg);
924 return Complex<T>{static_cast<T>(0.0), static_cast<T>(1.0)} * (static_cast<T>(1.0) - expValue)
925 / (static_cast<T>(1.0) + expValue);
926 }
927 };
928
929 //! The tanh trait specialization for complex types.
930 template<typename TAcc, typename T>
931 struct Tanh<TAcc, Complex<T>>
932 {
933 //! Take context as original (accelerator) type, since we call other math functions
934 template<typename TCtx>
935 ALPAKA_FN_ACC auto operator()(TCtx const& ctx, Complex<T> const& arg)
936 {
937 // tanh(z) = (e^z - e^-z)/(e^z+e^-z)
938 return (exp(ctx, arg) - exp(ctx, static_cast<T>(-1.0) * arg))
939 / (exp(ctx, arg) + exp(ctx, static_cast<T>(-1.0) * arg));
940 }
941 };
942 } // namespace math::trait
943
944#endif
945
946} // namespace alpaka
Implementation of a complex number useable on host and device.
Definition Complex.hpp:41
ALPAKA_FN_HOST_ACC Complex & operator+=(T const &other)
Addition assignment with a real number.
Definition Complex.hpp:106
constexpr ALPAKA_FN_HOST_ACC T imag() const
Get the imaginary part.
Definition Complex.hpp:94
constexpr ALPAKA_FN_HOST_ACC T real() const
Get the real part.
Definition Complex.hpp:82
ALPAKA_FN_HOST_ACC Complex & operator-=(T const &other)
Subtraction assignment with a real number.
Definition Complex.hpp:122
ALPAKA_FN_HOST_ACC Complex & operator/=(Complex< U > const &other)
Division assignment with a complex number.
Definition Complex.hpp:166
ALPAKA_FN_HOST_ACC Complex & operator-=(Complex< U > const &other)
Subtraction assignment with a complex number.
Definition Complex.hpp:130
constexpr ALPAKA_FN_HOST_ACC void imag(T value)
Set the imaginary part.
Definition Complex.hpp:100
constexpr Complex(Complex const &other)=default
Copy constructor.
ALPAKA_FN_HOST_ACC Complex & operator*=(Complex< U > const &other)
Multiplication assignment with a complex number.
Definition Complex.hpp:147
Complex & operator=(Complex const &)=default
Assignment.
constexpr ALPAKA_FN_HOST_ACC Complex(Complex< U > const &other)
Constructor from Complex of another type.
Definition Complex.hpp:59
constexpr ALPAKA_FN_HOST_ACC void real(T value)
Set the real part.
Definition Complex.hpp:88
ALPAKA_FN_HOST_ACC Complex & operator*=(T const &other)
Multiplication assignment with a real number.
Definition Complex.hpp:138
ALPAKA_FN_HOST_ACC Complex & operator/=(T const &other)
Division assignment with a real number.
Definition Complex.hpp:157
constexpr ALPAKA_FN_HOST_ACC Complex(std::complex< T > const &other)
Constructor from std::complex.
Definition Complex.hpp:66
constexpr ALPAKA_FN_HOST_ACC Complex(T const &real=T{}, T const &imag=T{})
Constructor from the given real and imaginary parts.
Definition Complex.hpp:50
T value_type
Type of the real and imaginary parts.
Definition Complex.hpp:47
ALPAKA_FN_HOST_ACC Complex & operator+=(Complex< U > const &other)
Addition assignment with a complex number.
Definition Complex.hpp:114
#define ALPAKA_FN_ACC
All functions that can be used on an accelerator have to be attributed with ALPAKA_FN_ACC or ALPAKA_F...
Definition Common.hpp:38
#define ALPAKA_FN_HOST_ACC
Definition Common.hpp:39
#define ALPAKA_NO_HOST_ACC_WARNING
Disable nvcc warning: 'calling a host function from host device function.' Usage: ALPAKA_NO_HOST_ACC_...
Definition Common.hpp:82
ALPAKA_NO_HOST_ACC_WARNING constexpr ALPAKA_FN_HOST_ACC Complex< T > tan(Complex< T > const &x)
Tangent.
Definition Complex.hpp:567
ALPAKA_NO_HOST_ACC_WARNING constexpr ALPAKA_FN_HOST_ACC Complex< T > cosh(Complex< T > const &x)
Hyperbolic cosine.
Definition Complex.hpp:460
ALPAKA_NO_HOST_ACC_WARNING constexpr ALPAKA_FN_HOST_ACC auto pow(Complex< T > const &x, Complex< U > const &y)
Complex power of a complex number.
Definition Complex.hpp:508
ALPAKA_NO_HOST_ACC_WARNING constexpr ALPAKA_FN_HOST_ACC Complex< T > acosh(Complex< T > const &x)
Arc hyperbolic cosine.
Definition Complex.hpp:396
ALPAKA_FN_HOST_ACC Complex< T > operator+(Complex< T > const &val)
Host-device arithmetic operations matching std::complex<T>.
Definition Complex.hpp:188
ALPAKA_NO_HOST_ACC_WARNING constexpr ALPAKA_FN_HOST_ACC Complex< T > asinh(Complex< T > const &x)
Arc hyperbolic sine.
Definition Complex.hpp:420
ALPAKA_NO_HOST_ACC_WARNING constexpr ALPAKA_FN_HOST_ACC Complex< T > log(Complex< T > const &x)
Natural logarithm.
Definition Complex.hpp:476
ALPAKA_NO_HOST_ACC_WARNING constexpr ALPAKA_FN_HOST_ACC Complex< T > conj(Complex< T > const &x)
Complex conjugate.
Definition Complex.hpp:444
ALPAKA_FN_HOST_ACC Complex< T > operator-(Complex< T > const &val)
Unary minus.
Definition Complex.hpp:195
constexpr ALPAKA_FN_HOST_ACC bool operator==(Complex< T > const &lhs, Complex< T > const &rhs)
Equality of two complex numbers.
Definition Complex.hpp:294
ALPAKA_NO_HOST_ACC_WARNING constexpr ALPAKA_FN_HOST_ACC Complex< T > polar(T const &r, T const &theta=T())
Get a complex number with given magnitude and phase angle.
Definition Complex.hpp:500
ALPAKA_NO_HOST_ACC_WARNING constexpr ALPAKA_FN_HOST_ACC Complex< T > atanh(Complex< T > const &x)
Arc hyperbolic tangent.
Definition Complex.hpp:436
ALPAKA_NO_HOST_ACC_WARNING constexpr ALPAKA_FN_HOST_ACC T arg(Complex< T > const &x)
Argument.
Definition Complex.hpp:404
ALPAKA_NO_HOST_ACC_WARNING constexpr ALPAKA_FN_HOST_ACC Complex< T > tanh(Complex< T > const &x)
Hyperbolic tangent.
Definition Complex.hpp:575
ALPAKA_NO_HOST_ACC_WARNING constexpr ALPAKA_FN_HOST_ACC Complex< T > sinh(Complex< T > const &x)
Hyperbolic sine.
Definition Complex.hpp:551
ALPAKA_NO_HOST_ACC_WARNING constexpr ALPAKA_FN_HOST_ACC T abs(Complex< T > const &x)
Host-only math functions matching std::complex<T>.
Definition Complex.hpp:380
ALPAKA_NO_HOST_ACC_WARNING constexpr ALPAKA_FN_HOST_ACC Complex< T > sqrt(Complex< T > const &x)
Square root.
Definition Complex.hpp:559
ALPAKA_NO_HOST_ACC_WARNING constexpr ALPAKA_FN_HOST_ACC Complex< T > proj(Complex< T > const &x)
Projection onto the Riemann sphere.
Definition Complex.hpp:535
ALPAKA_NO_HOST_ACC_WARNING constexpr ALPAKA_FN_HOST_ACC T norm(Complex< T > const &x)
Squared magnitude.
Definition Complex.hpp:492
std::basic_istream< TChar, TTraits > & operator>>(std::basic_istream< TChar, TTraits > &is, Complex< T > const &x)
Host-only input of a complex number.
Definition Complex.hpp:353
ALPAKA_NO_HOST_ACC_WARNING constexpr ALPAKA_FN_HOST_ACC Complex< T > acos(Complex< T > const &x)
Arc cosine.
Definition Complex.hpp:388
ALPAKA_NO_HOST_ACC_WARNING constexpr ALPAKA_FN_HOST_ACC Complex< T > cos(Complex< T > const &x)
Cosine.
Definition Complex.hpp:452
ALPAKA_NO_HOST_ACC_WARNING constexpr ALPAKA_FN_HOST_ACC Complex< T > sin(Complex< T > const &x)
Sine.
Definition Complex.hpp:543
ALPAKA_NO_HOST_ACC_WARNING constexpr ALPAKA_FN_HOST_ACC Complex< T > asin(Complex< T > const &x)
Arc sine.
Definition Complex.hpp:412
std::basic_ostream< TChar, TTraits > & operator<<(std::basic_ostream< TChar, TTraits > &os, Complex< T > const &x)
Host-only output of a complex number.
Definition Complex.hpp:345
ALPAKA_NO_HOST_ACC_WARNING constexpr ALPAKA_FN_HOST_ACC Complex< T > log10(Complex< T > const &x)
Base 10 logarithm.
Definition Complex.hpp:484
ALPAKA_FN_HOST_ACC Complex< T > operator*(Complex< T > const &lhs, Complex< T > const &rhs)
Muptiplication of two complex numbers.
Definition Complex.hpp:244
ALPAKA_FN_HOST_ACC Complex< T > operator/(Complex< T > const &lhs, Complex< T > const &rhs)
Division of two complex numbers.
Definition Complex.hpp:267
ALPAKA_NO_HOST_ACC_WARNING constexpr ALPAKA_FN_HOST_ACC Complex< T > atan(Complex< T > const &x)
Arc tangent.
Definition Complex.hpp:428
constexpr ALPAKA_FN_HOST_ACC bool operator!=(Complex< T > const &lhs, Complex< T > const &rhs)
Inequality of two complex numbers.
Definition Complex.hpp:320
ALPAKA_NO_HOST_ACC_WARNING constexpr ALPAKA_FN_HOST_ACC Complex< T > exp(Complex< T > const &x)
Exponential.
Definition Complex.hpp:468
ALPAKA_NO_HOST_ACC_WARNING ALPAKA_FN_HOST_ACC auto pow(T const &pow_ctx, TBase const &base, TExp const &exp)
Computes the value of base raised to the power exp.
Definition Traits.hpp:1300
ALPAKA_NO_HOST_ACC_WARNING ALPAKA_FN_HOST_ACC auto sqrt(T const &sqrt_ctx, TArg const &arg)
Computes the square root of arg.
Definition Traits.hpp:1441
ALPAKA_NO_HOST_ACC_WARNING ALPAKA_FN_HOST_ACC auto exp(T const &exp_ctx, TArg const &arg)
Computes the e (Euler's number, 2.7182818) raised to the given power arg.
Definition Traits.hpp:1102
ALPAKA_NO_HOST_ACC_WARNING ALPAKA_FN_HOST_ACC auto cos(T const &cos_ctx, TArg const &arg)
Computes the cosine (measured in radians).
Definition Traits.hpp:1060
ALPAKA_NO_HOST_ACC_WARNING ALPAKA_FN_HOST_ACC auto sincos(T const &sincos_ctx, TArg const &arg, TArg &result_sin, TArg &result_cos) -> void
Computes the sine and cosine (measured in radians).
Definition Traits.hpp:1423
ALPAKA_NO_HOST_ACC_WARNING ALPAKA_FN_HOST_ACC auto atan2(T const &atan2_ctx, Ty const &y, Tx const &x)
Computes the arc tangent of y/x using the signs of arguments to determine the correct quadrant.
Definition Traits.hpp:988
ALPAKA_NO_HOST_ACC_WARNING ALPAKA_FN_HOST_ACC auto sin(T const &sin_ctx, TArg const &arg)
Computes the sine (measured in radians).
Definition Traits.hpp:1393
ALPAKA_FN_INLINE ALPAKA_FN_HOST_ACC auto floatEqualExactNoWarning(T a, T b) -> bool
ALPAKA_NO_HOST_ACC_WARNING ALPAKA_FN_HOST_ACC auto abs(T const &abs_ctx, TArg const &arg)
Computes the absolute value.
Definition Traits.hpp:864
ALPAKA_NO_HOST_ACC_WARNING ALPAKA_FN_HOST_ACC auto log(T const &log_ctx, TArg const &arg)
Computes the the natural (base e) logarithm of arg.
Definition Traits.hpp:1210
ALPAKA_NO_HOST_ACC_WARNING ALPAKA_FN_HOST_ACC auto arg(T const &arg_ctx, TArgument const &argument)
Computes the complex argument of the value.
Definition Traits.hpp:912
The alpaka accelerator library.
ALPAKA_FN_HOST_ACC auto operator()(T const &, TArg const &arg)
Definition Traits.hpp:298
ALPAKA_FN_HOST_ACC auto operator()(T const &, TArg const &arg)
Definition Traits.hpp:311
ALPAKA_FN_HOST_ACC auto operator()(T const &, TArg const &arg)
Definition Traits.hpp:324
ALPAKA_NO_HOST_ACC_WARNING ALPAKA_FN_HOST_ACC auto operator()(T const &, TArgument const &argument)
Definition Traits.hpp:340
ALPAKA_FN_HOST_ACC auto operator()(T const &, TArg const &arg)
Definition Traits.hpp:353
ALPAKA_FN_HOST_ACC auto operator()(T const &, TArg const &arg)
Definition Traits.hpp:366
ALPAKA_FN_HOST_ACC auto operator()(T const &, TArg const &arg)
Definition Traits.hpp:379
ALPAKA_FN_HOST_ACC auto operator()(T const &, TArg const &arg)
Definition Traits.hpp:392
ALPAKA_FN_HOST_ACC auto operator()(T const &, TArg const &arg)
Definition Traits.hpp:444
ALPAKA_FN_HOST_ACC auto operator()(T const &, TArg const &arg)
Definition Traits.hpp:470
ALPAKA_FN_HOST_ACC auto operator()(T const &, TArg const &arg)
Definition Traits.hpp:483
ALPAKA_FN_HOST_ACC auto operator()(T const &, TArg const &arg)
Definition Traits.hpp:508
ALPAKA_FN_HOST_ACC auto operator()(T const &, TArg const &arg)
Definition Traits.hpp:625
ALPAKA_FN_HOST_ACC auto operator()(T const &, TArg const &arg)
Definition Traits.hpp:612
ALPAKA_FN_HOST_ACC auto operator()(T const &, TArg const &arg)
Definition Traits.hpp:599
ALPAKA_FN_HOST_ACC auto operator()(T const &, TBase const &base, TExp const &exp)
Definition Traits.hpp:664
ALPAKA_FN_HOST_ACC auto operator()(T const &, TArg const &arg)
Definition Traits.hpp:741
ALPAKA_FN_HOST_ACC auto operator()(T const &, TArg const &arg, TArg &result_sin, TArg &result_cos)
Definition Traits.hpp:794
ALPAKA_FN_HOST_ACC auto operator()(T const &, TArg const &arg)
Definition Traits.hpp:754
ALPAKA_FN_HOST_ACC auto operator()(T const &, TArg const &arg)
Definition Traits.hpp:767
ALPAKA_FN_HOST_ACC auto operator()(T const &, TArg const &arg)
Definition Traits.hpp:807
ALPAKA_FN_HOST_ACC auto operator()(T const &, TArg const &arg)
Definition Traits.hpp:820
ALPAKA_FN_HOST_ACC auto operator()(T const &, TArg const &arg)
Definition Traits.hpp:833