faer_core/complex_native/
c64_impl.rs

1use crate::complex_native::c64conj_impl::c64conj;
2use faer_entity::*;
3#[cfg(not(feature = "std"))]
4use num_traits::float::FloatCore;
5use num_traits::{One, Zero};
6use pulp::{cast, Simd};
7
8#[cfg(feature = "std")]
9use num_complex::ComplexFloat;
10
11#[cfg(feature = "std")]
12macro_rules! impl_from_num_complex {
13    ($( $method:ident ( self $( , $arg:ident : $ty:ty )* ) -> $ret:ty ; )*) => {
14        $(
15            #[inline(always)]
16            #[allow(missing_docs)]
17            pub fn $method(self $( , $arg : $ty )* ) -> $ret {
18                self.to_num_complex().$method( $( $arg , )* ).into()
19            }
20        )*
21    };
22}
23
24/// 64-bit complex floating point type. See the module-level documentation for more details.
25#[allow(non_camel_case_types)]
26#[derive(Copy, Clone, PartialEq)]
27#[repr(C)]
28pub struct c64 {
29    /// Real part.
30    pub re: f64,
31    /// Imaginary part.
32    pub im: f64,
33}
34
35impl c64 {
36    /// Create a new complex number.
37    #[inline(always)]
38    pub fn new(re: f64, im: f64) -> Self {
39        Self { re, im }
40    }
41
42    /// Construct the imaginary number.
43    #[inline(always)]
44    pub fn i() -> Self {
45        Self::new(0.0, 1.0)
46    }
47
48    /// Create a complex number from a phase.
49    #[cfg(feature = "std")]
50    #[inline(always)]
51    pub fn cis(phase: f64) -> Self {
52        Self::new(phase.cos(), phase.sin())
53    }
54
55    /// Create a complex number from polar coordinates.
56    #[cfg(feature = "std")]
57    #[inline(always)]
58    pub fn from_polar(r: f64, theta: f64) -> Self {
59        Self::new(r * theta.cos(), r * theta.sin())
60    }
61
62    /// Convert the number to a num_complex::Complex64.
63    #[inline(always)]
64    pub fn to_num_complex(self) -> num_complex::Complex<f64> {
65        self.into()
66    }
67
68    /// Returns the real part of the complex number.
69    #[inline(always)]
70    pub fn re(self) -> f64 {
71        self.re
72    }
73
74    /// Returns the imaginary part of the complex number.
75    #[inline(always)]
76    pub fn im(self) -> f64 {
77        self.im
78    }
79
80    /// Calculate the complex conjugate of self.
81    #[inline(always)]
82    pub fn conj(self) -> Self {
83        self.faer_conj()
84    }
85
86    #[cfg(feature = "std")]
87    impl_from_num_complex!(
88        is_nan(self) -> bool;
89        is_infinite(self) -> bool;
90        is_finite(self) -> bool;
91        is_normal(self) -> bool;
92        recip(self) -> Self;
93        powi(self, exp: i32) -> Self;
94        powu(self, exp: u32) -> Self;
95        powf(self, exp: f64) -> Self;
96        powc(self, exp: num_complex::Complex<f64>) -> Self;
97        sqrt(self) -> Self;
98        exp(self) -> Self;
99        exp2(self) -> Self;
100        expf(self, base: f64) -> Self;
101        ln(self) -> Self;
102        log(self, base: f64) -> Self;
103        log2(self) -> Self;
104        log10(self) -> Self;
105        cbrt(self) -> Self;
106        sin(self) -> Self;
107        cos(self) -> Self;
108        tan(self) -> Self;
109        asin(self) -> Self;
110        acos(self) -> Self;
111        atan(self) -> Self;
112        sinh(self) -> Self;
113        cosh(self) -> Self;
114        tanh(self) -> Self;
115        asinh(self) -> Self;
116        acosh(self) -> Self;
117        atanh(self) -> Self;
118        abs(self) -> f64;
119        arg(self) -> f64;
120    );
121
122    /// Computes the `l2` norm of `self`.
123    #[inline(always)]
124    pub fn norm(&self) -> f64 {
125        self.faer_abs()
126    }
127
128    /// Computes the `l1` norm of `self`.
129    #[inline(always)]
130    pub fn l1_norm(&self) -> f64 {
131        self.re.faer_abs() + self.im.faer_abs()
132    }
133
134    /// Computes the squared `l2` norm of `self`.
135    #[inline(always)]
136    pub fn norm_sqr(&self) -> f64 {
137        self.faer_abs2()
138    }
139
140    /// Computes the inverse of `self`.
141    #[inline(always)]
142    pub fn inv(&self) -> Self {
143        let norm_sqr = self.faer_abs2();
144        Self::new(self.re / norm_sqr, -self.im / norm_sqr)
145    }
146}
147
148impl num_traits::Zero for c64 {
149    #[inline(always)]
150    fn zero() -> Self {
151        Self::new(0.0, 0.0)
152    }
153
154    #[inline(always)]
155    fn is_zero(&self) -> bool {
156        self.re.is_zero() && self.im.is_zero()
157    }
158
159    #[inline(always)]
160    fn set_zero(&mut self) {
161        self.re.set_zero();
162        self.im.set_zero();
163    }
164}
165
166impl One for c64 {
167    #[inline(always)]
168    fn one() -> Self {
169        Self::new(1.0, 0.0)
170    }
171
172    #[inline(always)]
173    fn is_one(&self) -> bool {
174        self.re.is_one() && self.im.is_zero()
175    }
176
177    #[inline(always)]
178    fn set_one(&mut self) {
179        self.re.set_one();
180        self.im.set_zero();
181    }
182}
183
184impl core::ops::Neg for c64 {
185    type Output = c64;
186
187    #[inline(always)]
188    fn neg(self) -> Self::Output {
189        Self::new(-self.re, -self.im)
190    }
191}
192
193impl core::ops::Add<f64> for c64 {
194    type Output = c64;
195
196    #[inline(always)]
197    fn add(self, rhs: f64) -> Self::Output {
198        Self::new(self.re + rhs, self.im)
199    }
200}
201
202impl core::ops::Add<c64> for f64 {
203    type Output = c64;
204
205    #[inline(always)]
206    fn add(self, rhs: c64) -> Self::Output {
207        Self::Output::new(self + rhs.re, rhs.im)
208    }
209}
210
211impl core::ops::Add for c64 {
212    type Output = c64;
213
214    #[inline(always)]
215    fn add(self, rhs: Self) -> Self::Output {
216        Self::new(self.re + rhs.re, self.im + rhs.im)
217    }
218}
219
220impl core::ops::Add<c64conj> for c64 {
221    type Output = c64;
222
223    #[inline(always)]
224    fn add(self, rhs: c64conj) -> Self::Output {
225        Self::Output::new(self.re + rhs.re, self.im - rhs.neg_im)
226    }
227}
228
229impl core::ops::Add<c64> for c64conj {
230    type Output = c64;
231
232    #[inline(always)]
233    fn add(self, rhs: c64) -> Self::Output {
234        Self::Output::new(self.re + rhs.re, rhs.im - self.neg_im)
235    }
236}
237
238impl core::ops::Sub<f64> for c64 {
239    type Output = c64;
240
241    #[inline(always)]
242    fn sub(self, rhs: f64) -> Self::Output {
243        Self::new(self.re - rhs, self.im)
244    }
245}
246
247impl core::ops::Sub<c64> for f64 {
248    type Output = c64;
249
250    #[inline(always)]
251    fn sub(self, rhs: c64) -> Self::Output {
252        Self::Output::new(self - rhs.re, -rhs.im)
253    }
254}
255
256impl core::ops::Sub for c64 {
257    type Output = c64;
258
259    #[inline(always)]
260    fn sub(self, rhs: Self) -> Self::Output {
261        Self::new(self.re - rhs.re, self.im - rhs.im)
262    }
263}
264
265impl core::ops::Sub<c64conj> for c64 {
266    type Output = c64;
267
268    #[inline(always)]
269    fn sub(self, rhs: c64conj) -> Self::Output {
270        Self::Output::new(self.re - rhs.re, self.im + rhs.neg_im)
271    }
272}
273
274impl core::ops::Sub<c64> for c64conj {
275    type Output = c64;
276
277    #[inline(always)]
278    fn sub(self, rhs: c64) -> Self::Output {
279        Self::Output::new(self.re - rhs.re, -self.neg_im - rhs.im)
280    }
281}
282
283impl core::ops::Mul<f64> for c64 {
284    type Output = c64;
285
286    #[inline(always)]
287    fn mul(self, rhs: f64) -> Self::Output {
288        Self::new(self.re * rhs, self.im * rhs)
289    }
290}
291
292impl core::ops::Mul<c64> for f64 {
293    type Output = c64;
294
295    #[inline(always)]
296    fn mul(self, rhs: c64) -> Self::Output {
297        Self::Output::new(self * rhs.re, self * rhs.im)
298    }
299}
300
301impl core::ops::Mul for c64 {
302    type Output = c64;
303
304    #[inline(always)]
305    fn mul(self, rhs: Self) -> Self::Output {
306        Self::new(
307            self.re * rhs.re - self.im * rhs.im,
308            self.re * rhs.im + self.im * rhs.re,
309        )
310    }
311}
312
313impl core::ops::Mul<c64conj> for c64 {
314    type Output = c64;
315
316    #[inline(always)]
317    fn mul(self, rhs: c64conj) -> Self::Output {
318        Self::Output::new(
319            self.re * rhs.re + self.im * rhs.neg_im,
320            self.im * rhs.re - self.re * rhs.neg_im,
321        )
322    }
323}
324
325impl core::ops::Mul<c64> for c64conj {
326    type Output = c64;
327
328    #[inline(always)]
329    fn mul(self, rhs: c64) -> Self::Output {
330        Self::Output::new(
331            self.re * rhs.re + self.neg_im * rhs.im,
332            rhs.im * self.re - rhs.re * self.neg_im,
333        )
334    }
335}
336
337impl core::ops::Div<f64> for c64 {
338    type Output = c64;
339
340    #[inline(always)]
341    fn div(self, rhs: f64) -> Self::Output {
342        Self::new(self.re / rhs, self.im / rhs)
343    }
344}
345
346impl core::ops::Div<c64> for f64 {
347    type Output = c64;
348
349    #[allow(clippy::suspicious_arithmetic_impl)]
350    #[inline(always)]
351    fn div(self, rhs: c64) -> Self::Output {
352        self * rhs.faer_inv()
353    }
354}
355
356impl core::ops::Div for c64 {
357    type Output = c64;
358
359    #[allow(clippy::suspicious_arithmetic_impl)]
360    #[inline(always)]
361    fn div(self, rhs: Self) -> Self::Output {
362        self * rhs.faer_inv()
363    }
364}
365
366impl core::ops::Div<c64conj> for c64 {
367    type Output = c64;
368
369    #[allow(clippy::suspicious_arithmetic_impl)]
370    #[inline(always)]
371    fn div(self, rhs: c64conj) -> Self::Output {
372        self * rhs.canonicalize().faer_inv()
373    }
374}
375
376impl core::ops::Div<c64> for c64conj {
377    type Output = c64;
378
379    #[allow(clippy::suspicious_arithmetic_impl)]
380    #[inline(always)]
381    fn div(self, rhs: c64) -> Self::Output {
382        self * rhs.faer_inv()
383    }
384}
385
386impl core::ops::Rem<f64> for c64 {
387    type Output = c64;
388
389    #[inline(always)]
390    fn rem(self, rhs: f64) -> Self::Output {
391        Self::new(self.re % rhs, self.im % rhs)
392    }
393}
394
395impl core::ops::Rem<c64> for f64 {
396    type Output = c64;
397
398    #[inline(always)]
399    fn rem(self, rhs: c64) -> Self::Output {
400        self.rem(rhs.to_num_complex()).into()
401    }
402}
403
404impl core::ops::Rem for c64 {
405    type Output = c64;
406
407    #[inline(always)]
408    fn rem(self, rhs: Self) -> Self::Output {
409        self.to_num_complex().rem(rhs.to_num_complex()).into()
410    }
411}
412
413impl core::ops::Rem<c64conj> for c64 {
414    type Output = c64;
415
416    #[inline(always)]
417    fn rem(self, rhs: c64conj) -> Self::Output {
418        self.rem(rhs.canonicalize())
419    }
420}
421
422impl core::ops::Rem<c64> for c64conj {
423    type Output = c64;
424
425    #[inline(always)]
426    fn rem(self, rhs: c64) -> Self::Output {
427        self.canonicalize().rem(rhs)
428    }
429}
430
431impl core::ops::AddAssign<f64> for c64 {
432    #[inline(always)]
433    fn add_assign(&mut self, rhs: f64) {
434        self.re += rhs;
435    }
436}
437
438impl core::ops::AddAssign for c64 {
439    #[inline(always)]
440    fn add_assign(&mut self, rhs: c64) {
441        self.re += rhs.re;
442        self.im += rhs.im;
443    }
444}
445
446impl core::ops::AddAssign<c64conj> for c64 {
447    #[inline(always)]
448    fn add_assign(&mut self, rhs: c64conj) {
449        self.re += rhs.re;
450        self.im -= rhs.neg_im;
451    }
452}
453
454impl core::ops::SubAssign<f64> for c64 {
455    #[inline(always)]
456    fn sub_assign(&mut self, rhs: f64) {
457        self.re -= rhs;
458    }
459}
460
461impl core::ops::SubAssign for c64 {
462    #[inline(always)]
463    fn sub_assign(&mut self, rhs: c64) {
464        self.re -= rhs.re;
465        self.im -= rhs.im;
466    }
467}
468
469impl core::ops::SubAssign<c64conj> for c64 {
470    #[inline(always)]
471    fn sub_assign(&mut self, rhs: c64conj) {
472        self.re -= rhs.re;
473        self.im += rhs.neg_im;
474    }
475}
476
477impl core::ops::MulAssign<f64> for c64 {
478    #[inline(always)]
479    fn mul_assign(&mut self, rhs: f64) {
480        self.re *= rhs;
481        self.im *= rhs;
482    }
483}
484
485impl core::ops::MulAssign for c64 {
486    #[inline(always)]
487    fn mul_assign(&mut self, rhs: c64) {
488        *self = *self * rhs;
489    }
490}
491
492impl core::ops::MulAssign<c64conj> for c64 {
493    #[inline(always)]
494    fn mul_assign(&mut self, rhs: c64conj) {
495        *self = *self * rhs;
496    }
497}
498
499impl core::ops::DivAssign<f64> for c64 {
500    #[inline(always)]
501    fn div_assign(&mut self, rhs: f64) {
502        self.re /= rhs;
503        self.im /= rhs;
504    }
505}
506
507impl core::ops::DivAssign for c64 {
508    #[inline(always)]
509    fn div_assign(&mut self, rhs: c64) {
510        *self *= rhs.faer_inv();
511    }
512}
513
514impl core::ops::DivAssign<c64conj> for c64 {
515    #[inline(always)]
516    fn div_assign(&mut self, rhs: c64conj) {
517        *self *= rhs.canonicalize().faer_inv();
518    }
519}
520
521impl core::ops::RemAssign<f64> for c64 {
522    #[inline(always)]
523    fn rem_assign(&mut self, rhs: f64) {
524        self.re %= rhs;
525        self.im %= rhs;
526    }
527}
528
529impl core::ops::RemAssign for c64 {
530    #[inline(always)]
531    fn rem_assign(&mut self, rhs: c64) {
532        *self = *self % rhs;
533    }
534}
535
536impl core::ops::RemAssign<c64conj> for c64 {
537    #[inline(always)]
538    fn rem_assign(&mut self, rhs: c64conj) {
539        *self = *self % rhs;
540    }
541}
542
543impl num_traits::Inv for c64 {
544    type Output = c64;
545
546    #[inline(always)]
547    fn inv(self) -> Self::Output {
548        self.faer_inv()
549    }
550}
551
552impl num_traits::Num for c64 {
553    type FromStrRadixErr =
554        num_complex::ParseComplexError<<f64 as num_traits::Num>::FromStrRadixErr>;
555
556    #[inline(always)]
557    fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
558        let num_complex = num_complex::Complex64::from_str_radix(str, radix)?;
559        Ok(num_complex.into())
560    }
561}
562
563impl From<c64> for num_complex::Complex64 {
564    #[inline(always)]
565    fn from(value: c64) -> Self {
566        Self {
567            re: value.re,
568            im: value.im,
569        }
570    }
571}
572
573impl From<num_complex::Complex64> for c64 {
574    #[inline(always)]
575    fn from(value: num_complex::Complex64) -> Self {
576        c64 {
577            re: value.re,
578            im: value.im,
579        }
580    }
581}
582
583impl From<f64> for c64 {
584    #[inline(always)]
585    fn from(value: f64) -> Self {
586        Self::new(value, 0.0)
587    }
588}
589
590impl<'a> From<&'a f64> for c64 {
591    #[inline(always)]
592    fn from(value: &'a f64) -> Self {
593        Self::new(*value, 0.0)
594    }
595}
596
597unsafe impl bytemuck::Zeroable for c64 {}
598unsafe impl bytemuck::Pod for c64 {}
599
600impl core::fmt::Debug for c64 {
601    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
602        self.re.fmt(f)?;
603        let im_abs = self.im.faer_abs();
604        if self.im.is_sign_positive() {
605            f.write_str(" + ")?;
606            im_abs.fmt(f)?;
607        } else {
608            f.write_str(" - ")?;
609            im_abs.fmt(f)?;
610        }
611        f.write_str(" * I")
612    }
613}
614
615impl core::fmt::Display for c64 {
616    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
617        <Self as core::fmt::Debug>::fmt(self, f)
618    }
619}
620
621impl ComplexField for c64 {
622    type Real = f64;
623    type Simd = pulp::Arch;
624    type ScalarSimd = NoSimd;
625    type PortableSimd = pulp::Arch;
626
627    #[inline(always)]
628    fn faer_from_f64(value: f64) -> Self {
629        Self {
630            re: value as _,
631            im: 0.0,
632        }
633    }
634
635    #[inline(always)]
636    fn faer_add(self, rhs: Self) -> Self {
637        Self {
638            re: self.re + rhs.re,
639            im: self.im + rhs.im,
640        }
641    }
642
643    #[inline(always)]
644    fn faer_sub(self, rhs: Self) -> Self {
645        Self {
646            re: self.re - rhs.re,
647            im: self.im - rhs.im,
648        }
649    }
650
651    #[inline(always)]
652    fn faer_mul(self, rhs: Self) -> Self {
653        Self {
654            re: self.re * rhs.re - self.im * rhs.im,
655            im: self.re * rhs.im + self.im * rhs.re,
656        }
657    }
658
659    #[inline(always)]
660    fn faer_neg(self) -> Self {
661        Self {
662            re: -self.re,
663            im: -self.im,
664        }
665    }
666
667    #[inline(always)]
668    fn faer_conj(self) -> Self {
669        Self {
670            re: self.re,
671            im: -self.im,
672        }
673    }
674
675    #[inline(always)]
676    fn faer_scale_real(self, rhs: Self::Real) -> Self {
677        Self {
678            re: rhs * self.re,
679            im: rhs * self.im,
680        }
681    }
682
683    #[inline(always)]
684    fn faer_scale_power_of_two(self, rhs: Self::Real) -> Self {
685        Self {
686            re: rhs * self.re,
687            im: rhs * self.im,
688        }
689    }
690
691    #[inline(always)]
692    fn faer_score(self) -> Self::Real {
693        self.faer_abs2()
694    }
695
696    #[inline(always)]
697    fn faer_abs2(self) -> Self::Real {
698        self.re * self.re + self.im * self.im
699    }
700
701    #[inline(always)]
702    fn faer_nan() -> Self {
703        Self {
704            re: Self::Real::NAN,
705            im: Self::Real::NAN,
706        }
707    }
708
709    #[inline(always)]
710    fn faer_from_real(real: Self::Real) -> Self {
711        Self { re: real, im: 0.0 }
712    }
713
714    #[inline(always)]
715    fn faer_real(self) -> Self::Real {
716        self.re
717    }
718
719    #[inline(always)]
720    fn faer_imag(self) -> Self::Real {
721        self.im
722    }
723
724    #[inline(always)]
725    fn faer_zero() -> Self {
726        Self { re: 0.0, im: 0.0 }
727    }
728
729    #[inline(always)]
730    fn faer_one() -> Self {
731        Self { re: 1.0, im: 0.0 }
732    }
733
734    #[inline(always)]
735    fn faer_inv(self) -> Self {
736        self.to_num_complex().faer_inv().into()
737    }
738
739    #[inline(always)]
740    fn faer_sqrt(self) -> Self {
741        self.to_num_complex().faer_sqrt().into()
742    }
743
744    #[inline(always)]
745    fn faer_abs(self) -> Self::Real {
746        self.to_num_complex().faer_abs()
747    }
748
749    #[inline(always)]
750    fn faer_slice_as_simd<S: Simd>(slice: &[Self::Unit]) -> (&[Self::SimdUnit<S>], &[Self::Unit]) {
751        let (head, tail) = S::c64s_as_simd(bytemuck::cast_slice(slice));
752        (bytemuck::cast_slice(head), bytemuck::cast_slice(tail))
753    }
754
755    #[inline(always)]
756    fn faer_slice_as_simd_mut<S: Simd>(
757        slice: &mut [Self::Unit],
758    ) -> (&mut [Self::SimdUnit<S>], &mut [Self::Unit]) {
759        let (head, tail) = S::c64s_as_mut_simd(bytemuck::cast_slice_mut(slice));
760        (
761            bytemuck::cast_slice_mut(head),
762            bytemuck::cast_slice_mut(tail),
763        )
764    }
765
766    #[inline(always)]
767    fn faer_partial_load_last_unit<S: Simd>(simd: S, slice: &[Self::Unit]) -> Self::SimdUnit<S> {
768        simd.c64s_partial_load_last(bytemuck::cast_slice(slice))
769    }
770
771    #[inline(always)]
772    fn faer_partial_store_last_unit<S: Simd>(
773        simd: S,
774        slice: &mut [Self::Unit],
775        values: Self::SimdUnit<S>,
776    ) {
777        simd.c64s_partial_store_last(bytemuck::cast_slice_mut(slice), values)
778    }
779
780    #[inline(always)]
781    fn faer_partial_load_unit<S: Simd>(simd: S, slice: &[Self::Unit]) -> Self::SimdUnit<S> {
782        simd.c64s_partial_load(bytemuck::cast_slice(slice))
783    }
784
785    #[inline(always)]
786    fn faer_partial_store_unit<S: Simd>(
787        simd: S,
788        slice: &mut [Self::Unit],
789        values: Self::SimdUnit<S>,
790    ) {
791        simd.c64s_partial_store(bytemuck::cast_slice_mut(slice), values)
792    }
793
794    #[inline(always)]
795    fn faer_simd_splat_unit<S: Simd>(simd: S, unit: Self::Unit) -> Self::SimdUnit<S> {
796        simd.c64s_splat(pulp::cast(unit))
797    }
798
799    #[inline(always)]
800    fn faer_simd_neg<S: Simd>(simd: S, values: SimdGroupFor<Self, S>) -> SimdGroupFor<Self, S> {
801        simd.c64s_neg(values)
802    }
803
804    #[inline(always)]
805    fn faer_simd_conj<S: Simd>(simd: S, values: SimdGroupFor<Self, S>) -> SimdGroupFor<Self, S> {
806        let _ = simd;
807        values
808    }
809
810    #[inline(always)]
811    fn faer_simd_add<S: Simd>(
812        simd: S,
813        lhs: SimdGroupFor<Self, S>,
814        rhs: SimdGroupFor<Self, S>,
815    ) -> SimdGroupFor<Self, S> {
816        simd.c64s_add(lhs, rhs)
817    }
818
819    #[inline(always)]
820    fn faer_simd_sub<S: Simd>(
821        simd: S,
822        lhs: SimdGroupFor<Self, S>,
823        rhs: SimdGroupFor<Self, S>,
824    ) -> SimdGroupFor<Self, S> {
825        simd.c64s_sub(lhs, rhs)
826    }
827
828    #[inline(always)]
829    fn faer_simd_mul<S: Simd>(
830        simd: S,
831        lhs: SimdGroupFor<Self, S>,
832        rhs: SimdGroupFor<Self, S>,
833    ) -> SimdGroupFor<Self, S> {
834        simd.c64s_mul(lhs, rhs)
835    }
836    #[inline(always)]
837    fn faer_simd_scale_real<S: Simd>(
838        simd: S,
839        lhs: SimdGroupFor<Self::Real, S>,
840        rhs: SimdGroupFor<Self, S>,
841    ) -> SimdGroupFor<Self, S> {
842        if coe::is_same::<pulp::Scalar, S>() {
843            let lhs: f64 = bytemuck::cast(lhs);
844            let rhs: num_complex::Complex64 = bytemuck::cast(rhs);
845            bytemuck::cast(lhs * rhs)
846        } else {
847            bytemuck::cast(simd.f64s_mul(lhs, bytemuck::cast(rhs)))
848        }
849    }
850    #[inline(always)]
851    fn faer_simd_conj_mul<S: Simd>(
852        simd: S,
853        lhs: SimdGroupFor<Self, S>,
854        rhs: SimdGroupFor<Self, S>,
855    ) -> SimdGroupFor<Self, S> {
856        simd.c64s_conj_mul(lhs, rhs)
857    }
858
859    #[inline(always)]
860    fn faer_simd_mul_adde<S: Simd>(
861        simd: S,
862        lhs: SimdGroupFor<Self, S>,
863        rhs: SimdGroupFor<Self, S>,
864        acc: SimdGroupFor<Self, S>,
865    ) -> SimdGroupFor<Self, S> {
866        simd.c64s_mul_add_e(lhs, rhs, acc)
867    }
868
869    #[inline(always)]
870    fn faer_simd_conj_mul_adde<S: Simd>(
871        simd: S,
872        lhs: SimdGroupFor<Self, S>,
873        rhs: SimdGroupFor<Self, S>,
874        acc: SimdGroupFor<Self, S>,
875    ) -> SimdGroupFor<Self, S> {
876        simd.c64s_conj_mul_add_e(lhs, rhs, acc)
877    }
878
879    #[inline(always)]
880    fn faer_simd_reduce_add<S: Simd>(simd: S, values: SimdGroupFor<Self, S>) -> Self {
881        pulp::cast(simd.c64s_reduce_sum(values))
882    }
883
884    #[inline(always)]
885    fn faer_simd_abs2_adde<S: Simd>(
886        simd: S,
887        values: SimdGroupFor<Self, S>,
888        acc: SimdGroupFor<Self::Real, S>,
889    ) -> SimdGroupFor<Self::Real, S> {
890        let _ = (simd, values, acc);
891        unimplemented!("c64/c64 require special treatment when converted to their real counterparts in simd kernels");
892    }
893    #[inline(always)]
894    fn faer_simd_abs2<S: Simd>(
895        simd: S,
896        values: SimdGroupFor<Self, S>,
897    ) -> SimdGroupFor<Self::Real, S> {
898        let _ = (simd, values);
899        unimplemented!("c64/c64 require special treatment when converted to their real counterparts in simd kernels");
900    }
901    #[inline(always)]
902    fn faer_simd_score<S: Simd>(
903        simd: S,
904        values: SimdGroupFor<Self, S>,
905    ) -> SimdGroupFor<Self::Real, S> {
906        let _ = (simd, values);
907        unimplemented!("c64/c64 require special treatment when converted to their real counterparts in simd kernels");
908    }
909
910    #[inline(always)]
911    fn faer_simd_scalar_mul<S: Simd>(simd: S, lhs: Self, rhs: Self) -> Self {
912        cast(simd.c64_scalar_mul(cast(lhs), cast(rhs)))
913    }
914    #[inline(always)]
915    fn faer_simd_scalar_conj_mul<S: Simd>(simd: S, lhs: Self, rhs: Self) -> Self {
916        cast(simd.c64_scalar_conj_mul(cast(lhs), cast(rhs)))
917    }
918    #[inline(always)]
919    fn faer_simd_scalar_mul_adde<S: Simd>(simd: S, lhs: Self, rhs: Self, acc: Self) -> Self {
920        cast(simd.c64_scalar_mul_add_e(cast(lhs), cast(rhs), cast(acc)))
921    }
922    #[inline(always)]
923    fn faer_simd_scalar_conj_mul_adde<S: Simd>(simd: S, lhs: Self, rhs: Self, acc: Self) -> Self {
924        cast(simd.c64_scalar_conj_mul_add_e(cast(lhs), cast(rhs), cast(acc)))
925    }
926
927    #[inline(always)]
928    fn faer_align_offset<S: Simd>(
929        simd: S,
930        ptr: *const UnitFor<Self>,
931        len: usize,
932    ) -> pulp::Offset<SimdMaskFor<Self, S>> {
933        simd.c64s_align_offset(ptr as _, len)
934    }
935
936    #[inline(always)]
937    fn faer_slice_as_aligned_simd<S: Simd>(
938        simd: S,
939        slice: &[UnitFor<Self>],
940        offset: pulp::Offset<SimdMaskFor<Self, S>>,
941    ) -> (
942        Self::PrefixUnit<'_, S>,
943        &[SimdUnitFor<Self, S>],
944        Self::SuffixUnit<'_, S>,
945    ) {
946        simd.c64s_as_aligned_simd(bytemuck::cast_slice(slice), offset)
947    }
948
949    #[inline(always)]
950    fn faer_slice_as_aligned_simd_mut<S: Simd>(
951        simd: S,
952        slice: &mut [UnitFor<Self>],
953        offset: pulp::Offset<SimdMaskFor<Self, S>>,
954    ) -> (
955        Self::PrefixMutUnit<'_, S>,
956        &mut [SimdUnitFor<Self, S>],
957        Self::SuffixMutUnit<'_, S>,
958    ) {
959        simd.c64s_as_aligned_mut_simd(bytemuck::cast_slice_mut(slice), offset)
960    }
961
962    #[inline(always)]
963    fn faer_simd_rotate_left<S: Simd>(
964        simd: S,
965        values: SimdGroupFor<Self, S>,
966        amount: usize,
967    ) -> SimdGroupFor<Self, S> {
968        simd.c64s_rotate_left(values, amount)
969    }
970}
971
972unsafe impl Entity for c64 {
973    type Unit = Self;
974    type Index = u64;
975    type SimdUnit<S: Simd> = S::c64s;
976    type SimdMask<S: Simd> = S::m64s;
977    type SimdIndex<S: Simd> = S::u64s;
978    type Group = IdentityGroup;
979    type Iter<I: Iterator> = I;
980
981    type PrefixUnit<'a, S: Simd> = pulp::Prefix<'a, num_complex::Complex64, S, S::m64s>;
982    type SuffixUnit<'a, S: Simd> = pulp::Suffix<'a, num_complex::Complex64, S, S::m64s>;
983    type PrefixMutUnit<'a, S: Simd> = pulp::PrefixMut<'a, num_complex::Complex64, S, S::m64s>;
984    type SuffixMutUnit<'a, S: Simd> = pulp::SuffixMut<'a, num_complex::Complex64, S, S::m64s>;
985
986    const N_COMPONENTS: usize = 1;
987    const UNIT: GroupCopyFor<Self, ()> = ();
988
989    #[inline(always)]
990    fn faer_first<T>(group: GroupFor<Self, T>) -> T {
991        group
992    }
993
994    #[inline(always)]
995    fn faer_from_units(group: GroupFor<Self, Self::Unit>) -> Self {
996        group
997    }
998
999    #[inline(always)]
1000    fn faer_into_units(self) -> GroupFor<Self, Self::Unit> {
1001        self
1002    }
1003
1004    #[inline(always)]
1005    fn faer_as_ref<T>(group: &GroupFor<Self, T>) -> GroupFor<Self, &T> {
1006        group
1007    }
1008
1009    #[inline(always)]
1010    fn faer_as_mut<T>(group: &mut GroupFor<Self, T>) -> GroupFor<Self, &mut T> {
1011        group
1012    }
1013
1014    #[inline(always)]
1015    fn faer_as_ptr<T>(group: *mut GroupFor<Self, T>) -> GroupFor<Self, *mut T> {
1016        group
1017    }
1018
1019    #[inline(always)]
1020    fn faer_map_impl<T, U>(
1021        group: GroupFor<Self, T>,
1022        f: &mut impl FnMut(T) -> U,
1023    ) -> GroupFor<Self, U> {
1024        (*f)(group)
1025    }
1026
1027    #[inline(always)]
1028    fn faer_map_with_context<Ctx, T, U>(
1029        ctx: Ctx,
1030        group: GroupFor<Self, T>,
1031        f: &mut impl FnMut(Ctx, T) -> (Ctx, U),
1032    ) -> (Ctx, GroupFor<Self, U>) {
1033        (*f)(ctx, group)
1034    }
1035
1036    #[inline(always)]
1037    fn faer_zip<T, U>(
1038        first: GroupFor<Self, T>,
1039        second: GroupFor<Self, U>,
1040    ) -> GroupFor<Self, (T, U)> {
1041        (first, second)
1042    }
1043    #[inline(always)]
1044    fn faer_unzip<T, U>(zipped: GroupFor<Self, (T, U)>) -> (GroupFor<Self, T>, GroupFor<Self, U>) {
1045        zipped
1046    }
1047
1048    #[inline(always)]
1049    fn faer_into_iter<I: IntoIterator>(iter: GroupFor<Self, I>) -> Self::Iter<I::IntoIter> {
1050        iter.into_iter()
1051    }
1052}
1053
1054unsafe impl Conjugate for c64 {
1055    type Conj = c64conj;
1056    type Canonical = c64;
1057
1058    #[inline(always)]
1059    fn canonicalize(self) -> Self::Canonical {
1060        self
1061    }
1062}