Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

Loading...
Searching...
No Matches
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
38namespace ogdf {
39
40namespace sse {
41
43#ifdef OGDF_FME_KERNEL_USE_SSE
44class ComplexDouble {
45public:
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
222public:
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}
Definition of utility functions for FME layout.
Class to generate instrinsics for complex number arithmetic functions.
void store_unaligned(double *ptr) const
store to unaligned ptr
void operator*=(double scalar)
ComplexDouble operator/(const ComplexDouble &other) const
void load(const double *ptr)
load from 16byte aligned ptr
ComplexDouble(const ComplexDouble &other)
ComplexDouble operator*(unsigned int scalar) const
ComplexDouble operator+(const ComplexDouble &other) const
void operator/=(const ComplexDouble &other)
void operator+=(const ComplexDouble &other)
ComplexDouble conj() const
ComplexDouble & operator=(double *ptr)
load from 16byte aligned ptr
ComplexDouble operator*(double scalar) const
ComplexDouble & operator=(const ComplexDouble &other)
void load_unaligned(const double *ptr)
load from unaligned ptr
ComplexDouble(double x, double y)
ComplexDouble operator-(const ComplexDouble &other) const
ComplexDouble operator/(double scalar) const
void operator*=(const ComplexDouble &other)
void store(double *ptr) const
store to 16byte aligned ptr
void operator-=(const ComplexDouble &other)
ComplexDouble operator-(void) const
ComplexDouble operator*(const ComplexDouble &other) const
Include of header files for SSE-intrinsics.
The namespace for all OGDF objects.