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