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