Highly Efficient FFT for Exascale: HeFFTe v2.3
heffte_stock_complex.h
1 /*
2  -- heFFTe --
3  Univ. of Tennessee, Knoxville
4  @date
5 */
6 
7 #ifndef HEFFTE_STOCK_COMPLEX_H
8 #define HEFFTE_STOCK_COMPLEX_H
9 
10 #include <type_traits>
11 #include <iostream>
12 
13 #include "heffte_stock_vec_types.h"
14 
19 namespace heffte {
20 namespace stock {
28 template<typename F, int L>
29 class alignas(L*sizeof(F)) Complex {
30  public:
31  // One 64-bit Complex-- 2 doubles-- pack<double, 2>::type == _m128d
32  // Two 64-bit Complex-- 4 doubles-- pack<double, 4>::type == _m256d
33  // Two 64-bit Complex-- 4 floats -- pack<float, 4>::type == _m128
34  // Four 64-bit Complex-- 8 floats -- pack<float, 8>::type == _m256
35 
36  // Constructors for the Complex class
38  explicit Complex(F* const f): var(mm_load<F,L>(f)) {}
40  explicit Complex(std::initializer_list<F> il): var(mm_load<F,L>(il.begin())) {};
42  explicit Complex(typename pack<F,L>::type v): var(v) {}
44  explicit Complex(F x, F y): var(mm_pair_set<F,L>(x, y)) {}
46  explicit Complex(std::complex<F> const *c): var(mm_complex_load<F,L>(c)) {}
48  explicit Complex(std::complex<F> const *c, int stride): var(mm_complex_load<F,L>(c, stride)) {}
50  explicit Complex(std::initializer_list<std::complex<F>> il): var(il.size() == 1 ? mm_pair_set<F,L>((*il.begin()).real(), (*il.begin()).imag()) : mm_complex_load<F,L>(il.begin())) {};
52  explicit Complex(): var(mm_zero<F,L>()) {}
53 
55  /* Basic operations with another pack of complex numbers */
57 
60  return Complex(mm_add(var, o.var));
61  }
62 
65  return Complex(mm_sub(var, o.var));
66  }
67 
70  return Complex(mm_complex_mul(var, o.var));
71  }
72 
75  return Complex(mm_complex_div(var, o.var));
76  }
77 
80  var = mm_add(var, o.var);
81  return *this;
82  }
83 
86  var = mm_sub(var, o.var);
87  return *this;
88  }
89 
92  var = mm_complex_mul(var, o.var);
93  return *this;
94  }
95 
98  var = mm_complex_div(var, o.var);
99  return *this;
100  }
101 
103  /* Basic operations with a single real floating point number */
105 
108  return Complex(mm_add(var, mm_pair_set<F,L>(o, 0)));
109  }
110 
113  return Complex(mm_sub(var, mm_pair_set<F,L>(o, 0)));
114  }
115 
118  return Complex(mm_mul(var, mm_set1<F,L>(o)));
119  }
120 
123  return Complex(mm_div(var, mm_set1<F,L>(o)));
124  }
125 
128  var = mm_add(var, mm_pair_set<F,L>(o, 0));
129  return *this;
130  }
131 
134  var = mm_sub(var, mm_pair_set<F,L>(o, 0));
135  return *this;
136  }
137 
140  var = mm_mul(var, mm_set1<F,L>(o));
141  return *this;
142  }
143 
144  // Divide by and assign a floating point number
145  Complex<F,L> operator/=(F o) {
146  var = mm_div(var, mm_set1<F,L>(o));
147  return *this;
148  }
149 
151  /* Other methods */
153 
155  Complex<F,L> fmadd(Complex<F,L> const & y, Complex<F,L> const & z) {
156  return Complex(mm_complex_fmadd(var, y.var, z.var));
157  }
158 
160  Complex<F,L> fmsub(Complex<F,L> const & y, Complex<F,L> const & z) {
161  return Complex(mm_complex_fmsub(var, y.var, z.var));
162  }
163 
166  return Complex<F,L>(mm_neg(var));
167  }
168 
170  void modulus(F* dest) {
171  typename pack<F, L>::type res = mm_complex_mod(var);
172  for(int i = 0; i < L/2; i++) {
173  dest[i] = res[i*2];
174  }
175  }
176 
179  return mm_complex_mod(var);
180  }
181 
184  return Complex(mm_complex_conj(var));
185  }
186 
189  return Complex(mm_complex_mul_i(var));
190  }
191 
194  return Complex(mm_complex_mul_neg_i(var));
195  }
196 
198  void get(F* dest) {
199  mm_store<F,L>(dest, var);
200  }
201 
203  std::complex<F> operator[](std::size_t idx) {
204  return std::complex<F>(reinterpret_cast<F*>(&var)[2*idx], reinterpret_cast<F*>(&var)[2*idx + 1]);
205  }
206 
208  typename pack<F,L>::type get() const {
209  return var;
210  }
211 
212  private:
214  typename pack<F,L>::type var;
215 };
216 
217 
218 
219 
221 template<typename F, int L>
222 inline std::ostream& operator<<(std::ostream& os, const Complex<F,L>& dt){
223  typename pack<F, L>::type var = dt.get();
224  os << "( ";
225  for(int i = 0; i < L; i+=2) {
226  os << var[i];
227  if(var[i+1] < 0) os << " - " << -var[i+1] << "i";
228  else os << " + " << var[i+1] << "i";
229  if(i+2 < L) os << ", ";
230  }
231  os << " )";
232  return os;
233 }
234 
235 }
236 }
237 
238 #endif // HEFFTE_STOCK_COMPLEX_H
Custom complex type taking advantage of vectorization A Complex Type intrinsic to HeFFTe that takes a...
Definition: heffte_stock_complex.h:29
Complex< F, L > operator/(F o)
Divide by a floating point number.
Definition: heffte_stock_complex.h:122
Complex< F, L > fmadd(Complex< F, L > const &y, Complex< F, L > const &z)
Fused multiply add.
Definition: heffte_stock_complex.h:155
Complex< F, L > operator*(F o)
Multiply by a floating point number.
Definition: heffte_stock_complex.h:117
Complex< F, L > operator+=(Complex< F, L > const &o)
Add with and assign another complex number.
Definition: heffte_stock_complex.h:79
Complex(F x, F y)
Load from real and imaginary parts (repeating for all numbers in pack)
Definition: heffte_stock_complex.h:44
Complex(std::complex< F > const *c)
Load from pointer to existing std::complex numbers.
Definition: heffte_stock_complex.h:46
Complex< F, L > operator-(F o)
Subtract a floating point number.
Definition: heffte_stock_complex.h:112
Complex< F, L > conjugate()
Conjugate the current complex number.
Definition: heffte_stock_complex.h:183
Complex< F, L > operator-=(F o)
Subtract and assign a floating point number.
Definition: heffte_stock_complex.h:133
Complex< F, L > operator*(Complex< F, L > const &o)
Multiply by another pack of complex number.
Definition: heffte_stock_complex.h:69
Complex(F *const f)
Load from an array of primitives.
Definition: heffte_stock_complex.h:38
Complex()
Default constructor of zeros.
Definition: heffte_stock_complex.h:52
Complex< F, L > operator-=(Complex< F, L > const &o)
Subtract and assign another complex number from this.
Definition: heffte_stock_complex.h:85
Complex< F, L > operator*=(Complex< F, L > const &o)
Multiply by and assign another complex number.
Definition: heffte_stock_complex.h:91
void modulus(F *dest)
Store the modulus of the complex number in an array of size L/2.
Definition: heffte_stock_complex.h:170
Complex(std::initializer_list< std::complex< F >> il)
Load from initializer list of existing std::complex numbers.
Definition: heffte_stock_complex.h:50
Complex< F, L > operator*=(F o)
Multiply by and assign a floating point number.
Definition: heffte_stock_complex.h:139
Complex(std::complex< F > const *c, int stride)
Load from strided pointer to existing std::complex numbers.
Definition: heffte_stock_complex.h:48
Complex< F, L > operator+=(F o)
Add with and assign a floating point number.
Definition: heffte_stock_complex.h:127
Complex< F, L > __mul_neg_i()
Multiply the complex number by i.
Definition: heffte_stock_complex.h:193
pack< F, L >::type modulus()
Return the modulus of the complex number in a vector pack.
Definition: heffte_stock_complex.h:178
Complex< F, L > operator/(Complex< F, L > const &o)
Divide by another pack of complex number.
Definition: heffte_stock_complex.h:74
Complex< F, L > operator-(Complex< F, L > const &o)
Subtract another pack of complex number.
Definition: heffte_stock_complex.h:64
pack< F, L >::type get() const
Return a vector pack representation of this number.
Definition: heffte_stock_complex.h:208
Complex(typename pack< F, L >::type v)
Load from an existing vector pack.
Definition: heffte_stock_complex.h:42
void get(F *dest)
Store the Complex number in an array of length L.
Definition: heffte_stock_complex.h:198
Complex< F, L > operator+(F o)
Add with a floating point number.
Definition: heffte_stock_complex.h:107
Complex< F, L > __mul_i()
Multiply the complex number by i.
Definition: heffte_stock_complex.h:188
Complex< F, L > operator-()
Negate the complex number.
Definition: heffte_stock_complex.h:165
Complex< F, L > fmsub(Complex< F, L > const &y, Complex< F, L > const &z)
Fused multiply add.
Definition: heffte_stock_complex.h:160
Complex< F, L > operator+(Complex< F, L > const &o)
Add with another pack of complex number.
Definition: heffte_stock_complex.h:59
Complex(std::initializer_list< F > il)
Load from an initializer list of primitives.
Definition: heffte_stock_complex.h:40
std::complex< F > operator[](std::size_t idx)
Access the ith Complex number as a std::complex.
Definition: heffte_stock_complex.h:203
Complex< F, L > operator/=(Complex< F, L > const &o)
Divide by and assign another complex number.
Definition: heffte_stock_complex.h:97
std::ostream & operator<<(std::ostream &os, box3d< index > const box)
Debugging info, writes out the box to a stream.
Definition: heffte_geometry.h:146
Namespace containing all HeFFTe methods and classes.
Definition: heffte_backend_cuda.h:38
Struct to retrieve the vector type associated with the number of elements stored "per unit".
Definition: heffte_stock_vec_types.h:43