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 #include <tuple>
32 
33 namespace Kokkos {
34 
42 template <class RealType>
43 class
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 <
74  class RType,
75  std::enable_if_t<std::is_convertible<RType, RealType>::value, int> = 0>
76  KOKKOS_INLINE_FUNCTION complex(const complex<RType>& other) noexcept
77  // Intentionally do the conversions implicitly here so that users don't
78  // get any warnings about narrowing, etc., that they would expect to get
79  // otherwise.
80  : re_(other.real()), im_(other.imag()) {}
81 
87  KOKKOS_INLINE_FUNCTION
88  complex(const std::complex<RealType>& src) noexcept
89  // We can use this aspect of the standard to avoid calling
90  // non-device-marked functions `std::real` and `std::imag`: "For any
91  // object z of type complex<T>, reinterpret_cast<T(&)[2]>(z)[0] is the
92  // real part of z and reinterpret_cast<T(&)[2]>(z)[1] is the imaginary
93  // part of z." Now we don't have to provide a whole bunch of the overloads
94  // of things taking either Kokkos::complex or std::complex
95  : re_(reinterpret_cast<const RealType (&)[2]>(src)[0]),
96  im_(reinterpret_cast<const RealType (&)[2]>(src)[1]) {}
97 
103  // TODO: make explicit. DJS 2019-08-28
104  operator std::complex<RealType>() const noexcept {
105  return std::complex<RealType>(re_, im_);
106  }
107 
110  KOKKOS_INLINE_FUNCTION complex(const RealType& val) noexcept
111  : re_(val), im_(static_cast<RealType>(0)) {}
112 
114  KOKKOS_INLINE_FUNCTION
115  complex(const RealType& re, const RealType& im) noexcept : re_(re), im_(im) {}
116 
118  KOKKOS_INLINE_FUNCTION complex& operator=(const RealType& val) noexcept {
119  re_ = val;
120  im_ = RealType(0);
121  return *this;
122  }
123 
129  complex& operator=(const std::complex<RealType>& src) noexcept {
130  *this = complex(src);
131  return *this;
132  }
133 
135  KOKKOS_INLINE_FUNCTION
136  constexpr RealType& imag() noexcept { return im_; }
137 
139  KOKKOS_INLINE_FUNCTION
140  constexpr RealType& real() noexcept { return re_; }
141 
143  KOKKOS_INLINE_FUNCTION
144  constexpr RealType imag() const noexcept { return im_; }
145 
147  KOKKOS_INLINE_FUNCTION
148  constexpr RealType real() const noexcept { return re_; }
149 
151  KOKKOS_INLINE_FUNCTION
152  constexpr void imag(RealType v) noexcept { im_ = v; }
153 
155  KOKKOS_INLINE_FUNCTION
156  constexpr void real(RealType v) noexcept { re_ = v; }
157 
158  constexpr KOKKOS_INLINE_FUNCTION complex& operator+=(
159  const complex<RealType>& src) noexcept {
160  re_ += src.re_;
161  im_ += src.im_;
162  return *this;
163  }
164 
165  constexpr KOKKOS_INLINE_FUNCTION complex& operator+=(
166  const RealType& src) noexcept {
167  re_ += src;
168  return *this;
169  }
170 
171  constexpr KOKKOS_INLINE_FUNCTION complex& operator-=(
172  const complex<RealType>& src) noexcept {
173  re_ -= src.re_;
174  im_ -= src.im_;
175  return *this;
176  }
177 
178  constexpr KOKKOS_INLINE_FUNCTION complex& operator-=(
179  const RealType& src) noexcept {
180  re_ -= src;
181  return *this;
182  }
183 
184  constexpr KOKKOS_INLINE_FUNCTION complex& operator*=(
185  const complex<RealType>& src) noexcept {
186  const RealType realPart = re_ * src.re_ - im_ * src.im_;
187  const RealType imagPart = re_ * src.im_ + im_ * src.re_;
188  re_ = realPart;
189  im_ = imagPart;
190  return *this;
191  }
192 
193  constexpr KOKKOS_INLINE_FUNCTION complex& operator*=(
194  const RealType& src) noexcept {
195  re_ *= src;
196  im_ *= src;
197  return *this;
198  }
199 
200  // Conditional noexcept, just in case RType throws on divide-by-zero
201  constexpr KOKKOS_INLINE_FUNCTION complex& operator/=(
202  const complex<RealType>& y) noexcept(noexcept(RealType{} / RealType{})) {
203  // Scale (by the "1-norm" of y) to avoid unwarranted overflow.
204  // If the real part is +/-Inf and the imaginary part is -/+Inf,
205  // this won't change the result.
206  const RealType s = fabs(y.real()) + fabs(y.imag());
207 
208  // If s is 0, then y is zero, so x/y == real(x)/0 + i*imag(x)/0.
209  // In that case, the relation x/y == (x/s) / (y/s) doesn't hold,
210  // because y/s is NaN.
211  // TODO mark this branch unlikely
212  if (s == RealType(0)) {
213  this->re_ /= s;
214  this->im_ /= s;
215  } else {
216  const complex x_scaled(this->re_ / s, this->im_ / s);
217  const complex y_conj_scaled(y.re_ / s, -(y.im_) / s);
218  const RealType y_scaled_abs =
219  y_conj_scaled.re_ * y_conj_scaled.re_ +
220  y_conj_scaled.im_ * y_conj_scaled.im_; // abs(y) == abs(conj(y))
221  *this = x_scaled * y_conj_scaled;
222  *this /= y_scaled_abs;
223  }
224  return *this;
225  }
226 
227  constexpr KOKKOS_INLINE_FUNCTION complex& operator/=(
228  const std::complex<RealType>& y) noexcept(noexcept(RealType{} /
229  RealType{})) {
230  // Scale (by the "1-norm" of y) to avoid unwarranted overflow.
231  // If the real part is +/-Inf and the imaginary part is -/+Inf,
232  // this won't change the result.
233  const RealType s = fabs(y.real()) + fabs(y.imag());
234 
235  // If s is 0, then y is zero, so x/y == real(x)/0 + i*imag(x)/0.
236  // In that case, the relation x/y == (x/s) / (y/s) doesn't hold,
237  // because y/s is NaN.
238  if (s == RealType(0)) {
239  this->re_ /= s;
240  this->im_ /= s;
241  } else {
242  const complex x_scaled(this->re_ / s, this->im_ / s);
243  const complex y_conj_scaled(y.re_ / s, -(y.im_) / s);
244  const RealType y_scaled_abs =
245  y_conj_scaled.re_ * y_conj_scaled.re_ +
246  y_conj_scaled.im_ * y_conj_scaled.im_; // abs(y) == abs(conj(y))
247  *this = x_scaled * y_conj_scaled;
248  *this /= y_scaled_abs;
249  }
250  return *this;
251  }
252 
253  constexpr KOKKOS_INLINE_FUNCTION complex& operator/=(
254  const RealType& src) noexcept(noexcept(RealType{} / RealType{})) {
255  re_ /= src;
256  im_ /= src;
257  return *this;
258  }
259 
260  template <size_t I, typename RT>
261  friend constexpr const RT& get(const complex<RT>&) noexcept;
262 
263  template <size_t I, typename RT>
264  friend constexpr const RT&& get(const complex<RT>&&) noexcept;
265 
266 #ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
267  template <
269  class RType,
270  std::enable_if_t<std::is_convertible<RType, RealType>::value, int> = 0>
271  KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION
272  complex(const volatile complex<RType>& src) noexcept
273  // Intentionally do the conversions implicitly here so that users don't
274  // get any warnings about narrowing, etc., that they would expect to get
275  // otherwise.
276  : re_(src.re_), im_(src.im_) {}
277 
287  //
288  // Templated, so as not to be a copy assignment operator (Kokkos issue #2577)
289  // Intended to behave as
290  // void operator=(const complex&) volatile noexcept
291  //
292  // Use cases:
293  // complex r;
294  // const complex cr;
295  // volatile complex vl;
296  // vl = r;
297  // vl = cr;
298  template <class Complex,
299  std::enable_if_t<std::is_same<Complex, complex>::value, int> = 0>
300  KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION void operator=(
301  const Complex& src) volatile noexcept {
302  re_ = src.re_;
303  im_ = src.im_;
304  // We deliberately do not return anything here. See explanation
305  // in public documentation above.
306  }
307 
309  // TODO Should this return void like the other volatile assignment operators?
310  //
311  // Templated, so as not to be a copy assignment operator (Kokkos issue #2577)
312  // Intended to behave as
313  // volatile complex& operator=(const volatile complex&) volatile noexcept
314  //
315  // Use cases:
316  // volatile complex vr;
317  // const volatile complex cvr;
318  // volatile complex vl;
319  // vl = vr;
320  // vl = cvr;
321  template <class Complex,
322  std::enable_if_t<std::is_same<Complex, complex>::value, int> = 0>
323  KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION volatile complex& operator=(
324  const volatile Complex& src) volatile noexcept {
325  re_ = src.re_;
326  im_ = src.im_;
327  return *this;
328  }
329 
331  //
332  // Templated, so as not to be a copy assignment operator (Kokkos issue #2577)
333  // Intended to behave as
334  // complex& operator=(const volatile complex&) noexcept
335  //
336  // Use cases:
337  // volatile complex vr;
338  // const volatile complex cvr;
339  // complex l;
340  // l = vr;
341  // l = cvr;
342  //
343  template <class Complex,
344  std::enable_if_t<std::is_same<Complex, complex>::value, int> = 0>
345  KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION complex& operator=(
346  const volatile Complex& src) noexcept {
347  re_ = src.re_;
348  im_ = src.im_;
349  return *this;
350  }
351 
352  // Mirroring the behavior of the assignment operators from complex RHS in the
353  // RealType RHS versions.
354 
356  KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION void operator=(
357  const volatile RealType& val) noexcept {
358  re_ = val;
359  im_ = RealType(0);
360  // We deliberately do not return anything here. See explanation
361  // in public documentation above.
362  }
363 
365  KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION complex& operator=(
366  const RealType& val) volatile noexcept {
367  re_ = val;
368  im_ = RealType(0);
369  return *this;
370  }
371 
373  // TODO Should this return void like the other volatile assignment operators?
374  KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION complex& operator=(
375  const volatile RealType& val) volatile noexcept {
376  re_ = val;
377  im_ = RealType(0);
378  return *this;
379  }
380 
382  KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION volatile RealType&
383  imag() volatile noexcept {
384  return im_;
385  }
386 
388  KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION volatile RealType&
389  real() volatile noexcept {
390  return re_;
391  }
392 
394  KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION RealType imag() const
395  volatile noexcept {
396  return im_;
397  }
398 
400  KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION RealType real() const
401  volatile noexcept {
402  return re_;
403  }
404 
405  KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION void operator+=(
406  const volatile complex<RealType>& src) volatile noexcept {
407  re_ += src.re_;
408  im_ += src.im_;
409  }
410 
411  KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION void operator+=(
412  const volatile RealType& src) volatile noexcept {
413  re_ += src;
414  }
415 
416  KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION void operator*=(
417  const volatile complex<RealType>& src) volatile noexcept {
418  const RealType realPart = re_ * src.re_ - im_ * src.im_;
419  const RealType imagPart = re_ * src.im_ + im_ * src.re_;
420 
421  re_ = realPart;
422  im_ = imagPart;
423  }
424 
425  KOKKOS_DEPRECATED KOKKOS_INLINE_FUNCTION void operator*=(
426  const volatile RealType& src) volatile noexcept {
427  re_ *= src;
428  im_ *= src;
429  }
430 #endif // KOKKOS_ENABLE_DEPRECATED_CODE_4
431 };
432 
433 } // namespace Kokkos
434 
435 // Tuple protocol for complex based on https://wg21.link/P2819R2 (voted into
436 // the C++26 working draft on 2023-11)
437 
438 template <typename RealType>
439 struct std::tuple_size<Kokkos::complex<RealType>>
440  : std::integral_constant<size_t, 2> {};
441 
442 template <size_t I, typename RealType>
443 struct std::tuple_element<I, Kokkos::complex<RealType>> {
444  static_assert(I < 2);
445  using type = RealType;
446 };
447 
448 namespace Kokkos {
449 
450 // get<...>(...) defined here so as not to be hidden friends, as per P2819R2
451 
452 template <size_t I, typename RealType>
453 KOKKOS_FUNCTION constexpr RealType& get(complex<RealType>& z) noexcept {
454  static_assert(I < 2);
455  if constexpr (I == 0)
456  return z.real();
457  else
458  return z.imag();
459 #ifdef KOKKOS_COMPILER_INTEL
460  __builtin_unreachable();
461 #endif
462 }
463 
464 template <size_t I, typename RealType>
465 KOKKOS_FUNCTION constexpr RealType&& get(complex<RealType>&& z) noexcept {
466  static_assert(I < 2);
467  if constexpr (I == 0)
468  return std::move(z.real());
469  else
470  return std::move(z.imag());
471 #ifdef KOKKOS_COMPILER_INTEL
472  __builtin_unreachable();
473 #endif
474 }
475 
476 template <size_t I, typename RealType>
477 KOKKOS_FUNCTION constexpr const RealType& get(
478  const complex<RealType>& z) noexcept {
479  static_assert(I < 2);
480  if constexpr (I == 0)
481  return z.re_;
482  else
483  return z.im_;
484 #ifdef KOKKOS_COMPILER_INTEL
485  __builtin_unreachable();
486 #endif
487 }
488 
489 template <size_t I, typename RealType>
490 KOKKOS_FUNCTION constexpr const RealType&& get(
491  const complex<RealType>&& z) noexcept {
492  static_assert(I < 2);
493  if constexpr (I == 0)
494  return std::move(z.re_);
495  else
496  return std::move(z.im_);
497 #ifdef KOKKOS_COMPILER_INTEL
498  __builtin_unreachable();
499 #endif
500 }
501 
502 //==============================================================================
503 // <editor-fold desc="Equality and inequality"> {{{1
504 
505 // Note that this is not the same behavior as std::complex, which doesn't allow
506 // implicit conversions, but since this is the way we had it before, we have
507 // to do it this way now.
508 
510 template <class RealType1, class RealType2>
511 KOKKOS_INLINE_FUNCTION bool operator==(complex<RealType1> const& x,
512  complex<RealType2> const& y) noexcept {
513  using common_type = std::common_type_t<RealType1, RealType2>;
514  return common_type(x.real()) == common_type(y.real()) &&
515  common_type(x.imag()) == common_type(y.imag());
516 }
517 
518 // TODO (here and elsewhere) decide if we should convert to a Kokkos::complex
519 // and do the comparison in a device-marked function
521 template <class RealType1, class RealType2>
522 inline bool operator==(std::complex<RealType1> const& x,
523  complex<RealType2> const& y) noexcept {
524  using common_type = std::common_type_t<RealType1, RealType2>;
525  return common_type(x.real()) == common_type(y.real()) &&
526  common_type(x.imag()) == common_type(y.imag());
527 }
528 
530 template <class RealType1, class RealType2>
531 inline bool operator==(complex<RealType1> const& x,
532  std::complex<RealType2> const& y) noexcept {
533  using common_type = std::common_type_t<RealType1, RealType2>;
534  return common_type(x.real()) == common_type(y.real()) &&
535  common_type(x.imag()) == common_type(y.imag());
536 }
537 
539 template <
540  class RealType1, class RealType2,
541  // Constraints to avoid participation in oparator==() for every possible RHS
542  std::enable_if_t<std::is_convertible<RealType2, RealType1>::value, int> = 0>
543 KOKKOS_INLINE_FUNCTION bool operator==(complex<RealType1> const& x,
544  RealType2 const& y) noexcept {
545  using common_type = std::common_type_t<RealType1, RealType2>;
546  return common_type(x.real()) == common_type(y) &&
547  common_type(x.imag()) == common_type(0);
548 }
549 
551 template <
552  class RealType1, class RealType2,
553  // Constraints to avoid participation in oparator==() for every possible RHS
554  std::enable_if_t<std::is_convertible<RealType1, RealType2>::value, int> = 0>
555 KOKKOS_INLINE_FUNCTION bool operator==(RealType1 const& x,
556  complex<RealType2> const& y) noexcept {
557  using common_type = std::common_type_t<RealType1, RealType2>;
558  return common_type(x) == common_type(y.real()) &&
559  common_type(0) == common_type(y.imag());
560 }
561 
563 template <class RealType1, class RealType2>
564 KOKKOS_INLINE_FUNCTION bool operator!=(complex<RealType1> const& x,
565  complex<RealType2> const& y) noexcept {
566  using common_type = std::common_type_t<RealType1, RealType2>;
567  return common_type(x.real()) != common_type(y.real()) ||
568  common_type(x.imag()) != common_type(y.imag());
569 }
570 
572 template <class RealType1, class RealType2>
573 inline bool operator!=(std::complex<RealType1> const& x,
574  complex<RealType2> const& y) noexcept {
575  using common_type = std::common_type_t<RealType1, RealType2>;
576  return common_type(x.real()) != common_type(y.real()) ||
577  common_type(x.imag()) != common_type(y.imag());
578 }
579 
581 template <class RealType1, class RealType2>
582 inline bool operator!=(complex<RealType1> const& x,
583  std::complex<RealType2> const& y) noexcept {
584  using common_type = std::common_type_t<RealType1, RealType2>;
585  return common_type(x.real()) != common_type(y.real()) ||
586  common_type(x.imag()) != common_type(y.imag());
587 }
588 
590 template <
591  class RealType1, class RealType2,
592  // Constraints to avoid participation in oparator==() for every possible RHS
593  std::enable_if_t<std::is_convertible<RealType2, RealType1>::value, int> = 0>
594 KOKKOS_INLINE_FUNCTION bool operator!=(complex<RealType1> const& x,
595  RealType2 const& y) noexcept {
596  using common_type = std::common_type_t<RealType1, RealType2>;
597  return common_type(x.real()) != common_type(y) ||
598  common_type(x.imag()) != common_type(0);
599 }
600 
602 template <
603  class RealType1, class RealType2,
604  // Constraints to avoid participation in oparator==() for every possible RHS
605  std::enable_if_t<std::is_convertible<RealType1, RealType2>::value, int> = 0>
606 KOKKOS_INLINE_FUNCTION bool operator!=(RealType1 const& x,
607  complex<RealType2> const& y) noexcept {
608  using common_type = std::common_type_t<RealType1, RealType2>;
609  return common_type(x) != common_type(y.real()) ||
610  common_type(0) != common_type(y.imag());
611 }
612 
613 // </editor-fold> end Equality and inequality }}}1
614 //==============================================================================
615 
617 template <class RealType1, class RealType2>
618 KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
619 operator+(const complex<RealType1>& x, const complex<RealType2>& y) noexcept {
620  return complex<std::common_type_t<RealType1, RealType2>>(x.real() + y.real(),
621  x.imag() + y.imag());
622 }
623 
625 template <class RealType1, class RealType2>
626 KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
627 operator+(const complex<RealType1>& x, const RealType2& y) noexcept {
628  return complex<std::common_type_t<RealType1, RealType2>>(x.real() + y,
629  x.imag());
630 }
631 
633 template <class RealType1, class RealType2>
634 KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
635 operator+(const RealType1& x, const complex<RealType2>& y) noexcept {
636  return complex<std::common_type_t<RealType1, RealType2>>(x + y.real(),
637  y.imag());
638 }
639 
641 template <class RealType>
642 KOKKOS_INLINE_FUNCTION complex<RealType> operator+(
643  const complex<RealType>& x) noexcept {
644  return complex<RealType>{+x.real(), +x.imag()};
645 }
646 
648 template <class RealType1, class RealType2>
649 KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
650 operator-(const complex<RealType1>& x, const complex<RealType2>& y) noexcept {
651  return complex<std::common_type_t<RealType1, RealType2>>(x.real() - y.real(),
652  x.imag() - y.imag());
653 }
654 
656 template <class RealType1, class RealType2>
657 KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
658 operator-(const complex<RealType1>& x, const RealType2& y) noexcept {
659  return complex<std::common_type_t<RealType1, RealType2>>(x.real() - y,
660  x.imag());
661 }
662 
664 template <class RealType1, class RealType2>
665 KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
666 operator-(const RealType1& x, const complex<RealType2>& y) noexcept {
667  return complex<std::common_type_t<RealType1, RealType2>>(x - y.real(),
668  -y.imag());
669 }
670 
672 template <class RealType>
673 KOKKOS_INLINE_FUNCTION complex<RealType> operator-(
674  const complex<RealType>& x) noexcept {
675  return complex<RealType>(-x.real(), -x.imag());
676 }
677 
679 template <class RealType1, class RealType2>
680 KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
681 operator*(const complex<RealType1>& x, const complex<RealType2>& y) noexcept {
682  return complex<std::common_type_t<RealType1, RealType2>>(
683  x.real() * y.real() - x.imag() * y.imag(),
684  x.real() * y.imag() + x.imag() * y.real());
685 }
686 
695 template <class RealType1, class RealType2>
696 inline complex<std::common_type_t<RealType1, RealType2>> operator*(
697  const std::complex<RealType1>& x, const complex<RealType2>& y) {
698  return complex<std::common_type_t<RealType1, RealType2>>(
699  x.real() * y.real() - x.imag() * y.imag(),
700  x.real() * y.imag() + x.imag() * y.real());
701 }
702 
707 template <class RealType1, class RealType2>
708 KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
709 operator*(const RealType1& x, const complex<RealType2>& y) noexcept {
710  return complex<std::common_type_t<RealType1, RealType2>>(x * y.real(),
711  x * y.imag());
712 }
713 
718 template <class RealType1, class RealType2>
719 KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
720 operator*(const complex<RealType1>& y, const RealType2& x) noexcept {
721  return complex<std::common_type_t<RealType1, RealType2>>(x * y.real(),
722  x * y.imag());
723 }
724 
726 template <class RealType>
727 KOKKOS_INLINE_FUNCTION RealType imag(const complex<RealType>& x) noexcept {
728  return x.imag();
729 }
730 
731 template <class ArithmeticType>
732 KOKKOS_INLINE_FUNCTION constexpr Impl::promote_t<ArithmeticType> imag(
733  ArithmeticType) {
734  return ArithmeticType();
735 }
736 
738 template <class RealType>
739 KOKKOS_INLINE_FUNCTION RealType real(const complex<RealType>& x) noexcept {
740  return x.real();
741 }
742 
743 template <class ArithmeticType>
744 KOKKOS_INLINE_FUNCTION constexpr Impl::promote_t<ArithmeticType> real(
745  ArithmeticType x) {
746  return x;
747 }
748 
750 template <class T>
751 KOKKOS_INLINE_FUNCTION complex<T> polar(const T& r, const T& theta = T()) {
752  KOKKOS_EXPECTS(r >= 0);
753  return complex<T>(r * cos(theta), r * sin(theta));
754 }
755 
757 template <class RealType>
758 KOKKOS_INLINE_FUNCTION RealType abs(const complex<RealType>& x) {
759  return hypot(x.real(), x.imag());
760 }
761 
763 template <class T>
764 KOKKOS_INLINE_FUNCTION complex<T> pow(const complex<T>& x, const T& y) {
765  T r = abs(x);
766  T theta = atan2(x.imag(), x.real());
767  return polar(pow(r, y), y * theta);
768 }
769 
770 template <class T>
771 KOKKOS_INLINE_FUNCTION complex<T> pow(const T& x, const complex<T>& y) {
772  return pow(complex<T>(x), y);
773 }
774 
775 template <class T>
776 KOKKOS_INLINE_FUNCTION complex<T> pow(const complex<T>& x,
777  const complex<T>& y) {
778  return x == T() ? T() : exp(y * log(x));
779 }
780 
781 template <class T, class U,
782  class = std::enable_if_t<std::is_arithmetic<T>::value>>
783 KOKKOS_INLINE_FUNCTION complex<Impl::promote_2_t<T, U>> pow(
784  const T& x, const complex<U>& y) {
785  using type = Impl::promote_2_t<T, U>;
786  return pow(type(x), complex<type>(y));
787 }
788 
789 template <class T, class U,
790  class = std::enable_if_t<std::is_arithmetic<U>::value>>
791 KOKKOS_INLINE_FUNCTION complex<Impl::promote_2_t<T, U>> pow(const complex<T>& x,
792  const U& y) {
793  using type = Impl::promote_2_t<T, U>;
794  return pow(complex<type>(x), type(y));
795 }
796 
797 template <class T, class U>
798 KOKKOS_INLINE_FUNCTION complex<Impl::promote_2_t<T, U>> pow(
799  const complex<T>& x, const complex<U>& y) {
800  using type = Impl::promote_2_t<T, U>;
801  return pow(complex<type>(x), complex<type>(y));
802 }
803 
806 template <class RealType>
807 KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> sqrt(
808  const complex<RealType>& x) {
809  RealType r = x.real();
810  RealType i = x.imag();
811 
812  if (r == RealType()) {
813  RealType t = sqrt(fabs(i) / 2);
814  return Kokkos::complex<RealType>(t, i < RealType() ? -t : t);
815  } else {
816  RealType t = sqrt(2 * (abs(x) + fabs(r)));
817  RealType u = t / 2;
818  return r > RealType() ? Kokkos::complex<RealType>(u, i / t)
819  : Kokkos::complex<RealType>(fabs(i) / t,
820  i < RealType() ? -u : u);
821  }
822 }
823 
825 template <class RealType>
826 KOKKOS_INLINE_FUNCTION complex<RealType> conj(
827  const complex<RealType>& x) noexcept {
828  return complex<RealType>(real(x), -imag(x));
829 }
830 
831 template <class ArithmeticType>
832 KOKKOS_INLINE_FUNCTION constexpr complex<Impl::promote_t<ArithmeticType>> conj(
833  ArithmeticType x) {
834  using type = Impl::promote_t<ArithmeticType>;
835  return complex<type>(x, -type());
836 }
837 
839 template <class RealType>
840 KOKKOS_INLINE_FUNCTION complex<RealType> exp(const complex<RealType>& x) {
841  return exp(x.real()) * complex<RealType>(cos(x.imag()), sin(x.imag()));
842 }
843 
845 template <class RealType>
846 KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> log(
847  const complex<RealType>& x) {
848  RealType phi = atan2(x.imag(), x.real());
849  return Kokkos::complex<RealType>(log(abs(x)), phi);
850 }
851 
853 template <class RealType>
854 KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> log10(
855  const complex<RealType>& x) {
856  return log(x) / log(RealType(10));
857 }
858 
860 template <class RealType>
861 KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> sin(
862  const complex<RealType>& x) {
863  return Kokkos::complex<RealType>(sin(x.real()) * cosh(x.imag()),
864  cos(x.real()) * sinh(x.imag()));
865 }
866 
868 template <class RealType>
869 KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> cos(
870  const complex<RealType>& x) {
871  return Kokkos::complex<RealType>(cos(x.real()) * cosh(x.imag()),
872  -sin(x.real()) * sinh(x.imag()));
873 }
874 
876 template <class RealType>
877 KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> tan(
878  const complex<RealType>& x) {
879  return sin(x) / cos(x);
880 }
881 
883 template <class RealType>
884 KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> sinh(
885  const complex<RealType>& x) {
886  return Kokkos::complex<RealType>(sinh(x.real()) * cos(x.imag()),
887  cosh(x.real()) * sin(x.imag()));
888 }
889 
891 template <class RealType>
892 KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> cosh(
893  const complex<RealType>& x) {
894  return Kokkos::complex<RealType>(cosh(x.real()) * cos(x.imag()),
895  sinh(x.real()) * sin(x.imag()));
896 }
897 
899 template <class RealType>
900 KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> tanh(
901  const complex<RealType>& x) {
902  return sinh(x) / cosh(x);
903 }
904 
906 template <class RealType>
907 KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> asinh(
908  const complex<RealType>& x) {
909  return log(x + sqrt(x * x + RealType(1.0)));
910 }
911 
913 template <class RealType>
914 KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> acosh(
915  const complex<RealType>& x) {
916  return RealType(2.0) * log(sqrt(RealType(0.5) * (x + RealType(1.0))) +
917  sqrt(RealType(0.5) * (x - RealType(1.0))));
918 }
919 
921 template <class RealType>
922 KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> atanh(
923  const complex<RealType>& x) {
924  const RealType i2 = x.imag() * x.imag();
925  const RealType r = RealType(1.0) - i2 - x.real() * x.real();
926 
927  RealType p = RealType(1.0) + x.real();
928  RealType m = RealType(1.0) - x.real();
929 
930  p = i2 + p * p;
931  m = i2 + m * m;
932 
933  RealType phi = atan2(RealType(2.0) * x.imag(), r);
934  return Kokkos::complex<RealType>(RealType(0.25) * (log(p) - log(m)),
935  RealType(0.5) * phi);
936 }
937 
939 template <class RealType>
940 KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> asin(
941  const complex<RealType>& x) {
943  asinh(Kokkos::complex<RealType>(-x.imag(), x.real()));
944  return Kokkos::complex<RealType>(t.imag(), -t.real());
945 }
946 
948 template <class RealType>
949 KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> acos(
950  const complex<RealType>& x) {
951  Kokkos::complex<RealType> t = asin(x);
952  RealType pi_2 = acos(RealType(0.0));
953  return Kokkos::complex<RealType>(pi_2 - t.real(), -t.imag());
954 }
955 
957 template <class RealType>
958 KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> atan(
959  const complex<RealType>& x) {
960  const RealType r2 = x.real() * x.real();
961  const RealType i = RealType(1.0) - r2 - x.imag() * x.imag();
962 
963  RealType p = x.imag() + RealType(1.0);
964  RealType m = x.imag() - RealType(1.0);
965 
966  p = r2 + p * p;
967  m = r2 + m * m;
968 
970  RealType(0.5) * atan2(RealType(2.0) * x.real(), i),
971  RealType(0.25) * log(p / m));
972 }
973 
977 template <class RealType>
978 inline complex<RealType> exp(const std::complex<RealType>& c) {
979  return complex<RealType>(std::exp(c.real()) * std::cos(c.imag()),
980  std::exp(c.real()) * std::sin(c.imag()));
981 }
982 
984 template <class RealType1, class RealType2>
985 KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
986 operator/(const complex<RealType1>& x,
987  const RealType2& y) noexcept(noexcept(RealType1{} / RealType2{})) {
988  return complex<std::common_type_t<RealType1, RealType2>>(real(x) / y,
989  imag(x) / y);
990 }
991 
993 template <class RealType1, class RealType2>
994 KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
995 operator/(const complex<RealType1>& x,
996  const complex<RealType2>& y) noexcept(noexcept(RealType1{} /
997  RealType2{})) {
998  // Scale (by the "1-norm" of y) to avoid unwarranted overflow.
999  // If the real part is +/-Inf and the imaginary part is -/+Inf,
1000  // this won't change the result.
1001  using common_real_type = std::common_type_t<RealType1, RealType2>;
1002  const common_real_type s = fabs(real(y)) + fabs(imag(y));
1003 
1004  // If s is 0, then y is zero, so x/y == real(x)/0 + i*imag(x)/0.
1005  // In that case, the relation x/y == (x/s) / (y/s) doesn't hold,
1006  // because y/s is NaN.
1007  if (s == 0.0) {
1008  return complex<common_real_type>(real(x) / s, imag(x) / s);
1009  } else {
1010  const complex<common_real_type> x_scaled(real(x) / s, imag(x) / s);
1011  const complex<common_real_type> y_conj_scaled(real(y) / s, -imag(y) / s);
1012  const RealType1 y_scaled_abs =
1013  real(y_conj_scaled) * real(y_conj_scaled) +
1014  imag(y_conj_scaled) * imag(y_conj_scaled); // abs(y) == abs(conj(y))
1015  complex<common_real_type> result = x_scaled * y_conj_scaled;
1016  result /= y_scaled_abs;
1017  return result;
1018  }
1019 }
1020 
1022 template <class RealType1, class RealType2>
1023 KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
1024 operator/(const RealType1& x,
1025  const complex<RealType2>& y) noexcept(noexcept(RealType1{} /
1026  RealType2{})) {
1027  return complex<std::common_type_t<RealType1, RealType2>>(x) / y;
1028 }
1029 
1030 template <class RealType>
1031 std::ostream& operator<<(std::ostream& os, const complex<RealType>& x) {
1032  const std::complex<RealType> x_std(Kokkos::real(x), Kokkos::imag(x));
1033  os << x_std;
1034  return os;
1035 }
1036 
1037 template <class RealType>
1038 std::istream& operator>>(std::istream& is, complex<RealType>& x) {
1039  std::complex<RealType> x_std;
1040  is >> x_std;
1041  x = x_std; // only assigns on success of above
1042  return is;
1043 }
1044 
1045 template <class T>
1046 struct reduction_identity<Kokkos::complex<T>> {
1047  using t_red_ident = reduction_identity<T>;
1048  KOKKOS_FORCEINLINE_FUNCTION constexpr static Kokkos::complex<T>
1049  sum() noexcept {
1050  return Kokkos::complex<T>(t_red_ident::sum(), t_red_ident::sum());
1051  }
1052  KOKKOS_FORCEINLINE_FUNCTION constexpr static Kokkos::complex<T>
1053  prod() noexcept {
1054  return Kokkos::complex<T>(t_red_ident::prod(), t_red_ident::sum());
1055  }
1056 };
1057 
1058 } // namespace Kokkos
1059 
1060 #ifdef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_COMPLEX
1061 #undef KOKKOS_IMPL_PUBLIC_INCLUDE
1062 #undef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_COMPLEX
1063 #endif
1064 #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.