Kokkos Core Kernels Package  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
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 
32 namespace Kokkos {
33 
41 template <class RealType>
42 class
43 #ifdef KOKKOS_ENABLE_COMPLEX_ALIGN
44  alignas(2 * sizeof(RealType))
45 #endif
46  complex {
47  static_assert(std::is_floating_point_v<RealType> &&
48  std::is_same_v<RealType, std::remove_cv_t<RealType>>,
49  "Kokkos::complex can only be instantiated for a cv-unqualified "
50  "floating point type");
51 
52  private:
53  RealType re_{};
54  RealType im_{};
55 
56  public:
58  using value_type = RealType;
59 
61  KOKKOS_DEFAULTED_FUNCTION
62  complex() = default;
63 
65  KOKKOS_DEFAULTED_FUNCTION
66  complex(const complex&) noexcept = default;
67 
68  KOKKOS_DEFAULTED_FUNCTION
69  complex& operator=(const complex&) noexcept = default;
70 
72  template <
73  class RType,
74  std::enable_if_t<std::is_convertible<RType, RealType>::value, 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 #ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
260  template <
262  class RType,
263  std::enable_if_t<std::is_convertible<RType, RealType>::value, int> = 0>
264  KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION
265  complex(const volatile complex<RType>& src) noexcept
266  // Intentionally do the conversions implicitly here so that users don't
267  // get any warnings about narrowing, etc., that they would expect to get
268  // otherwise.
269  : re_(src.re_), im_(src.im_) {}
270 
280  //
281  // Templated, so as not to be a copy assignment operator (Kokkos issue #2577)
282  // Intended to behave as
283  // void operator=(const complex&) volatile noexcept
284  //
285  // Use cases:
286  // complex r;
287  // const complex cr;
288  // volatile complex vl;
289  // vl = r;
290  // vl = cr;
291  template <class Complex,
292  std::enable_if_t<std::is_same<Complex, complex>::value, int> = 0>
293  KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION void operator=(
294  const Complex& src) volatile noexcept {
295  re_ = src.re_;
296  im_ = src.im_;
297  // We deliberately do not return anything here. See explanation
298  // in public documentation above.
299  }
300 
302  // TODO Should this return void like the other volatile assignment operators?
303  //
304  // Templated, so as not to be a copy assignment operator (Kokkos issue #2577)
305  // Intended to behave as
306  // volatile complex& operator=(const volatile complex&) volatile noexcept
307  //
308  // Use cases:
309  // volatile complex vr;
310  // const volatile complex cvr;
311  // volatile complex vl;
312  // vl = vr;
313  // vl = cvr;
314  template <class Complex,
315  std::enable_if_t<std::is_same<Complex, complex>::value, int> = 0>
316  KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION volatile complex& operator=(
317  const volatile Complex& src) volatile noexcept {
318  re_ = src.re_;
319  im_ = src.im_;
320  return *this;
321  }
322 
324  //
325  // Templated, so as not to be a copy assignment operator (Kokkos issue #2577)
326  // Intended to behave as
327  // complex& operator=(const volatile complex&) noexcept
328  //
329  // Use cases:
330  // volatile complex vr;
331  // const volatile complex cvr;
332  // complex l;
333  // l = vr;
334  // l = cvr;
335  //
336  template <class Complex,
337  std::enable_if_t<std::is_same<Complex, complex>::value, int> = 0>
338  KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION complex& operator=(
339  const volatile Complex& src) noexcept {
340  re_ = src.re_;
341  im_ = src.im_;
342  return *this;
343  }
344 
345  // Mirroring the behavior of the assignment operators from complex RHS in the
346  // RealType RHS versions.
347 
349  KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION void operator=(
350  const volatile RealType& val) noexcept {
351  re_ = val;
352  im_ = RealType(0);
353  // We deliberately do not return anything here. See explanation
354  // in public documentation above.
355  }
356 
358  KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION complex& operator=(
359  const RealType& val) volatile noexcept {
360  re_ = val;
361  im_ = RealType(0);
362  return *this;
363  }
364 
366  // TODO Should this return void like the other volatile assignment operators?
367  KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION complex& operator=(
368  const volatile RealType& val) volatile noexcept {
369  re_ = val;
370  im_ = RealType(0);
371  return *this;
372  }
373 
375  KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION volatile RealType&
376  imag() volatile noexcept {
377  return im_;
378  }
379 
381  KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION volatile RealType&
382  real() volatile noexcept {
383  return re_;
384  }
385 
387  KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION RealType imag() const
388  volatile noexcept {
389  return im_;
390  }
391 
393  KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION RealType real() const
394  volatile noexcept {
395  return re_;
396  }
397 
398  KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION void operator+=(
399  const volatile complex<RealType>& src) volatile noexcept {
400  re_ += src.re_;
401  im_ += src.im_;
402  }
403 
404  KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION void operator+=(
405  const volatile RealType& src) volatile noexcept {
406  re_ += src;
407  }
408 
409  KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION void operator*=(
410  const volatile complex<RealType>& src) volatile noexcept {
411  const RealType realPart = re_ * src.re_ - im_ * src.im_;
412  const RealType imagPart = re_ * src.im_ + im_ * src.re_;
413 
414  re_ = realPart;
415  im_ = imagPart;
416  }
417 
418  KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION void operator*=(
419  const volatile RealType& src) volatile noexcept {
420  re_ *= src;
421  im_ *= src;
422  }
423 #endif // KOKKOS_ENABLE_DEPRECATED_CODE_4
424 };
425 
426 //==============================================================================
427 // <editor-fold desc="Equality and inequality"> {{{1
428 
429 // Note that this is not the same behavior as std::complex, which doesn't allow
430 // implicit conversions, but since this is the way we had it before, we have
431 // to do it this way now.
432 
434 template <class RealType1, class RealType2>
435 KOKKOS_INLINE_FUNCTION bool operator==(complex<RealType1> const& x,
436  complex<RealType2> const& y) noexcept {
437  using common_type = std::common_type_t<RealType1, RealType2>;
438  return common_type(x.real()) == common_type(y.real()) &&
439  common_type(x.imag()) == common_type(y.imag());
440 }
441 
442 // TODO (here and elsewhere) decide if we should convert to a Kokkos::complex
443 // and do the comparison in a device-marked function
445 template <class RealType1, class RealType2>
446 inline bool operator==(std::complex<RealType1> const& x,
447  complex<RealType2> const& y) noexcept {
448  using common_type = std::common_type_t<RealType1, RealType2>;
449  return common_type(x.real()) == common_type(y.real()) &&
450  common_type(x.imag()) == common_type(y.imag());
451 }
452 
454 template <class RealType1, class RealType2>
455 inline bool operator==(complex<RealType1> const& x,
456  std::complex<RealType2> const& y) noexcept {
457  using common_type = std::common_type_t<RealType1, RealType2>;
458  return common_type(x.real()) == common_type(y.real()) &&
459  common_type(x.imag()) == common_type(y.imag());
460 }
461 
463 template <
464  class RealType1, class RealType2,
465  // Constraints to avoid participation in oparator==() for every possible RHS
466  std::enable_if_t<std::is_convertible<RealType2, RealType1>::value, int> = 0>
467 KOKKOS_INLINE_FUNCTION bool operator==(complex<RealType1> const& x,
468  RealType2 const& y) noexcept {
469  using common_type = std::common_type_t<RealType1, RealType2>;
470  return common_type(x.real()) == common_type(y) &&
471  common_type(x.imag()) == common_type(0);
472 }
473 
475 template <
476  class RealType1, class RealType2,
477  // Constraints to avoid participation in oparator==() for every possible RHS
478  std::enable_if_t<std::is_convertible<RealType1, RealType2>::value, int> = 0>
479 KOKKOS_INLINE_FUNCTION bool operator==(RealType1 const& x,
480  complex<RealType2> const& y) noexcept {
481  using common_type = std::common_type_t<RealType1, RealType2>;
482  return common_type(x) == common_type(y.real()) &&
483  common_type(0) == common_type(y.imag());
484 }
485 
487 template <class RealType1, class RealType2>
488 KOKKOS_INLINE_FUNCTION bool operator!=(complex<RealType1> const& x,
489  complex<RealType2> const& y) noexcept {
490  using common_type = std::common_type_t<RealType1, RealType2>;
491  return common_type(x.real()) != common_type(y.real()) ||
492  common_type(x.imag()) != common_type(y.imag());
493 }
494 
496 template <class RealType1, class RealType2>
497 inline bool operator!=(std::complex<RealType1> const& x,
498  complex<RealType2> const& y) noexcept {
499  using common_type = std::common_type_t<RealType1, RealType2>;
500  return common_type(x.real()) != common_type(y.real()) ||
501  common_type(x.imag()) != common_type(y.imag());
502 }
503 
505 template <class RealType1, class RealType2>
506 inline bool operator!=(complex<RealType1> const& x,
507  std::complex<RealType2> const& y) noexcept {
508  using common_type = std::common_type_t<RealType1, RealType2>;
509  return common_type(x.real()) != common_type(y.real()) ||
510  common_type(x.imag()) != common_type(y.imag());
511 }
512 
514 template <
515  class RealType1, class RealType2,
516  // Constraints to avoid participation in oparator==() for every possible RHS
517  std::enable_if_t<std::is_convertible<RealType2, RealType1>::value, int> = 0>
518 KOKKOS_INLINE_FUNCTION bool operator!=(complex<RealType1> const& x,
519  RealType2 const& y) noexcept {
520  using common_type = std::common_type_t<RealType1, RealType2>;
521  return common_type(x.real()) != common_type(y) ||
522  common_type(x.imag()) != common_type(0);
523 }
524 
526 template <
527  class RealType1, class RealType2,
528  // Constraints to avoid participation in oparator==() for every possible RHS
529  std::enable_if_t<std::is_convertible<RealType1, RealType2>::value, int> = 0>
530 KOKKOS_INLINE_FUNCTION bool operator!=(RealType1 const& x,
531  complex<RealType2> const& y) noexcept {
532  using common_type = std::common_type_t<RealType1, RealType2>;
533  return common_type(x) != common_type(y.real()) ||
534  common_type(0) != common_type(y.imag());
535 }
536 
537 // </editor-fold> end Equality and inequality }}}1
538 //==============================================================================
539 
541 template <class RealType1, class RealType2>
542 KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
543 operator+(const complex<RealType1>& x, const complex<RealType2>& y) noexcept {
544  return complex<std::common_type_t<RealType1, RealType2>>(x.real() + y.real(),
545  x.imag() + y.imag());
546 }
547 
549 template <class RealType1, class RealType2>
550 KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
551 operator+(const complex<RealType1>& x, const RealType2& y) noexcept {
552  return complex<std::common_type_t<RealType1, RealType2>>(x.real() + y,
553  x.imag());
554 }
555 
557 template <class RealType1, class RealType2>
558 KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
559 operator+(const RealType1& x, const complex<RealType2>& y) noexcept {
560  return complex<std::common_type_t<RealType1, RealType2>>(x + y.real(),
561  y.imag());
562 }
563 
565 template <class RealType>
566 KOKKOS_INLINE_FUNCTION complex<RealType> operator+(
567  const complex<RealType>& x) noexcept {
568  return complex<RealType>{+x.real(), +x.imag()};
569 }
570 
572 template <class RealType1, class RealType2>
573 KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
574 operator-(const complex<RealType1>& x, const complex<RealType2>& y) noexcept {
575  return complex<std::common_type_t<RealType1, RealType2>>(x.real() - y.real(),
576  x.imag() - y.imag());
577 }
578 
580 template <class RealType1, class RealType2>
581 KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
582 operator-(const complex<RealType1>& x, const RealType2& y) noexcept {
583  return complex<std::common_type_t<RealType1, RealType2>>(x.real() - y,
584  x.imag());
585 }
586 
588 template <class RealType1, class RealType2>
589 KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
590 operator-(const RealType1& x, const complex<RealType2>& y) noexcept {
591  return complex<std::common_type_t<RealType1, RealType2>>(x - y.real(),
592  -y.imag());
593 }
594 
596 template <class RealType>
597 KOKKOS_INLINE_FUNCTION complex<RealType> operator-(
598  const complex<RealType>& x) noexcept {
599  return complex<RealType>(-x.real(), -x.imag());
600 }
601 
603 template <class RealType1, class RealType2>
604 KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
605 operator*(const complex<RealType1>& x, const complex<RealType2>& y) noexcept {
606  return complex<std::common_type_t<RealType1, RealType2>>(
607  x.real() * y.real() - x.imag() * y.imag(),
608  x.real() * y.imag() + x.imag() * y.real());
609 }
610 
619 template <class RealType1, class RealType2>
620 inline complex<std::common_type_t<RealType1, RealType2>> operator*(
621  const std::complex<RealType1>& x, const complex<RealType2>& y) {
622  return complex<std::common_type_t<RealType1, RealType2>>(
623  x.real() * y.real() - x.imag() * y.imag(),
624  x.real() * y.imag() + x.imag() * y.real());
625 }
626 
631 template <class RealType1, class RealType2>
632 KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
633 operator*(const RealType1& x, const complex<RealType2>& y) noexcept {
634  return complex<std::common_type_t<RealType1, RealType2>>(x * y.real(),
635  x * y.imag());
636 }
637 
642 template <class RealType1, class RealType2>
643 KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
644 operator*(const complex<RealType1>& y, const RealType2& x) noexcept {
645  return complex<std::common_type_t<RealType1, RealType2>>(x * y.real(),
646  x * y.imag());
647 }
648 
650 template <class RealType>
651 KOKKOS_INLINE_FUNCTION RealType imag(const complex<RealType>& x) noexcept {
652  return x.imag();
653 }
654 
655 template <class ArithmeticType>
656 KOKKOS_INLINE_FUNCTION constexpr Impl::promote_t<ArithmeticType> imag(
657  ArithmeticType) {
658  return ArithmeticType();
659 }
660 
662 template <class RealType>
663 KOKKOS_INLINE_FUNCTION RealType real(const complex<RealType>& x) noexcept {
664  return x.real();
665 }
666 
667 template <class ArithmeticType>
668 KOKKOS_INLINE_FUNCTION constexpr Impl::promote_t<ArithmeticType> real(
669  ArithmeticType x) {
670  return x;
671 }
672 
674 template <class T>
675 KOKKOS_INLINE_FUNCTION complex<T> polar(const T& r, const T& theta = T()) {
676  KOKKOS_EXPECTS(r >= 0);
677  return complex<T>(r * cos(theta), r * sin(theta));
678 }
679 
681 template <class RealType>
682 KOKKOS_INLINE_FUNCTION RealType abs(const complex<RealType>& x) {
683  return hypot(x.real(), x.imag());
684 }
685 
687 template <class T>
688 KOKKOS_INLINE_FUNCTION complex<T> pow(const complex<T>& x, const T& y) {
689  T r = abs(x);
690  T theta = atan2(x.imag(), x.real());
691  return polar(pow(r, y), y * theta);
692 }
693 
694 template <class T>
695 KOKKOS_INLINE_FUNCTION complex<T> pow(const T& x, const complex<T>& y) {
696  return pow(complex<T>(x), y);
697 }
698 
699 template <class T>
700 KOKKOS_INLINE_FUNCTION complex<T> pow(const complex<T>& x,
701  const complex<T>& y) {
702  return x == T() ? T() : exp(y * log(x));
703 }
704 
705 template <class T, class U,
706  class = std::enable_if_t<std::is_arithmetic<T>::value>>
707 KOKKOS_INLINE_FUNCTION complex<Impl::promote_2_t<T, U>> pow(
708  const T& x, const complex<U>& y) {
709  using type = Impl::promote_2_t<T, U>;
710  return pow(type(x), complex<type>(y));
711 }
712 
713 template <class T, class U,
714  class = std::enable_if_t<std::is_arithmetic<U>::value>>
715 KOKKOS_INLINE_FUNCTION complex<Impl::promote_2_t<T, U>> pow(const complex<T>& x,
716  const U& y) {
717  using type = Impl::promote_2_t<T, U>;
718  return pow(complex<type>(x), type(y));
719 }
720 
721 template <class T, class U>
722 KOKKOS_INLINE_FUNCTION complex<Impl::promote_2_t<T, U>> pow(
723  const complex<T>& x, const complex<U>& y) {
724  using type = Impl::promote_2_t<T, U>;
725  return pow(complex<type>(x), complex<type>(y));
726 }
727 
730 template <class RealType>
731 KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> sqrt(
732  const complex<RealType>& x) {
733  RealType r = x.real();
734  RealType i = x.imag();
735 
736  if (r == RealType()) {
737  RealType t = sqrt(fabs(i) / 2);
738  return Kokkos::complex<RealType>(t, i < RealType() ? -t : t);
739  } else {
740  RealType t = sqrt(2 * (abs(x) + fabs(r)));
741  RealType u = t / 2;
742  return r > RealType() ? Kokkos::complex<RealType>(u, i / t)
743  : Kokkos::complex<RealType>(fabs(i) / t,
744  i < RealType() ? -u : u);
745  }
746 }
747 
749 template <class RealType>
750 KOKKOS_INLINE_FUNCTION complex<RealType> conj(
751  const complex<RealType>& x) noexcept {
752  return complex<RealType>(real(x), -imag(x));
753 }
754 
755 template <class ArithmeticType>
756 KOKKOS_INLINE_FUNCTION constexpr complex<Impl::promote_t<ArithmeticType>> conj(
757  ArithmeticType x) {
758  using type = Impl::promote_t<ArithmeticType>;
759  return complex<type>(x, -type());
760 }
761 
763 template <class RealType>
764 KOKKOS_INLINE_FUNCTION complex<RealType> exp(const complex<RealType>& x) {
765  return exp(x.real()) * complex<RealType>(cos(x.imag()), sin(x.imag()));
766 }
767 
769 template <class RealType>
770 KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> log(
771  const complex<RealType>& x) {
772  RealType phi = atan2(x.imag(), x.real());
773  return Kokkos::complex<RealType>(log(abs(x)), phi);
774 }
775 
777 template <class RealType>
778 KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> log10(
779  const complex<RealType>& x) {
780  return log(x) / log(RealType(10));
781 }
782 
784 template <class RealType>
785 KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> sin(
786  const complex<RealType>& x) {
787  return Kokkos::complex<RealType>(sin(x.real()) * cosh(x.imag()),
788  cos(x.real()) * sinh(x.imag()));
789 }
790 
792 template <class RealType>
793 KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> cos(
794  const complex<RealType>& x) {
795  return Kokkos::complex<RealType>(cos(x.real()) * cosh(x.imag()),
796  -sin(x.real()) * sinh(x.imag()));
797 }
798 
800 template <class RealType>
801 KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> tan(
802  const complex<RealType>& x) {
803  return sin(x) / cos(x);
804 }
805 
807 template <class RealType>
808 KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> sinh(
809  const complex<RealType>& x) {
810  return Kokkos::complex<RealType>(sinh(x.real()) * cos(x.imag()),
811  cosh(x.real()) * sin(x.imag()));
812 }
813 
815 template <class RealType>
816 KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> cosh(
817  const complex<RealType>& x) {
818  return Kokkos::complex<RealType>(cosh(x.real()) * cos(x.imag()),
819  sinh(x.real()) * sin(x.imag()));
820 }
821 
823 template <class RealType>
824 KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> tanh(
825  const complex<RealType>& x) {
826  return sinh(x) / cosh(x);
827 }
828 
830 template <class RealType>
831 KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> asinh(
832  const complex<RealType>& x) {
833  return log(x + sqrt(x * x + RealType(1.0)));
834 }
835 
837 template <class RealType>
838 KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> acosh(
839  const complex<RealType>& x) {
840  return RealType(2.0) * log(sqrt(RealType(0.5) * (x + RealType(1.0))) +
841  sqrt(RealType(0.5) * (x - RealType(1.0))));
842 }
843 
845 template <class RealType>
846 KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> atanh(
847  const complex<RealType>& x) {
848  const RealType i2 = x.imag() * x.imag();
849  const RealType r = RealType(1.0) - i2 - x.real() * x.real();
850 
851  RealType p = RealType(1.0) + x.real();
852  RealType m = RealType(1.0) - x.real();
853 
854  p = i2 + p * p;
855  m = i2 + m * m;
856 
857  RealType phi = atan2(RealType(2.0) * x.imag(), r);
858  return Kokkos::complex<RealType>(RealType(0.25) * (log(p) - log(m)),
859  RealType(0.5) * phi);
860 }
861 
863 template <class RealType>
864 KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> asin(
865  const complex<RealType>& x) {
867  asinh(Kokkos::complex<RealType>(-x.imag(), x.real()));
868  return Kokkos::complex<RealType>(t.imag(), -t.real());
869 }
870 
872 template <class RealType>
873 KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> acos(
874  const complex<RealType>& x) {
875  Kokkos::complex<RealType> t = asin(x);
876  RealType pi_2 = acos(RealType(0.0));
877  return Kokkos::complex<RealType>(pi_2 - t.real(), -t.imag());
878 }
879 
881 template <class RealType>
882 KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> atan(
883  const complex<RealType>& x) {
884  const RealType r2 = x.real() * x.real();
885  const RealType i = RealType(1.0) - r2 - x.imag() * x.imag();
886 
887  RealType p = x.imag() + RealType(1.0);
888  RealType m = x.imag() - RealType(1.0);
889 
890  p = r2 + p * p;
891  m = r2 + m * m;
892 
894  RealType(0.5) * atan2(RealType(2.0) * x.real(), i),
895  RealType(0.25) * log(p / m));
896 }
897 
901 template <class RealType>
902 inline complex<RealType> exp(const std::complex<RealType>& c) {
903  return complex<RealType>(std::exp(c.real()) * std::cos(c.imag()),
904  std::exp(c.real()) * std::sin(c.imag()));
905 }
906 
908 template <class RealType1, class RealType2>
909 KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
910 operator/(const complex<RealType1>& x,
911  const RealType2& y) noexcept(noexcept(RealType1{} / RealType2{})) {
912  return complex<std::common_type_t<RealType1, RealType2>>(real(x) / y,
913  imag(x) / y);
914 }
915 
917 template <class RealType1, class RealType2>
918 KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
919 operator/(const complex<RealType1>& x,
920  const complex<RealType2>& y) noexcept(noexcept(RealType1{} /
921  RealType2{})) {
922  // Scale (by the "1-norm" of y) to avoid unwarranted overflow.
923  // If the real part is +/-Inf and the imaginary part is -/+Inf,
924  // this won't change the result.
925  using common_real_type = std::common_type_t<RealType1, RealType2>;
926  const common_real_type s = fabs(real(y)) + fabs(imag(y));
927 
928  // If s is 0, then y is zero, so x/y == real(x)/0 + i*imag(x)/0.
929  // In that case, the relation x/y == (x/s) / (y/s) doesn't hold,
930  // because y/s is NaN.
931  if (s == 0.0) {
932  return complex<common_real_type>(real(x) / s, imag(x) / s);
933  } else {
934  const complex<common_real_type> x_scaled(real(x) / s, imag(x) / s);
935  const complex<common_real_type> y_conj_scaled(real(y) / s, -imag(y) / s);
936  const RealType1 y_scaled_abs =
937  real(y_conj_scaled) * real(y_conj_scaled) +
938  imag(y_conj_scaled) * imag(y_conj_scaled); // abs(y) == abs(conj(y))
939  complex<common_real_type> result = x_scaled * y_conj_scaled;
940  result /= y_scaled_abs;
941  return result;
942  }
943 }
944 
946 template <class RealType1, class RealType2>
947 KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
948 operator/(const RealType1& x,
949  const complex<RealType2>& y) noexcept(noexcept(RealType1{} /
950  RealType2{})) {
951  return complex<std::common_type_t<RealType1, RealType2>>(x) / y;
952 }
953 
954 template <class RealType>
955 std::ostream& operator<<(std::ostream& os, const complex<RealType>& x) {
956  const std::complex<RealType> x_std(Kokkos::real(x), Kokkos::imag(x));
957  os << x_std;
958  return os;
959 }
960 
961 template <class RealType>
962 std::istream& operator>>(std::istream& is, complex<RealType>& x) {
963  std::complex<RealType> x_std;
964  is >> x_std;
965  x = x_std; // only assigns on success of above
966  return is;
967 }
968 
969 template <class T>
970 struct reduction_identity<Kokkos::complex<T>> {
971  using t_red_ident = reduction_identity<T>;
972  KOKKOS_FORCEINLINE_FUNCTION constexpr static Kokkos::complex<T>
973  sum() noexcept {
974  return Kokkos::complex<T>(t_red_ident::sum(), t_red_ident::sum());
975  }
976  KOKKOS_FORCEINLINE_FUNCTION constexpr static Kokkos::complex<T>
977  prod() noexcept {
978  return Kokkos::complex<T>(t_red_ident::prod(), t_red_ident::sum());
979  }
980 };
981 
982 } // namespace Kokkos
983 
984 #ifdef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_COMPLEX
985 #undef KOKKOS_IMPL_PUBLIC_INCLUDE
986 #undef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_COMPLEX
987 #endif
988 #endif // KOKKOS_COMPLEX_HPP
KOKKOS_INLINE_FUNCTION constexpr void real(RealType v) noexcept
Set the real part of this complex number.
KOKKOS_INLINE_FUNCTION constexpr RealType & imag() noexcept
The imaginary part of this complex number.
Partial reimplementation of std::complex that works as the result of a Kokkos::parallel_reduce.
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 complex(const RealType &val) noexcept
Constructor that takes just the real part, and sets the imaginary part to zero.
complex & operator=(const std::complex< RealType > &src) noexcept
Assignment operator from std::complex.
KOKKOS_INLINE_FUNCTION constexpr RealType & real() noexcept
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() const noexcept
The imaginary part of this complex number.
KOKKOS_INLINE_FUNCTION constexpr void imag(RealType v) noexcept
Set the imaginary part of this complex number.
KOKKOS_INLINE_FUNCTION complex(const std::complex< RealType > &src) noexcept
Conversion constructor from std::complex.
Atomic functions.
RealType value_type
The type of the real or imaginary parts of this complex number.