Kokkos Core Kernels Package  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Kokkos_Complex.hpp
1 /*
2 //@HEADER
3 // ************************************************************************
4 //
5 // Kokkos v. 3.0
6 // Copyright (2020) National Technology & Engineering
7 // Solutions of Sandia, LLC (NTESS).
8 //
9 // Under the terms of Contract DE-NA0003525 with NTESS,
10 // the U.S. Government retains certain rights in this software.
11 //
12 // Redistribution and use in source and binary forms, with or without
13 // modification, are permitted provided that the following conditions are
14 // met:
15 //
16 // 1. Redistributions of source code must retain the above copyright
17 // notice, this list of conditions and the following disclaimer.
18 //
19 // 2. Redistributions in binary form must reproduce the above copyright
20 // notice, this list of conditions and the following disclaimer in the
21 // documentation and/or other materials provided with the distribution.
22 //
23 // 3. Neither the name of the Corporation nor the names of the
24 // contributors may be used to endorse or promote products derived from
25 // this software without specific prior written permission.
26 //
27 // THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
28 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
31 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
32 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
33 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
34 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
35 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
36 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 //
39 // Questions? Contact Christian R. Trott (crtrott@sandia.gov)
40 //
41 // ************************************************************************
42 //@HEADER
43 */
44 #ifndef KOKKOS_COMPLEX_HPP
45 #define KOKKOS_COMPLEX_HPP
46 
47 #include <Kokkos_Atomic.hpp>
48 #include <Kokkos_NumericTraits.hpp>
49 #include <complex>
50 #include <iostream>
51 
52 namespace Kokkos {
53 
61 template <class RealType>
62 class
63 #ifdef KOKKOS_ENABLE_COMPLEX_ALIGN
64  alignas(2 * sizeof(RealType))
65 #endif
66  complex {
67  private:
68  RealType re_{};
69  RealType im_{};
70 
71  public:
73  using value_type = RealType;
74 
76  KOKKOS_DEFAULTED_FUNCTION
77  complex() noexcept = default;
78 
80  KOKKOS_DEFAULTED_FUNCTION
81  complex(const complex&) noexcept = default;
82 
83  KOKKOS_DEFAULTED_FUNCTION
84  complex& operator=(const complex&) noexcept = default;
85 
87  template <class RType,
88  typename std::enable_if<std::is_convertible<RType, RealType>::value,
89  int>::type = 0>
90  KOKKOS_INLINE_FUNCTION complex(const complex<RType>& other) noexcept
91  // Intentionally do the conversions implicitly here so that users don't
92  // get any warnings about narrowing, etc., that they would expect to get
93  // otherwise.
94  : re_(other.real()), im_(other.imag()) {}
95 
101  KOKKOS_INLINE_FUNCTION
102  complex(const std::complex<RealType>& src) noexcept
103  // We can use this aspect of the standard to avoid calling
104  // non-device-marked functions `std::real` and `std::imag`: "For any
105  // object z of type complex<T>, reinterpret_cast<T(&)[2]>(z)[0] is the
106  // real part of z and reinterpret_cast<T(&)[2]>(z)[1] is the imaginary
107  // part of z." Now we don't have to provide a whole bunch of the overloads
108  // of things taking either Kokkos::complex or std::complex
109  : re_(reinterpret_cast<const RealType (&)[2]>(src)[0]),
110  im_(reinterpret_cast<const RealType (&)[2]>(src)[1]) {}
111 
117  // TODO: make explicit. DJS 2019-08-28
118  operator std::complex<RealType>() const noexcept {
119  return std::complex<RealType>(re_, im_);
120  }
121 
124  KOKKOS_INLINE_FUNCTION complex(const RealType& val) noexcept
125  : re_(val), im_(static_cast<RealType>(0)) {}
126 
128  KOKKOS_INLINE_FUNCTION
129  complex(const RealType& re, const RealType& im) noexcept : re_(re), im_(im) {}
130 
132  KOKKOS_INLINE_FUNCTION complex& operator=(const RealType& val) noexcept {
133  re_ = val;
134  im_ = RealType(0);
135  return *this;
136  }
137 
143  complex& operator=(const std::complex<RealType>& src) noexcept {
144  *this = complex(src);
145  return *this;
146  }
147 
149  KOKKOS_INLINE_FUNCTION
150  KOKKOS_CONSTEXPR_14 RealType& imag() noexcept { return im_; }
151 
153  KOKKOS_INLINE_FUNCTION
154  KOKKOS_CONSTEXPR_14 RealType& real() noexcept { return re_; }
155 
157  KOKKOS_INLINE_FUNCTION
158  constexpr RealType imag() const noexcept { return im_; }
159 
161  KOKKOS_INLINE_FUNCTION
162  constexpr RealType real() const noexcept { return re_; }
163 
165  KOKKOS_INLINE_FUNCTION
166  KOKKOS_CONSTEXPR_14
167  void imag(RealType v) noexcept { im_ = v; }
168 
170  KOKKOS_INLINE_FUNCTION
171  KOKKOS_CONSTEXPR_14
172  void real(RealType v) noexcept { re_ = v; }
173 
174  KOKKOS_CONSTEXPR_14 KOKKOS_INLINE_FUNCTION complex& operator+=(
175  const complex<RealType>& src) noexcept {
176  re_ += src.re_;
177  im_ += src.im_;
178  return *this;
179  }
180 
181  KOKKOS_CONSTEXPR_14 KOKKOS_INLINE_FUNCTION complex& operator+=(
182  const RealType& src) noexcept {
183  re_ += src;
184  return *this;
185  }
186 
187  KOKKOS_CONSTEXPR_14 KOKKOS_INLINE_FUNCTION complex& operator-=(
188  const complex<RealType>& src) noexcept {
189  re_ -= src.re_;
190  im_ -= src.im_;
191  return *this;
192  }
193 
194  KOKKOS_CONSTEXPR_14 KOKKOS_INLINE_FUNCTION complex& operator-=(
195  const RealType& src) noexcept {
196  re_ -= src;
197  return *this;
198  }
199 
200  KOKKOS_CONSTEXPR_14 KOKKOS_INLINE_FUNCTION complex& operator*=(
201  const complex<RealType>& src) noexcept {
202  const RealType realPart = re_ * src.re_ - im_ * src.im_;
203  const RealType imagPart = re_ * src.im_ + im_ * src.re_;
204  re_ = realPart;
205  im_ = imagPart;
206  return *this;
207  }
208 
209  KOKKOS_CONSTEXPR_14 KOKKOS_INLINE_FUNCTION complex& operator*=(
210  const RealType& src) noexcept {
211  re_ *= src;
212  im_ *= src;
213  return *this;
214  }
215 
216  // Conditional noexcept, just in case RType throws on divide-by-zero
217  KOKKOS_CONSTEXPR_14 KOKKOS_INLINE_FUNCTION complex& operator/=(
218  const complex<RealType>& y) noexcept(noexcept(RealType{} / RealType{})) {
219  // Scale (by the "1-norm" of y) to avoid unwarranted overflow.
220  // If the real part is +/-Inf and the imaginary part is -/+Inf,
221  // this won't change the result.
222 #if !defined(__HIP_DEVICE_COMPILE__) // FIXME_HIP
223  using std::fabs;
224 #endif
225  const RealType s = fabs(y.real()) + fabs(y.imag());
226 
227  // If s is 0, then y is zero, so x/y == real(x)/0 + i*imag(x)/0.
228  // In that case, the relation x/y == (x/s) / (y/s) doesn't hold,
229  // because y/s is NaN.
230  // TODO mark this branch unlikely
231  if (s == RealType(0)) {
232  this->re_ /= s;
233  this->im_ /= s;
234  } else {
235  const complex x_scaled(this->re_ / s, this->im_ / s);
236  const complex y_conj_scaled(y.re_ / s, -(y.im_) / s);
237  const RealType y_scaled_abs =
238  y_conj_scaled.re_ * y_conj_scaled.re_ +
239  y_conj_scaled.im_ * y_conj_scaled.im_; // abs(y) == abs(conj(y))
240  *this = x_scaled * y_conj_scaled;
241  *this /= y_scaled_abs;
242  }
243  return *this;
244  }
245 
246  KOKKOS_CONSTEXPR_14
247  KOKKOS_INLINE_FUNCTION complex& operator/=(
248  const std::complex<RealType>& y) noexcept(noexcept(RealType{} /
249  RealType{})) {
250  // Scale (by the "1-norm" of y) to avoid unwarranted overflow.
251  // If the real part is +/-Inf and the imaginary part is -/+Inf,
252  // this won't change the result.
253 #if !defined(__HIP_DEVICE_COMPILE__) // FIXME_HIP
254  using std::fabs;
255 #endif
256  const RealType s = fabs(y.real()) + fabs(y.imag());
257 
258  // If s is 0, then y is zero, so x/y == real(x)/0 + i*imag(x)/0.
259  // In that case, the relation x/y == (x/s) / (y/s) doesn't hold,
260  // because y/s is NaN.
261  if (s == RealType(0)) {
262  this->re_ /= s;
263  this->im_ /= s;
264  } else {
265  const complex x_scaled(this->re_ / s, this->im_ / s);
266  const complex y_conj_scaled(y.re_ / s, -(y.im_) / s);
267  const RealType y_scaled_abs =
268  y_conj_scaled.re_ * y_conj_scaled.re_ +
269  y_conj_scaled.im_ * y_conj_scaled.im_; // abs(y) == abs(conj(y))
270  *this = x_scaled * y_conj_scaled;
271  *this /= y_scaled_abs;
272  }
273  return *this;
274  }
275 
276  KOKKOS_CONSTEXPR_14 KOKKOS_INLINE_FUNCTION complex& operator/=(
277  const RealType& src) noexcept(noexcept(RealType{} / RealType{})) {
278  re_ /= src;
279  im_ /= src;
280  return *this;
281  }
282 
283  //---------------------------------------------------------------------------
284  // TODO: refactor Kokkos reductions to remove dependency on
285  // volatile member overloads since they are being deprecated in c++20
286  //---------------------------------------------------------------------------
287 
289  template <class RType,
290  typename std::enable_if<std::is_convertible<RType, RealType>::value,
291  int>::type = 0>
292  KOKKOS_INLINE_FUNCTION complex(const volatile complex<RType>& src) noexcept
293  // Intentionally do the conversions implicitly here so that users don't
294  // get any warnings about narrowing, etc., that they would expect to get
295  // otherwise.
296  : re_(src.re_), im_(src.im_) {}
297 
307  //
308  // Templated, so as not to be a copy assignment operator (Kokkos issue #2577)
309  // Intended to behave as
310  // void operator=(const complex&) volatile noexcept
311  //
312  // Use cases:
313  // complex r;
314  // const complex cr;
315  // volatile complex vl;
316  // vl = r;
317  // vl = cr;
318  template <class Complex,
319  typename std::enable_if<std::is_same<Complex, complex>::value,
320  int>::type = 0>
321  KOKKOS_INLINE_FUNCTION void operator=(const Complex& src) volatile noexcept {
322  re_ = src.re_;
323  im_ = src.im_;
324  // We deliberately do not return anything here. See explanation
325  // in public documentation above.
326  }
327 
329  // TODO Should this return void like the other volatile assignment operators?
330  //
331  // Templated, so as not to be a copy assignment operator (Kokkos issue #2577)
332  // Intended to behave as
333  // volatile complex& operator=(const volatile complex&) volatile noexcept
334  //
335  // Use cases:
336  // volatile complex vr;
337  // const volatile complex cvr;
338  // volatile complex vl;
339  // vl = vr;
340  // vl = cvr;
341  template <class Complex,
342  typename std::enable_if<std::is_same<Complex, complex>::value,
343  int>::type = 0>
344  KOKKOS_INLINE_FUNCTION volatile complex& operator=(
345  const volatile Complex& src) volatile noexcept {
346  re_ = src.re_;
347  im_ = src.im_;
348  return *this;
349  }
350 
352  //
353  // Templated, so as not to be a copy assignment operator (Kokkos issue #2577)
354  // Intended to behave as
355  // complex& operator=(const volatile complex&) noexcept
356  //
357  // Use cases:
358  // volatile complex vr;
359  // const volatile complex cvr;
360  // complex l;
361  // l = vr;
362  // l = cvr;
363  //
364  template <class Complex,
365  typename std::enable_if<std::is_same<Complex, complex>::value,
366  int>::type = 0>
367  KOKKOS_INLINE_FUNCTION complex& operator=(
368  const volatile Complex& src) noexcept {
369  re_ = src.re_;
370  im_ = src.im_;
371  return *this;
372  }
373 
374  // Mirroring the behavior of the assignment operators from complex RHS in the
375  // RealType RHS versions.
376 
378  KOKKOS_INLINE_FUNCTION void operator=(const volatile RealType& val) noexcept {
379  re_ = val;
380  im_ = RealType(0);
381  // We deliberately do not return anything here. See explanation
382  // in public documentation above.
383  }
384 
386  KOKKOS_INLINE_FUNCTION complex& operator=(
387  const RealType& val) volatile noexcept {
388  re_ = val;
389  im_ = RealType(0);
390  return *this;
391  }
392 
394  // TODO Should this return void like the other volatile assignment operators?
395  KOKKOS_INLINE_FUNCTION complex& operator=(
396  const volatile RealType& val) volatile noexcept {
397  re_ = val;
398  im_ = RealType(0);
399  return *this;
400  }
401 
403  KOKKOS_INLINE_FUNCTION
404  volatile RealType& imag() volatile noexcept { return im_; }
405 
407  KOKKOS_INLINE_FUNCTION
408  volatile RealType& real() volatile noexcept { return re_; }
409 
411  KOKKOS_INLINE_FUNCTION
412  RealType imag() const volatile noexcept { return im_; }
413 
415  KOKKOS_INLINE_FUNCTION
416  RealType real() const volatile noexcept { return re_; }
417 
418  KOKKOS_INLINE_FUNCTION void operator+=(
419  const volatile complex<RealType>& src) volatile noexcept {
420  re_ += src.re_;
421  im_ += src.im_;
422  }
423 
424  KOKKOS_INLINE_FUNCTION void operator+=(
425  const volatile RealType& src) volatile noexcept {
426  re_ += src;
427  }
428 
429  KOKKOS_INLINE_FUNCTION void operator*=(
430  const volatile complex<RealType>& src) volatile noexcept {
431  const RealType realPart = re_ * src.re_ - im_ * src.im_;
432  const RealType imagPart = re_ * src.im_ + im_ * src.re_;
433 
434  re_ = realPart;
435  im_ = imagPart;
436  }
437 
438  KOKKOS_INLINE_FUNCTION void operator*=(
439  const volatile RealType& src) volatile noexcept {
440  re_ *= src;
441  im_ *= src;
442  }
443 
444  // TODO DSH 2019-10-7 why are there no volatile /= and friends?
445 };
446 
447 //==============================================================================
448 // <editor-fold desc="Equality and inequality"> {{{1
449 
450 // Note that this is not the same behavior as std::complex, which doesn't allow
451 // implicit conversions, but since this is the way we had it before, we have
452 // to do it this way now.
453 
455 template <class RealType1, class RealType2>
456 KOKKOS_INLINE_FUNCTION bool operator==(complex<RealType1> const& x,
457  complex<RealType2> const& y) noexcept {
458  using common_type = typename std::common_type<RealType1, RealType2>::type;
459  return common_type(x.real()) == common_type(y.real()) &&
460  common_type(x.imag()) == common_type(y.imag());
461 }
462 
463 // TODO (here and elsewhere) decide if we should convert to a Kokkos::complex
464 // and do the comparison in a device-marked function
466 template <class RealType1, class RealType2>
467 inline bool operator==(std::complex<RealType1> const& x,
468  complex<RealType2> const& y) noexcept {
469  using common_type = typename std::common_type<RealType1, RealType2>::type;
470  return common_type(x.real()) == common_type(y.real()) &&
471  common_type(x.imag()) == common_type(y.imag());
472 }
473 
475 template <class RealType1, class RealType2>
476 inline bool operator==(complex<RealType1> const& x,
477  std::complex<RealType2> const& y) noexcept {
478  using common_type = typename std::common_type<RealType1, RealType2>::type;
479  return common_type(x.real()) == common_type(y.real()) &&
480  common_type(x.imag()) == common_type(y.imag());
481 }
482 
484 template <
485  class RealType1, class RealType2,
486  // Constraints to avoid participation in oparator==() for every possible RHS
487  typename std::enable_if<std::is_convertible<RealType2, RealType1>::value,
488  int>::type = 0>
489 KOKKOS_INLINE_FUNCTION bool operator==(complex<RealType1> const& x,
490  RealType2 const& y) noexcept {
491  using common_type = typename std::common_type<RealType1, RealType2>::type;
492  return common_type(x.real()) == common_type(y) &&
493  common_type(x.imag()) == common_type(0);
494 }
495 
497 template <
498  class RealType1, class RealType2,
499  // Constraints to avoid participation in oparator==() for every possible RHS
500  typename std::enable_if<std::is_convertible<RealType1, RealType2>::value,
501  int>::type = 0>
502 KOKKOS_INLINE_FUNCTION bool operator==(RealType1 const& x,
503  complex<RealType2> const& y) noexcept {
504  using common_type = typename std::common_type<RealType1, RealType2>::type;
505  return common_type(x) == common_type(y.real()) &&
506  common_type(0) == common_type(y.imag());
507 }
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 = typename std::common_type<RealType1, RealType2>::type;
514  return common_type(x.real()) != common_type(y.real()) ||
515  common_type(x.imag()) != common_type(y.imag());
516 }
517 
519 template <class RealType1, class RealType2>
520 inline bool operator!=(std::complex<RealType1> const& x,
521  complex<RealType2> const& y) noexcept {
522  using common_type = typename std::common_type<RealType1, RealType2>::type;
523  return common_type(x.real()) != common_type(y.real()) ||
524  common_type(x.imag()) != common_type(y.imag());
525 }
526 
528 template <class RealType1, class RealType2>
529 inline bool operator!=(complex<RealType1> const& x,
530  std::complex<RealType2> const& y) noexcept {
531  using common_type = typename std::common_type<RealType1, RealType2>::type;
532  return common_type(x.real()) != common_type(y.real()) ||
533  common_type(x.imag()) != common_type(y.imag());
534 }
535 
537 template <
538  class RealType1, class RealType2,
539  // Constraints to avoid participation in oparator==() for every possible RHS
540  typename std::enable_if<std::is_convertible<RealType2, RealType1>::value,
541  int>::type = 0>
542 KOKKOS_INLINE_FUNCTION bool operator!=(complex<RealType1> const& x,
543  RealType2 const& y) noexcept {
544  using common_type = typename std::common_type<RealType1, RealType2>::type;
545  return common_type(x.real()) != common_type(y) ||
546  common_type(x.imag()) != common_type(0);
547 }
548 
550 template <
551  class RealType1, class RealType2,
552  // Constraints to avoid participation in oparator==() for every possible RHS
553  typename std::enable_if<std::is_convertible<RealType1, RealType2>::value,
554  int>::type = 0>
555 KOKKOS_INLINE_FUNCTION bool operator!=(RealType1 const& x,
556  complex<RealType2> const& y) noexcept {
557  using common_type = typename std::common_type<RealType1, RealType2>::type;
558  return common_type(x) != common_type(y.real()) ||
559  common_type(0) != common_type(y.imag());
560 }
561 
562 // </editor-fold> end Equality and inequality }}}1
563 //==============================================================================
564 
566 template <class RealType1, class RealType2>
567 KOKKOS_INLINE_FUNCTION
568  complex<typename std::common_type<RealType1, RealType2>::type>
570  const complex<RealType2>& y) noexcept {
572  x.real() + y.real(), x.imag() + y.imag());
573 }
574 
576 template <class RealType1, class RealType2>
577 KOKKOS_INLINE_FUNCTION
578  complex<typename std::common_type<RealType1, RealType2>::type>
579  operator+(const complex<RealType1>& x, const RealType2& y) noexcept {
581  x.real() + y, x.imag());
582 }
583 
585 template <class RealType1, class RealType2>
586 KOKKOS_INLINE_FUNCTION
587  complex<typename std::common_type<RealType1, RealType2>::type>
588  operator+(const RealType1& x, const complex<RealType2>& y) noexcept {
590  x + y.real(), y.imag());
591 }
592 
594 template <class RealType>
595 KOKKOS_INLINE_FUNCTION complex<RealType> operator+(
596  const complex<RealType>& x) noexcept {
597  return complex<RealType>{+x.real(), +x.imag()};
598 }
599 
601 template <class RealType1, class RealType2>
602 KOKKOS_INLINE_FUNCTION
603  complex<typename std::common_type<RealType1, RealType2>::type>
605  const complex<RealType2>& y) noexcept {
607  x.real() - y.real(), x.imag() - y.imag());
608 }
609 
611 template <class RealType1, class RealType2>
612 KOKKOS_INLINE_FUNCTION
613  complex<typename std::common_type<RealType1, RealType2>::type>
614  operator-(const complex<RealType1>& x, const RealType2& y) noexcept {
616  x.real() - y, x.imag());
617 }
618 
620 template <class RealType1, class RealType2>
621 KOKKOS_INLINE_FUNCTION
622  complex<typename std::common_type<RealType1, RealType2>::type>
623  operator-(const RealType1& x, const complex<RealType2>& y) noexcept {
625  x - y.real(), -y.imag());
626 }
627 
629 template <class RealType>
630 KOKKOS_INLINE_FUNCTION complex<RealType> operator-(
631  const complex<RealType>& x) noexcept {
632  return complex<RealType>(-x.real(), -x.imag());
633 }
634 
636 template <class RealType1, class RealType2>
637 KOKKOS_INLINE_FUNCTION
638  complex<typename std::common_type<RealType1, RealType2>::type>
640  const complex<RealType2>& y) noexcept {
642  x.real() * y.real() - x.imag() * y.imag(),
643  x.real() * y.imag() + x.imag() * y.real());
644 }
645 
654 template <class RealType1, class RealType2>
656  const std::complex<RealType1>& x, const complex<RealType2>& y) {
658  x.real() * y.real() - x.imag() * y.imag(),
659  x.real() * y.imag() + x.imag() * y.real());
660 }
661 
666 template <class RealType1, class RealType2>
667 KOKKOS_INLINE_FUNCTION
668  complex<typename std::common_type<RealType1, RealType2>::type>
669  operator*(const RealType1& x, const complex<RealType2>& y) noexcept {
671  x * y.real(), x * y.imag());
672 }
673 
678 template <class RealType1, class RealType2>
679 KOKKOS_INLINE_FUNCTION
680  complex<typename std::common_type<RealType1, RealType2>::type>
681  operator*(const complex<RealType1>& y, const RealType2& x) noexcept {
683  x * y.real(), x * y.imag());
684 }
685 
687 template <class RealType>
688 KOKKOS_INLINE_FUNCTION RealType imag(const complex<RealType>& x) noexcept {
689  return x.imag();
690 }
691 
693 template <class RealType>
694 KOKKOS_INLINE_FUNCTION RealType real(const complex<RealType>& x) noexcept {
695  return x.real();
696 }
697 
699 template <class RealType>
700 KOKKOS_INLINE_FUNCTION RealType abs(const complex<RealType>& x) {
701 #if !defined(__CUDA_ARCH__) && \
702  !defined(__HIP_DEVICE_COMPILE__) // FIXME_CUDA FIXME_HIP
703  using std::hypot;
704 #endif
705  return hypot(x.real(), x.imag());
706 }
707 
709 template <class RealType>
710 KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> pow(const complex<RealType>& x,
711  const RealType& e) {
712  RealType r = abs(x);
713 #if !defined(__HIP_DEVICE_COMPILE__) // FIXME_HIP
714  using std::atan;
715  using std::cos;
716  using std::pow;
717  using std::sin;
718 #endif
719  using ::pow;
720  RealType phi = atan(x.imag() / x.real());
721  return pow(r, e) * Kokkos::complex<RealType>(cos(phi * e), sin(phi * e));
722 }
723 
725 template <class RealType>
726 KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> sqrt(
727  const complex<RealType>& x) {
728  RealType r = abs(x);
729 #if !defined(__HIP_DEVICE_COMPILE__) // FIXME_HIP
730  using std::atan;
731  using std::cos;
732  using std::sin;
733  using std::sqrt;
734 #endif
735  using ::sqrt;
736  RealType phi = atan(x.imag() / x.real());
737  return sqrt(r) * Kokkos::complex<RealType>(cos(phi * 0.5), sin(phi * 0.5));
738 }
739 
741 template <class RealType>
742 KOKKOS_INLINE_FUNCTION complex<RealType> conj(
743  const complex<RealType>& x) noexcept {
744  return complex<RealType>(real(x), -imag(x));
745 }
746 
748 template <class RealType>
749 KOKKOS_INLINE_FUNCTION complex<RealType> exp(const complex<RealType>& x) {
750 #if !defined(__HIP_DEVICE_COMPILE__) // FIXME_HIP
751  using std::cos;
752  using std::exp;
753  using std::sin;
754 #else
755  using ::exp;
756 #endif
757  return exp(x.real()) * complex<RealType>(cos(x.imag()), sin(x.imag()));
758 }
759 
763 template <class RealType>
764 inline complex<RealType> exp(const std::complex<RealType>& c) {
765  return complex<RealType>(std::exp(c.real()) * std::cos(c.imag()),
766  std::exp(c.real()) * std::sin(c.imag()));
767 }
768 
770 template <class RealType1, class RealType2>
771 KOKKOS_INLINE_FUNCTION
772  complex<typename std::common_type<RealType1, RealType2>::type>
774  const RealType2& y) noexcept(noexcept(RealType1{} /
775  RealType2{})) {
776  return complex<typename std::common_type<RealType1, RealType2>::type>(
777  real(x) / y, imag(x) / y);
778 }
779 
781 template <class RealType1, class RealType2>
782 KOKKOS_INLINE_FUNCTION
783  complex<typename std::common_type<RealType1, RealType2>::type>
785  const complex<RealType2>& y) noexcept(noexcept(RealType1{} /
786  RealType2{})) {
787  // Scale (by the "1-norm" of y) to avoid unwarranted overflow.
788  // If the real part is +/-Inf and the imaginary part is -/+Inf,
789  // this won't change the result.
790 #if !defined(__HIP_DEVICE_COMPILE__) // FIXME_HIP
791  using std::fabs;
792 #endif
793  typedef
794  typename std::common_type<RealType1, RealType2>::type common_real_type;
795  const common_real_type s = fabs(real(y)) + fabs(imag(y));
796 
797  // If s is 0, then y is zero, so x/y == real(x)/0 + i*imag(x)/0.
798  // In that case, the relation x/y == (x/s) / (y/s) doesn't hold,
799  // because y/s is NaN.
800  if (s == 0.0) {
801  return complex<common_real_type>(real(x) / s, imag(x) / s);
802  } else {
803  const complex<common_real_type> x_scaled(real(x) / s, imag(x) / s);
804  const complex<common_real_type> y_conj_scaled(real(y) / s, -imag(y) / s);
805  const RealType1 y_scaled_abs =
806  real(y_conj_scaled) * real(y_conj_scaled) +
807  imag(y_conj_scaled) * imag(y_conj_scaled); // abs(y) == abs(conj(y))
808  complex<common_real_type> result = x_scaled * y_conj_scaled;
809  result /= y_scaled_abs;
810  return result;
811  }
812 }
813 
815 template <class RealType1, class RealType2>
816 KOKKOS_INLINE_FUNCTION
817  complex<typename std::common_type<RealType1, RealType2>::type>
818  operator/(const RealType1& x,
819  const complex<RealType2>& y) noexcept(noexcept(RealType1{} /
820  RealType2{})) {
821  return complex<typename std::common_type<RealType1, RealType2>::type>(x) / y;
822 }
823 
824 template <class RealType>
825 std::ostream& operator<<(std::ostream& os, const complex<RealType>& x) {
826  const std::complex<RealType> x_std(Kokkos::real(x), Kokkos::imag(x));
827  os << x_std;
828  return os;
829 }
830 
831 template <class RealType>
832 std::istream& operator>>(std::istream& is, complex<RealType>& x) {
833  std::complex<RealType> x_std;
834  is >> x_std;
835  x = x_std; // only assigns on success of above
836  return is;
837 }
838 
839 template <class T>
840 struct reduction_identity<Kokkos::complex<T> > {
841  typedef reduction_identity<T> t_red_ident;
842  KOKKOS_FORCEINLINE_FUNCTION constexpr static Kokkos::complex<T>
843  sum() noexcept {
844  return Kokkos::complex<T>(t_red_ident::sum(), t_red_ident::sum());
845  }
846  KOKKOS_FORCEINLINE_FUNCTION constexpr static Kokkos::complex<T>
847  prod() noexcept {
848  return Kokkos::complex<T>(t_red_ident::prod(), t_red_ident::sum());
849  }
850 };
851 
852 } // namespace Kokkos
853 
854 #endif // KOKKOS_COMPLEX_HPP
KOKKOS_INLINE_FUNCTION volatile RealType & imag() volatilenoexcept
The imaginary part of this complex number (volatile overload).
KOKKOS_INLINE_FUNCTION RealType real(const complex< RealType > &x) noexcept
Real part of a complex number.
KOKKOS_INLINE_FUNCTION KOKKOS_CONSTEXPR_14 RealType & real() noexcept
The real part of this complex number.
KOKKOS_INLINE_FUNCTION complex< RealType > conj(const complex< RealType > &x) noexcept
Conjugate of a complex number.
KOKKOS_INLINE_FUNCTION bool operator==(complex< RealType1 > const &x, complex< RealType2 > const &y) noexcept
Binary == operator for complex complex.
KOKKOS_INLINE_FUNCTION KOKKOS_CONSTEXPR_14 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 RealType imag() const volatilenoexcept
The imaginary part of this complex number (volatile overload).
KOKKOS_INLINE_FUNCTION Kokkos::complex< RealType > pow(const complex< RealType > &x, const RealType &e)
Power of a complex 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 complex< typename std::common_type< RealType1, RealType2 >::type > operator+(const complex< RealType1 > &x, const complex< RealType2 > &y) noexcept
Binary + operator for complex complex.
KOKKOS_INLINE_FUNCTION RealType abs(const complex< RealType > &x)
Absolute value (magnitude) of a complex number.
KOKKOS_INLINE_FUNCTION RealType imag(const complex< RealType > &x) noexcept
Imaginary part of a complex number.
KOKKOS_INLINE_FUNCTION complex(const RealType &re, const RealType &im) noexcept
Constructor that takes the real and imaginary parts.
KOKKOS_INLINE_FUNCTION RealType real() const volatilenoexcept
The real part of this complex number (volatile overload).
KOKKOS_INLINE_FUNCTION complex< typename std::common_type< RealType1, RealType2 >::type > operator/(const complex< RealType1 > &x, const RealType2 &y) noexcept(noexcept(RealType1{}/RealType2{}))
Binary operator / for complex and real numbers.
KOKKOS_INLINE_FUNCTION constexpr RealType imag() const noexcept
The imaginary part of this complex number.
KOKKOS_INLINE_FUNCTION complex & operator=(const volatile RealType &val) volatilenoexcept
Assignment operator volatile LHS and volatile RHS.
KOKKOS_INLINE_FUNCTION complex(const std::complex< RealType > &src) noexcept
Conversion constructor from std::complex.
KOKKOS_INLINE_FUNCTION volatile complex & operator=(const volatile Complex &src) volatilenoexcept
Assignment operator, volatile LHS and volatile RHS.
KOKKOS_INLINE_FUNCTION KOKKOS_CONSTEXPR_14 void imag(RealType v) noexcept
Set the imaginary part of this complex number.
KOKKOS_INLINE_FUNCTION Kokkos::complex< RealType > sqrt(const complex< RealType > &x)
Square root of a complex number.
KOKKOS_INLINE_FUNCTION complex & operator=(const RealType &val) volatilenoexcept
Assignment operator volatile LHS and non-volatile RHS.
Atomic functions.
KOKKOS_INLINE_FUNCTION complex(const volatile complex< RType > &src) noexcept
Copy constructor from volatile.
KOKKOS_INLINE_FUNCTION volatile RealType & real() volatilenoexcept
The real part of this complex number (volatile overload).
KOKKOS_INLINE_FUNCTION bool operator!=(complex< RealType1 > const &x, complex< RealType2 > const &y) noexcept
Binary != operator for complex complex.
RealType value_type
The type of the real or imaginary parts of this complex number.
KOKKOS_INLINE_FUNCTION complex< RealType > exp(const complex< RealType > &x)
Exponential of a complex number.
KOKKOS_INLINE_FUNCTION void operator=(const volatile RealType &val) noexcept
Assignment operator (from a volatile real number).
KOKKOS_INLINE_FUNCTION complex< typename std::common_type< RealType1, RealType2 >::type > operator-(const complex< RealType1 > &x, const complex< RealType2 > &y) noexcept
Binary - operator for complex.
KOKKOS_INLINE_FUNCTION void operator=(const Complex &src) volatilenoexcept
Assignment operator, for volatile *this and nonvolatile input.
KOKKOS_INLINE_FUNCTION KOKKOS_CONSTEXPR_14 void real(RealType v) noexcept
Set the real part of this complex number.
KOKKOS_INLINE_FUNCTION complex & operator=(const volatile Complex &src) noexcept
Assignment operator, volatile RHS and non-volatile LHS.
KOKKOS_INLINE_FUNCTION complex< typename std::common_type< RealType1, RealType2 >::type > operator*(const complex< RealType1 > &x, const complex< RealType2 > &y) noexcept
Binary * operator for complex.