Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

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