Kokkos Core Kernels Package Version of the Day
Loading...
Searching...
No Matches
Kokkos_Complex.hpp
1//@HEADER
2// ************************************************************************
3//
4// Kokkos v. 4.0
5// Copyright (2022) National Technology & Engineering
6// Solutions of Sandia, LLC (NTESS).
7//
8// Under the terms of Contract DE-NA0003525 with NTESS,
9// the U.S. Government retains certain rights in this software.
10//
11// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
12// See https://kokkos.org/LICENSE for license information.
13// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
14//
15//@HEADER
16#ifndef KOKKOS_COMPLEX_HPP
17#define KOKKOS_COMPLEX_HPP
18#ifndef KOKKOS_IMPL_PUBLIC_INCLUDE
19#define KOKKOS_IMPL_PUBLIC_INCLUDE
20#define KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_COMPLEX
21#endif
22
23#include <Kokkos_Atomic.hpp>
24#include <Kokkos_MathematicalFunctions.hpp>
25#include <Kokkos_NumericTraits.hpp>
26#include <Kokkos_ReductionIdentity.hpp>
27#include <impl/Kokkos_Error.hpp>
28#include <complex>
29#include <type_traits>
30#include <iosfwd>
31#include <tuple>
32
33namespace Kokkos {
34
42template <class RealType>
43class
44#ifdef KOKKOS_ENABLE_COMPLEX_ALIGN
45 alignas(2 * sizeof(RealType))
46#endif
47 complex {
48 static_assert(std::is_floating_point_v<RealType> &&
49 std::is_same_v<RealType, std::remove_cv_t<RealType>>,
50 "Kokkos::complex can only be instantiated for a cv-unqualified "
51 "floating point type");
52
53 private:
54 RealType re_{};
55 RealType im_{};
56
57 public:
59 using value_type = RealType;
60
62 KOKKOS_DEFAULTED_FUNCTION
63 complex() = default;
64
66 KOKKOS_DEFAULTED_FUNCTION
67 complex(const complex&) noexcept = default;
68
69 KOKKOS_DEFAULTED_FUNCTION
70 complex& operator=(const complex&) noexcept = default;
71
73 template <class RType,
74 std::enable_if_t<std::is_convertible_v<RType, RealType>, int> = 0>
75 KOKKOS_INLINE_FUNCTION complex(const complex<RType>& other) noexcept
76 // Intentionally do the conversions implicitly here so that users don't
77 // get any warnings about narrowing, etc., that they would expect to get
78 // otherwise.
79 : re_(other.real()), im_(other.imag()) {}
80
86 KOKKOS_INLINE_FUNCTION
87 complex(const std::complex<RealType>& src) noexcept
88 // We can use this aspect of the standard to avoid calling
89 // non-device-marked functions `std::real` and `std::imag`: "For any
90 // object z of type complex<T>, reinterpret_cast<T(&)[2]>(z)[0] is the
91 // real part of z and reinterpret_cast<T(&)[2]>(z)[1] is the imaginary
92 // part of z." Now we don't have to provide a whole bunch of the overloads
93 // of things taking either Kokkos::complex or std::complex
94 : re_(reinterpret_cast<const RealType (&)[2]>(src)[0]),
95 im_(reinterpret_cast<const RealType (&)[2]>(src)[1]) {}
96
102 // TODO: make explicit. DJS 2019-08-28
103 operator std::complex<RealType>() const noexcept {
104 return std::complex<RealType>(re_, im_);
105 }
106
109 KOKKOS_INLINE_FUNCTION complex(const RealType& val) noexcept
110 : re_(val), im_(static_cast<RealType>(0)) {}
111
113 KOKKOS_INLINE_FUNCTION
114 complex(const RealType& re, const RealType& im) noexcept : re_(re), im_(im) {}
115
117 KOKKOS_INLINE_FUNCTION complex& operator=(const RealType& val) noexcept {
118 re_ = val;
119 im_ = RealType(0);
120 return *this;
121 }
122
128 complex& operator=(const std::complex<RealType>& src) noexcept {
129 *this = complex(src);
130 return *this;
131 }
132
134 KOKKOS_INLINE_FUNCTION
135 constexpr RealType& imag() noexcept { return im_; }
136
138 KOKKOS_INLINE_FUNCTION
139 constexpr RealType& real() noexcept { return re_; }
140
142 KOKKOS_INLINE_FUNCTION
143 constexpr RealType imag() const noexcept { return im_; }
144
146 KOKKOS_INLINE_FUNCTION
147 constexpr RealType real() const noexcept { return re_; }
148
150 KOKKOS_INLINE_FUNCTION
151 constexpr void imag(RealType v) noexcept { im_ = v; }
152
154 KOKKOS_INLINE_FUNCTION
155 constexpr void real(RealType v) noexcept { re_ = v; }
156
157 constexpr KOKKOS_INLINE_FUNCTION complex& operator+=(
158 const complex<RealType>& src) noexcept {
159 re_ += src.re_;
160 im_ += src.im_;
161 return *this;
162 }
163
164 constexpr KOKKOS_INLINE_FUNCTION complex& operator+=(
165 const RealType& src) noexcept {
166 re_ += src;
167 return *this;
168 }
169
170 constexpr KOKKOS_INLINE_FUNCTION complex& operator-=(
171 const complex<RealType>& src) noexcept {
172 re_ -= src.re_;
173 im_ -= src.im_;
174 return *this;
175 }
176
177 constexpr KOKKOS_INLINE_FUNCTION complex& operator-=(
178 const RealType& src) noexcept {
179 re_ -= src;
180 return *this;
181 }
182
183 constexpr KOKKOS_INLINE_FUNCTION complex& operator*=(
184 const complex<RealType>& src) noexcept {
185 const RealType realPart = re_ * src.re_ - im_ * src.im_;
186 const RealType imagPart = re_ * src.im_ + im_ * src.re_;
187 re_ = realPart;
188 im_ = imagPart;
189 return *this;
190 }
191
192 constexpr KOKKOS_INLINE_FUNCTION complex& operator*=(
193 const RealType& src) noexcept {
194 re_ *= src;
195 im_ *= src;
196 return *this;
197 }
198
199 // Conditional noexcept, just in case RType throws on divide-by-zero
200 constexpr KOKKOS_INLINE_FUNCTION complex& operator/=(
201 const complex<RealType>& y) noexcept(noexcept(RealType{} / RealType{})) {
202 // Scale (by the "1-norm" of y) to avoid unwarranted overflow.
203 // If the real part is +/-Inf and the imaginary part is -/+Inf,
204 // this won't change the result.
205 const RealType s = fabs(y.real()) + fabs(y.imag());
206
207 // If s is 0, then y is zero, so x/y == real(x)/0 + i*imag(x)/0.
208 // In that case, the relation x/y == (x/s) / (y/s) doesn't hold,
209 // because y/s is NaN.
210 // TODO mark this branch unlikely
211 if (s == RealType(0)) {
212 this->re_ /= s;
213 this->im_ /= s;
214 } else {
215 const complex x_scaled(this->re_ / s, this->im_ / s);
216 const complex y_conj_scaled(y.re_ / s, -(y.im_) / s);
217 const RealType y_scaled_abs =
218 y_conj_scaled.re_ * y_conj_scaled.re_ +
219 y_conj_scaled.im_ * y_conj_scaled.im_; // abs(y) == abs(conj(y))
220 *this = x_scaled * y_conj_scaled;
221 *this /= y_scaled_abs;
222 }
223 return *this;
224 }
225
226 constexpr KOKKOS_INLINE_FUNCTION complex& operator/=(
227 const std::complex<RealType>& y) noexcept(noexcept(RealType{} /
228 RealType{})) {
229 // Scale (by the "1-norm" of y) to avoid unwarranted overflow.
230 // If the real part is +/-Inf and the imaginary part is -/+Inf,
231 // this won't change the result.
232 const RealType s = fabs(y.real()) + fabs(y.imag());
233
234 // If s is 0, then y is zero, so x/y == real(x)/0 + i*imag(x)/0.
235 // In that case, the relation x/y == (x/s) / (y/s) doesn't hold,
236 // because y/s is NaN.
237 if (s == RealType(0)) {
238 this->re_ /= s;
239 this->im_ /= s;
240 } else {
241 const complex x_scaled(this->re_ / s, this->im_ / s);
242 const complex y_conj_scaled(y.re_ / s, -(y.im_) / s);
243 const RealType y_scaled_abs =
244 y_conj_scaled.re_ * y_conj_scaled.re_ +
245 y_conj_scaled.im_ * y_conj_scaled.im_; // abs(y) == abs(conj(y))
246 *this = x_scaled * y_conj_scaled;
247 *this /= y_scaled_abs;
248 }
249 return *this;
250 }
251
252 constexpr KOKKOS_INLINE_FUNCTION complex& operator/=(
253 const RealType& src) noexcept(noexcept(RealType{} / RealType{})) {
254 re_ /= src;
255 im_ /= src;
256 return *this;
257 }
258
259 template <size_t I, typename RT>
260 friend constexpr const RT& get(const complex<RT>&) noexcept;
261
262 template <size_t I, typename RT>
263 friend constexpr const RT&& get(const complex<RT>&&) noexcept;
264
265#ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
267 template <class RType,
268 std::enable_if_t<std::is_convertible_v<RType, RealType>, int> = 0>
269 KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION
270 complex(const volatile complex<RType>& src) noexcept
271 // Intentionally do the conversions implicitly here so that users don't
272 // get any warnings about narrowing, etc., that they would expect to get
273 // otherwise.
274 : re_(src.re_), im_(src.im_) {}
275
285 //
286 // Templated, so as not to be a copy assignment operator (Kokkos issue #2577)
287 // Intended to behave as
288 // void operator=(const complex&) volatile noexcept
289 //
290 // Use cases:
291 // complex r;
292 // const complex cr;
293 // volatile complex vl;
294 // vl = r;
295 // vl = cr;
296 template <class Complex,
297 std::enable_if_t<std::is_same_v<Complex, complex>, int> = 0>
298 KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION void operator=(
299 const Complex& src) volatile noexcept {
300 re_ = src.re_;
301 im_ = src.im_;
302 // We deliberately do not return anything here. See explanation
303 // in public documentation above.
304 }
305
307 // TODO Should this return void like the other volatile assignment operators?
308 //
309 // Templated, so as not to be a copy assignment operator (Kokkos issue #2577)
310 // Intended to behave as
311 // volatile complex& operator=(const volatile complex&) volatile noexcept
312 //
313 // Use cases:
314 // volatile complex vr;
315 // const volatile complex cvr;
316 // volatile complex vl;
317 // vl = vr;
318 // vl = cvr;
319 template <class Complex,
320 std::enable_if_t<std::is_same_v<Complex, complex>, int> = 0>
321 KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION volatile complex& operator=(
322 const volatile Complex& src) volatile noexcept {
323 re_ = src.re_;
324 im_ = src.im_;
325 return *this;
326 }
327
329 //
330 // Templated, so as not to be a copy assignment operator (Kokkos issue #2577)
331 // Intended to behave as
332 // complex& operator=(const volatile complex&) noexcept
333 //
334 // Use cases:
335 // volatile complex vr;
336 // const volatile complex cvr;
337 // complex l;
338 // l = vr;
339 // l = cvr;
340 //
341 template <class Complex,
342 std::enable_if_t<std::is_same_v<Complex, complex>, int> = 0>
343 KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION complex& operator=(
344 const volatile Complex& src) noexcept {
345 re_ = src.re_;
346 im_ = src.im_;
347 return *this;
348 }
349
350 // Mirroring the behavior of the assignment operators from complex RHS in the
351 // RealType RHS versions.
352
354 KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION void operator=(
355 const volatile RealType& val) noexcept {
356 re_ = val;
357 im_ = RealType(0);
358 // We deliberately do not return anything here. See explanation
359 // in public documentation above.
360 }
361
363 KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION complex& operator=(
364 const RealType& val) volatile noexcept {
365 re_ = val;
366 im_ = RealType(0);
367 return *this;
368 }
369
371 // TODO Should this return void like the other volatile assignment operators?
372 KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION complex& operator=(
373 const volatile RealType& val) volatile noexcept {
374 re_ = val;
375 im_ = RealType(0);
376 return *this;
377 }
378
380 KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION volatile RealType&
381 imag() volatile noexcept {
382 return im_;
383 }
384
386 KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION volatile RealType&
387 real() volatile noexcept {
388 return re_;
389 }
390
392 KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION RealType imag() const
393 volatile noexcept {
394 return im_;
395 }
396
398 KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION RealType real() const
399 volatile noexcept {
400 return re_;
401 }
402
403 KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION void operator+=(
404 const volatile complex<RealType>& src) volatile noexcept {
405 re_ += src.re_;
406 im_ += src.im_;
407 }
408
409 KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION void operator+=(
410 const volatile RealType& src) volatile noexcept {
411 re_ += src;
412 }
413
414 KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION void operator*=(
415 const volatile complex<RealType>& src) volatile noexcept {
416 const RealType realPart = re_ * src.re_ - im_ * src.im_;
417 const RealType imagPart = re_ * src.im_ + im_ * src.re_;
418
419 re_ = realPart;
420 im_ = imagPart;
421 }
422
423 KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION void operator*=(
424 const volatile RealType& src) volatile noexcept {
425 re_ *= src;
426 im_ *= src;
427 }
428#endif // KOKKOS_ENABLE_DEPRECATED_CODE_4
429};
430
431} // namespace Kokkos
432
433// Tuple protocol for complex based on https://wg21.link/P2819R2 (voted into
434// the C++26 working draft on 2023-11)
435
436template <typename RealType>
437struct std::tuple_size<Kokkos::complex<RealType>>
438 : std::integral_constant<size_t, 2> {};
439
440template <size_t I, typename RealType>
441struct std::tuple_element<I, Kokkos::complex<RealType>> {
442 static_assert(I < 2);
443 using type = RealType;
444};
445
446namespace Kokkos {
447
448// get<...>(...) defined here so as not to be hidden friends, as per P2819R2
449
450template <size_t I, typename RealType>
451KOKKOS_FUNCTION constexpr RealType& get(complex<RealType>& z) noexcept {
452 static_assert(I < 2);
453 if constexpr (I == 0)
454 return z.real();
455 else
456 return z.imag();
457#ifdef KOKKOS_COMPILER_INTEL
458 __builtin_unreachable();
459#endif
460}
461
462template <size_t I, typename RealType>
463KOKKOS_FUNCTION constexpr RealType&& get(complex<RealType>&& z) noexcept {
464 static_assert(I < 2);
465 if constexpr (I == 0)
466 return std::move(z.real());
467 else
468 return std::move(z.imag());
469#ifdef KOKKOS_COMPILER_INTEL
470 __builtin_unreachable();
471#endif
472}
473
474template <size_t I, typename RealType>
475KOKKOS_FUNCTION constexpr const RealType& get(
476 const complex<RealType>& z) noexcept {
477 static_assert(I < 2);
478 if constexpr (I == 0)
479 return z.re_;
480 else
481 return z.im_;
482#ifdef KOKKOS_COMPILER_INTEL
483 __builtin_unreachable();
484#endif
485}
486
487template <size_t I, typename RealType>
488KOKKOS_FUNCTION constexpr const RealType&& get(
489 const complex<RealType>&& z) noexcept {
490 static_assert(I < 2);
491 if constexpr (I == 0)
492 return std::move(z.re_);
493 else
494 return std::move(z.im_);
495#ifdef KOKKOS_COMPILER_INTEL
496 __builtin_unreachable();
497#endif
498}
499
500//==============================================================================
501// <editor-fold desc="Equality and inequality"> {{{1
502
503// Note that this is not the same behavior as std::complex, which doesn't allow
504// implicit conversions, but since this is the way we had it before, we have
505// to do it this way now.
506
508template <class RealType1, class RealType2>
509KOKKOS_INLINE_FUNCTION bool operator==(complex<RealType1> const& x,
510 complex<RealType2> const& y) noexcept {
511 using common_type = std::common_type_t<RealType1, RealType2>;
512 return common_type(x.real()) == common_type(y.real()) &&
513 common_type(x.imag()) == common_type(y.imag());
514}
515
516// TODO (here and elsewhere) decide if we should convert to a Kokkos::complex
517// and do the comparison in a device-marked function
519template <class RealType1, class RealType2>
520inline bool operator==(std::complex<RealType1> const& x,
521 complex<RealType2> const& y) noexcept {
522 using common_type = std::common_type_t<RealType1, RealType2>;
523 return common_type(x.real()) == common_type(y.real()) &&
524 common_type(x.imag()) == common_type(y.imag());
525}
526
528template <class RealType1, class RealType2>
529inline bool operator==(complex<RealType1> const& x,
530 std::complex<RealType2> const& y) noexcept {
531 using common_type = std::common_type_t<RealType1, RealType2>;
532 return common_type(x.real()) == common_type(y.real()) &&
533 common_type(x.imag()) == common_type(y.imag());
534}
535
537template <
538 class RealType1, class RealType2,
539 // Constraints to avoid participation in oparator==() for every possible RHS
540 std::enable_if_t<std::is_convertible_v<RealType2, RealType1>, int> = 0>
541KOKKOS_INLINE_FUNCTION bool operator==(complex<RealType1> const& x,
542 RealType2 const& y) noexcept {
543 using common_type = std::common_type_t<RealType1, RealType2>;
544 return common_type(x.real()) == common_type(y) &&
545 common_type(x.imag()) == common_type(0);
546}
547
549template <
550 class RealType1, class RealType2,
551 // Constraints to avoid participation in oparator==() for every possible RHS
552 std::enable_if_t<std::is_convertible_v<RealType1, RealType2>, int> = 0>
553KOKKOS_INLINE_FUNCTION bool operator==(RealType1 const& x,
554 complex<RealType2> const& y) noexcept {
555 using common_type = std::common_type_t<RealType1, RealType2>;
556 return common_type(x) == common_type(y.real()) &&
557 common_type(0) == common_type(y.imag());
558}
559
561template <class RealType1, class RealType2>
562KOKKOS_INLINE_FUNCTION bool operator!=(complex<RealType1> const& x,
563 complex<RealType2> const& y) noexcept {
564 using common_type = std::common_type_t<RealType1, RealType2>;
565 return common_type(x.real()) != common_type(y.real()) ||
566 common_type(x.imag()) != common_type(y.imag());
567}
568
570template <class RealType1, class RealType2>
571inline bool operator!=(std::complex<RealType1> const& x,
572 complex<RealType2> const& y) noexcept {
573 using common_type = std::common_type_t<RealType1, RealType2>;
574 return common_type(x.real()) != common_type(y.real()) ||
575 common_type(x.imag()) != common_type(y.imag());
576}
577
579template <class RealType1, class RealType2>
580inline bool operator!=(complex<RealType1> const& x,
581 std::complex<RealType2> const& y) noexcept {
582 using common_type = std::common_type_t<RealType1, RealType2>;
583 return common_type(x.real()) != common_type(y.real()) ||
584 common_type(x.imag()) != common_type(y.imag());
585}
586
588template <
589 class RealType1, class RealType2,
590 // Constraints to avoid participation in oparator==() for every possible RHS
591 std::enable_if_t<std::is_convertible_v<RealType2, RealType1>, int> = 0>
592KOKKOS_INLINE_FUNCTION bool operator!=(complex<RealType1> const& x,
593 RealType2 const& y) noexcept {
594 using common_type = std::common_type_t<RealType1, RealType2>;
595 return common_type(x.real()) != common_type(y) ||
596 common_type(x.imag()) != common_type(0);
597}
598
600template <
601 class RealType1, class RealType2,
602 // Constraints to avoid participation in oparator==() for every possible RHS
603 std::enable_if_t<std::is_convertible_v<RealType1, RealType2>, int> = 0>
604KOKKOS_INLINE_FUNCTION bool operator!=(RealType1 const& x,
605 complex<RealType2> const& y) noexcept {
606 using common_type = std::common_type_t<RealType1, RealType2>;
607 return common_type(x) != common_type(y.real()) ||
608 common_type(0) != common_type(y.imag());
609}
610
611// </editor-fold> end Equality and inequality }}}1
612//==============================================================================
613
615template <class RealType1, class RealType2>
617operator+(const complex<RealType1>& x, const complex<RealType2>& y) noexcept {
618 return complex<std::common_type_t<RealType1, RealType2>>(x.real() + y.real(),
619 x.imag() + y.imag());
620}
621
623template <class RealType1, class RealType2>
625operator+(const complex<RealType1>& x, const RealType2& y) noexcept {
627 x.imag());
628}
629
631template <class RealType1, class RealType2>
633operator+(const RealType1& x, const complex<RealType2>& y) noexcept {
635 y.imag());
636}
637
639template <class RealType>
640KOKKOS_INLINE_FUNCTION complex<RealType> operator+(
641 const complex<RealType>& x) noexcept {
642 return complex<RealType>{+x.real(), +x.imag()};
643}
644
646template <class RealType1, class RealType2>
648operator-(const complex<RealType1>& x, const complex<RealType2>& y) noexcept {
649 return complex<std::common_type_t<RealType1, RealType2>>(x.real() - y.real(),
650 x.imag() - y.imag());
651}
652
654template <class RealType1, class RealType2>
656operator-(const complex<RealType1>& x, const RealType2& y) noexcept {
658 x.imag());
659}
660
662template <class RealType1, class RealType2>
664operator-(const RealType1& x, const complex<RealType2>& y) noexcept {
666 -y.imag());
667}
668
670template <class RealType>
671KOKKOS_INLINE_FUNCTION complex<RealType> operator-(
672 const complex<RealType>& x) noexcept {
673 return complex<RealType>(-x.real(), -x.imag());
674}
675
677template <class RealType1, class RealType2>
679operator*(const complex<RealType1>& x, const complex<RealType2>& y) noexcept {
681 x.real() * y.real() - x.imag() * y.imag(),
682 x.real() * y.imag() + x.imag() * y.real());
683}
684
693template <class RealType1, class RealType2>
695 const std::complex<RealType1>& x, const complex<RealType2>& y) {
697 x.real() * y.real() - x.imag() * y.imag(),
698 x.real() * y.imag() + x.imag() * y.real());
699}
700
705template <class RealType1, class RealType2>
707operator*(const RealType1& x, const complex<RealType2>& y) noexcept {
709 x * y.imag());
710}
711
716template <class RealType1, class RealType2>
718operator*(const complex<RealType1>& y, const RealType2& x) noexcept {
720 x * y.imag());
721}
722
724template <class RealType>
725KOKKOS_INLINE_FUNCTION RealType imag(const complex<RealType>& x) noexcept {
726 return x.imag();
727}
728
729template <class ArithmeticType>
730KOKKOS_INLINE_FUNCTION constexpr Impl::promote_t<ArithmeticType> imag(
731 ArithmeticType) {
732 return ArithmeticType();
733}
734
736template <class RealType>
737KOKKOS_INLINE_FUNCTION RealType real(const complex<RealType>& x) noexcept {
738 return x.real();
739}
740
741template <class ArithmeticType>
742KOKKOS_INLINE_FUNCTION constexpr Impl::promote_t<ArithmeticType> real(
743 ArithmeticType x) {
744 return x;
745}
746
748template <class T>
749KOKKOS_INLINE_FUNCTION complex<T> polar(const T& r, const T& theta = T()) {
750 KOKKOS_EXPECTS(r >= 0);
751 return complex<T>(r * cos(theta), r * sin(theta));
752}
753
755template <class RealType>
756KOKKOS_INLINE_FUNCTION RealType abs(const complex<RealType>& x) {
757 return hypot(x.real(), x.imag());
758}
759
761template <class T>
762KOKKOS_INLINE_FUNCTION complex<T> pow(const complex<T>& x, const T& y) {
763 T r = abs(x);
764 T theta = atan2(x.imag(), x.real());
765 return polar(pow(r, y), y * theta);
766}
767
768template <class T>
769KOKKOS_INLINE_FUNCTION complex<T> pow(const T& x, const complex<T>& y) {
770 return pow(complex<T>(x), y);
771}
772
773template <class T>
774KOKKOS_INLINE_FUNCTION complex<T> pow(const complex<T>& x,
775 const complex<T>& y) {
776 return x == T() ? T() : exp(y * log(x));
777}
778
779template <class T, class U, class = std::enable_if_t<std::is_arithmetic_v<T>>>
780KOKKOS_INLINE_FUNCTION complex<Impl::promote_2_t<T, U>> pow(
781 const T& x, const complex<U>& y) {
782 using type = Impl::promote_2_t<T, U>;
783 return pow(type(x), complex<type>(y));
784}
785
786template <class T, class U, class = std::enable_if_t<std::is_arithmetic_v<U>>>
787KOKKOS_INLINE_FUNCTION complex<Impl::promote_2_t<T, U>> pow(const complex<T>& x,
788 const U& y) {
789 using type = Impl::promote_2_t<T, U>;
790 return pow(complex<type>(x), type(y));
791}
792
793template <class T, class U>
794KOKKOS_INLINE_FUNCTION complex<Impl::promote_2_t<T, U>> pow(
795 const complex<T>& x, const complex<U>& y) {
796 using type = Impl::promote_2_t<T, U>;
797 return pow(complex<type>(x), complex<type>(y));
798}
799
802template <class RealType>
803KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> sqrt(
804 const complex<RealType>& x) {
805 RealType r = x.real();
806 RealType i = x.imag();
807
808 if (r == RealType()) {
809 RealType t = sqrt(fabs(i) / 2);
810 return Kokkos::complex<RealType>(t, i < RealType() ? -t : t);
811 } else {
812 RealType t = sqrt(2 * (abs(x) + fabs(r)));
813 RealType u = t / 2;
814 return r > RealType() ? Kokkos::complex<RealType>(u, i / t)
815 : Kokkos::complex<RealType>(fabs(i) / t,
816 i < RealType() ? -u : u);
817 }
818}
819
821template <class RealType>
822KOKKOS_INLINE_FUNCTION complex<RealType> conj(
823 const complex<RealType>& x) noexcept {
824 return complex<RealType>(real(x), -imag(x));
825}
826
827template <class ArithmeticType>
828KOKKOS_INLINE_FUNCTION constexpr complex<Impl::promote_t<ArithmeticType>> conj(
829 ArithmeticType x) {
830 using type = Impl::promote_t<ArithmeticType>;
831 return complex<type>(x, -type());
832}
833
835template <class RealType>
836KOKKOS_INLINE_FUNCTION complex<RealType> exp(const complex<RealType>& x) {
837 return exp(x.real()) * complex<RealType>(cos(x.imag()), sin(x.imag()));
838}
839
841template <class RealType>
842KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> log(
843 const complex<RealType>& x) {
844 RealType phi = atan2(x.imag(), x.real());
845 return Kokkos::complex<RealType>(log(abs(x)), phi);
846}
847
849template <class RealType>
850KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> log10(
851 const complex<RealType>& x) {
852 return log(x) / log(RealType(10));
853}
854
856template <class RealType>
857KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> sin(
858 const complex<RealType>& x) {
859 return Kokkos::complex<RealType>(sin(x.real()) * cosh(x.imag()),
860 cos(x.real()) * sinh(x.imag()));
861}
862
864template <class RealType>
865KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> cos(
866 const complex<RealType>& x) {
867 return Kokkos::complex<RealType>(cos(x.real()) * cosh(x.imag()),
868 -sin(x.real()) * sinh(x.imag()));
869}
870
872template <class RealType>
873KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> tan(
874 const complex<RealType>& x) {
875 return sin(x) / cos(x);
876}
877
879template <class RealType>
880KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> sinh(
881 const complex<RealType>& x) {
882 return Kokkos::complex<RealType>(sinh(x.real()) * cos(x.imag()),
883 cosh(x.real()) * sin(x.imag()));
884}
885
887template <class RealType>
888KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> cosh(
889 const complex<RealType>& x) {
890 return Kokkos::complex<RealType>(cosh(x.real()) * cos(x.imag()),
891 sinh(x.real()) * sin(x.imag()));
892}
893
895template <class RealType>
896KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> tanh(
897 const complex<RealType>& x) {
898 return sinh(x) / cosh(x);
899}
900
902template <class RealType>
903KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> asinh(
904 const complex<RealType>& x) {
905 return log(x + sqrt(x * x + RealType(1.0)));
906}
907
909template <class RealType>
910KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> acosh(
911 const complex<RealType>& x) {
912 return RealType(2.0) * log(sqrt(RealType(0.5) * (x + RealType(1.0))) +
913 sqrt(RealType(0.5) * (x - RealType(1.0))));
914}
915
917template <class RealType>
918KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> atanh(
919 const complex<RealType>& x) {
920 const RealType i2 = x.imag() * x.imag();
921 const RealType r = RealType(1.0) - i2 - x.real() * x.real();
922
923 RealType p = RealType(1.0) + x.real();
924 RealType m = RealType(1.0) - x.real();
925
926 p = i2 + p * p;
927 m = i2 + m * m;
928
929 RealType phi = atan2(RealType(2.0) * x.imag(), r);
930 return Kokkos::complex<RealType>(RealType(0.25) * (log(p) - log(m)),
931 RealType(0.5) * phi);
932}
933
935template <class RealType>
936KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> asin(
937 const complex<RealType>& x) {
938 Kokkos::complex<RealType> t =
939 asinh(Kokkos::complex<RealType>(-x.imag(), x.real()));
940 return Kokkos::complex<RealType>(t.imag(), -t.real());
941}
942
944template <class RealType>
945KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> acos(
946 const complex<RealType>& x) {
947 Kokkos::complex<RealType> t = asin(x);
948 RealType pi_2 = acos(RealType(0.0));
949 return Kokkos::complex<RealType>(pi_2 - t.real(), -t.imag());
950}
951
953template <class RealType>
954KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> atan(
955 const complex<RealType>& x) {
956 const RealType r2 = x.real() * x.real();
957 const RealType i = RealType(1.0) - r2 - x.imag() * x.imag();
958
959 RealType p = x.imag() + RealType(1.0);
960 RealType m = x.imag() - RealType(1.0);
961
962 p = r2 + p * p;
963 m = r2 + m * m;
964
965 return Kokkos::complex<RealType>(
966 RealType(0.5) * atan2(RealType(2.0) * x.real(), i),
967 RealType(0.25) * log(p / m));
968}
969
973template <class RealType>
974inline complex<RealType> exp(const std::complex<RealType>& c) {
975 return complex<RealType>(std::exp(c.real()) * std::cos(c.imag()),
976 std::exp(c.real()) * std::sin(c.imag()));
977}
978
980template <class RealType1, class RealType2>
982operator/(const complex<RealType1>& x,
983 const RealType2& y) noexcept(noexcept(RealType1{} / RealType2{})) {
985 imag(x) / y);
986}
987
989template <class RealType1, class RealType2>
991operator/(const complex<RealType1>& x,
992 const complex<RealType2>& y) noexcept(noexcept(RealType1{} /
993 RealType2{})) {
994 // Scale (by the "1-norm" of y) to avoid unwarranted overflow.
995 // If the real part is +/-Inf and the imaginary part is -/+Inf,
996 // this won't change the result.
997 using common_real_type = std::common_type_t<RealType1, RealType2>;
998 const common_real_type s = fabs(real(y)) + fabs(imag(y));
999
1000 // If s is 0, then y is zero, so x/y == real(x)/0 + i*imag(x)/0.
1001 // In that case, the relation x/y == (x/s) / (y/s) doesn't hold,
1002 // because y/s is NaN.
1003 if (s == 0.0) {
1004 return complex<common_real_type>(real(x) / s, imag(x) / s);
1005 } else {
1006 const complex<common_real_type> x_scaled(real(x) / s, imag(x) / s);
1007 const complex<common_real_type> y_conj_scaled(real(y) / s, -imag(y) / s);
1008 const RealType1 y_scaled_abs =
1009 real(y_conj_scaled) * real(y_conj_scaled) +
1010 imag(y_conj_scaled) * imag(y_conj_scaled); // abs(y) == abs(conj(y))
1011 complex<common_real_type> result = x_scaled * y_conj_scaled;
1012 result /= y_scaled_abs;
1013 return result;
1014 }
1015}
1016
1018template <class RealType1, class RealType2>
1020operator/(const RealType1& x,
1021 const complex<RealType2>& y) noexcept(noexcept(RealType1{} /
1022 RealType2{})) {
1024}
1025
1026template <class RealType>
1027std::ostream& operator<<(std::ostream& os, const complex<RealType>& x) {
1028 const std::complex<RealType> x_std(Kokkos::real(x), Kokkos::imag(x));
1029 os << x_std;
1030 return os;
1031}
1032
1033template <class RealType>
1034std::istream& operator>>(std::istream& is, complex<RealType>& x) {
1035 std::complex<RealType> x_std;
1036 is >> x_std;
1037 x = x_std; // only assigns on success of above
1038 return is;
1039}
1040
1041template <class T>
1042struct reduction_identity<Kokkos::complex<T>> {
1043 using t_red_ident = reduction_identity<T>;
1044 KOKKOS_FORCEINLINE_FUNCTION constexpr static Kokkos::complex<T>
1045 sum() noexcept {
1046 return Kokkos::complex<T>(t_red_ident::sum(), t_red_ident::sum());
1047 }
1048 KOKKOS_FORCEINLINE_FUNCTION constexpr static Kokkos::complex<T>
1049 prod() noexcept {
1050 return Kokkos::complex<T>(t_red_ident::prod(), t_red_ident::sum());
1051 }
1052};
1053
1054} // namespace Kokkos
1055
1056#ifdef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_COMPLEX
1057#undef KOKKOS_IMPL_PUBLIC_INCLUDE
1058#undef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_COMPLEX
1059#endif
1060#endif // KOKKOS_COMPLEX_HPP
Atomic functions.
Partial reimplementation of std::complex that works as the result of a Kokkos::parallel_reduce.
KOKKOS_INLINE_FUNCTION constexpr RealType imag() const noexcept
The imaginary part of this complex number.
RealType value_type
The type of the real or imaginary parts of this complex number.
KOKKOS_INLINE_FUNCTION constexpr RealType & real() noexcept
The real part of this complex number.
complex & operator=(const std::complex< RealType > &src) noexcept
Assignment operator from std::complex.
KOKKOS_DEFAULTED_FUNCTION complex(const complex &) noexcept=default
Copy constructor.
KOKKOS_INLINE_FUNCTION constexpr void real(RealType v) noexcept
Set the real part of this complex number.
KOKKOS_INLINE_FUNCTION complex(const RealType &re, const RealType &im) noexcept
Constructor that takes the real and imaginary parts.
KOKKOS_INLINE_FUNCTION constexpr RealType & imag() noexcept
The imaginary part of this complex number.
KOKKOS_INLINE_FUNCTION constexpr RealType real() const noexcept
The real part of this complex number.
KOKKOS_INLINE_FUNCTION complex & operator=(const RealType &val) noexcept
Assignment operator (from a real number).
KOKKOS_INLINE_FUNCTION constexpr void imag(RealType v) noexcept
Set the imaginary part of this complex number.
KOKKOS_DEFAULTED_FUNCTION complex()=default
Default constructor (initializes both real and imaginary parts to zero).
KOKKOS_INLINE_FUNCTION complex(const RealType &val) noexcept
Constructor that takes just the real part, and sets the imaginary part to zero.
KOKKOS_INLINE_FUNCTION complex(const std::complex< RealType > &src) noexcept
Conversion constructor from std::complex.
KOKKOS_INLINE_FUNCTION complex(const complex< RType > &other) noexcept
Conversion constructor from compatible RType.