Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

ComplexDouble.h
Go to the documentation of this file.
1 
32 #pragma once
33 
34 
35 #include <ogdf/basic/internal/intrinsics.h> // IWYU pragma: keep
36 
37 namespace ogdf {
38 
39 namespace sse {
40 
42 #ifdef OGDF_FME_KERNEL_USE_SSE
43 class ComplexDouble {
44 public:
45  __m128d reg;
46 
47  inline ComplexDouble() { reg = _mm_setzero_pd(); }
48 
49  inline ComplexDouble(const ComplexDouble& other) { reg = other.reg; }
50 
51  inline ComplexDouble(double x) { reg = _mm_setr_pd((x), (0)); }
52 
53  inline ComplexDouble(double x, double y) { reg = _mm_setr_pd((x), (y)); }
54 
55  inline ComplexDouble(const double* ptr) { reg = _mm_load_pd(ptr); }
56 
57  inline ComplexDouble(__m128d r) : reg(r) { }
58 
59  inline ComplexDouble(float x, float y) { reg = _mm_cvtps_pd(_mm_setr_ps((x), (y), 0, 0)); }
60 
63 
64  inline ComplexDouble operator+(const ComplexDouble& other) const {
65  return ComplexDouble(_mm_add_pd(reg, other.reg));
66  }
67 
68  inline ComplexDouble operator-(const ComplexDouble& other) const {
69  return ComplexDouble(_mm_sub_pd(reg, other.reg));
70  }
71 
72  inline ComplexDouble operator-(void) const {
73  return ComplexDouble(_mm_sub_pd(_mm_setzero_pd(), reg));
74  }
75 
76  inline ComplexDouble operator*(const ComplexDouble& other) const {
77  // ---------------------------------
78  // | a0*b0 - a1*b1 | a0*b1 + a1*b0 |
79  // ---------------------------------
80  // bt = | b1 | b0 |
81  __m128d b_t = _mm_shuffle_pd(other.reg, other.reg, _MM_SHUFFLE2(0, 1));
82  // left = | a0*b0 | a1*b1 |
83  __m128d left = _mm_mul_pd(reg, other.reg);
84  // right = | a0*b1 | a1*b0 |
85  __m128d right = _mm_mul_pd(reg, b_t);
86  // left = | a0*b0 | -a1*b1 |
87  left = _mm_mul_pd(left, _mm_setr_pd(1.0, -1.0));
88  // left = | a0*b0 + (-a1*b1) | a0*b1 + a1*b0 |
89  return ComplexDouble(_mm_hadd_pd(left, right));
90  }
91 
92  inline ComplexDouble operator/(const ComplexDouble& other) const {
93  // 1/(length(other)^2 * this * other.conj;
94  // bt = | b0 | -b1 |
95  __m128d conj_reg = _mm_mul_pd(other.reg, _mm_setr_pd(1.0, -1.0));
96  // bt = | b1 | b0 |
97  __m128d b_t = _mm_shuffle_pd(conj_reg, conj_reg, _MM_SHUFFLE2(0, 1));
98  // left = | a0*b0 | a1*b1 |
99  __m128d left = _mm_mul_pd(reg, conj_reg);
100  // right = | a0*b1 | a1*b0 |
101  __m128d right = _mm_mul_pd(reg, b_t);
102  // left = | a0*b0 | -a1*b1 |
103  left = _mm_mul_pd(left, _mm_setr_pd(1.0, -1.0));
104  // left = | a0*b0 + (-a1*b1) | a0*b1 + a1*b0 |
105  __m128d product = _mm_hadd_pd(left, right);
106  // product = reg*other.reg.conj
107  // ell = b0*b0 | b1*b1
108  __m128d ell = _mm_mul_pd(conj_reg, conj_reg);
109  // ell = b0*b0 + b1*b1 | b0*b0 + b1*b1
110  ell = _mm_hadd_pd(ell, ell);
111  // ell = length^2 | length^2
112  return ComplexDouble(_mm_div_pd(product, ell));
113  }
114 
115  inline ComplexDouble operator*(double scalar) const {
116  return ComplexDouble(_mm_mul_pd(reg, _mm_setr_pd(scalar, scalar)));
117  }
118 
119  inline ComplexDouble operator/(double scalar) const {
120  //double rcp = 1.0/scalar;
121  return ComplexDouble(_mm_div_pd(reg, _mm_setr_pd(scalar, scalar)));
122  }
123 
124  inline ComplexDouble operator*(unsigned int scalar) const {
125  return ComplexDouble(_mm_mul_pd(reg, _mm_setr_pd((double)scalar, (double)scalar)));
126  }
127 
128  inline void operator+=(const ComplexDouble& other) { reg = _mm_add_pd(reg, other.reg); }
129 
130  inline void operator-=(const ComplexDouble& other) { reg = _mm_sub_pd(reg, other.reg); }
131 
132  inline void operator*=(const ComplexDouble& other) {
133  // bt = | b1 | b0 |
134  __m128d b_t = _mm_shuffle_pd(other.reg, other.reg, _MM_SHUFFLE2(0, 1));
135  // left = | a0*b0 | a1*b1 |
136  __m128d left = _mm_mul_pd(reg, other.reg);
137  // right = | a0*b1 | a1*b0 |
138  __m128d right = _mm_mul_pd(reg, b_t);
139  // left = | a0*b0 | -a1*b1 |
140  left = _mm_mul_pd(left, _mm_setr_pd(1.0, -1.0));
141  // left = | a0*b0 + (-a1*b1) | a0*b1 + a1*b0 |
142  reg = _mm_hadd_pd(left, right);
143  }
144 
145  inline void operator*=(double scalar) {
146  // (real*scalar, imag*scalar)
147  reg = _mm_mul_pd(reg, _mm_setr_pd(scalar, scalar));
148  }
149 
150  inline void operator/=(const ComplexDouble& other) {
151  // 1/(length(other)^2 * this * other.conj;
152  // bt = | b0 | -b1 |
153  __m128d conj_reg = _mm_mul_pd(other.reg, _mm_setr_pd(1.0, -1.0));
154  // bt = | b1 | b0 |
155  __m128d b_t = _mm_shuffle_pd(conj_reg, conj_reg, _MM_SHUFFLE2(0, 1));
156  // left = | a0*b0 | a1*b1 |
157  __m128d left = _mm_mul_pd(reg, conj_reg);
158  // right = | a0*b1 | a1*b0 |
159  __m128d right = _mm_mul_pd(reg, b_t);
160  // left = | a0*b0 | -a1*b1 |
161  left = _mm_mul_pd(left, _mm_setr_pd(1.0, -1.0));
162  // left = | a0*b0 + (-a1*b1) | a0*b1 + a1*b0 |
163  __m128d product = _mm_hadd_pd(left, right);
164  // ell = b0*b0 | b1*b1
165  __m128d ell = _mm_mul_pd(conj_reg, conj_reg);
166  // ell = b0*b0 + b1*b1 | b0*b0 + b1*b1
167  ell = _mm_hadd_pd(ell, ell);
168  // ell = length^2 | length^2
169  reg = _mm_div_pd(product, ell);
170  }
171 
175 
176  inline double length() const {
177  // sqrt(real*real + imag*imag)
178  double res;
179  __m128d r = _mm_mul_pd(reg, reg);
180  r = _mm_hadd_pd(r, _mm_setzero_pd());
181  r = _mm_sqrt_sd(r, r);
182  _mm_store_sd(&res, r);
183  return res;
184  }
185 
186  inline ComplexDouble conj() const {
187  // (real, -imag)
188  return ComplexDouble(_mm_mul_pd(reg, _mm_setr_pd(1.0, -1.0)));
189  }
190 
194 
195  inline void operator=(const ComplexDouble& other) { reg = other.reg; }
196 
198  inline void operator=(double* ptr) { reg = _mm_load_pd(ptr); }
199 
203 
205  inline void load(const double* ptr) { reg = _mm_load_pd(ptr); }
206 
208  inline void load_unaligned(const double* ptr) { reg = _mm_loadu_pd(ptr); }
209 
211  inline void store(double* ptr) const { _mm_store_pd(ptr, reg); }
212 
214  inline void store_unaligned(double* ptr) const { _mm_storeu_pd(ptr, reg); }
215 
217 };
218 
219 #else
221 public:
222  double reg[2];
223 
224  inline ComplexDouble() {
225  reg[0] = 0.0;
226  reg[1] = 0.0;
227  }
228 
229  inline ComplexDouble(const ComplexDouble& other) {
230  reg[0] = other.reg[0];
231  reg[1] = other.reg[1];
232  }
233 
234  inline ComplexDouble(double x) {
235  reg[0] = x;
236  reg[1] = 0;
237  }
238 
239  inline ComplexDouble(double x, double y) {
240  reg[0] = x;
241  reg[1] = y;
242  }
243 
244  inline ComplexDouble(double* ptr) {
245  reg[0] = ptr[0];
246  reg[1] = ptr[1];
247  }
248 
251  inline ComplexDouble operator+(const ComplexDouble& other) const {
252  return ComplexDouble(reg[0] + other.reg[0], reg[1] + other.reg[1]);
253  }
254 
255  inline ComplexDouble operator-(const ComplexDouble& other) const {
256  return ComplexDouble(reg[0] - other.reg[0], reg[1] - other.reg[1]);
257  }
258 
259  inline ComplexDouble operator-(void) const { return ComplexDouble(-reg[0], -reg[1]); }
260 
261  inline ComplexDouble operator*(const ComplexDouble& other) const {
262  return ComplexDouble(reg[0] * other.reg[0] - reg[1] * other.reg[1],
263  reg[0] * other.reg[1] + reg[1] * other.reg[0]);
264  }
265 
266  inline ComplexDouble operator/(const ComplexDouble& other) const {
267  return (*this) * other.conj() / (other.reg[0] * other.reg[0] + other.reg[1] * other.reg[1]);
268  }
269 
270  inline ComplexDouble operator*(double scalar) const {
271  return ComplexDouble(reg[0] * scalar, reg[1] * scalar);
272  }
273 
274  inline ComplexDouble operator/(double scalar) const {
275  return ComplexDouble(reg[0] / scalar, reg[1] / scalar);
276  }
277 
278  inline ComplexDouble operator*(unsigned int scalar) const {
279  return ComplexDouble(reg[0] * (double)scalar, reg[1] * (double)scalar);
280  }
281 
282  inline void operator+=(const ComplexDouble& other) {
283  reg[0] += other.reg[0];
284  reg[1] += other.reg[1];
285  }
286 
287  inline void operator-=(const ComplexDouble& other) {
288  reg[0] -= other.reg[0];
289  reg[1] -= other.reg[1];
290  }
291 
292  inline void operator*=(const ComplexDouble& other) {
293  double t[2];
294  t[0] = reg[0] * other.reg[0] - reg[1] * other.reg[1];
295  t[1] = reg[0] * other.reg[1] + reg[1] * other.reg[0];
296  reg[0] = t[0];
297  reg[1] = t[1];
298  }
299 
300  inline void operator*=(double scalar) {
301  reg[0] *= scalar;
302  reg[1] *= scalar;
303  }
304 
305  inline void operator/=(const ComplexDouble& other) {
306  ComplexDouble t = other.conj() / (other.reg[0] * other.reg[0] + other.reg[1] * other.reg[1]);
307  double r[2];
308  r[0] = reg[0] * t.reg[0] - reg[1] * t.reg[1];
309  r[1] = reg[0] * t.reg[1] + reg[1] * t.reg[0];
310  reg[0] = r[0];
311  reg[1] = r[1];
312  }
313 
317 
318  inline double length() const {
319  // sqrt(real*real + imag*imag)
320  return sqrt(reg[0] * reg[0] + reg[1] * reg[1]);
321  }
322 
323  inline ComplexDouble conj() const {
324  // (real, -imag)
325  return ComplexDouble(reg[0], -reg[1]);
326  }
327 
331 
332  inline ComplexDouble& operator=(const ComplexDouble& other) {
333  reg[0] = other.reg[0];
334  reg[1] = other.reg[1];
335  return *this;
336  }
337 
339  inline ComplexDouble& operator=(double* ptr) {
340  reg[0] = ptr[0];
341  reg[1] = ptr[1];
342  return *this;
343  }
344 
348 
350  inline void load(const double* ptr) {
351  reg[0] = ptr[0];
352  reg[1] = ptr[1];
353  }
354 
356  inline void load_unaligned(const double* ptr) {
357  reg[0] = ptr[0];
358  reg[1] = ptr[1];
359  }
360 
362  inline void store(double* ptr) const {
363  ptr[0] = reg[0];
364  ptr[1] = reg[1];
365  }
366 
368  inline void store_unaligned(double* ptr) const {
369  ptr[0] = reg[0];
370  ptr[1] = reg[1];
371  }
372 
374 };
375 
376 #endif
377 }
378 
379 }
ogdf
The namespace for all OGDF objects.
Definition: multilevelmixer.cpp:39
ogdf::sse::ComplexDouble::reg
double reg[2]
Definition: ComplexDouble.h:222
ogdf::sse::ComplexDouble::ComplexDouble
ComplexDouble(double *ptr)
Definition: ComplexDouble.h:244
ogdf::sse::ComplexDouble::operator/
ComplexDouble operator/(double scalar) const
Definition: ComplexDouble.h:274
ogdf::sse::ComplexDouble::operator-=
void operator-=(const ComplexDouble &other)
Definition: ComplexDouble.h:287
ogdf::sse::ComplexDouble::operator-
ComplexDouble operator-(void) const
Definition: ComplexDouble.h:259
ogdf::sse::ComplexDouble::operator=
ComplexDouble & operator=(double *ptr)
load from 16byte aligned ptr
Definition: ComplexDouble.h:339
ogdf::sse::ComplexDouble::length
double length() const
Definition: ComplexDouble.h:318
ogdf::sse::ComplexDouble::conj
ComplexDouble conj() const
Definition: ComplexDouble.h:323
ogdf::sse::ComplexDouble::operator/
ComplexDouble operator/(const ComplexDouble &other) const
Definition: ComplexDouble.h:266
ogdf::sse::ComplexDouble::operator+=
void operator+=(const ComplexDouble &other)
Definition: ComplexDouble.h:282
ogdf::sse::ComplexDouble::operator*
ComplexDouble operator*(unsigned int scalar) const
Definition: ComplexDouble.h:278
ogdf::sse::ComplexDouble::operator*=
void operator*=(const ComplexDouble &other)
Definition: ComplexDouble.h:292
ogdf::sse::ComplexDouble::operator*
ComplexDouble operator*(const ComplexDouble &other) const
Definition: ComplexDouble.h:261
ogdf::sse::ComplexDouble::ComplexDouble
ComplexDouble()
Definition: ComplexDouble.h:224
ogdf::sse::ComplexDouble::operator+
ComplexDouble operator+(const ComplexDouble &other) const
Definition: ComplexDouble.h:251
r
int r[]
Definition: hierarchical-ranking.cpp:13
ogdf::sse::ComplexDouble::store_unaligned
void store_unaligned(double *ptr) const
store to unaligned ptr
Definition: ComplexDouble.h:368
ogdf::sse::ComplexDouble::ComplexDouble
ComplexDouble(const ComplexDouble &other)
Definition: ComplexDouble.h:229
ogdf::sse::ComplexDouble
Class to generate instrinsics for complex number arithmetic functions.
Definition: ComplexDouble.h:220
ogdf::sse::ComplexDouble::ComplexDouble
ComplexDouble(double x)
Definition: ComplexDouble.h:234
ogdf::sse::ComplexDouble::operator/=
void operator/=(const ComplexDouble &other)
Definition: ComplexDouble.h:305
ogdf::sse::ComplexDouble::operator*
ComplexDouble operator*(double scalar) const
Definition: ComplexDouble.h:270
ogdf::sse::ComplexDouble::operator-
ComplexDouble operator-(const ComplexDouble &other) const
Definition: ComplexDouble.h:255
ogdf::sse::ComplexDouble::load_unaligned
void load_unaligned(const double *ptr)
load from unaligned ptr
Definition: ComplexDouble.h:356
ogdf::sse::ComplexDouble::ComplexDouble
ComplexDouble(double x, double y)
Definition: ComplexDouble.h:239
ogdf::sse::ComplexDouble::operator=
ComplexDouble & operator=(const ComplexDouble &other)
Definition: ComplexDouble.h:332
intrinsics.h
Include of header files for SSE-intrinsics.
ogdf::sse::ComplexDouble::store
void store(double *ptr) const
store to 16byte aligned ptr
Definition: ComplexDouble.h:362
ogdf::sse::ComplexDouble::load
void load(const double *ptr)
load from 16byte aligned ptr
Definition: ComplexDouble.h:350
ogdf::sse::ComplexDouble::operator*=
void operator*=(double scalar)
Definition: ComplexDouble.h:300