Kokkos Core Kernels Package Version of the Day
Loading...
Searching...
No Matches
Kokkos_Complex.hpp
1//@HEADER
2// ************************************************************************
3//
4// Kokkos v. 4.0
5// Copyright (2022) National Technology & Engineering
6// Solutions of Sandia, LLC (NTESS).
7//
8// Under the terms of Contract DE-NA0003525 with NTESS,
9// the U.S. Government retains certain rights in this software.
10//
11// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
12// See https://kokkos.org/LICENSE for license information.
13// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
14//
15//@HEADER
16#ifndef KOKKOS_COMPLEX_HPP
17#define KOKKOS_COMPLEX_HPP
18#ifndef KOKKOS_IMPL_PUBLIC_INCLUDE
19#define KOKKOS_IMPL_PUBLIC_INCLUDE
20#define KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_COMPLEX
21#endif
22
23#include <Kokkos_Atomic.hpp>
24#include <Kokkos_MathematicalFunctions.hpp>
25#include <Kokkos_NumericTraits.hpp>
26#include <Kokkos_ReductionIdentity.hpp>
27#include <impl/Kokkos_Error.hpp>
28#include <complex>
29#include <type_traits>
30#include <iosfwd>
31#include <tuple>
32
33namespace Kokkos {
34
42template <class RealType>
43class
44#ifdef KOKKOS_ENABLE_COMPLEX_ALIGN
45 alignas(2 * sizeof(RealType))
46#endif
47 complex {
48 static_assert(std::is_floating_point_v<RealType> &&
49 std::is_same_v<RealType, std::remove_cv_t<RealType>>,
50 "Kokkos::complex can only be instantiated for a cv-unqualified "
51 "floating point type");
52
53 private:
54 RealType re_{};
55 RealType im_{};
56
57 public:
60
62 KOKKOS_DEFAULTED_FUNCTION
63 complex() = default;
64
66 KOKKOS_DEFAULTED_FUNCTION
67 complex(const complex&) noexcept = default;
68
69 KOKKOS_DEFAULTED_FUNCTION
70 complex& operator=(const complex&) noexcept = default;
71
73 template <class RType,
74 std::enable_if_t<std::is_convertible_v<RType, RealType>, int> = 0>
75 KOKKOS_INLINE_FUNCTION complex(const complex<RType>& other) noexcept
76 // Intentionally do the conversions implicitly here so that users don't
77 // get any warnings about narrowing, etc., that they would expect to get
78 // otherwise.
79 : re_(other.real()), im_(other.imag()) {}
80
86 KOKKOS_INLINE_FUNCTION
87 complex(const std::complex<RealType>& src) noexcept
88 // We can use this aspect of the standard to avoid calling
89 // non-device-marked functions `std::real` and `std::imag`: "For any
90 // object z of type complex<T>, reinterpret_cast<T(&)[2]>(z)[0] is the
91 // real part of z and reinterpret_cast<T(&)[2]>(z)[1] is the imaginary
92 // part of z." Now we don't have to provide a whole bunch of the overloads
93 // of things taking either Kokkos::complex or std::complex
94 : re_(reinterpret_cast<const RealType (&)[2]>(src)[0]),
95 im_(reinterpret_cast<const RealType (&)[2]>(src)[1]) {}
96
102 // TODO: make explicit. DJS 2019-08-28
103 operator std::complex<RealType>() const noexcept {
104 return std::complex<RealType>(re_, im_);
105 }
106
109 KOKKOS_INLINE_FUNCTION constexpr complex(const RealType& val) noexcept
110 : re_(val), im_(static_cast<RealType>(0)) {}
111
113 KOKKOS_INLINE_FUNCTION
114 constexpr complex(const RealType& re, const RealType& im) noexcept
115 : re_(re), im_(im) {}
116
118 KOKKOS_INLINE_FUNCTION constexpr complex& operator=(
119 const RealType& val) noexcept {
120 re_ = val;
121 im_ = RealType(0);
122 return *this;
123 }
124
130 complex& operator=(const std::complex<RealType>& src) noexcept {
131 *this = complex(src);
132 return *this;
133 }
134
136 KOKKOS_INLINE_FUNCTION
137 constexpr RealType& imag() noexcept { return im_; }
138
140 KOKKOS_INLINE_FUNCTION
141 constexpr RealType& real() noexcept { return re_; }
142
144 KOKKOS_INLINE_FUNCTION
145 constexpr RealType imag() const noexcept { return im_; }
146
148 KOKKOS_INLINE_FUNCTION
149 constexpr RealType real() const noexcept { return re_; }
150
152 KOKKOS_INLINE_FUNCTION
153 constexpr void imag(RealType v) noexcept { im_ = v; }
154
156 KOKKOS_INLINE_FUNCTION
157 constexpr void real(RealType v) noexcept { re_ = v; }
158
159 constexpr KOKKOS_INLINE_FUNCTION complex& operator+=(
160 const complex<RealType>& src) noexcept {
161 re_ += src.re_;
162 im_ += src.im_;
163 return *this;
164 }
165
166 constexpr KOKKOS_INLINE_FUNCTION complex& operator+=(
167 const RealType& src) noexcept {
168 re_ += src;
169 return *this;
170 }
171
172 constexpr KOKKOS_INLINE_FUNCTION complex& operator-=(
173 const complex<RealType>& src) noexcept {
174 re_ -= src.re_;
175 im_ -= src.im_;
176 return *this;
177 }
178
179 constexpr KOKKOS_INLINE_FUNCTION complex& operator-=(
180 const RealType& src) noexcept {
181 re_ -= src;
182 return *this;
183 }
184
185 constexpr KOKKOS_INLINE_FUNCTION complex& operator*=(
186 const complex<RealType>& src) noexcept {
187 const RealType realPart = re_ * src.re_ - im_ * src.im_;
188 const RealType imagPart = re_ * src.im_ + im_ * src.re_;
189 re_ = realPart;
190 im_ = imagPart;
191 return *this;
192 }
193
194 constexpr KOKKOS_INLINE_FUNCTION complex& operator*=(
195 const RealType& src) noexcept {
196 re_ *= src;
197 im_ *= src;
198 return *this;
199 }
200
201 // Conditional noexcept, just in case RType throws on divide-by-zero
202 constexpr KOKKOS_INLINE_FUNCTION complex& operator/=(
203 const complex<RealType>& y) noexcept(noexcept(RealType{} / RealType{})) {
204 // Scale (by the "1-norm" of y) to avoid unwarranted overflow.
205 // If the real part is +/-Inf and the imaginary part is -/+Inf,
206 // this won't change the result.
207 const RealType s = fabs(y.real()) + fabs(y.imag());
208
209 // If s is 0, then y is zero, so x/y == real(x)/0 + i*imag(x)/0.
210 // In that case, the relation x/y == (x/s) / (y/s) doesn't hold,
211 // because y/s is NaN.
212 // TODO mark this branch unlikely
213 if (s == RealType(0)) {
214 this->re_ /= s;
215 this->im_ /= s;
216 } else {
217 const complex x_scaled(this->re_ / s, this->im_ / s);
218 const complex y_conj_scaled(y.re_ / s, -(y.im_) / s);
219 const RealType y_scaled_abs =
220 y_conj_scaled.re_ * y_conj_scaled.re_ +
221 y_conj_scaled.im_ * y_conj_scaled.im_; // abs(y) == abs(conj(y))
222 *this = x_scaled * y_conj_scaled;
223 *this /= y_scaled_abs;
224 }
225 return *this;
226 }
227
228 constexpr KOKKOS_INLINE_FUNCTION complex& operator/=(
229 const std::complex<RealType>& y) noexcept(noexcept(RealType{} /
230 RealType{})) {
231 // Scale (by the "1-norm" of y) to avoid unwarranted overflow.
232 // If the real part is +/-Inf and the imaginary part is -/+Inf,
233 // this won't change the result.
234 const RealType s = fabs(y.real()) + fabs(y.imag());
235
236 // If s is 0, then y is zero, so x/y == real(x)/0 + i*imag(x)/0.
237 // In that case, the relation x/y == (x/s) / (y/s) doesn't hold,
238 // because y/s is NaN.
239 if (s == RealType(0)) {
240 this->re_ /= s;
241 this->im_ /= s;
242 } else {
243 const complex x_scaled(this->re_ / s, this->im_ / s);
244 const complex y_conj_scaled(y.re_ / s, -(y.im_) / s);
245 const RealType y_scaled_abs =
246 y_conj_scaled.re_ * y_conj_scaled.re_ +
247 y_conj_scaled.im_ * y_conj_scaled.im_; // abs(y) == abs(conj(y))
248 *this = x_scaled * y_conj_scaled;
249 *this /= y_scaled_abs;
250 }
251 return *this;
252 }
253
254 constexpr KOKKOS_INLINE_FUNCTION complex& operator/=(
255 const RealType& src) noexcept(noexcept(RealType{} / RealType{})) {
256 re_ /= src;
257 im_ /= src;
258 return *this;
259 }
260
261 template <size_t I, typename RT>
262 friend constexpr const RT& get(const complex<RT>&) noexcept;
263
264 template <size_t I, typename RT>
265 friend constexpr const RT&& get(const complex<RT>&&) noexcept;
266
267#ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
269 template <class RType,
270 std::enable_if_t<std::is_convertible_v<RType, RealType>, 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_v<Complex, complex>, 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_v<Complex, complex>, 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_v<Complex, complex>, 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
438template <typename RealType>
439struct std::tuple_size<Kokkos::complex<RealType>>
440 : std::integral_constant<size_t, 2> {};
441
442template <size_t I, typename RealType>
443struct std::tuple_element<I, Kokkos::complex<RealType>> {
444 static_assert(I < 2);
445 using type = RealType;
446};
447
448namespace Kokkos {
449
450// get<...>(...) defined here so as not to be hidden friends, as per P2819R2
451
452template <size_t I, typename RealType>
453KOKKOS_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}
460
461template <size_t I, typename RealType>
462KOKKOS_FUNCTION constexpr RealType&& get(complex<RealType>&& z) noexcept {
463 static_assert(I < 2);
464 if constexpr (I == 0)
465 return std::move(z.real());
466 else
467 return std::move(z.imag());
468}
469
470template <size_t I, typename RealType>
471KOKKOS_FUNCTION constexpr const RealType& get(
472 const complex<RealType>& z) noexcept {
473 static_assert(I < 2);
474 if constexpr (I == 0)
475 return z.re_;
476 else
477 return z.im_;
478}
479
480template <size_t I, typename RealType>
481KOKKOS_FUNCTION constexpr const RealType&& get(
482 const complex<RealType>&& z) noexcept {
483 static_assert(I < 2);
484 if constexpr (I == 0)
485 return std::move(z.re_);
486 else
487 return std::move(z.im_);
488}
489
490//==============================================================================
491// <editor-fold desc="Equality and inequality"> {{{1
492
493// Note that this is not the same behavior as std::complex, which doesn't allow
494// implicit conversions, but since this is the way we had it before, we have
495// to do it this way now.
496
498template <class RealType1, class RealType2>
499KOKKOS_INLINE_FUNCTION constexpr bool operator==(
500 complex<RealType1> const& x, complex<RealType2> const& y) noexcept {
501 using common_type = std::common_type_t<RealType1, RealType2>;
502 return common_type(x.real()) == common_type(y.real()) &&
503 common_type(x.imag()) == common_type(y.imag());
504}
505
506// TODO (here and elsewhere) decide if we should convert to a Kokkos::complex
507// and do the comparison in a device-marked function
509template <class RealType1, class RealType2>
510inline bool operator==(std::complex<RealType1> const& x,
511 complex<RealType2> const& y) noexcept {
512 using common_type = std::common_type_t<RealType1, RealType2>;
513 return common_type(x.real()) == common_type(y.real()) &&
514 common_type(x.imag()) == common_type(y.imag());
515}
516
518template <class RealType1, class RealType2>
519inline bool operator==(complex<RealType1> const& x,
520 std::complex<RealType2> const& y) noexcept {
521 using common_type = std::common_type_t<RealType1, RealType2>;
522 return common_type(x.real()) == common_type(y.real()) &&
523 common_type(x.imag()) == common_type(y.imag());
524}
525
527template <
528 class RealType1, class RealType2,
529 // Constraints to avoid participation in oparator==() for every possible RHS
530 std::enable_if_t<std::is_convertible_v<RealType2, RealType1>, int> = 0>
531KOKKOS_INLINE_FUNCTION constexpr bool operator==(complex<RealType1> const& x,
532 RealType2 const& y) noexcept {
533 using common_type = std::common_type_t<RealType1, RealType2>;
534 return common_type(x.real()) == common_type(y) &&
535 common_type(x.imag()) == common_type(0);
536}
537
539template <
540 class RealType1, class RealType2,
541 // Constraints to avoid participation in oparator==() for every possible RHS
542 std::enable_if_t<std::is_convertible_v<RealType1, RealType2>, int> = 0>
543KOKKOS_INLINE_FUNCTION constexpr bool operator==(
544 RealType1 const& x, complex<RealType2> const& y) noexcept {
545 using common_type = std::common_type_t<RealType1, RealType2>;
546 return common_type(x) == common_type(y.real()) &&
547 common_type(0) == common_type(y.imag());
548}
549
551template <class RealType1, class RealType2>
552KOKKOS_INLINE_FUNCTION constexpr bool operator!=(
553 complex<RealType1> const& x, complex<RealType2> const& y) noexcept {
554 using common_type = std::common_type_t<RealType1, RealType2>;
555 return common_type(x.real()) != common_type(y.real()) ||
556 common_type(x.imag()) != common_type(y.imag());
557}
558
560template <class RealType1, class RealType2>
561inline bool operator!=(std::complex<RealType1> const& x,
562 complex<RealType2> const& y) noexcept {
563 using common_type = std::common_type_t<RealType1, RealType2>;
564 return common_type(x.real()) != common_type(y.real()) ||
565 common_type(x.imag()) != common_type(y.imag());
566}
567
569template <class RealType1, class RealType2>
570inline bool operator!=(complex<RealType1> const& x,
571 std::complex<RealType2> const& y) noexcept {
572 using common_type = std::common_type_t<RealType1, RealType2>;
573 return common_type(x.real()) != common_type(y.real()) ||
574 common_type(x.imag()) != common_type(y.imag());
575}
576
578template <
579 class RealType1, class RealType2,
580 // Constraints to avoid participation in oparator==() for every possible RHS
581 std::enable_if_t<std::is_convertible_v<RealType2, RealType1>, int> = 0>
582KOKKOS_INLINE_FUNCTION constexpr bool operator!=(complex<RealType1> const& x,
583 RealType2 const& y) noexcept {
584 using common_type = std::common_type_t<RealType1, RealType2>;
585 return common_type(x.real()) != common_type(y) ||
586 common_type(x.imag()) != common_type(0);
587}
588
590template <
591 class RealType1, class RealType2,
592 // Constraints to avoid participation in oparator==() for every possible RHS
593 std::enable_if_t<std::is_convertible_v<RealType1, RealType2>, int> = 0>
594KOKKOS_INLINE_FUNCTION constexpr bool operator!=(
595 RealType1 const& x, complex<RealType2> const& y) noexcept {
596 using common_type = std::common_type_t<RealType1, RealType2>;
597 return common_type(x) != common_type(y.real()) ||
598 common_type(0) != common_type(y.imag());
599}
600
601// </editor-fold> end Equality and inequality }}}1
602//==============================================================================
603
605template <class RealType1, class RealType2>
606KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
607operator+(const complex<RealType1>& x, const complex<RealType2>& y) noexcept {
608 return complex<std::common_type_t<RealType1, RealType2>>(x.real() + y.real(),
609 x.imag() + y.imag());
610}
611
613template <class RealType1, class RealType2>
614KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
615operator+(const complex<RealType1>& x, const RealType2& y) noexcept {
616 return complex<std::common_type_t<RealType1, RealType2>>(x.real() + y,
617 x.imag());
618}
619
621template <class RealType1, class RealType2>
622KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
623operator+(const RealType1& x, const complex<RealType2>& y) noexcept {
624 return complex<std::common_type_t<RealType1, RealType2>>(x + y.real(),
625 y.imag());
626}
627
629template <class RealType>
630KOKKOS_INLINE_FUNCTION complex<RealType> operator+(
631 const complex<RealType>& x) noexcept {
632 return complex<RealType>{+x.real(), +x.imag()};
633}
634
636template <class RealType1, class RealType2>
637KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
638operator-(const complex<RealType1>& x, const complex<RealType2>& y) noexcept {
639 return complex<std::common_type_t<RealType1, RealType2>>(x.real() - y.real(),
640 x.imag() - y.imag());
641}
642
644template <class RealType1, class RealType2>
645KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
646operator-(const complex<RealType1>& x, const RealType2& y) noexcept {
647 return complex<std::common_type_t<RealType1, RealType2>>(x.real() - y,
648 x.imag());
649}
650
652template <class RealType1, class RealType2>
653KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
654operator-(const RealType1& x, const complex<RealType2>& y) noexcept {
655 return complex<std::common_type_t<RealType1, RealType2>>(x - y.real(),
656 -y.imag());
657}
658
660template <class RealType>
661KOKKOS_INLINE_FUNCTION complex<RealType> operator-(
662 const complex<RealType>& x) noexcept {
663 return complex<RealType>(-x.real(), -x.imag());
664}
665
667template <class RealType1, class RealType2>
668KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
669operator*(const complex<RealType1>& x, const complex<RealType2>& y) noexcept {
670 return complex<std::common_type_t<RealType1, RealType2>>(
671 x.real() * y.real() - x.imag() * y.imag(),
672 x.real() * y.imag() + x.imag() * y.real());
673}
674
683template <class RealType1, class RealType2>
684inline complex<std::common_type_t<RealType1, RealType2>> operator*(
685 const std::complex<RealType1>& x, const complex<RealType2>& y) {
686 return complex<std::common_type_t<RealType1, RealType2>>(
687 x.real() * y.real() - x.imag() * y.imag(),
688 x.real() * y.imag() + x.imag() * y.real());
689}
690
695template <class RealType1, class RealType2>
696KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
697operator*(const RealType1& x, const complex<RealType2>& y) noexcept {
698 return complex<std::common_type_t<RealType1, RealType2>>(x * y.real(),
699 x * y.imag());
700}
701
706template <class RealType1, class RealType2>
707KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
708operator*(const complex<RealType1>& y, const RealType2& x) noexcept {
709 return complex<std::common_type_t<RealType1, RealType2>>(x * y.real(),
710 x * y.imag());
711}
712
714template <class RealType>
715KOKKOS_INLINE_FUNCTION RealType imag(const complex<RealType>& x) noexcept {
716 return x.imag();
717}
718
719template <class ArithmeticType>
720KOKKOS_INLINE_FUNCTION constexpr Impl::promote_t<ArithmeticType> imag(
721 ArithmeticType) {
722 return ArithmeticType();
723}
724
726template <class RealType>
727KOKKOS_INLINE_FUNCTION RealType real(const complex<RealType>& x) noexcept {
728 return x.real();
729}
730
731template <class ArithmeticType>
732KOKKOS_INLINE_FUNCTION constexpr Impl::promote_t<ArithmeticType> real(
733 ArithmeticType x) {
734 return x;
735}
736
738template <class T>
739KOKKOS_INLINE_FUNCTION complex<T> polar(const T& r, const T& theta = T()) {
740 KOKKOS_EXPECTS(r >= 0);
741 return complex<T>(r * cos(theta), r * sin(theta));
742}
743
745template <class RealType>
746KOKKOS_INLINE_FUNCTION RealType abs(const complex<RealType>& x) {
747 return hypot(x.real(), x.imag());
748}
749
751template <class T>
752KOKKOS_INLINE_FUNCTION complex<T> pow(const complex<T>& x, const T& y) {
753 T r = abs(x);
754 T theta = atan2(x.imag(), x.real());
755 return polar(pow(r, y), y * theta);
756}
757
758template <class T>
759KOKKOS_INLINE_FUNCTION complex<T> pow(const T& x, const complex<T>& y) {
760 return pow(complex<T>(x), y);
761}
762
763template <class T>
764KOKKOS_INLINE_FUNCTION complex<T> pow(const complex<T>& x,
765 const complex<T>& y) {
766 return x == T() ? T() : exp(y * log(x));
767}
768
769template <class T, class U, class = std::enable_if_t<std::is_arithmetic_v<T>>>
770KOKKOS_INLINE_FUNCTION complex<Impl::promote_2_t<T, U>> pow(
771 const T& x, const complex<U>& y) {
772 using type = Impl::promote_2_t<T, U>;
773 return pow(type(x), complex<type>(y));
774}
775
776template <class T, class U, class = std::enable_if_t<std::is_arithmetic_v<U>>>
777KOKKOS_INLINE_FUNCTION complex<Impl::promote_2_t<T, U>> pow(const complex<T>& x,
778 const U& y) {
779 using type = Impl::promote_2_t<T, U>;
780 return pow(complex<type>(x), type(y));
781}
782
783template <class T, class U>
784KOKKOS_INLINE_FUNCTION complex<Impl::promote_2_t<T, U>> pow(
785 const complex<T>& x, const complex<U>& y) {
786 using type = Impl::promote_2_t<T, U>;
787 return pow(complex<type>(x), complex<type>(y));
788}
789
792template <class RealType>
793KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> sqrt(
794 const complex<RealType>& x) {
795 RealType r = x.real();
796 RealType i = x.imag();
797
798 if (r == RealType()) {
799 RealType t = sqrt(fabs(i) / 2);
800 return Kokkos::complex<RealType>(t, i < RealType() ? -t : t);
801 } else {
802 RealType t = sqrt(2 * (abs(x) + fabs(r)));
803 RealType u = t / 2;
804 return r > RealType() ? Kokkos::complex<RealType>(u, i / t)
805 : Kokkos::complex<RealType>(fabs(i) / t,
806 i < RealType() ? -u : u);
807 }
808}
809
811template <class RealType>
812KOKKOS_INLINE_FUNCTION complex<RealType> conj(
813 const complex<RealType>& x) noexcept {
814 return complex<RealType>(real(x), -imag(x));
815}
816
817template <class ArithmeticType>
818KOKKOS_INLINE_FUNCTION constexpr complex<Impl::promote_t<ArithmeticType>> conj(
819 ArithmeticType x) {
820 using type = Impl::promote_t<ArithmeticType>;
821 return complex<type>(x, -type());
822}
823
825template <class RealType>
826KOKKOS_INLINE_FUNCTION complex<RealType> exp(const complex<RealType>& x) {
827 return exp(x.real()) * complex<RealType>(cos(x.imag()), sin(x.imag()));
828}
829
831template <class RealType>
832KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> log(
833 const complex<RealType>& x) {
834 RealType phi = atan2(x.imag(), x.real());
835 return Kokkos::complex<RealType>(log(abs(x)), phi);
836}
837
839template <class RealType>
840KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> log10(
841 const complex<RealType>& x) {
842 return log(x) / log(RealType(10));
843}
844
846template <class RealType>
847KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> sin(
848 const complex<RealType>& x) {
849 return Kokkos::complex<RealType>(sin(x.real()) * cosh(x.imag()),
850 cos(x.real()) * sinh(x.imag()));
851}
852
854template <class RealType>
855KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> cos(
856 const complex<RealType>& x) {
857 return Kokkos::complex<RealType>(cos(x.real()) * cosh(x.imag()),
858 -sin(x.real()) * sinh(x.imag()));
859}
860
862template <class RealType>
863KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> tan(
864 const complex<RealType>& x) {
865 return sin(x) / cos(x);
866}
867
869template <class RealType>
870KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> sinh(
871 const complex<RealType>& x) {
872 return Kokkos::complex<RealType>(sinh(x.real()) * cos(x.imag()),
873 cosh(x.real()) * sin(x.imag()));
874}
875
877template <class RealType>
878KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> cosh(
879 const complex<RealType>& x) {
880 return Kokkos::complex<RealType>(cosh(x.real()) * cos(x.imag()),
881 sinh(x.real()) * sin(x.imag()));
882}
883
885template <class RealType>
886KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> tanh(
887 const complex<RealType>& x) {
888 return sinh(x) / cosh(x);
889}
890
892template <class RealType>
893KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> asinh(
894 const complex<RealType>& x) {
895 return log(x + sqrt(x * x + RealType(1.0)));
896}
897
899template <class RealType>
900KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> acosh(
901 const complex<RealType>& x) {
902 return RealType(2.0) * log(sqrt(RealType(0.5) * (x + RealType(1.0))) +
903 sqrt(RealType(0.5) * (x - RealType(1.0))));
904}
905
907template <class RealType>
908KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> atanh(
909 const complex<RealType>& x) {
910 const RealType i2 = x.imag() * x.imag();
911 const RealType r = RealType(1.0) - i2 - x.real() * x.real();
912
913 RealType p = RealType(1.0) + x.real();
914 RealType m = RealType(1.0) - x.real();
915
916 p = i2 + p * p;
917 m = i2 + m * m;
918
919 RealType phi = atan2(RealType(2.0) * x.imag(), r);
920 return Kokkos::complex<RealType>(RealType(0.25) * (log(p) - log(m)),
921 RealType(0.5) * phi);
922}
923
925template <class RealType>
926KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> asin(
927 const complex<RealType>& x) {
929 asinh(Kokkos::complex<RealType>(-x.imag(), x.real()));
930 return Kokkos::complex<RealType>(t.imag(), -t.real());
931}
932
934template <class RealType>
935KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> acos(
936 const complex<RealType>& x) {
937 Kokkos::complex<RealType> t = asin(x);
938 RealType pi_2 = acos(RealType(0.0));
939 return Kokkos::complex<RealType>(pi_2 - t.real(), -t.imag());
940}
941
943template <class RealType>
944KOKKOS_INLINE_FUNCTION Kokkos::complex<RealType> atan(
945 const complex<RealType>& x) {
946 const RealType r2 = x.real() * x.real();
947 const RealType i = RealType(1.0) - r2 - x.imag() * x.imag();
948
949 RealType p = x.imag() + RealType(1.0);
950 RealType m = x.imag() - RealType(1.0);
951
952 p = r2 + p * p;
953 m = r2 + m * m;
954
956 RealType(0.5) * atan2(RealType(2.0) * x.real(), i),
957 RealType(0.25) * log(p / m));
958}
959
963template <class RealType>
964inline complex<RealType> exp(const std::complex<RealType>& c) {
965 return complex<RealType>(std::exp(c.real()) * std::cos(c.imag()),
966 std::exp(c.real()) * std::sin(c.imag()));
967}
968
970template <class RealType1, class RealType2>
971KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
972operator/(const complex<RealType1>& x,
973 const RealType2& y) noexcept(noexcept(RealType1{} / RealType2{})) {
974 return complex<std::common_type_t<RealType1, RealType2>>(real(x) / y,
975 imag(x) / y);
976}
977
979template <class RealType1, class RealType2>
980KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
981operator/(const complex<RealType1>& x,
982 const complex<RealType2>& y) noexcept(noexcept(RealType1{} /
983 RealType2{})) {
984 // Scale (by the "1-norm" of y) to avoid unwarranted overflow.
985 // If the real part is +/-Inf and the imaginary part is -/+Inf,
986 // this won't change the result.
987 using common_real_type = std::common_type_t<RealType1, RealType2>;
988 const common_real_type s = fabs(real(y)) + fabs(imag(y));
989
990 // If s is 0, then y is zero, so x/y == real(x)/0 + i*imag(x)/0.
991 // In that case, the relation x/y == (x/s) / (y/s) doesn't hold,
992 // because y/s is NaN.
993 if (s == 0.0) {
994 return complex<common_real_type>(real(x) / s, imag(x) / s);
995 } else {
996 const complex<common_real_type> x_scaled(real(x) / s, imag(x) / s);
997 const complex<common_real_type> y_conj_scaled(real(y) / s, -imag(y) / s);
998 const RealType1 y_scaled_abs =
999 real(y_conj_scaled) * real(y_conj_scaled) +
1000 imag(y_conj_scaled) * imag(y_conj_scaled); // abs(y) == abs(conj(y))
1001 complex<common_real_type> result = x_scaled * y_conj_scaled;
1002 result /= y_scaled_abs;
1003 return result;
1004 }
1005}
1006
1008template <class RealType1, class RealType2>
1009KOKKOS_INLINE_FUNCTION complex<std::common_type_t<RealType1, RealType2>>
1010operator/(const RealType1& x,
1011 const complex<RealType2>& y) noexcept(noexcept(RealType1{} /
1012 RealType2{})) {
1013 return complex<std::common_type_t<RealType1, RealType2>>(x) / y;
1014}
1015
1016template <class RealType>
1017std::ostream& operator<<(std::ostream& os, const complex<RealType>& x) {
1018 const std::complex<RealType> x_std(Kokkos::real(x), Kokkos::imag(x));
1019 os << x_std;
1020 return os;
1021}
1022
1023template <class RealType>
1024std::istream& operator>>(std::istream& is, complex<RealType>& x) {
1025 std::complex<RealType> x_std;
1026 is >> x_std;
1027 x = x_std; // only assigns on success of above
1028 return is;
1029}
1030
1031template <class T>
1032struct reduction_identity<Kokkos::complex<T>> {
1033 using t_red_ident = reduction_identity<T>;
1034 KOKKOS_FORCEINLINE_FUNCTION constexpr static Kokkos::complex<T>
1035 sum() noexcept {
1036 return Kokkos::complex<T>(t_red_ident::sum(), t_red_ident::sum());
1037 }
1038 KOKKOS_FORCEINLINE_FUNCTION constexpr static Kokkos::complex<T>
1039 prod() noexcept {
1040 return Kokkos::complex<T>(t_red_ident::prod(), t_red_ident::sum());
1041 }
1042};
1043
1044} // namespace Kokkos
1045
1046#ifdef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_COMPLEX
1047#undef KOKKOS_IMPL_PUBLIC_INCLUDE
1048#undef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_COMPLEX
1049#endif
1050#endif // KOKKOS_COMPLEX_HPP
Atomic functions.
A thread safe view to a bitset.
Partial reimplementation of std::complex that works as the result of a Kokkos::parallel_reduce.
KOKKOS_INLINE_FUNCTION constexpr RealType imag() const noexcept
The imaginary part of this complex number.
KOKKOS_INLINE_FUNCTION constexpr RealType & real() noexcept
The real part of this complex number.
complex & operator=(const std::complex< RealType > &src) noexcept
Assignment operator from std::complex.
KOKKOS_INLINE_FUNCTION constexpr complex(const RealType &re, const RealType &im) noexcept
Constructor that takes the real and imaginary parts.
KOKKOS_DEFAULTED_FUNCTION complex(const complex &) noexcept=default
Copy constructor.
KOKKOS_INLINE_FUNCTION constexpr complex(const RealType &val) noexcept
Constructor that takes just the real part, and sets the imaginary part to zero.
KOKKOS_INLINE_FUNCTION constexpr void real(RealType v) noexcept
Set the real part of this complex number.
KOKKOS_INLINE_FUNCTION constexpr complex & operator=(const RealType &val) noexcept
Assignment operator (from a real number).
KOKKOS_INLINE_FUNCTION constexpr RealType & imag() noexcept
The imaginary part of this complex number.
KOKKOS_INLINE_FUNCTION constexpr RealType real() const noexcept
The real part of this complex number.
KOKKOS_INLINE_FUNCTION constexpr void imag(RealType v) noexcept
Set the imaginary part of this complex number.
KOKKOS_DEFAULTED_FUNCTION complex()=default
Default constructor (initializes both real and imaginary parts to zero).
KOKKOS_INLINE_FUNCTION complex(const std::complex< RealType > &src) noexcept
Conversion constructor from std::complex.
KOKKOS_INLINE_FUNCTION complex(const complex< RType > &other) noexcept
Conversion constructor from compatible RType.