1use core::marker::PhantomData;
8
9use crate::math::vector::traits::{Vector, VectorMask};
10use crate::Transcendental;
11
12#[derive(Copy, Clone, Debug, PartialEq)]
14pub struct ComplexVector<T: Transcendental, V: Vector<T, 4>> {
15 data: V,
16 _phantom: PhantomData<T>,
17}
18
19impl<T: Transcendental, V: Vector<T, 4>> ComplexVector<T, V> {
20 pub fn from_raw(data: V) -> Self {
22 Self {
23 data,
24 _phantom: PhantomData,
25 }
26 }
27
28 pub fn splat_pair(re: T, im: T) -> Self {
30 Self {
31 data: V::load(&[re, im, re, im]),
32 _phantom: PhantomData,
33 }
34 }
35
36 pub fn from_pair(c: (T, T)) -> Self {
38 Self::splat_pair(c.0, c.1)
39 }
40
41 pub fn from_two(c0: (T, T), c1: (T, T)) -> Self {
44 Self {
45 data: V::load(&[c0.0, c0.1, c1.0, c1.1]),
46 _phantom: PhantomData,
47 }
48 }
49
50 pub fn inner(&self) -> &V {
52 &self.data
53 }
54
55 pub fn extract(&self, i: usize) -> T {
57 self.data.extract(i)
58 }
59 pub fn re0(&self) -> T {
61 self.data.extract(0)
62 }
63 pub fn im0(&self) -> T {
65 self.data.extract(1)
66 }
67
68 pub fn conj(&self) -> Self {
70 let v = V::load(&[
71 self.data.extract(0),
72 -self.data.extract(1),
73 self.data.extract(2),
74 -self.data.extract(3),
75 ]);
76 Self {
77 data: v,
78 _phantom: PhantomData,
79 }
80 }
81
82 pub fn cmul(&self, other: &Self) -> Self {
84 let a_re = V::load(&[
85 self.data.extract(0),
86 self.data.extract(0),
87 self.data.extract(2),
88 self.data.extract(2),
89 ]);
90 let a_im = V::load(&[
91 self.data.extract(1),
92 self.data.extract(1),
93 self.data.extract(3),
94 self.data.extract(3),
95 ]);
96 let b_re = V::load(&[
97 other.data.extract(0),
98 other.data.extract(0),
99 other.data.extract(2),
100 other.data.extract(2),
101 ]);
102 let b_im = V::load(&[
103 other.data.extract(1),
104 other.data.extract(1),
105 other.data.extract(3),
106 other.data.extract(3),
107 ]);
108 let out_re = a_re * b_re - a_im * b_im;
109 let out_im = a_re * b_im + a_im * b_re;
110 Self {
111 data: V::load(&[
112 out_re.extract(0),
113 out_im.extract(0),
114 out_re.extract(2),
115 out_im.extract(2),
116 ]),
117 _phantom: PhantomData,
118 }
119 }
120
121 pub fn cadd(&self, other: &Self) -> Self {
123 Self {
124 data: self.data + other.data,
125 _phantom: PhantomData,
126 }
127 }
128
129 pub fn csub(&self, other: &Self) -> Self {
131 Self {
132 data: self.data - other.data,
133 _phantom: PhantomData,
134 }
135 }
136
137 pub fn norm_sqr(&self) -> (T, T) {
139 let r0 = self.data.extract(0);
140 let i0 = self.data.extract(1);
141 let r1 = self.data.extract(2);
142 let i1 = self.data.extract(3);
143 (r0 * r0 + i0 * i0, r1 * r1 + i1 * i1)
144 }
145
146 pub fn scale_real(&self, scalar: T) -> Self {
148 Self {
149 data: self.data * V::splat(scalar),
150 _phantom: PhantomData,
151 }
152 }
153
154 pub fn to_complex0(&self) -> (T, T) {
156 (self.data.extract(0), self.data.extract(1))
157 }
158
159 pub fn to_complex1(&self) -> (T, T) {
161 (self.data.extract(2), self.data.extract(3))
162 }
163
164 pub fn map_complex<F>(&self, f: F) -> Self
166 where
167 F: Fn((T, T)) -> (T, T),
168 {
169 let c0 = f(self.to_complex0());
170 let c1 = f(self.to_complex1());
171 Self::from_two(c0, c1)
172 }
173
174 pub fn iter_complex(&self) -> impl Iterator<Item = (T, T)> {
176 [self.to_complex0(), self.to_complex1()].into_iter()
177 }
178}
179
180impl<T: Transcendental, V: Vector<T, 4>> core::ops::Add for ComplexVector<T, V> {
185 type Output = Self;
186 fn add(self, rhs: Self) -> Self {
187 self.cadd(&rhs)
188 }
189}
190
191impl<T: Transcendental, V: Vector<T, 4>> core::ops::Sub for ComplexVector<T, V> {
192 type Output = Self;
193 fn sub(self, rhs: Self) -> Self {
194 self.csub(&rhs)
195 }
196}
197
198impl<T: Transcendental, V: Vector<T, 4>> core::ops::Mul for ComplexVector<T, V> {
199 type Output = Self;
200 fn mul(self, rhs: Self) -> Self {
201 self.cmul(&rhs)
202 }
203}
204
205impl<T: Transcendental, V: Vector<T, 4>> core::ops::Neg for ComplexVector<T, V> {
206 type Output = Self;
207 fn neg(self) -> Self {
208 Self {
209 data: -self.data,
210 _phantom: PhantomData,
211 }
212 }
213}
214
215impl<T: Transcendental, V: Vector<T, 4>> core::ops::Mul<T> for ComplexVector<T, V> {
217 type Output = Self;
218 fn mul(self, rhs: T) -> Self {
219 self.scale_real(rhs)
220 }
221}
222
223impl<T: Transcendental, V: Vector<T, 4>> core::ops::AddAssign for ComplexVector<T, V> {
224 fn add_assign(&mut self, rhs: Self) {
225 *self = *self + rhs;
226 }
227}
228
229impl<T: Transcendental, V: Vector<T, 4>> core::ops::SubAssign for ComplexVector<T, V> {
230 fn sub_assign(&mut self, rhs: Self) {
231 *self = *self - rhs;
232 }
233}
234
235impl<T: Transcendental, V: Vector<T, 4>> core::ops::MulAssign for ComplexVector<T, V> {
236 fn mul_assign(&mut self, rhs: Self) {
237 *self = *self * rhs;
238 }
239}
240
241impl<T: Transcendental, V: Vector<T, 4>> core::ops::DivAssign for ComplexVector<T, V> {
242 fn div_assign(&mut self, rhs: Self) {
243 *self = *self / rhs;
244 }
245}
246
247impl<T: Transcendental, V: Vector<T, 4>> core::ops::Div for ComplexVector<T, V> {
249 type Output = Self;
250 fn div(self, rhs: Self) -> Self {
251 let a_re = self.data.extract(0);
252 let a_im = self.data.extract(1);
253 let a2_re = self.data.extract(2);
254 let a2_im = self.data.extract(3);
255 let b_re = rhs.data.extract(0);
256 let b_im = rhs.data.extract(1);
257 let b2_re = rhs.data.extract(2);
258 let b2_im = rhs.data.extract(3);
259 let denom0 = b_re * b_re + b_im * b_im;
260 let denom1 = b2_re * b2_re + b2_im * b2_im;
261 Self {
262 data: V::load(&[
263 (a_re * b_re + a_im * b_im) / denom0,
264 (a_im * b_re - a_re * b_im) / denom0,
265 (a2_re * b2_re + a2_im * b2_im) / denom1,
266 (a2_im * b2_re - a2_re * b2_im) / denom1,
267 ]),
268 _phantom: PhantomData,
269 }
270 }
271}
272
273#[derive(Copy, Clone, Debug, PartialEq)]
275pub struct ComplexSoa<T: Transcendental, V: Vector<T, 4>> {
276 pub re: V,
278 pub im: V,
280 _phantom: PhantomData<T>,
281}
282
283impl<T: Transcendental, V: Vector<T, 4> + VectorMask<T, 4>> ComplexSoa<T, V> {
284 pub fn load(re_slice: &[T], im_slice: &[T]) -> Self {
286 Self {
287 re: V::load(re_slice),
288 im: V::load(im_slice),
289 _phantom: PhantomData,
290 }
291 }
292
293 pub fn from_pairs(p: [(T, T); 4]) -> Self {
295 Self {
296 re: V::load(&[p[0].0, p[1].0, p[2].0, p[3].0]),
297 im: V::load(&[p[0].1, p[1].1, p[2].1, p[3].1]),
298 _phantom: PhantomData,
299 }
300 }
301
302 pub fn store(&self, re_slice: &mut [T], im_slice: &mut [T]) {
304 self.re.store(re_slice);
305 self.im.store(im_slice);
306 }
307
308 pub fn extract_complex(&self, i: usize) -> (T, T) {
310 (self.re.extract(i), self.im.extract(i))
311 }
312
313 pub fn to_complexes(&self) -> [(T, T); 4] {
315 [
316 (self.re.extract(0), self.im.extract(0)),
317 (self.re.extract(1), self.im.extract(1)),
318 (self.re.extract(2), self.im.extract(2)),
319 (self.re.extract(3), self.im.extract(3)),
320 ]
321 }
322
323 pub fn map_complex<F>(&self, f: F) -> Self
325 where
326 F: Fn((T, T)) -> (T, T),
327 {
328 let c = self.to_complexes();
329 Self::from_pairs([f(c[0]), f(c[1]), f(c[2]), f(c[3])])
330 }
331
332 pub fn iter_complex(&self) -> impl Iterator<Item = (T, T)> {
334 self.to_complexes().into_iter()
335 }
336
337 pub fn cmul(&self, other: &Self) -> Self {
339 Self {
340 re: self.re * other.re - self.im * other.im,
341 im: self.re * other.im + self.im * other.re,
342 _phantom: PhantomData,
343 }
344 }
345
346 pub fn cmul_add(&mut self, a: &Self, b: &Self) {
348 self.re = self.re + (a.re * b.re - a.im * b.im);
349 self.im = self.im + (a.re * b.im + a.im * b.re);
350 }
351
352 pub fn conj(&self) -> Self {
354 Self {
355 re: self.re,
356 im: -self.im,
357 _phantom: PhantomData,
358 }
359 }
360
361 pub fn norm_sqr(&self) -> V {
363 self.re * self.re + self.im * self.im
364 }
365
366 pub fn all_norm_sqr_lt(&self, threshold_sq: T) -> bool {
368 let t = V::splat(threshold_sq);
369 V::all(&self.norm_sqr().lt(&t))
370 }
371
372 pub fn cadd(&self, other: &Self) -> Self {
374 Self {
375 re: self.re + other.re,
376 im: self.im + other.im,
377 _phantom: PhantomData,
378 }
379 }
380
381 pub fn csub(&self, other: &Self) -> Self {
383 Self {
384 re: self.re - other.re,
385 im: self.im - other.im,
386 _phantom: PhantomData,
387 }
388 }
389
390 pub fn scale_real(&self, scalar: V) -> Self {
392 Self {
393 re: self.re * scalar,
394 im: self.im * scalar,
395 _phantom: PhantomData,
396 }
397 }
398}
399
400impl<T: Transcendental, V: Vector<T, 4> + VectorMask<T, 4>> core::ops::Add for ComplexSoa<T, V> {
405 type Output = Self;
406 fn add(self, rhs: Self) -> Self {
407 self.cadd(&rhs)
408 }
409}
410
411impl<T: Transcendental, V: Vector<T, 4> + VectorMask<T, 4>> core::ops::Sub for ComplexSoa<T, V> {
412 type Output = Self;
413 fn sub(self, rhs: Self) -> Self {
414 self.csub(&rhs)
415 }
416}
417
418impl<T: Transcendental, V: Vector<T, 4> + VectorMask<T, 4>> core::ops::Mul for ComplexSoa<T, V> {
419 type Output = Self;
420 fn mul(self, rhs: Self) -> Self {
421 self.cmul(&rhs)
422 }
423}
424
425impl<T: Transcendental, V: Vector<T, 4> + VectorMask<T, 4>> core::ops::Neg for ComplexSoa<T, V> {
426 type Output = Self;
427 fn neg(self) -> Self {
428 Self {
429 re: -self.re,
430 im: -self.im,
431 _phantom: PhantomData,
432 }
433 }
434}
435
436impl<T: Transcendental, V: Vector<T, 4> + VectorMask<T, 4>> core::ops::Mul<V> for ComplexSoa<T, V> {
438 type Output = Self;
439 fn mul(self, rhs: V) -> Self {
440 self.scale_real(rhs)
441 }
442}
443
444impl<T: Transcendental, V: Vector<T, 4> + VectorMask<T, 4>> core::ops::AddAssign
445 for ComplexSoa<T, V>
446{
447 fn add_assign(&mut self, rhs: Self) {
448 *self = *self + rhs;
449 }
450}
451
452impl<T: Transcendental, V: Vector<T, 4> + VectorMask<T, 4>> core::ops::SubAssign
453 for ComplexSoa<T, V>
454{
455 fn sub_assign(&mut self, rhs: Self) {
456 *self = *self - rhs;
457 }
458}
459
460impl<T: Transcendental, V: Vector<T, 4> + VectorMask<T, 4>> core::ops::MulAssign
461 for ComplexSoa<T, V>
462{
463 fn mul_assign(&mut self, rhs: Self) {
464 *self = *self * rhs;
465 }
466}
467
468impl<T: Transcendental, V: Vector<T, 4> + VectorMask<T, 4>> core::ops::DivAssign
469 for ComplexSoa<T, V>
470{
471 fn div_assign(&mut self, rhs: Self) {
472 *self = *self / rhs;
473 }
474}
475
476impl<T: Transcendental, V: Vector<T, 4> + VectorMask<T, 4>> core::ops::Div for ComplexSoa<T, V> {
481 type Output = Self;
482 fn div(self, rhs: Self) -> Self {
483 let denom = rhs.re * rhs.re + rhs.im * rhs.im;
484 Self {
485 re: (self.re * rhs.re + self.im * rhs.im) / denom,
486 im: (self.im * rhs.re - self.re * rhs.im) / denom,
487 _phantom: PhantomData,
488 }
489 }
490}
491
492#[cfg(test)]
493mod tests {
494 use super::*;
495 use crate::math::vector::scalar::ScalarVector4;
496
497 fn approx_eq(a: f32, b: f32) -> bool {
498 (a - b).abs() < 1e-4
499 }
500
501 #[test]
502 fn test_complex_vector_conj() {
503 type CV = ComplexVector<f32, ScalarVector4<f32>>;
504 let cv = CV::splat_pair(1.0, 2.0);
505 assert!(approx_eq(cv.re0(), 1.0));
506 assert!(approx_eq(cv.im0(), 2.0));
507 let conj = cv.conj();
508 assert!(approx_eq(conj.re0(), 1.0));
509 assert!(approx_eq(conj.im0(), -2.0));
510 }
511
512 #[test]
513 fn test_complex_vector_cmul() {
514 type CV = ComplexVector<f32, ScalarVector4<f32>>;
515 let a = CV::splat_pair(1.0, 2.0);
516 let b = CV::splat_pair(3.0, 4.0);
517 let prod = a.cmul(&b);
518 assert!(approx_eq(prod.re0(), -5.0));
519 assert!(approx_eq(prod.im0(), 10.0));
520 }
521
522 #[test]
523 fn test_complex_soa_cmul() {
524 type CS = ComplexSoa<f32, ScalarVector4<f32>>;
525 let a = CS::load(&[1.0, 0.0, 0.5, -0.5], &[0.0, 1.0, 0.5, 0.5]);
526 let b = CS::load(&[2.0, 0.0, 1.0, 1.0], &[3.0, 1.0, 1.0, -1.0]);
527 let prod = a.cmul(&b);
528 assert!(approx_eq(prod.re.extract(0), 2.0));
529 assert!(approx_eq(prod.im.extract(0), 3.0));
530 assert!(approx_eq(prod.re.extract(1), -1.0));
531 assert!(approx_eq(prod.im.extract(1), 0.0));
532 }
533
534 #[test]
535 fn test_complex_soa_conj_norm() {
536 type CS = ComplexSoa<f32, ScalarVector4<f32>>;
537 let a = CS::load(&[3.0, 1.0, 0.0, 2.0], &[4.0, 1.0, 1.0, 3.0]);
538 let conj = a.conj();
539 assert!(approx_eq(conj.im.extract(0), -4.0));
540 let mag2 = a.norm_sqr();
541 assert!(approx_eq(mag2.extract(0), 25.0));
542 assert!(approx_eq(mag2.extract(1), 2.0));
543 assert!(approx_eq(mag2.extract(2), 1.0));
544 assert!(approx_eq(mag2.extract(3), 13.0));
545 }
546
547 #[test]
548 fn test_complex_soa_cmul_add() {
549 type CS = ComplexSoa<f32, ScalarVector4<f32>>;
550 let a = CS::load(&[1.0, 2.0, 0.0, 4.0], &[0.0, 0.0, 1.0, 0.0]);
551 let b = CS::load(&[2.0, 3.0, 0.0, 0.0], &[3.0, 0.0, 1.0, 0.0]);
552 let mut acc = CS::load(&[0.0; 4], &[0.0; 4]);
553 acc.cmul_add(&a, &b);
554 assert!(approx_eq(acc.re.extract(0), 2.0));
555 assert!(approx_eq(acc.im.extract(0), 3.0));
556 assert!(approx_eq(acc.re.extract(1), 6.0));
557 assert!(approx_eq(acc.im.extract(1), 0.0));
558 }
559
560 #[test]
561 fn test_from_pair() {
562 type CV = ComplexVector<f32, ScalarVector4<f32>>;
563 let cv = CV::from_pair((1.0, 2.0));
564 assert!(approx_eq(cv.to_complex0().0, 1.0));
565 assert!(approx_eq(cv.to_complex0().1, 2.0));
566 assert!(approx_eq(cv.to_complex1().0, 1.0));
567 assert!(approx_eq(cv.to_complex1().1, 2.0));
568 }
569
570 #[test]
571 fn test_from_pairs() {
572 type CS = ComplexSoa<f32, ScalarVector4<f32>>;
573 let soa = CS::from_pairs([(1.0, 0.0), (0.0, 1.0), (-1.0, 0.0), (0.0, -1.0)]);
574 let c = soa.to_complexes();
575 assert!(approx_eq(c[0].0, 1.0));
576 assert!(approx_eq(c[0].1, 0.0));
577 assert!(approx_eq(c[1].0, 0.0));
578 assert!(approx_eq(c[1].1, 1.0));
579 assert!(approx_eq(c[2].0, -1.0));
580 assert!(approx_eq(c[2].1, 0.0));
581 assert!(approx_eq(c[3].0, 0.0));
582 assert!(approx_eq(c[3].1, -1.0));
583 }
584
585 #[test]
586 fn test_map_complex_soa() {
587 type CS = ComplexSoa<f32, ScalarVector4<f32>>;
588 let soa = CS::from_pairs([(1.0, 0.0), (2.0, 0.0), (3.0, 0.0), (4.0, 0.0)]);
589 let scaled = soa.map_complex(|(re, im)| (re * 2.0, im * 2.0));
591 let c = scaled.to_complexes();
592 assert!(approx_eq(c[0].0, 2.0));
593 assert!(approx_eq(c[1].0, 4.0));
594 assert!(approx_eq(c[2].0, 6.0));
595 assert!(approx_eq(c[3].0, 8.0));
596 }
597
598 #[test]
599 fn test_map_complex_vector() {
600 type CV = ComplexVector<f32, ScalarVector4<f32>>;
601 let cv = CV::from_two((1.0, 2.0), (3.0, 4.0));
602 let neg = cv.map_complex(|(re, im)| (-re, -im));
604 assert!(approx_eq(neg.to_complex0().0, -1.0));
605 assert!(approx_eq(neg.to_complex0().1, -2.0));
606 assert!(approx_eq(neg.to_complex1().0, -3.0));
607 assert!(approx_eq(neg.to_complex1().1, -4.0));
608 }
609
610 #[test]
611 fn test_complex_vector_csub() {
612 type CV = ComplexVector<f32, ScalarVector4<f32>>;
613 let a = CV::from_two((3.0, 5.0), (2.0, 1.0));
614 let b = CV::from_two((1.0, 2.0), (1.0, 0.0));
615 let diff = a.csub(&b);
616 assert!(approx_eq(diff.to_complex0().0, 2.0));
617 assert!(approx_eq(diff.to_complex0().1, 3.0));
618 assert!(approx_eq(diff.to_complex1().0, 1.0));
619 assert!(approx_eq(diff.to_complex1().1, 1.0));
620 }
621
622 #[test]
623 fn test_complex_vector_norm_sqr() {
624 type CV = ComplexVector<f32, ScalarVector4<f32>>;
625 let cv = CV::from_two((3.0, 4.0), (1.0, 1.0));
626 let (n0, n1) = cv.norm_sqr();
627 assert!(approx_eq(n0, 25.0)); assert!(approx_eq(n1, 2.0)); }
630
631 #[test]
632 fn test_operators_complex_vector() {
633 type CV = ComplexVector<f32, ScalarVector4<f32>>;
634 let a = CV::from_two((1.0, 2.0), (3.0, 4.0));
635 let b = CV::from_two((0.5, 1.0), (1.0, 0.0));
636 let sum = a + b;
637 assert!(approx_eq(sum.to_complex0().0, 1.5));
638 assert!(approx_eq(sum.to_complex0().1, 3.0));
639 let diff = a - b;
640 assert!(approx_eq(diff.to_complex0().0, 0.5));
641 assert!(approx_eq(diff.to_complex0().1, 1.0));
642 let neg = -a;
643 assert!(approx_eq(neg.to_complex0().0, -1.0));
644 assert!(approx_eq(neg.to_complex0().1, -2.0));
645 }
646
647 #[test]
648 fn test_operators_complex_soa() {
649 type CS = ComplexSoa<f32, ScalarVector4<f32>>;
650 let a = CS::load(&[1.0, 2.0, 3.0, 4.0], &[0.0; 4]);
651 let b = CS::load(&[5.0, 6.0, 7.0, 8.0], &[0.0; 4]);
652 let sum = a + b;
653 assert!(approx_eq(sum.re.extract(0), 6.0));
654 let neg = -a;
655 assert!(approx_eq(neg.re.extract(0), -1.0));
656 }
657}