HILA
Loading...
Searching...
No Matches
cmplx.h
Go to the documentation of this file.
1/**
2 * @file cmplx.h
3 * @brief Definition of Complex types
4 * @details This file contains definitions and methods for Complex numbers and Imaginary type.
5 *
6 * > NOTE: All overloads for operators +,-,/,* are not documented separately since there exists a
7 * > function for each combinations of scalar,imaginary and complex number representations. All
8 * > versions are documented in the Complex -- Complex definitions.
9 *
10 */
11
12#ifndef CMPLX_H_
13#define CMPLX_H_
14
15// let's not include the std::complex
16// #include <complex>
17// #include <cmath>
18
19#include "plumbing/defs.h"
20
21// TEMPORARY location for vector intrinsic analogues -- result obvious
22
23template <typename T, std::enable_if_t<hila::is_arithmetic<T>::value, int> = 0>
24inline T mul_add(T a, T b, T c) {
25 return a * b + c;
26}
27
28template <typename T, std::enable_if_t<hila::is_arithmetic<T>::value, int> = 0>
29inline T mul_sub(T a, T b, T c) {
30 return a * b - c;
31}
32
33template <typename T, std::enable_if_t<hila::is_arithmetic<T>::value, int> = 0>
34inline T nmul_add(T a, T b, T c) {
35 return c - a * b;
36}
37
38/**
39 * @brief Complex definition
40 * @details Define complex type as a class. This allows Hilapp to replace the internal type with
41 * a vector.
42 *
43 * __NOTE:__ T must be arithmetic and integrable. In the following documentation MyType refers to T,
44 * as in an arithmetic and integrable type.
45 * @param re Real part
46 * @param im Imaginary part
47 * @tparam T Arithmetic type
48 */
49template <typename T>
50class Complex {
51
52 static_assert((hila::is_arithmetic<T>::value && !std::is_integral<T>::value),
53 "Complex can be used only with floating point type");
54 // This incantation is needed to make Field<Complex<>> vectorized
55
56 public:
57 using base_type = hila::arithmetic_type<T>;
58 using argument_type = T;
59
60 // and the content of the complex number
61 T re, im;
62
63 /**
64 * @brief Default constructo
65 * @details
66 *
67 * \code{.cpp}
68 * Complex<MyType> C;
69 * \endcode
70 *
71 * The default constructor initializes \p Complex#re and \p Complex#im to 0
72 *
73 */
74 Complex<T>() = default;
75 ~Complex<T>() = default;
76
77
78 /**
79 * @brief Copy constructor
80 *
81 * Initialize form already existing Complex number
82 *
83 * \code {.cpp}
84 * MyType a,b;
85 * a = hila::random();
86 * b = hila::random();
87 * Complex<MyType> C(a,b);
88 * Complex<MyType> B = C; // B.re = a, B.im = b
89 * \endcode
90 *
91 * Equivalent initializing is `Complex<MyType> B(C)`
92 * @param a
93 */
94 Complex<T>(const Complex<T> &a) = default;
95
96 // constructor from single complex --IS THIS NEEDED?
97 // template <typename A,
98 // std::enable_if_t<hila::is_arithmetic<A>::value, int> = 0 >
99 // constexpr Complex<T>(const Complex<A> a) : re(static_cast<T>(a.re)),
100 // im(static_cast<T>(a.im)) {}
101
102 // constructor from single scalar value
103 // Remember to mark this explicit, we do not want this to be invoked
104 // in automatic conversions (there should be methods)
105
106 //#pragma hila loop_function
107 /**
108 * @brief Real constructor
109 *
110 * Initialize only real element and sets imaginary to 0
111 *
112 * \code {.cpp}
113 * MyType a = hila::random();
114 * Complex<MyType> C(a); // C.re = a, C.im = 0
115 * \endcode
116 *
117 * Not equivalent to `Complex<MyType> C = a`
118 * @tparam S Type for value val
119 */
120 template <typename S, std::enable_if_t<hila::is_arithmetic<S>::value, int> = 0>
121 explicit constexpr Complex<T>(const S val) : re(val), im(0) {}
122
123 /**
124 * @brief Zero constructor
125 *
126 * Initialize to zero with nullpointer trick
127 *
128 * \code {.cpp}
129 * Complex<MyType> C = 0; // C.re = 0, C.im = 0
130 * \endcode
131 *
132 * Equivalent to `Complex<MyType> C` and `Complex<MyType> C(0)`
133 * @internal
134 */
135 constexpr Complex<T>(const std::nullptr_t n) : re(0), im(0) {}
136
137 // constructor c(a,b)
138 /**
139 * @brief Complex constructor
140 *
141 * Initialize both real and imaginary element
142 *
143 * \code{.cpp}
144 * MyType a,b;
145 * a = hila::random();
146 * b = hila::random();
147 * Complex<MyType> C(a,b); // C.re = a, C.im = b
148 * \endcode
149 *
150 * @tparam A Type for value a
151 * @tparam B Type for value b
152 */
153 template <typename A, typename B, std::enable_if_t<hila::is_arithmetic<A>::value, int> = 0,
154 std::enable_if_t<hila::is_arithmetic<B>::value, int> = 0>
155 explicit constexpr Complex<T>(const A &a, const B &b) : re(a), im(b) {}
156
157 // make also std accessors real() and imag() - don't return reference, because
158 // v.real() would not then work inside loops!
159
160
161 /**
162 * @brief Real part of Complex number
163 * @details Pass by value if Complex number is defined as const
164 *
165 * @return T Real part
166 */
167 inline T real() const {
168 return re;
169 }
170 /**
171 * @brief Imaginary part of Complex number
172 * @details Pass by value if Complex number is defined as const
173 * @return T Imaginary part
174 */
175 inline T imag() const {
176 return im;
177 }
178
179 /**
180 * @brief Real part of Complex number
181 * @details Pass by reference
182 *
183 * @return T & Real part
184 */
185 inline T &real() const_function {
186 return re;
187 }
188 /**
189 * @brief Imaginary part of Complex number
190 * @details Pass by reference
191 *
192 * @return T & Imaginary part
193 */
194 inline T &imag() const_function {
195 return im;
196 }
197 // automatic casting from Complex<T> -> Complex<A>
198 // TODO: ensure this works if A is vector type!
199 template <typename A>
200#pragma hila loop_function // TODO
201 operator Complex<A>() const {
202 return Complex<A>(re, im);
203 }
204
205 /**
206 * @brief Assignment operator
207 * @details The following ways of assigning a Complex object are
208 *
209 * __Assignment for Complex:__
210 *
211 * \code {.cpp}
212 * Complex<MyType> C(hila::random(),hila::random());
213 * Complex<MyType> B;
214 * B = C; // B.re = C.re, B.im = C.im
215 * \endcode
216 *
217 * __Assignment from real:__
218 *
219 * Assigns real part and imaginary part to zero
220 *
221 * \code {.cpp}
222 * Complex<MyType> B;
223 * MyType a = hila::random;
224 * B = a; // B.re = a, B.im = 0
225 * \endcode
226 *
227 * @param s
228 * @return Complex<T>&
229 */
230 inline Complex<T> &operator=(const Complex<T> &s) = default;
231
232 /**
233 * @brief Assignment from complex
234 *
235 * \code {.cpp}
236 * Complex<MyType> C(hila::random(),hila::random());
237 * Complex<MyType> B;
238 * B = C; // B.re = C.re, B.im = C.im
239 * \endcode
240 *
241 * @tparam A Type for Complex value s
242 * @param s Value to assign
243 * @return Complex<T>&
244 */
245 template <typename A>
246 inline Complex<T> &operator=(const Complex<A> &s) {
247 re = s.re;
248 im = s.im;
249 return *this;
250 }
251
252 /**
253 * @brief Assignment from real
254 *
255 * Assigns real part and imaginary part to zero
256 *
257 * \code {.cpp}
258 * Complex<MyType> B;
259 * MyType a = hila::random;
260 * B = a; // B.re = a, B.im = 0
261 * \endcode
262 *
263 * @tparam S Type for real value s
264 * @param s Value to assign
265 * @return Complex<T>&
266 */
267 template <typename S, std::enable_if_t<hila::is_arithmetic<S>::value, int> = 0>
268 inline Complex<T> &operator=(S s) {
269 re = s;
270 im = 0;
271 return *this;
272 }
273
274 /**
275 * @brief Compute square norm of Complex number
276 * @details
277 * \f{align}{ |z|^2 = \Re(z)^2 + \Im(z)^2\f}
278 *
279 * @return T Squared norm
280 */
281 inline T squarenorm() const {
282 return re * re + im * im;
283 }
284
285 /**
286 * @brief Compute absolute value of Complex number
287 * @details Essentially sqrt(squarenorm(z)):
288 * \f{align}{ |z| = \sqrt{\Re(z)^2 + \Im(z)^2}\f}
289 *
290 * @return T
291 */
292 inline T abs() const {
293 return sqrt(squarenorm());
294 }
295
296 /**
297 * @brief Compute argument of Complex number
298 * @details
299 * \f{align}{ \arg(z) = \arctan2(\Im(z)),\Re(z)\f}
300 *
301 * @return T
302 */
303 inline T arg() const {
304 return atan2(im, re);
305 }
306
307 /**
308 * @brief Compute conjugate of Complex number
309 * @details
310 * \f{align}{ z &= x + i\cdot y \\
311 * \Rightarrow z^* &= x - i\cdot y\f}
312 *
313 * @return Complex<T>
314 */
315 inline Complex<T> conj() const {
316 return Complex<T>(re, -im);
317 }
318
319 /**
320 * @brief Compute dagger of Complex number
321 * @details Alias to Complex::conj
322 *
323 * \f{align}{ z^* = z^\dagger \f}
324 * @return Complex<T>
325 */
326 inline Complex<T> dagger() const {
327 return Complex<T>(re, -im);
328 }
329
330 /**
331 * @brief Stores and returns Complex number given in polar coordinates
332 *
333 * \f{align}{ z = r\cdot e^{i\theta} \f}
334 * \code {.cpp}
335 * Complex<double> c;
336 * double r = 1;
337 * double theta = 3.14159265358979/2; // pi/2
338 * c.polar(r,theta); // c.re = 0, c.im = 1
339 * \endcode
340 *
341 *
342 * @param r Radius of Complex number
343 * @param theta Angle of complex number in radians
344 * @return Complex<T> Complex number
345 */
346 inline Complex<T> polar(const T r, const T theta) out_only {
347 re = r * cos(theta);
348 im = r * sin(theta);
349 return *this;
350 }
351
352 /**
353 * @brief Assign random values to Complex real and imaginary part
354 * @details Uses hila::random for both real and imaginary part
355 *
356 * @return Complex<T>&
357 */
358 inline Complex<T> &random() out_only {
359 re = hila::random();
360 im = hila::random();
361 return *this;
362 }
363
364 /**
365 * @brief Produces complex gaussian random values
366 * @details Uses hila::gaussrand2 for both real and imaignary part
367 * Assigns same random value for both real and imaginary part
368 * @param width gaussian_random
369 * @return Complex<T>&
370 */
371 inline Complex<T> &gaussian_random(double width = 1.0) out_only {
372 double d;
373 re = hila::gaussrand2(d) * width;
374 im = d * width;
375 return *this;
376 }
377
378 /**
379 * @brief Unary + operator
380 * @details Identity operation
381 *
382 * \code {.cpp}
383 * Complex<MyType> z;
384 * z == +z;
385 * \endcode
386 *
387 * @return Complex<Tr>
388 */
389 inline Complex<T> operator+() const {
390 return *this;
391 }
392
393 /**
394 * @brief Unary - operator
395 * @details Negates Complex number
396 *
397 * \code {.cpp}
398 * Complex<MyType> z;
399 * z = -z; // Results in -Re.z and -Im.z
400 * \endcode
401 *
402 * @return Complex<T>
403 */
404 inline Complex<T> operator-() const {
405 return Complex<T>(-re, -im);
406 }
407
408 // mark += and *= as loop_functions, because these can be used
409 // in reductions implicitly
410
411 /**
412 * @brief Complex addition assignment operator
413 * @details
414 *
415 * \code{.cpp}
416 * Complex<double> z(0,0);
417 * Complex<double> w(1,1);
418 * z += w; // z.re = 1, z.im = 1
419 * \endcode
420 *
421 * @tparam A Typpe of Complex number to add
422 * @param lhs Complex number to add
423 * @return Complex<T>&
424 */
425 template <typename A>
426 inline Complex<T> &operator+=(const Complex<A> &lhs) {
427 re += lhs.re;
428 im += lhs.im;
429 return *this;
430 }
431
432 /**
433 * @brief Real addition assignment operator
434 *
435 * Add assign only to real part of Complex number
436 *
437 * \code {.cpp}
438 * Complex<double> z(0,0);
439 * z += 1; // z.re = 1, z.im = 0
440 * \endcode
441 *
442 * @tparam A Type for real value a
443 * @param a Real value to add
444 * @return Complex<T>&
445 */
446 template <typename A, std::enable_if_t<hila::is_arithmetic<A>::value, int> = 0>
447 inline Complex<T> &operator+=(const A &a) {
448 re += a;
449 return *this;
450 }
451
452 /**
453 * @brief Complex subtraction assignment operator
454 * @details
455 *
456 * \code{.cpp}
457 * Complex<double> z(0,0);
458 * Complex<double> w(1,1);
459 * z -= w; // z.re = -1, z.im = -1
460 * \endcode
461 *
462 * @tparam A Type for complex number to subtract
463 * @param lhs Complex number to subtract
464 * @return Complex<T>&
465 */
466 template <typename A>
467 inline Complex<T> &operator-=(const Complex<A> &lhs) {
468 re -= lhs.re;
469 im -= lhs.im;
470 return *this;
471 }
472
473 /**
474 * @brief Real subtraction assignment operator
475 * Subtract assign only to real part of Complex number
476 *
477 * \code {.cpp}
478 * Complex<double> z(0,0);
479 * z -= 1; // z.re = -1, z.im = 0
480 * \endcode
481 *
482 * @tparam A Type for real value a
483 * @param a Real value to subtract
484 * @return Complex<T>&
485 */
486 template <typename A, std::enable_if_t<hila::is_arithmetic<A>::value, int> = 0>
487 inline Complex<T> &operator-=(const A &a) {
488 re -= a;
489 return *this;
490 }
491
492 // inline Complex<T> & operator*= (const Complex<T> & lhs) {
493 // T r = re * lhs.re - im * lhs.im;
494 // im = im * lhs.re + re * lhs.im;
495 // re = r;
496 // return *this;
497 // }
498
499 /**
500 * @brief Complex multiply assignment operator
501 * @details
502 * Standard Complex number multiplication
503 *
504 * \f{align}{z &= x + iy, w = x' + iy' \\
505 * z w &= (x + iy)(x' + iy') = (xx'-yy') + i(xy' + yx')\f}
506 * \code{.cpp}
507 * Complex<double> z,w;
508 * //
509 * // z,w get values
510 * //
511 * z*=w; // z = zw as defined above
512 * \endcode
513 *
514 * @tparam A Type for Complex number multiply
515 * @param lhs Complex number to multiply
516 * @return Complex<T>&
517 */
518 //#pragma hila loop_function
519
520 template <typename A>
521 inline Complex<T> &operator*=(const Complex<A> &lhs) {
522 T r = mul_sub(re, lhs.re, im * lhs.im); // a*b-c
523 im = mul_add(im, lhs.re, re * lhs.im); // a*b+c
524 re = r;
525 return *this;
526 }
527
528 /**
529 * @brief Real multiply assign operator
530 * @details Multiply assign by real number to both components of Complex number
531 *
532 * \code {.cpp}
533 * Complex<double> z(1,1);
534 * z *= 2; // z.re = 2, z.im = 2
535 * \endcode
536 * @tparam A Type for real value a
537 * @param a Real value to multiply
538 * @return Complex<T>&
539 */
540 template <typename A, std::enable_if_t<hila::is_arithmetic<A>::value, int> = 0>
541 inline Complex<T> &operator*=(const A a) {
542 re *= a;
543 im *= a;
544 return *this;
545 }
546
547 // a/b = a b*/|b|^2 = (a.re*b.re + a.im*b.im + i(a.im*b.re - a.re*b.im))/|b|^2
548 // inline Complex<T> & operator/= (const Complex<T> & lhs) {
549 // T n = lhs.squarenorm();
550 // T r = (re * lhs.re + im * lhs.im)/n;
551 // im = (im * lhs.re - re * lhs.im)/n;
552 // re = r;
553 // return *this;
554 // }
555
556 /**
557 * @brief Complex divide assignment operator
558 * @details
559 *
560 * Standard Complex number division
561 *
562 * \f{align}{z &= x + iy, w = x' + iy' \\
563 * \frac{z}{w} &= \frac{x + iy}{x' + iy'} = \frac{(xx'+ yy') + i( yx' - xy')}{|w|^2}\f}
564 * \code{.cpp}
565 * Complex<double> z,w;
566 * //
567 * // z,w get values
568 * //
569 * z/=w; // z = z/w as defined above
570 * \endcode
571 *
572 * @tparam A Type for Complex number divide
573 * @param lhs Complex number to divide
574 * @return Complex<T>&
575 */
576 template <typename A>
577 inline Complex<T> &operator/=(const Complex<A> &lhs) {
578 T n = lhs.squarenorm();
579 T r = mul_add(re, lhs.re, im * lhs.im) / n; // a*b+c
580 im = mul_sub(im, lhs.re, re * lhs.im) / n; // a*b-c
581 re = r;
582 return *this;
583 }
584
585 /**
586 * @brief Real divide assignment operator
587 * @details Divide assign by real number to both components of Complex number
588 *
589 * \code {.cpp}
590 * Complex<double> z(2,2);
591 * z /= 2; // z.re = 1, z.im = 1
592 * \endcode
593 * @tparam A Type for real value to divide
594 * @param a Real value to divide
595 * @return Complex<T>&
596 */
597 template <typename A, std::enable_if_t<hila::is_arithmetic<A>::value, int> = 0>
598 inline Complex<T> &operator/=(const A &a) {
599 re /= a;
600 im /= a;
601 return *this;
602 }
603
604 // define also increment and decrement operators (though not so intuitive for complex)
605
606 /**
607 * @brief Single increment operator
608 *
609 * Increments real part of Complex number
610 *
611 * \code {.cpp}
612 * Complex<double> z(1,1);
613 * z++; // z.re = 2, z.im = 1
614 * \endcode
615 *
616 *
617 * @return Complex<T>&
618 */
620 this->re++;
621 return *this;
622 }
623 /**
624 * @brief Single decrement operator
625 *
626 * Decrement real part of Complex number
627 *
628 * \code {.cpp}
629 * Complex<double> z(1,1);
630 * z--; // z.re = 0, z.im = 1
631 * \endcode
632 *
633 *
634 * @return Complex<T>&
635 */
637 this->re--;
638 return *this;
639 }
640 /**
641 * @brief Multiple increment operator
642 *
643 * Increments real part of Complex number
644 *
645 * \code {.cpp}
646 * Complex<double> z(2,1);
647 * z++2; // z.re = 4, z.im = 1
648 * \endcode
649 *
650 *
651 * @return Complex<T>&
652 */
653 inline Complex<T> operator++(int) {
654 Complex<T> a = *this;
655 this->re++;
656 return a;
657 }
658
659 /**
660 * @brief Multiple decrement operator
661 *
662 * Decrement real part of Complex number
663 *
664 * \code {.cpp}
665 * Complex<double> z(2,1);
666 * z--2; // z.re = 0, z.im = 1
667 * \endcode
668 *
669 *
670 * @return Complex<T>&
671 */
672 inline Complex<T> operator--(int) {
673 Complex<T> a = *this;
674 this->re--;
675 return a;
676 }
677
678 std::string str(int prec = 8, char separator = ' ') const {
679 std::stringstream ss;
680 ss.precision(prec);
681 ss << re << separator << im;
682 return ss.str();
683 }
684
685
686 // Convenience method a.conj_mul(b) == a^* b
687
688 /**
689 * @brief Conjugate multiply method
690 * @details Conjugate a (*this) and multiply with give argument b: `a.conj_mul(b)` \f$ \equiv
691 * a^* \cdot b\f$
692 *
693 * @tparam A Type for Complex number b
694 * @param b number to multiply with
695 * @return Complex<T>
696 */
697 template <typename A>
698 inline Complex<T> conj_mul(const Complex<A> &b) const {
699 return Complex<T>(re * b.re + im * b.im, re * b.im - im * b.re);
700 }
701
702 // Convenience method a.mul_conj(b) == a * b^*
703
704 /**
705 * @brief Multiply conjugate method
706 * @details Multiply a (*this) with conjugate of given argument b: `a.mul_conj(b)` \f$ \equiv a
707 * \cdot b^*\f$
708 *
709 * @tparam A Type for Complex number b
710 * @param b number to conjugate and multiply withv
711 * @return Complex<T>
712 */
713 template <typename A>
714 inline Complex<T> mul_conj(const Complex<A> &b) const {
715 return Complex<T>(re * b.re + im * b.im, im * b.re - re * b.im);
716 }
717
718 // cast to another number type (IS THIS NEEDED FOR COMPLEX?)
719 template <typename Ntype>
720 Complex<Ntype> cast_to() const {
721 Complex<Ntype> res;
722 res.re = re;
723 res.im = im;
724 return res;
725 }
726};
727
728
729namespace hila {
730////////////////////////////////////////////////////////////////////////
731// Section for adding complex utility templates (in namespace hila)
732// hila::is_complex_or_arithmetic<T>::value
733// hila::contains_complex<T>::value
734// hila::number_type<T> returns Complex or arithmetic type
735// hila::ntype_op<A,B> returns the conventionally upgraded complex or scalar number type
736// hila::complex_x_scalar_type<A,B> type of operation Complex<A> * scalar<B>
737
738
739////////////////////////////////////////////////////////////////////////
740// Define hila::is_complex<T>::value -template, using specialization
741template <typename T>
742struct is_complex : std::integral_constant<bool, false> {};
743
744template <typename T>
745struct is_complex<Complex<T>> : std::integral_constant<bool, true> {};
746
747/// hila::is_complex_or_arithmetic<T>::value
748template <typename T>
750 : std::integral_constant<bool, hila::is_arithmetic<T>::value || hila::is_complex<T>::value> {};
751
752/////////////////////////////////////////////////////////////////////////
753// Utility to check that the type contains complex numbers
754// Use as contains_complex<T>::value
755
756template <typename T, typename Enable = void>
757struct contains_complex : std::integral_constant<bool, false> {};
758
759template <typename T>
760struct contains_complex<T, typename std::enable_if_t<hila::is_field_class_type<T>::value>>
761 : std::integral_constant<bool,
762 hila::contains_type<T, Complex<hila::arithmetic_type<T>>>::value> {};
763
764/////////////////////////////////////////////////////////////////////////
765// Utility hila::number_type<T> returns complex or arithmetic type
766// depending on the type
767
768template <typename T, typename Enable = void, typename N = hila::arithmetic_type<T>>
769struct complex_or_arithmetic_type_struct {
770 using type = N;
771};
772
773template <typename T>
774struct complex_or_arithmetic_type_struct<
775 T, typename std::enable_if_t<hila::contains_complex<T>::value>> {
777};
778
779template <typename T>
780using number_type = typename complex_or_arithmetic_type_struct<T>::type;
781
782/////////////////////////////////////////////////////////////////////////
783// Utility hila::ntype_op<T1,T2> returns real or complex type,
784// "conventionally" defined double/float etc. upgrading.
785// Note: hila::type_plus<T1,T2> gives e.g. Complex<float>,double -> Complex<float>
786
787template <typename T1, typename T2, typename Enable = void>
788struct ntype_op_s {
789 using type = hila::type_plus<hila::arithmetic_type<T1>, hila::arithmetic_type<T2>>;
790};
791
792// if one type is complex?
793template <typename T1, typename T2>
794struct ntype_op_s<T1, T2,
795 typename std::enable_if_t<(hila::contains_complex<T1>::value ||
796 hila::contains_complex<T2>::value)>> {
797 using type = Complex<hila::type_plus<hila::arithmetic_type<T1>, hila::arithmetic_type<T2>>>;
798};
799
800template <typename T1, typename T2>
801using ntype_op = typename ntype_op_s<T1, T2>::type;
802
803////////////////////////////////////////////////////////////////////////////
804// utility complex_x_scalar, used in Complex<A> + scalar<B> ops
805// - if result is convertible to Complex<A>, return Complex<A>
806// - otherwise return Complex<type_plus<A,B>>
807// This is done in order to keep vector types as vectors
808
809template <typename A, typename B, typename Enable = void>
810struct complex_x_scalar_s {
811 using type = Complex<hila::type_plus<A, B>>;
812};
813
814template <typename A, typename B>
815struct complex_x_scalar_s<
816 A, B, typename std::enable_if_t<std::is_assignable<A &, hila::type_plus<A, B>>::value>> {
817 using type = Complex<A>;
818};
819
820template <typename A, typename B>
821using complex_x_scalar_type = typename complex_x_scalar_s<A, B>::type;
822
823////////////////////////////////////////////////////////////////////////
824// as_complex_array(T var)
825// casts the var to a pointer to complex<scalar_type<T>>
826// assuming var contains complex type. This enables access
827// of complex elements as
828// as_complex_array(var)[i]
829// comment out as hilapp gets confused at the moment
830////////////////////////////////////////////////////////////////////////
831
832// #pragma hila loop_function
833// template <typename T, std::enable_if_t<hila::contains_complex<T>::value, int> = 0>
834// inline const Complex<hila::arithmetic_type<T>> * as_complex_array(const T &var) {
835// return (const Complex<hila::arithmetic_type<T>> *)(void *)&var;
836// }
837
838// #pragma hila loop_function
839// template <typename T, std::enable_if_t<hila::contains_complex<T>::value, int> = 0>
840// inline Complex<hila::arithmetic_type<T>> * as_complex_array(T &var) {
841// return (Complex<hila::arithmetic_type<T>> *)(void *)&var;
842// }
843
844////////////////////////////////////////////////////////////////////////
845// get_complex_element(var,i)
846// returns the i:th complex number embedded in variable v
847// set_complex_element(var,i,value)
848// sets the i:th element in var
849////////////////////////////////////////////////////////////////////////
850
851template <typename T, std::enable_if_t<hila::contains_complex<T>::value, int> = 0>
852inline Complex<hila::arithmetic_type<T>> get_complex_in_var(const T &var, int i) {
853 return *(reinterpret_cast<const Complex<hila::arithmetic_type<T>> *>(&var) + i);
854}
855
856template <typename T, std::enable_if_t<hila::contains_complex<T>::value, int> = 0>
857inline void set_complex_in_var(T &var, int i, const Complex<hila::arithmetic_type<T>> &val) {
858 *(reinterpret_cast<Complex<hila::arithmetic_type<T>> *>(&var) + i) = val;
859}
860
861} // namespace hila
862
863// generic Complex constructor - type from arguments
864template <typename T, std::enable_if_t<hila::is_floating_point<T>::value, int> = 0>
865Complex<T> complex(const T re, const T im) {
866 return Complex<T>(re, im);
867}
868
869
870/**
871 * @brief Return real value of Complex number
872 * @details Wrapper around Complex::real
873 * @tparam T Arithmetic type of a
874 * @param a Complex number to get real value from
875 * @return T
876 */
877template <typename T>
878inline T real(const Complex<T> &a) {
879 return a.re;
880}
881
882/**
883 * @brief Retrun imaginary value of Complex number
884 * @details Wrapper around Complex::imag
885 * @tparam T Arithmetic type of a
886 * @param a Complex number to get imaginary value from
887 * @return T
888 */
889template <typename T>
890inline T imag(const Complex<T> &a) {
891 return a.im;
892}
893
894/**
895 * @brief Return complex number given by polar representation
896 * @details Same as Complex::polar
897 * @tparam T Arithmetic type r and arg
898 * @param r Radial component of Complex number
899 * @param arg Argument of Complex number
900 * @return Complex<T>
901 */
902template <typename T>
904 Complex<T> res(r * cos(arg), r * sin(arg));
905 return res;
906}
907
908
909// template <typename T>
910// inline Complex<T> operator+(const Complex<T> & a, const Complex<T> & b) {
911// return Complex<T>(a.re + b.re, a.im + b.im);
912// }
913
914
915#pragma hila loop_function
916/**
917 * @brief Addition operator Complex + Complex
918 * @memberof Complex
919 * @details Addition between Complex numbers is defined in the usual way:
920 *
921 * \f{align}{ z_1, z_2 &\in \mathbf{C} \\ z_1 + z_2 &= \Re(z_1) + \Re(z_2) + [\Im(z_1) + \Im(z_2)]i
922 * \f}
923 *
924 * \code {.cpp}
925 * z = z_1 + z_2;
926 * \endcode
927 *
928 * @tparam T1 Type for first complex number
929 * @tparam T2 Type for second complex number
930 * @tparam Tr Conversion type between T1 and T2
931 * @param a First complex number
932 * @param b Second complex number
933 * @return Complex<Tr>
934 */
935template <typename T1, typename T2, typename Tr = hila::type_plus<T1, T2>>
936inline Complex<Tr> operator+(const Complex<T1> &a, const Complex<T2> &b) {
937 return Complex<Tr>(a.re + b.re, a.im + b.im);
938}
939
940// TODO: for avx vector too -- #define new template macro
941/**
942 * @brief Addition operator Complex + Scalar
943 * @memberof Complex
944 * @details Defined in the usual way. \f$z,z_1 \in \mathbb{C}, a \in \mathbb{R}\f$
945 * \code {.cpp}
946 * z = z_1 + a;
947 * \endcode
948 * @tparam T Arithmetic type of c
949 * @tparam A Arithmetic type of a
950 * @param c Complex number to sum
951 * @param a Scalar to sum
952 * @return auto
953 */
954template <typename T, typename A, std::enable_if_t<hila::is_arithmetic<A>::value, int> = 0>
955inline auto operator+(const Complex<T> &c, const A &a) {
956 return hila::complex_x_scalar_type<T, A>(c.re + a, c.im);
957}
958
959/**
960 * @brief Addition operator Scalar + Complex
961 * @memberof Complex
962 * @details Defined in the usual way. \f$z,z_1 \in \mathbb{C}, a \in \mathbb{R}\f$
963 * \code {.cpp}
964 * z = a + z_1;
965 * \endcode
966 * @tparam T Arithmetic type of c
967 * @tparam A Arithmetic type of a
968 * @param a Scalar to sum
969 * @param c Complex number to sum
970 * @return auto
971 */
972template <typename T, typename A, std::enable_if_t<hila::is_arithmetic<A>::value, int> = 0>
973inline auto operator+(const A &a, const Complex<T> &c) {
974 return hila::complex_x_scalar_type<T, A>(c.re + a, c.im);
975}
976
977/**
978 * @brief Subtraction operator Complex - Complex
979 * @memberof Complex
980 * @details Subtraction between Complex numbers is defined in the usual way
981 * \f{align}{ z_1, z_2 &\in \mathbf{C} \\ z_1 - z_2 &= \Re(z_1) - \Re(z_2) + [\Im(z_1) -
982 * \Im(z_2)]i\f}
983 *
984 * \code {.cpp}
985 * z = z_1 - z_2;
986 * \endcode
987 *
988 * @tparam T1 Arithmetic type of a
989 * @tparam T2 Arithmetic type of b
990 * @tparam Tr Resulting type after subtraction
991 * @param a First complex number
992 * @param b Second complex number to subtract
993 * @return Complex<Tr>
994 */
995template <typename T1, typename T2, typename Tr = hila::type_plus<T1, T2>>
996inline Complex<Tr> operator-(const Complex<T1> &a, const Complex<T2> &b) {
997 return Complex<Tr>(a.re - b.re, a.im - b.im);
998}
999
1000/**
1001 * @brief Subtraction operator Complex - Scalar
1002 * @memberof Complex
1003 * @details Defined in the usual way. \f$z,z_1 \in \mathbb{C}, a \in \mathbb{R}\f$
1004 * \code {.cpp}
1005 * z = z_1 - a;
1006 * \endcode
1007 * @tparam T Arithmetic type of c
1008 * @tparam A Arithmetic type of a
1009 * @param c Complex number
1010 * @param a Scalar to subtract
1011 * @return auto
1012 */
1013template <typename T, typename A, std::enable_if_t<hila::is_arithmetic<A>::value, int> = 0>
1014inline auto operator-(const Complex<T> &c, const A &a) {
1015 return hila::complex_x_scalar_type<T, A>(c.re - a, c.im);
1016}
1017
1018/**
1019 * @memberof Complex
1020 * @brief Subtraction operator Scalar - Complex
1021 * @details Defined in the usual way. \f$z,z_1 \in \mathbb{C}, a \in \mathbb{R}\f$
1022 * \code {.cpp}
1023 * z = a - z_1;
1024 * \endcode
1025 * @tparam T Arithmetic type of c
1026 * @tparam A Arithmetic type of a
1027 * @param a Scalar
1028 * @param c Complex number to subtract
1029 * @return auto
1030 */
1031template <typename T, typename A, std::enable_if_t<hila::is_arithmetic<A>::value, int> = 0>
1032inline auto operator-(const A &a, const Complex<T> &c) {
1033 return hila::complex_x_scalar_type<T, A>(a - c.re, -c.im);
1034}
1035
1036/**
1037 * @brief Multiplication operator Complex * Complex
1038 * @memberof Complex
1039 * @details Defined in the usual way
1040 *
1041 * \f{align}{z, z_1 &= x + iy, z_2 = x' + iy' \in \mathbb{C} \\
1042 * z_1 z_2 &= (x + iy)(x' + iy') = (xx'-yy') + i(xy' + yx')\f}
1043 * \code {.cpp}
1044 * z = z_1 * z_2;
1045 * \endcode
1046 * @tparam T1 Arithmetic type of a
1047 * @tparam T2 Arithmetic type of b
1048 * @tparam Tr Resulting type after multiplication
1049 * @param a
1050 * @param b
1051 * @return Complex<Tr>
1052 */
1053template <typename T1, typename T2, typename Tr = hila::type_mul<T1, T2>>
1054inline Complex<Tr> operator*(const Complex<T1> &a, const Complex<T2> &b) {
1055 return Complex<Tr>(a.re * b.re - a.im * b.im, a.re * b.im + a.im * b.re);
1056}
1057
1058/**
1059 * @brief Multiplication operator Complex * Scalar
1060 * @memberof Complex
1061 * @details Multiplication between Complex and scalar is defined in the usual way
1062 * \f{align}{z,z_1 &= x + iy \in \mathbb{C}, a \in \mathbb{R} \\
1063 * z_1 * a &= (x\cdot a + iy\cdot a)\f}
1064 * \code {.cpp}
1065 * z = z_1 * a;
1066 * \endcode
1067 * @tparam T Arithmetic type of c
1068 * @tparam A Arithmetic type of a
1069 * @param c Complex number to multiply
1070 * @param a Scalar to multiply
1071 * @return auto
1072 */
1073template <typename T, typename A, std::enable_if_t<hila::is_arithmetic<A>::value, int> = 0>
1074inline auto operator*(const Complex<T> &c, const A &a) {
1075 return hila::complex_x_scalar_type<T, A>(c.re * a, c.im * a);
1076}
1077
1078/**
1079 * @brief Multiplication operator Scalar * Complex
1080 * @memberof Complex
1081 * @details Multiplication between Complex and scalar is defined in the usual way
1082 * \f{align}{z,z_1 &= x + iy \in \mathbb{C}, a \in \mathbb{R} \\
1083 * z * a &= (x\cdot a + iy\cdot a)\f}
1084 * \code {.cpp}
1085 * z = a * z_1;
1086 * \endcode
1087 * @tparam T Arithmetic type of c
1088 * @tparam A Arithmetic type of a
1089 * @param c Complex number to multiply
1090 * @param a Scalar to multiply
1091 * @return auto
1092 */
1093template <typename T, typename A, std::enable_if_t<hila::is_arithmetic<A>::value, int> = 0>
1094inline auto operator*(const A &a, const Complex<T> &c) {
1095 return hila::complex_x_scalar_type<T, A>(a * c.re, a * c.im);
1096}
1097
1098// / a/b = ab*/| b |^2
1099// template <typename T>
1100// inline Complex<T> operator/(const Complex<T> & a, const Complex<T> & b) {
1101// T n = b.squarenorm();
1102// return Complex<T>( (a.re*b.re + a.im*b.im)/n, (a.im*b.re - a.re*b.im)/n );
1103// }
1104
1105/**
1106 * @brief Division operator Complex / Complex
1107 * @memberof Complex
1108 * @details Defined in the usual way
1109 * \f{align}{ z,z_1,z_2 &\in \mathbb{C} \\
1110 * \frac{z_1}{z_2} &= \frac{z_1\cdot z_2^{*}}{|z_2|^2} \f}
1111 * \code {.cpp}
1112 * z =z_1 / z_2;
1113 * \endcode
1114 * @tparam T1 Arithmetic type of a
1115 * @tparam T2 Arithmetic type of b
1116 * @tparam Tr Resulting type after division
1117 * @param a Complex number to divide
1118 * @param b Complex number to divide with
1119 * @return Complex<Tr>
1120 */
1121template <typename T1, typename T2, typename Tr = hila::type_mul<T1, T2>>
1122inline Complex<Tr> operator/(const Complex<T1> &a, const Complex<T2> &b) {
1123 T2 n = 1.0 / b.squarenorm();
1124 return Complex<Tr>((a.re * b.re + a.im * b.im) * n, (a.im * b.re - a.re * b.im) * n);
1125}
1126
1127/**
1128 * @memberof Complex
1129 * @brief Division operator Complex / Scalar
1130 * @details Defined in the usual way
1131 * \f{align}{z, z_1=x + iy &\in \mathbb{C}, a \in \mathbb{R} \\
1132 * \frac{z_1}{a} &= \frac{x}{a} + i\cdot \frac{y}{a} \f}
1133 * \code {.cpp}
1134 * z = z_1 / a;
1135 * \endcode
1136 * @tparam T Arithmetic type of c
1137 * @tparam A Arithmetic type of a
1138 * @param c Complex number to divide
1139 * @param a Scalar to divide with
1140 * @return auto
1141 */
1142template <typename T, typename A, std::enable_if_t<hila::is_arithmetic<A>::value, int> = 0>
1143inline auto operator/(const Complex<T> &c, const A &a) {
1144 return hila::complex_x_scalar_type<T, A>(c.re / a, c.im / a);
1145}
1146
1147// a/c = ac*/|c|^2
1148/**
1149 * @memberof Complex
1150 * @brief Division operator Scalar / Complex
1151 * @details Defined in the usual way
1152 * \f{align}{ z,z_1=x + iy &\in \mathbb{C}, a \in \mathbb{R} \\
1153 * \frac{a}{z_1} &= \frac{az^*}{|z|^2} \f}
1154 * \code {.cpp}
1155 * z = a / z_1;
1156 * \endcode
1157 * @tparam T Arithmetic type of c
1158 * @tparam A Arithmetic type of a
1159 * @param c Complex number to divide
1160 * @param a Scalar to divide with
1161 * @return auto
1162 */
1163template <typename T, typename A, std::enable_if_t<hila::is_arithmetic<A>::value, int> = 0>
1164inline auto operator/(const A &a, const Complex<T> &c) {
1165 T n = c.squarenorm();
1166 return hila::complex_x_scalar_type<T, A>((a * c.re) / n, -(a * c.im) / n);
1167}
1168
1169/**
1170 * @brief Multiply add with Complex numbers
1171 * @memberof Complex
1172 * @details Defined as
1173 *
1174 * \code{.cpp}
1175 * mul_add(a,b,c) = a*b + c;
1176 * \endcode
1177 * @tparam T Arithmetic type of a,b and c
1178 * @param a Complex number to multiply
1179 * @param b Complex number to multiply
1180 * @param c Complex number to add to result of multiplication
1181 * @return Complex<T>
1182 */
1183template <typename T>
1184inline Complex<T> mul_add(const Complex<T> &a, const Complex<T> &b, const Complex<T> &c) {
1185 // a*b + c
1186 Complex<T> r;
1187 T t1 = mul_add(a.re, b.re, c.re);
1188 T t2 = mul_add(a.re, b.im, c.im);
1189 r.re = mul_add(a.im, b.im, t1); // -a.im*b.im + a.re*b.re + c.re
1190 r.im = mul_add(a.im, b.re, t2); // a.im*b.re + a.re*b.im + c.im
1191 return r;
1192}
1193
1194/**
1195 * @brief Compare equality of two complex numbers
1196 * @memberof Complex
1197 * Two numbers are equal, if the real and imaginary components are respectively equal
1198 *
1199 * @tparam A Arithmetic type of a
1200 * @tparam B Arithmetic type of b
1201 * @param a Complex number to compare
1202 * @param b Complex number to compare
1203 * @return true if values compare to equal
1204 */
1205
1206template <typename A, typename B>
1207inline bool operator==(const Complex<A> &a, const Complex<B> &b) {
1208 return (a.re == b.re && a.im == b.im);
1209}
1210
1211/**
1212 * @memberof Complex
1213 * @brief Compare equality of Complex and scalar
1214 *
1215 * Two numbers are equal, if the arithmetic values are equal: thus,
1216 * complex and real comparison (a + i b) == a
1217 * is true if b == 0.
1218 *
1219 * @tparam A Arithmetic type of a
1220 * @tparam B Arithmetic type of b
1221 * @param a Complex number to compare
1222 * @param b Scalar to compare
1223 * @return true if values compare to equal
1224 */
1225template <typename A, typename B, std::enable_if_t<hila::is_arithmetic<B>::value, int> = 0>
1226inline bool operator==(const Complex<A> &a, const B b) {
1227 return (a.re == b && a.im == 0);
1228}
1229
1230/**
1231 * @memberof Complex
1232 * @brief Compare equality of Scalar and Complex
1233 *
1234 * Two numbers are equal, if the arithmetic values are equal: thus,
1235 * complex and real comparison (a + i b) == a
1236 * is true if b == 0.
1237 *
1238 * @tparam A Arithmetic type of a
1239 * @tparam B Arithmetic type of b
1240 * @param b Complex number to compare
1241 * @param a Scalar to compare
1242 * @return true if values compare to equal
1243 */
1244template <typename A, typename B, std::enable_if_t<hila::is_arithmetic<A>::value, int> = 0>
1245inline bool operator==(const A a, const Complex<B> &b) {
1246 return b == a;
1247}
1248
1249/**
1250 * @brief Compare non-equality of two complex numbers
1251 * @memberof Complex
1252 * @details Negation of operator==()
1253 *
1254 * @tparam A Arithmetic type of a
1255 * @tparam B Arithmetic type of b
1256 * @param a Complex number to compare
1257 * @param b Complex number to compare
1258 * @return true if values are not arithmetically equal
1259 */
1260template <typename A, typename B>
1261inline bool operator!=(const Complex<A> &a, const Complex<B> &b) {
1262 return (a.re != b.re || a.im != b.im);
1263}
1264
1265/**
1266 * @brief Compare non-equality of Complex number and Scalar
1267 * @memberof Complex
1268 * @details Negation of operator==()
1269 *
1270 * @tparam A Arithmetic type of a
1271 * @tparam B Arithmetic type of b
1272 * @param a Complex number to compare
1273 * @param b Scalar to compare
1274 * @return true if values are not arithmetically equal
1275 */
1276template <typename A, typename B, std::enable_if_t<hila::is_arithmetic<B>::value, int> = 0>
1277inline bool operator!=(const Complex<A> &a, const B b) {
1278 return (a.re != b || a.im != 0);
1279}
1280
1281/**
1282 * @brief Compare non-equality of Scalar and Complex number
1283 * @memberof Complex
1284 * @details Negation of operator==()
1285 *
1286 * @tparam A Arithmetic type of a
1287 * @tparam B Arithmetic type of b
1288 * @param a Scalar to compare
1289 * @param b Complex number to compare
1290 * @return true if values are not arithmetically equal
1291 */
1292template <typename A, typename B, std::enable_if_t<hila::is_arithmetic<A>::value, int> = 0>
1293inline bool operator!=(const A a, const Complex<B> &b) {
1294 return b != a;
1295}
1296
1297
1298// Cast operators to different number or Complex type
1299// cast_to<double>(a);
1300// cast_to<float>(b);
1301// Cast from number->number, number->Complex, Complex->Complex OK,
1302// Complex->number not.
1303
1304template <typename Ntype, typename T, std::enable_if_t<hila::is_arithmetic<Ntype>::value, int> = 0>
1305Complex<Ntype> cast_to(const Complex<T> &m) {
1306 Complex<Ntype> res;
1307 res = m;
1308 return res;
1309}
1310
1311//////////////////////////////////////////////////////////////////////////////////
1312// Some operations in function form. Useful in templates when the arg type is not known
1313
1314/**
1315 * @brief Return absolute value of Complex number
1316 * @details Wrapper around Complex::abs
1317 * @tparam T Arithmetic type of a
1318 * @param a Complex number to get abs from
1319 * @return T
1320 */
1321template <typename T>
1322inline T abs(const Complex<T> &a) {
1323 return a.abs();
1324}
1325
1326/**
1327 * @brief Return argument of Complex number
1328 * @details Wrapper around Complex::arg
1329 * @tparam T Arithmetic type of a
1330 * @param a Complex number to get arg from
1331 * @return T
1332 */
1333template <typename T>
1334inline T arg(const Complex<T> &a) {
1335 return a.arg();
1336}
1337
1338/**
1339 * @brief Return conjugate of Complex number
1340 * @details Wrapper around Complex::conj
1341 * @tparam T Arithmetic type of a
1342 * @param a Complex number to get conjugate from
1343 * @return Complex<T>
1344 */
1345template <typename T>
1346inline Complex<T> conj(const Complex<T> &val) {
1347 return val.conj();
1348}
1349
1350/**
1351 * @brief Return dagger of Complex number
1352 * @details Wrapper around Complex::conj
1353 * @tparam T Arithmetic type of a
1354 * @param a Complex number to get conjugate from
1355 * @return Complex<T>
1356 */
1357template <typename T>
1358inline Complex<T> dagger(const Complex<T> &val) {
1359 return val.conj();
1360}
1361
1362/**
1363 * @brief Return Squarenorm of Complex number
1364 * @details Wrapper around Complex::squarenorm
1365 * @tparam T Arithmetic type of a
1366 * @param a Complex number to compute squarenorm of
1367 * @return T
1368 */
1369template <typename T>
1370inline auto squarenorm(const Complex<T> &val) {
1371 return val.squarenorm();
1372}
1373
1374
1375//////////////////////////////////////////////////////////////////////////////////
1376/// Print a complex value as (re,im)
1377//////////////////////////////////////////////////////////////////////////////////
1378
1379/**
1380 * @brief Stream operator
1381 * @details Print Complex number as "A.re A.im"
1382 * @tparam T Arithmetic type of A
1383 * @param strm
1384 * @param A Complex number to print
1385 * @return std::ostream&
1386 */
1387template <typename T>
1388std::ostream &operator<<(std::ostream &strm, const Complex<T> &A) {
1389 return strm << A.real() << ' ' << A.imag();
1390}
1391
1392/// //////////////////////////////////////////////////////////////////////////////
1393/// Function hila::to_string
1394
1395namespace hila {
1396/**
1397 * @brief Return Complex number as std::string
1398 *
1399 * @tparam T Arithmetic type of A
1400 * @param A Complex number to convert
1401 * @param prec Precision to represent Complex number at
1402 * @param separator Separator for Complex number
1403 * @return std::string
1404 */
1405template <typename T>
1406std::string to_string(const Complex<T> &A, int prec = 8, char separator = ' ') {
1407 return A.str(prec, separator);
1408}
1409
1410/**
1411 * @brief Return well formatted Complex number as std::string
1412 * @details Output is as "(A.re, A.im)"
1413 *
1414 * @tparam T Arithmetic type of A
1415 * @param A Complex number to print
1416 * @param prec Precision to print Complex number as
1417 * @return std::string
1418 */
1419template <typename T>
1420std::string prettyprint(const Complex<T> &A, int prec = 8) {
1421 std::stringstream ss;
1422 ss.precision(prec);
1423 ss << "( " << A.real() << ", " << A.imag() << " )";
1424 return ss.str();
1425}
1426
1427} // namespace hila
1428
1429
1430/**
1431 * @brief Imaginary type, used to represent purely imaginary numbers
1432 *
1433 * Useful for reducing multiply operations in im * complex or im * real -ops
1434 * Derived from Complex class, so generic complex ops should remain valid
1435 * Defines only operators * and /, others go via Complex class
1436 *
1437 * Note: Imaginary_t should be used in Field variables
1438 *
1439 * @tparam T type of imaginary (float/double)
1440 */
1441template <typename T>
1442class Imaginary_t : public Complex<T> {
1443 public:
1444 constexpr Imaginary_t() = default;
1445 ~Imaginary_t() = default;
1446 constexpr Imaginary_t(const Imaginary_t &i) = default;
1447
1448 // construct from scalar
1449#pragma hila loop_function
1450 template <typename A, std::enable_if_t<hila::is_arithmetic<A>::value, int> = 0>
1451 explicit constexpr Imaginary_t(const A v) : Complex<T>(0, v) {}
1452
1453 constexpr Imaginary_t operator-() const {
1454 return Imaginary_t<T>(-this->im);
1455 }
1456
1457 constexpr Imaginary_t operator+() const {
1458 return *this;
1459 }
1460};
1461
1462///////////////////////////////////////////////////////////////////////////////////////
1463/// @brief Imaginary unit I - global variable
1464///
1465/// Don't use #define'd I : this will conflict with some headers in rocm
1466///
1467/// For some reason it is sufficient to use only __device__
1468#if defined(CUDA) || defined(HIP)
1469__device__
1470#endif
1471 constexpr Imaginary_t<double>
1472 I(1.0);
1473
1474// constexpr Complex<double> I(0,1);
1475// #define I Imaginary_t<double>(1.0)
1476
1477///////////////////////////////////////////////////////////////////////////////////////
1478
1479// Imaginary * object containing complex
1480template <typename A, typename T, std::enable_if_t<hila::contains_complex<T>::value, int> = 0>
1481inline auto operator*(const Imaginary_t<A> &i, const T &c) {
1483 T res;
1484 constexpr int n_cmplx = sizeof(T) / sizeof(Complex<hila::arithmetic_type<T>>);
1485 for (int k = 0; k < n_cmplx; k++) {
1486 ca = hila::get_complex_in_var(c, k);
1487 cb.re = -ca.im * i.imag();
1488 cb.im = ca.re * i.imag();
1489 hila::set_complex_in_var(res, k, cb);
1490 }
1491 return res;
1492}
1493
1494// object containing complex * imaginary
1495template <typename A, typename T, std::enable_if_t<hila::contains_complex<T>::value, int> = 0>
1496inline auto operator*(const T &c, const Imaginary_t<A> &i) {
1497 return i * c;
1498}
1499
1500
1501// Imag * scalar, returns imag
1502// note: using std::is_arithmetic, not done for vector types
1503template <typename A, typename T, std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
1504inline Imaginary_t<A> operator*(Imaginary_t<A> i, const T &c) {
1505 i.imag() *= c;
1506 return i;
1507}
1508
1509// scalar * imag, returns imag
1510template <typename A, typename T, std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
1511inline Imaginary_t<A> operator*(const T &c, Imaginary_t<A> i) {
1512 i.imag() *= c;
1513 return i;
1514}
1515
1516// Imaginary * Imaginary, returns scalar
1517template <typename A, typename B>
1518inline auto operator*(const Imaginary_t<A> &a, const Imaginary_t<B> &b) {
1519 return -(a.imag() * b.imag());
1520}
1521
1522////////////////////////////
1523
1524
1525// @brief Imaginary / real value, returning imaginary
1526// Note: for vectorized types the generic version is used
1527template <typename T, typename A, std::enable_if_t<std::is_arithmetic<A>::value, int> = 0>
1528inline auto operator/(Imaginary_t<T> i, const A &a) {
1529 i.imag() /= a;
1530 return i;
1531}
1532
1533// @brief Imaginary / Imaginary, returning real
1534template <typename A, typename B>
1535inline auto operator/(const Imaginary_t<A> &a, const Imaginary_t<B> &b) {
1536 return a.imag() / b.imag();
1537}
1538
1539
1540///////////////////////////////////////////////////////////////////////////////
1541// Set of complex functions
1542///////////////////////////////////////////////////////////////////////////////
1543/**
1544 * @name Mathematical functions
1545 * @return Complex T
1546 * @memberof Complex
1547 *
1548 * @{
1549 */
1550/// \f$\exp(z)\f$
1551template <typename T>
1552inline Complex<T> exp(const Complex<T> z) {
1553 return exp(z.re) * Complex<T>(cos(z.im), sin(z.im));
1554}
1555
1556/// \f$\exp(i\cdot x)\f$
1557template <typename T, std::enable_if_t<hila::is_arithmetic<T>::value, int> = 0>
1558inline Complex<T> expi(T a) {
1559 return Complex<T>(cos(a), sin(a));
1560}
1561
1562/// \f$\exp(\Im(z))\f$
1563template <typename T>
1565 return expi(im.imag());
1566}
1567
1568/// \f$\log{z}\f$
1569template <typename T>
1571 return Complex<T>(static_cast<T>(0.5) * log(z.squarenorm()), z.arg());
1572}
1573
1574// sqrt(z) branch cut at -x axis
1575
1576/// \f$\sqrt{z}\f$
1577template <typename T>
1579 T r = z.squarenorm();
1580 T a = z.arg();
1581 return pow(r, 0.25) * expi(0.5 * a);
1582}
1583
1584/// \f$\sqrt[3]{z}\f$
1585template <typename T>
1587 T r = z.squarenorm();
1588 T a = z.arg();
1589 return pow(r, (1.0 / 6.0)) * expi((1.0 / 3.0) * a);
1590}
1591
1592/// pow(z.p) = \f$z^p\f$ = \f$exp(p*log(z))\f$
1593template <typename A, typename B>
1594inline auto pow(Complex<A> z, Complex<B> p) {
1595 return exp(p * log(z));
1596}
1597
1598/// pow(z.p) with scalar power
1599template <typename T, typename S, std::enable_if_t<hila::is_arithmetic<S>::value, int> = 0>
1600inline Complex<T> pow(Complex<T> z, S p) {
1601 return exp(p * log(z));
1602}
1603
1604/// pow(z.p) with scalar base
1605template <typename T, typename S, std::enable_if_t<hila::is_arithmetic<S>::value, int> = 0>
1606inline Complex<T> pow(S z, Complex<T> p) {
1607 return exp(p * log(z));
1608}
1609
1610/// \f{align}{sin(z) &= \sin(\Re(z) + i \Im(z)) \\
1611/// &= \sin(\Re(z))\cos(i \Im(z)) + \cos(\Re(z))\sin(i \Im(z)) \\
1612/// &= \sin(\Re(z)) \cosh(\Im(z)) + i \cos(\Re(z)) \sinh(\Im(z)) \f}
1613template <typename T>
1615 return Complex<T>(sin(z.re) * cosh(z.im), cos(z.re) * sinh(z.im));
1616}
1617
1618/// \f{align}{\cos(z) &= \cos(\Re{z})\cos(i \Im(z)) - \sin(\Re{z})\sin(i \Im{z}) \\
1619/// &= \cos(\Re{z})\cosh(\Im(z)) - i \sin(\Re{z})\sinh(\Im(z))\f}
1620template <typename T>
1622 return Complex<T>(cos(z.re) * cosh(z.im), -sin(z.re) * sinh(z.im));
1623}
1624
1625/// \f$\tan(z) = \frac{\sin(z)}{\cos(z)}\f$ - rely on optimizer to simplify
1626template <typename T>
1628 return sin(z) / cos(z);
1629}
1630
1631/// sinh(z) = sinh(re)cosh(i im) + cosh(re)sinh(i im)
1632/// = sinh(re)cos(im) + i cosh(re)sin(im)
1633template <typename T>
1635 return Complex<T>(sinh(z.re) * cos(z.im), cosh(z.re) * sin(z.im));
1636}
1637
1638/// cosh(z) = cosh(re)cosh(i im) - sinh(re)sinh(i im)
1639/// = cosh(re)cos(im) - i sinh(re)sin(im)
1640template <typename T>
1642 return Complex<T>(cosh(z.re) * cos(z.im), sinh(z.re) * sin(z.im));
1643}
1644
1645/// \f$\tanh(z)\f$
1646template <typename T>
1648 return sinh(z) / cosh(z);
1649}
1650
1651/// \f$\arctan(z)\f$
1652template <typename T>
1654 return -0.5 * I * (log((I - z) / (I + z)));
1655}
1656
1657/// \f$\arcsin(z)\f$
1658template <typename T>
1660 return -I * (log(I * z + sqrt(1 - z * z)));
1661}
1662
1663/// \f$\arccos(z)\f$
1664template <typename T>
1666 return -I * (log(z + I * (sqrt(1 - z * z))));
1667}
1668
1669/// \f$\text{artanh}(z)\f$
1670template <typename T>
1672 return 0.5 * log((1 + z) / (1 - z));
1673}
1674
1675/// \f$\text{arsinh}(z)\f$
1676template <typename T>
1678 return log(z + sqrt(1 + z * z));
1679}
1680
1681/// \f$\text{arcosh}(z)\f$
1682template <typename T>
1684 return log(z + sqrt(z * z - 1));
1685}
1686
1687/** @} */
1688
1689
1690//////////////////////////////////////////////////////////////////////////////////
1691/// Operators to implement imaginary unit 1_i, enablig expressions 3 + 2_i etc.
1692/// This is defined as an user-defined literal, which requires an underscore.
1693////////////////////////////////////////////////////////////////////////////////
1694
1695constexpr Imaginary_t<double> operator""_i(long double a) {
1696 return Imaginary_t<double>{a};
1697}
1698
1699constexpr Imaginary_t<double> operator""_i(unsigned long long a) {
1700 return Imaginary_t<double>(a);
1701}
1702
1703
1704#endif
Complex definition.
Definition cmplx.h:50
Complex< T > dagger() const
Compute dagger of Complex number.
Definition cmplx.h:326
auto operator*(const A &a, const Complex< T > &c)
Multiplication operator Scalar * Complex.
Definition cmplx.h:1094
Complex< T > asin(Complex< T > z)
Definition cmplx.h:1659
Complex< T > & operator/=(const Complex< A > &lhs)
Complex divide assignment operator.
Definition cmplx.h:577
auto operator+(const A &a, const Complex< T > &c)
Addition operator Scalar + Complex.
Definition cmplx.h:973
Complex< T > & operator-=(const Complex< A > &lhs)
Complex subtraction assignment operator.
Definition cmplx.h:467
Complex< T > cbrt(Complex< T > z)
Definition cmplx.h:1586
bool operator!=(const A a, const Complex< B > &b)
Compare non-equality of Scalar and Complex number.
Definition cmplx.h:1293
Complex< T > exp(const Imaginary_t< T > im)
Definition cmplx.h:1564
Complex< Tr > operator-(const Complex< T1 > &a, const Complex< T2 > &b)
Subtraction operator Complex - Complex.
Definition cmplx.h:996
auto operator-(const Complex< T > &c, const A &a)
Subtraction operator Complex - Scalar.
Definition cmplx.h:1014
bool operator==(const Complex< A > &a, const Complex< B > &b)
Compare equality of two complex numbersTwo numbers are equal, if the real and imaginary components ar...
Definition cmplx.h:1207
Complex< T > & operator*=(const A a)
Real multiply assign operator.
Definition cmplx.h:541
Complex< T > conj() const
Compute conjugate of Complex number.
Definition cmplx.h:315
auto operator*(const Complex< T > &c, const A &a)
Multiplication operator Complex * Scalar.
Definition cmplx.h:1074
Complex< T > cosh(Complex< T > z)
Definition cmplx.h:1641
Complex< T > acosh(Complex< T > z)
Definition cmplx.h:1683
bool operator==(const A a, const Complex< B > &b)
Compare equality of Scalar and Complex.
Definition cmplx.h:1245
T abs() const
Compute absolute value of Complex number.
Definition cmplx.h:292
auto operator/(const Complex< T > &c, const A &a)
Division operator Complex / Scalar.
Definition cmplx.h:1143
Complex< T > polar(const T r, const T theta)
Stores and returns Complex number given in polar coordinates.
Definition cmplx.h:346
T real() const
Real part of Complex number.
Definition cmplx.h:167
Complex< Tr > operator*(const Complex< T1 > &a, const Complex< T2 > &b)
Multiplication operator Complex * Complex.
Definition cmplx.h:1054
Complex< T > & operator++()
Single increment operator.
Definition cmplx.h:619
T arg() const
Compute argument of Complex number.
Definition cmplx.h:303
Complex< T > pow(Complex< T > z, S p)
pow(z.p) with scalar power
Definition cmplx.h:1600
Complex< Tr > operator/(const Complex< T1 > &a, const Complex< T2 > &b)
Division operator Complex / Complex.
Definition cmplx.h:1122
Complex< Tr > operator+(const Complex< T1 > &a, const Complex< T2 > &b)
Addition operator Complex + Complex.
Definition cmplx.h:936
bool operator!=(const Complex< A > &a, const Complex< B > &b)
Compare non-equality of two complex numbers.
Definition cmplx.h:1261
Complex< T > operator++(int)
Multiple increment operator.
Definition cmplx.h:653
Complex< T > & operator+=(const Complex< A > &lhs)
Complex addition assignment operator.
Definition cmplx.h:426
T & imag()
Imaginary part of Complex number.
Definition cmplx.h:194
Complex< T > tanh(Complex< T > z)
Definition cmplx.h:1647
Complex< T > sin(Complex< T > z)
Definition cmplx.h:1614
Complex< T > atan(Complex< T > z)
Definition cmplx.h:1653
Complex< T > tan(Complex< T > z)
- rely on optimizer to simplify
Definition cmplx.h:1627
Complex< T > operator--(int)
Multiple decrement operator.
Definition cmplx.h:672
T squarenorm() const
Compute square norm of Complex number.
Definition cmplx.h:281
Complex< T > log(Complex< T > z)
Definition cmplx.h:1570
Complex< T > & operator*=(const Complex< A > &lhs)
Complex multiply assignment operator.
Definition cmplx.h:521
Complex< T > & gaussian_random(double width=1.0)
Produces complex gaussian random values.
Definition cmplx.h:371
Complex< T > & operator/=(const A &a)
Real divide assignment operator.
Definition cmplx.h:598
Complex< T > & operator--()
Single decrement operator.
Definition cmplx.h:636
T & real()
Real part of Complex number.
Definition cmplx.h:185
Complex< T > operator+() const
Unary + operator.
Definition cmplx.h:389
Complex< T > & operator=(S s)
Assignment from real.
Definition cmplx.h:268
Complex< T > & operator-=(const A &a)
Real subtraction assignment operator Subtract assign only to real part of Complex number.
Definition cmplx.h:487
T imag() const
Imaginary part of Complex number.
Definition cmplx.h:175
Complex< T > mul_add(const Complex< T > &a, const Complex< T > &b, const Complex< T > &c)
Multiply add with Complex numbers.
Definition cmplx.h:1184
Complex< T > & random()
Assign random values to Complex real and imaginary part.
Definition cmplx.h:358
Complex< T > pow(S z, Complex< T > p)
pow(z.p) with scalar base
Definition cmplx.h:1606
Complex< T > operator-() const
Unary - operator.
Definition cmplx.h:404
Complex< T > mul_conj(const Complex< A > &b) const
Multiply conjugate method.
Definition cmplx.h:714
Complex< T > expi(T a)
Definition cmplx.h:1558
auto operator+(const Complex< T > &c, const A &a)
Addition operator Complex + Scalar.
Definition cmplx.h:955
bool operator==(const Complex< A > &a, const B b)
Compare equality of Complex and scalar.
Definition cmplx.h:1226
Complex< T > & operator=(const Complex< A > &s)
Assignment from complex.
Definition cmplx.h:246
Complex< T > & operator=(const Complex< T > &s)=default
Assignment operator.
Complex< T > conj_mul(const Complex< A > &b) const
Conjugate multiply method.
Definition cmplx.h:698
Complex< T > cos(Complex< T > z)
Definition cmplx.h:1621
Complex< T > sinh(Complex< T > z)
Definition cmplx.h:1634
auto pow(Complex< A > z, Complex< B > p)
pow(z.p) = =
Definition cmplx.h:1594
Complex< T > atanh(Complex< T > z)
Definition cmplx.h:1671
Complex< T > acos(Complex< T > z)
Definition cmplx.h:1665
bool operator!=(const Complex< A > &a, const B b)
Compare non-equality of Complex number and Scalar.
Definition cmplx.h:1277
auto operator-(const A &a, const Complex< T > &c)
Subtraction operator Scalar - Complex.
Definition cmplx.h:1032
auto operator/(const A &a, const Complex< T > &c)
Division operator Scalar / Complex.
Definition cmplx.h:1164
Complex< T > sqrt(Complex< T > z)
Definition cmplx.h:1578
Complex< T > asinh(Complex< T > z)
Definition cmplx.h:1677
Complex< T > exp(const Complex< T > z)
Definition cmplx.h:1552
Complex< T > & operator+=(const A &a)
Real addition assignment operator.
Definition cmplx.h:447
Imaginary type, used to represent purely imaginary numbers.
Definition cmplx.h:1442
T imag(const Complex< T > &a)
Retrun imaginary value of Complex number.
Definition cmplx.h:890
Complex< T > conj(const Complex< T > &val)
Return conjugate of Complex number.
Definition cmplx.h:1346
auto squarenorm(const Complex< T > &val)
Return Squarenorm of Complex number.
Definition cmplx.h:1370
Complex< T > dagger(const Complex< T > &val)
Return dagger of Complex number.
Definition cmplx.h:1358
Complex< T > polar(T r, T arg)
Return complex number given by polar representation.
Definition cmplx.h:903
T real(const Complex< T > &a)
Return real value of Complex number.
Definition cmplx.h:878
constexpr Imaginary_t< double > I(1.0)
Imaginary unit I - global variable.
T abs(const Complex< T > &a)
Return absolute value of Complex number.
Definition cmplx.h:1322
std::ostream & operator<<(std::ostream &strm, const Complex< T > &A)
Print a complex value as (re,im)
Definition cmplx.h:1388
T arg(const Complex< T > &a)
Return argument of Complex number.
Definition cmplx.h:1334
This file defines all includes for HILA.
Invert diagonal + const. matrix using Sherman-Morrison formula.
Definition array.h:920
double random()
Real valued uniform random number generator.
Definition hila_gpu.cpp:120
double gaussrand2(double &out2)
hila::gaussrand2 returns 2 Gaussian distributed random numbers with variance .
Definition random.cpp:177
decltype(std::declval< A >()+std::declval< B >()) type_plus
Definition type_tools.h:103
std::string to_string(const Array< n, m, T > &A, int prec=8, char separator=' ')
Converts Array object to string.
Definition array.h:934
std:swap() for Fields
Definition field.h:1847
hila::is_complex_or_arithmetic<T>::value
Definition cmplx.h:750