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
35
36namespace ogdf {
37
38namespace sse {
39
41#ifdef OGDF_FME_KERNEL_USE_SSE
42class ComplexDouble {
43public:
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 {
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 |
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 |
97 // left = | a0*b0 | a1*b1 |
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
108 // ell = b0*b0 + b1*b1 | b0*b0 + b1*b1
110 // ell = length^2 | length^2
112 }
113
114 inline ComplexDouble operator*(double scalar) const {
116 }
117
118 inline ComplexDouble operator/(double scalar) const {
119 //double rcp = 1.0/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 |
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)
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 |
155 // left = | a0*b0 | a1*b1 |
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
165 // ell = b0*b0 + b1*b1 | b0*b0 + b1*b1
167 // ell = length^2 | length^2
169 }
170
174
175 inline double length() const {
176 // sqrt(real*real + imag*imag)
177 double res;
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
220public:
221 double reg[2];
222
223 inline ComplexDouble() {
224 reg[0] = 0.0;
225 reg[1] = 0.0;
226 }
227
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
251 return ComplexDouble(reg[0] + other.reg[0], reg[1] + other.reg[1]);
252 }
253
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
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
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
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}
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
int r[]
static MultilevelBuilder * getDoubleFactoredZeroAdjustedMerger()
The namespace for all OGDF objects.