simba/simd/
auto_simd_impl.rs

1#![allow(missing_docs)]
2#![allow(non_camel_case_types)] // For the simd type aliases.
3
4//! SIMD values based on auto-vectorization.
5
6use crate::scalar::{Field, SubsetOf, SupersetOf};
7use crate::simd::{
8    PrimitiveSimdValue, SimdBool, SimdComplexField, SimdPartialOrd, SimdRealField, SimdSigned,
9    SimdValue,
10};
11use approx::AbsDiffEq;
12#[cfg(feature = "decimal")]
13use decimal::d128;
14use num::{FromPrimitive, Num, One, Zero};
15use std::{
16    fmt,
17    ops::{
18        Add, AddAssign, BitAnd, BitOr, BitXor, Div, DivAssign, Mul, MulAssign, Neg, Not, Rem,
19        RemAssign, Sub, SubAssign,
20    },
21};
22
23// This is a hack to allow use to reuse `_0` as integers or as identifier,
24// depending on whether or not `ident_to_value` has been called in scope.
25// This helps writing macros that define both `::new` and `From([T; lanes()])`.
26macro_rules! ident_to_value (
27    () => {
28        const _0: usize = 0; const _1: usize = 1; const _2: usize = 2; const _3: usize = 3; const _4: usize = 4; const _5: usize = 5; const _6: usize = 6; const _7: usize = 7;
29        const _8: usize = 8; const _9: usize = 9; const _10: usize = 10; const _11: usize = 11; const _12: usize = 12; const _13: usize = 13; const _14: usize = 14; const _15: usize = 15;
30        const _16: usize = 16; const _17: usize = 17; const _18: usize = 18; const _19: usize = 19; const _20: usize = 20; const _21: usize = 21; const _22: usize = 22; const _23: usize = 23;
31        const _24: usize = 24; const _25: usize = 25; const _26: usize = 26; const _27: usize = 27; const _28: usize = 28; const _29: usize = 29; const _30: usize = 30; const _31: usize = 31;
32        const _32: usize = 32; const _33: usize = 33; const _34: usize = 34; const _35: usize = 35; const _36: usize = 36; const _37: usize = 37; const _38: usize = 38; const _39: usize = 39;
33        const _40: usize = 40; const _41: usize = 41; const _42: usize = 42; const _43: usize = 43; const _44: usize = 44; const _45: usize = 45; const _46: usize = 46; const _47: usize = 47;
34        const _48: usize = 48; const _49: usize = 49; const _50: usize = 50; const _51: usize = 51; const _52: usize = 52; const _53: usize = 53; const _54: usize = 54; const _55: usize = 55;
35        const _56: usize = 56; const _57: usize = 57; const _58: usize = 58; const _59: usize = 59; const _60: usize = 60; const _61: usize = 61; const _62: usize = 62; const _63: usize = 63;
36    }
37);
38
39/// A SIMD structure that implements all the relevant traits from `num` an `simba`.
40///
41/// This is needed to overcome the orphan rules.
42#[repr(align(16))]
43#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
44#[cfg_attr(
45    feature = "rkyv",
46    derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize),
47    archive(as = "Self", bound(archive = "N: rkyv::Archive<Archived = N>"))
48)]
49pub struct AutoSimd<N>(pub N);
50
51/// A SIMD boolean structure that implements all the relevant traits from `num` an `simba`.
52///
53/// This is needed to overcome the orphan rules.
54#[repr(align(16))]
55#[derive(Copy, Clone, PartialEq, Eq, Debug)]
56#[cfg_attr(
57    feature = "rkyv",
58    derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize),
59    archive(as = "Self", bound(archive = "N: rkyv::Archive<Archived = N>"))
60)]
61pub struct AutoBoolSimd<N>(pub N);
62
63macro_rules! impl_bool_simd (
64    ($($t: ty, $lanes: expr, $($i: ident),*;)*) => {$(
65        impl_simd_value!($t, bool, $lanes, AutoSimd<$t> $(, $i)*;);
66
67        impl AutoSimd<$t> {
68            pub const ZERO: Self = AutoSimd([false; $lanes]);
69            pub const ONE: Self = AutoSimd([true; $lanes]);
70
71            #[inline(always)]
72            pub fn new($($i: bool),*) -> Self {
73                AutoSimd([$($i),*])
74            }
75        }
76
77        impl From<[bool; $lanes]> for AutoSimd<$t> {
78            #[inline(always)]
79            fn from(vals: [bool; $lanes]) -> Self {
80                Self(vals)
81            }
82        }
83
84        impl Not for AutoSimd<$t> {
85            type Output = Self;
86
87            #[inline(always)]
88            fn not(self) -> Self {
89                self.map(|x| !x)
90            }
91        }
92
93        impl BitAnd<AutoSimd<$t>> for AutoSimd<$t> {
94            type Output = Self;
95
96            #[inline(always)]
97            fn bitand(self, rhs: Self) -> Self {
98                self.zip_map(rhs, |x, y| x & y)
99            }
100        }
101
102        impl BitOr<AutoSimd<$t>> for AutoSimd<$t> {
103            type Output = Self;
104
105            #[inline(always)]
106            fn bitor(self, rhs: Self) -> Self {
107                self.zip_map(rhs, |x, y| x | y)
108            }
109        }
110
111        impl BitXor<AutoSimd<$t>> for AutoSimd<$t> {
112            type Output = Self;
113
114            #[inline(always)]
115            fn bitxor(self, rhs: Self) -> Self {
116                self.zip_map(rhs, |x, y| x ^ y)
117            }
118        }
119
120        impl SimdBool for AutoSimd<$t> {
121            #[inline(always)]
122            fn bitmask(self) -> u64 {
123                ident_to_value!();
124                0u64 $(
125                    | ((self.0[$i] as u64) << $i)
126                 )*
127            }
128
129            #[inline(always)]
130            fn and(self) -> bool {
131                ident_to_value!();
132                true $(
133                    && self.0[$i]
134                 )*
135            }
136
137            #[inline(always)]
138            fn or(self) -> bool {
139                ident_to_value!();
140                false $(
141                    || self.0[$i]
142                 )*
143            }
144
145            #[inline(always)]
146            fn xor(self) -> bool {
147                ident_to_value!();
148                false $(
149                    ^ self.0[$i]
150                 )*
151            }
152
153            #[inline(always)]
154            fn all(self) -> bool {
155                self.and()
156            }
157
158            #[inline(always)]
159            fn any(self) -> bool {
160                self.or()
161            }
162
163            #[inline(always)]
164            fn none(self) -> bool {
165                !self.any()
166            }
167
168            #[inline(always)]
169            fn if_else<Res: SimdValue<SimdBool = Self>>(
170                self,
171                if_value: impl FnOnce() -> Res,
172                else_value: impl FnOnce() -> Res,
173            ) -> Res {
174                let a = if_value();
175                let b = else_value();
176                a.select(self, b)
177            }
178
179            #[inline(always)]
180            fn if_else2<Res: SimdValue<SimdBool = Self>>(
181                self,
182                if_value: impl FnOnce() -> Res,
183                else_if: (impl FnOnce() -> Self, impl FnOnce() -> Res),
184                else_value: impl FnOnce() -> Res,
185            ) -> Res {
186                let a = if_value();
187                let b = else_if.1();
188                let c = else_value();
189
190                let cond_a = self;
191                let cond_b = else_if.0();
192
193                a.select(cond_a, b.select(cond_b, c))
194            }
195
196            #[inline(always)]
197            fn if_else3<Res: SimdValue<SimdBool = Self>>(
198                self,
199                if_value: impl FnOnce() -> Res,
200                else_if: (impl FnOnce() -> Self, impl FnOnce() -> Res),
201                else_else_if: (impl FnOnce() -> Self, impl FnOnce() -> Res),
202                else_value: impl FnOnce() -> Res,
203            ) -> Res {
204                let a = if_value();
205                let b = else_if.1();
206                let c = else_else_if.1();
207                let d = else_value();
208
209                let cond_a = self;
210                let cond_b = else_if.0();
211                let cond_c = else_else_if.0();
212
213                a.select(cond_a, b.select(cond_b, c.select(cond_c, d)))
214            }
215        }
216    )*}
217);
218
219macro_rules! impl_scalar_subset_of_simd (
220    ($($t: ty),*) => {$(
221        impl<N2> SubsetOf<AutoSimd<N2>> for $t
222            where AutoSimd<N2>: SimdValue + Copy,
223                  <AutoSimd<N2> as SimdValue>::Element: SupersetOf<$t> + PartialEq, {
224            #[inline(always)]
225            fn to_superset(&self) -> AutoSimd<N2> {
226                AutoSimd::<N2>::splat(<AutoSimd<N2> as SimdValue>::Element::from_subset(self))
227            }
228
229            #[inline(always)]
230            fn from_superset_unchecked(element: &AutoSimd<N2>) -> $t {
231                element.extract(0).to_subset_unchecked()
232            }
233
234            #[inline(always)]
235            fn is_in_subset(c: &AutoSimd<N2>) -> bool {
236                let elt0 = c.extract(0);
237                elt0.is_in_subset() &&
238                (1..AutoSimd::<N2>::LANES).all(|i| c.extract(i) == elt0)
239            }
240        }
241    )*}
242);
243
244impl_scalar_subset_of_simd!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize, f32, f64);
245#[cfg(feature = "decimal")]
246impl_scalar_subset_of_simd!(d128);
247
248macro_rules! impl_simd_value (
249    ($($t: ty, $elt: ty, $lanes: expr, $bool: ty, $($i: ident),*;)*) => ($(
250        impl ArrTransform for AutoSimd<$t> {
251            #[inline(always)]
252            fn map(self, f: impl Fn(Self::Element) -> Self::Element) -> Self {
253                ident_to_value!();
254                Self([$(f(self.0[$i])),*])
255            }
256
257            #[inline(always)]
258            fn zip_map(self, other: Self, f: impl Fn(Self::Element, Self::Element) -> Self::Element) -> Self {
259                ident_to_value!();
260                Self([$(f(self.0[$i], other.0[$i])),*])
261            }
262
263            #[inline(always)]
264            fn zip_zip_map(self, b: Self, c: Self, f: impl Fn(Self::Element, Self::Element, Self::Element) -> Self::Element) -> Self {
265                ident_to_value!();
266                Self([$(f(self.0[$i], b.0[$i], c.0[$i])),*])
267            }
268
269            #[inline(always)]
270            fn map_bool(self, f: impl Fn(Self::Element) -> bool) -> Self::SimdBool {
271                ident_to_value!();
272                AutoSimd([$(f(self.0[$i])),*])
273            }
274
275            #[inline(always)]
276            fn zip_map_bool(self, other: Self, f: impl Fn(Self::Element, Self::Element) -> bool) -> Self::SimdBool {
277                ident_to_value!();
278                AutoSimd([$(f(self.0[$i], other.0[$i])),*])
279            }
280        }
281
282        impl fmt::Display for AutoSimd<$t> {
283            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
284                if Self::LANES == 1 {
285                    return self.extract(0).fmt(f);
286                }
287
288                write!(f, "({}", self.extract(0))?;
289
290                #[allow(clippy::reversed_empty_ranges)] // Needed for LANES == 1 that’s in a different code path.
291                for i in 1..Self::LANES {
292                    write!(f, ", {}", self.extract(i))?;
293                }
294
295                write!(f, ")")
296            }
297        }
298
299        impl PrimitiveSimdValue for AutoSimd<$t> {}
300
301        impl SimdValue for AutoSimd<$t> {
302            const LANES: usize = $lanes;
303            type Element = $elt;
304            type SimdBool = $bool;
305
306
307            #[inline(always)]
308            fn splat(val: Self::Element) -> Self {
309                AutoSimd([val; $lanes])
310            }
311
312            #[inline(always)]
313            fn extract(&self, i: usize) -> Self::Element {
314                self.0[i]
315            }
316
317            #[inline(always)]
318            unsafe fn extract_unchecked(&self, i: usize) -> Self::Element {
319                *self.0.get_unchecked(i)
320            }
321
322            #[inline(always)]
323            fn replace(&mut self, i: usize, val: Self::Element) {
324                self.0[i] = val
325            }
326
327            #[inline(always)]
328            unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) {
329                *self.0.get_unchecked_mut(i) = val
330            }
331
332            #[inline(always)]
333            fn select(self, cond: Self::SimdBool, other: Self) -> Self {
334                ident_to_value!();
335                Self([
336                    $(if cond.0[$i] { self.0[$i] } else { other.0[$i] }),*
337                ])
338            }
339        }
340    )*)
341);
342
343macro_rules! impl_uint_simd (
344    ($($t: ty, $elt: ty, $lanes: expr, $bool: ty, $($i: ident),*;)*) => ($(
345        impl_simd_value!($t, $elt, $lanes, $bool $(, $i)*;);
346
347        impl AutoSimd<$t> {
348            pub const ZERO: Self = AutoSimd([0 as $elt; $lanes]);
349            pub const ONE: Self = AutoSimd([1 as $elt; $lanes]);
350
351            pub fn new($($i: $elt),*) -> Self {
352                AutoSimd([$($i),*])
353            }
354        }
355
356        impl From<[$elt; $lanes]> for AutoSimd<$t> {
357            #[inline(always)]
358            fn from(vals: [$elt; $lanes]) -> Self {
359                AutoSimd(vals)
360            }
361        }
362
363        impl From<AutoSimd<$t>> for [$elt; $lanes] {
364            #[inline(always)]
365            fn from(val: AutoSimd<$t>) -> [$elt; $lanes] {
366                val.0
367            }
368        }
369
370        impl SubsetOf<AutoSimd<$t>> for AutoSimd<$t> {
371            #[inline(always)]
372            fn to_superset(&self) -> Self {
373                *self
374            }
375
376            #[inline(always)]
377            fn from_superset(element: &Self) -> Option<Self> {
378                Some(*element)
379            }
380
381            #[inline(always)]
382            fn from_superset_unchecked(element: &Self) -> Self {
383                *element
384            }
385
386            #[inline(always)]
387            fn is_in_subset(_: &Self) -> bool {
388                true
389            }
390        }
391
392        impl Num for AutoSimd<$t> {
393            type FromStrRadixErr = <$elt as Num>::FromStrRadixErr;
394
395            #[inline(always)]
396            fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
397                <$elt>::from_str_radix(str, radix).map(Self::splat)
398            }
399        }
400
401        impl FromPrimitive for AutoSimd<$t> {
402            #[inline(always)]
403            fn from_i64(n: i64) -> Option<Self> {
404                <$elt>::from_i64(n).map(Self::splat)
405            }
406
407            #[inline(always)]
408            fn from_u64(n: u64) -> Option<Self> {
409                <$elt>::from_u64(n).map(Self::splat)
410            }
411
412            #[inline(always)]
413            fn from_isize(n: isize) -> Option<Self>  {
414                <$elt>::from_isize(n).map(Self::splat)
415            }
416
417            #[inline(always)]
418            fn from_i8(n: i8) -> Option<Self>  {
419                <$elt>::from_i8(n).map(Self::splat)
420            }
421
422            #[inline(always)]
423            fn from_i16(n: i16) -> Option<Self>  {
424                <$elt>::from_i16(n).map(Self::splat)
425            }
426
427            #[inline(always)]
428            fn from_i32(n: i32) -> Option<Self>  {
429                <$elt>::from_i32(n).map(Self::splat)
430            }
431
432            #[inline(always)]
433            fn from_usize(n: usize) -> Option<Self>  {
434                <$elt>::from_usize(n).map(Self::splat)
435            }
436
437            #[inline(always)]
438            fn from_u8(n: u8) -> Option<Self>  {
439                <$elt>::from_u8(n).map(Self::splat)
440            }
441
442            #[inline(always)]
443            fn from_u16(n: u16) -> Option<Self>  {
444                <$elt>::from_u16(n).map(Self::splat)
445            }
446
447            #[inline(always)]
448            fn from_u32(n: u32) -> Option<Self>  {
449                <$elt>::from_u32(n).map(Self::splat)
450            }
451
452            #[inline(always)]
453            fn from_f32(n: f32) -> Option<Self>  {
454                <$elt>::from_f32(n).map(Self::splat)
455            }
456
457            #[inline(always)]
458            fn from_f64(n: f64) -> Option<Self>  {
459                <$elt>::from_f64(n).map(Self::splat)
460            }
461        }
462
463
464        impl Zero for AutoSimd<$t> {
465            #[inline(always)]
466            fn zero() -> Self {
467                AutoSimd([<$elt>::zero(); $lanes])
468            }
469
470            #[inline(always)]
471            fn is_zero(&self) -> bool {
472                *self == Self::zero()
473            }
474        }
475
476        impl One for AutoSimd<$t> {
477            #[inline(always)]
478            fn one() -> Self {
479                AutoSimd([<$elt>::one(); $lanes])
480            }
481        }
482
483        impl Add<AutoSimd<$t>> for AutoSimd<$t> {
484            type Output = Self;
485
486            #[inline(always)]
487            fn add(self, rhs: Self) -> Self {
488                self.zip_map(rhs, |x, y| x + y)
489            }
490        }
491
492        impl Sub<AutoSimd<$t>> for AutoSimd<$t> {
493            type Output = Self;
494
495            #[inline(always)]
496            fn sub(self, rhs: Self) -> Self {
497                self.zip_map(rhs, |x, y| x - y)
498            }
499        }
500
501        impl Mul<AutoSimd<$t>> for AutoSimd<$t> {
502            type Output = Self;
503
504            #[inline(always)]
505            fn mul(self, rhs: Self) -> Self {
506                self.zip_map(rhs, |x, y| x * y)
507            }
508        }
509
510        impl Div<AutoSimd<$t>> for AutoSimd<$t> {
511            type Output = Self;
512
513            #[inline(always)]
514            fn div(self, rhs: Self) -> Self {
515                self.zip_map(rhs, |x, y| x / y)
516            }
517        }
518
519        impl Rem<AutoSimd<$t>> for AutoSimd<$t> {
520            type Output = Self;
521
522            #[inline(always)]
523            fn rem(self, rhs: Self) -> Self {
524                self.zip_map(rhs, |x, y| x % y)
525            }
526        }
527
528        impl AddAssign<AutoSimd<$t>> for AutoSimd<$t> {
529            #[inline(always)]
530            fn add_assign(&mut self, rhs: Self) {
531                *self = *self + rhs;
532            }
533        }
534
535        impl SubAssign<AutoSimd<$t>> for AutoSimd<$t> {
536            #[inline(always)]
537            fn sub_assign(&mut self, rhs: Self) {
538                *self = *self - rhs;
539            }
540        }
541
542        impl DivAssign<AutoSimd<$t>> for AutoSimd<$t> {
543            #[inline(always)]
544            fn div_assign(&mut self, rhs: Self) {
545                *self = *self / rhs;
546            }
547        }
548
549        impl MulAssign<AutoSimd<$t>> for AutoSimd<$t> {
550            #[inline(always)]
551            fn mul_assign(&mut self, rhs: Self) {
552                *self = *self * rhs;
553            }
554        }
555
556        impl RemAssign<AutoSimd<$t>> for AutoSimd<$t> {
557            #[inline(always)]
558            fn rem_assign(&mut self, rhs: Self) {
559                *self = *self % rhs;
560            }
561        }
562
563        impl SimdPartialOrd for AutoSimd<$t> {
564            #[inline(always)]
565            fn simd_gt(self, other: Self) -> Self::SimdBool {
566                self.zip_map_bool(other, |x, y| x.simd_gt(y))
567            }
568
569            #[inline(always)]
570            fn simd_lt(self, other: Self) -> Self::SimdBool {
571                self.zip_map_bool(other, |x, y| x.simd_lt(y))
572            }
573
574            #[inline(always)]
575            fn simd_ge(self, other: Self) -> Self::SimdBool {
576                self.zip_map_bool(other, |x, y| x.simd_ge(y))
577            }
578
579            #[inline(always)]
580            fn simd_le(self, other: Self) -> Self::SimdBool {
581                self.zip_map_bool(other, |x, y| x.simd_le(y))
582            }
583
584            #[inline(always)]
585            fn simd_eq(self, other: Self) -> Self::SimdBool {
586                self.zip_map_bool(other, |x, y| x.simd_eq(y))
587            }
588
589            #[inline(always)]
590            fn simd_ne(self, other: Self) -> Self::SimdBool {
591                self.zip_map_bool(other, |x, y| x.simd_ne(y))
592            }
593
594            #[inline(always)]
595            fn simd_max(self, other: Self) -> Self {
596                self.zip_map(other, |x, y| x.simd_max(y))
597            }
598            #[inline(always)]
599            fn simd_min(self, other: Self) -> Self {
600                self.zip_map(other, |x, y| x.simd_min(y))
601            }
602
603            #[inline(always)]
604            fn simd_clamp(self, min: Self, max: Self) -> Self {
605                self.simd_max(min).simd_min(max)
606            }
607
608            #[inline(always)]
609            fn simd_horizontal_min(self) -> Self::Element {
610                ident_to_value!();
611                self.0[0] $(.simd_min(self.0[$i]))*
612            }
613
614            #[inline(always)]
615            fn simd_horizontal_max(self) -> Self::Element {
616                ident_to_value!();
617                self.0[0] $(.simd_max(self.0[$i]))*
618            }
619        }
620
621//        impl MeetSemilattice for AutoSimd<$t> {
622//            #[inline(always)]
623//            fn meet(&self, other: &Self) -> Self {
624//                AutoSimd(self.0.min(other.0))
625//            }
626//        }
627//
628//        impl JoinSemilattice for AutoSimd<$t> {
629//            #[inline(always)]
630//            fn join(&self, other: &Self) -> Self {
631//                AutoSimd(self.0.max(other.0))
632//            }
633//        }
634    )*)
635);
636
637macro_rules! impl_int_simd (
638    ($($t: ty, $elt: ty, $lanes: expr, $bool: ty, $($i: ident),*;)*) => ($(
639        impl_uint_simd!($t, $elt, $lanes, $bool $(, $i)*;);
640
641        impl Neg for AutoSimd<$t> {
642            type Output = Self;
643
644            #[inline(always)]
645            fn neg(self) -> Self {
646                self.map(|x| -x)
647            }
648        }
649    )*)
650);
651
652macro_rules! impl_float_simd (
653    ($($t: ty, $elt: ty, $lanes: expr, $int: ty, $bool: ty, $($i: ident),*;)*) => ($(
654        impl_int_simd!($t, $elt, $lanes, $bool $(, $i)*;);
655
656        // TODO: this should be part of impl_int_simd
657        impl SimdSigned for AutoSimd<$t> {
658            #[inline(always)]
659            fn simd_abs(&self) -> Self {
660                self.map(|x| x.simd_abs())
661            }
662
663            #[inline(always)]
664            fn simd_abs_sub(&self, other: &Self) -> Self {
665                self.zip_map(*other, |x, y| x.simd_abs_sub(&y))
666            }
667
668            #[inline(always)]
669            fn simd_signum(&self) -> Self {
670                self.map(|x| x.simd_signum())
671            }
672
673            #[inline(always)]
674            fn is_simd_positive(&self) -> Self::SimdBool {
675                self.map_bool(|x| x.is_simd_positive())
676            }
677
678            #[inline(always)]
679            fn is_simd_negative(&self) -> Self::SimdBool {
680                self.map_bool(|x| x.is_simd_negative())
681            }
682        }
683
684        impl Field for AutoSimd<$t> {}
685
686        #[cfg(any(feature = "std", feature = "libm", feature = "libm_force"))]
687        impl SimdRealField for AutoSimd<$t> {
688            #[inline(always)]
689            fn simd_atan2(self, other: Self) -> Self {
690                self.zip_map(other, |x, y| x.simd_atan2(y))
691            }
692
693            #[inline(always)]
694            fn simd_copysign(self, sign: Self) -> Self {
695                self.zip_map(sign, |me, sgn| me.simd_copysign(sgn))
696            }
697
698            #[inline(always)]
699            fn simd_default_epsilon() -> Self {
700                Self::splat(<$elt>::default_epsilon())
701            }
702
703            #[inline(always)]
704            fn simd_pi() -> Self {
705                Self::splat(<$elt>::simd_pi())
706            }
707
708            #[inline(always)]
709            fn simd_two_pi() -> Self {
710                Self::splat(<$elt>::simd_two_pi())
711            }
712
713            #[inline(always)]
714            fn simd_frac_pi_2() -> Self {
715                Self::splat(<$elt>::simd_frac_pi_2())
716            }
717
718            #[inline(always)]
719            fn simd_frac_pi_3() -> Self {
720                Self::splat(<$elt>::simd_frac_pi_3())
721            }
722
723            #[inline(always)]
724            fn simd_frac_pi_4() -> Self {
725                Self::splat(<$elt>::simd_frac_pi_4())
726            }
727
728            #[inline(always)]
729            fn simd_frac_pi_6() -> Self {
730                Self::splat(<$elt>::simd_frac_pi_6())
731            }
732
733            #[inline(always)]
734            fn simd_frac_pi_8() -> Self {
735                Self::splat(<$elt>::simd_frac_pi_8())
736            }
737
738            #[inline(always)]
739            fn simd_frac_1_pi() -> Self {
740                Self::splat(<$elt>::simd_frac_1_pi())
741            }
742
743            #[inline(always)]
744            fn simd_frac_2_pi() -> Self {
745                Self::splat(<$elt>::simd_frac_2_pi())
746            }
747
748            #[inline(always)]
749            fn simd_frac_2_sqrt_pi() -> Self {
750                Self::splat(<$elt>::simd_frac_2_sqrt_pi())
751            }
752
753
754            #[inline(always)]
755            fn simd_e() -> Self {
756                Self::splat(<$elt>::simd_e())
757            }
758
759            #[inline(always)]
760            fn simd_log2_e() -> Self {
761                Self::splat(<$elt>::simd_log2_e())
762            }
763
764            #[inline(always)]
765            fn simd_log10_e() -> Self {
766                Self::splat(<$elt>::simd_log10_e() )
767            }
768
769            #[inline(always)]
770            fn simd_ln_2() -> Self {
771                Self::splat(<$elt>::simd_ln_2())
772            }
773
774            #[inline(always)]
775            fn simd_ln_10() -> Self {
776                Self::splat(<$elt>::simd_ln_10())
777            }
778        }
779
780        #[cfg(any(feature = "std", feature = "libm", feature = "libm_force"))]
781        impl SimdComplexField for AutoSimd<$t> {
782            type SimdRealField = Self;
783
784            #[inline(always)]
785            fn simd_horizontal_sum(self) -> Self::Element {
786                self.0.iter().sum()
787            }
788
789            #[inline(always)]
790            fn simd_horizontal_product(self) -> Self::Element {
791                self.0.iter().product()
792            }
793
794            #[inline(always)]
795            fn from_simd_real(re: Self::SimdRealField) -> Self {
796                re
797            }
798
799            #[inline(always)]
800            fn simd_real(self) -> Self::SimdRealField {
801                self
802            }
803
804            #[inline(always)]
805            fn simd_imaginary(self) -> Self::SimdRealField {
806                Self::zero()
807            }
808
809            #[inline(always)]
810            fn simd_norm1(self) -> Self::SimdRealField {
811                self.map(|x| x.simd_norm1())
812            }
813
814            #[inline(always)]
815            fn simd_modulus(self) -> Self::SimdRealField {
816                self.map(|x| x.simd_modulus())
817            }
818
819            #[inline(always)]
820            fn simd_modulus_squared(self) -> Self::SimdRealField {
821                self.map(|x| x.simd_modulus_squared())
822            }
823
824            #[inline(always)]
825            fn simd_argument(self) -> Self::SimdRealField {
826                self.map(|x| x.simd_argument())
827            }
828
829            #[inline(always)]
830            fn simd_to_exp(self) -> (Self::SimdRealField, Self) {
831                let ge = self.simd_ge(Self::one());
832                let exp = Self::one().select(ge, -Self::one());
833                (self * exp, exp)
834            }
835
836            #[inline(always)]
837            fn simd_recip(self) -> Self {
838                self.map(|x| x.simd_recip())
839            }
840
841            #[inline(always)]
842            fn simd_conjugate(self) -> Self {
843                self.map(|x| x.simd_conjugate())
844            }
845
846            #[inline(always)]
847            fn simd_scale(self, factor: Self::SimdRealField) -> Self {
848                self.zip_map(factor, |x, y| x.simd_scale(y))
849            }
850
851            #[inline(always)]
852            fn simd_unscale(self, factor: Self::SimdRealField) -> Self {
853                self.zip_map(factor, |x, y| x.simd_unscale(y))
854            }
855
856            #[inline(always)]
857            fn simd_floor(self) -> Self {
858                self.map(|e| e.simd_floor())
859            }
860
861            #[inline(always)]
862            fn simd_ceil(self) -> Self {
863                self.map(|e| e.simd_ceil())
864            }
865
866            #[inline(always)]
867            fn simd_round(self) -> Self {
868                self.map(|e| e.simd_round())
869            }
870
871            #[inline(always)]
872            fn simd_trunc(self) -> Self {
873                self.map(|e| e.simd_trunc())
874            }
875
876            #[inline(always)]
877            fn simd_fract(self) -> Self {
878                self.map(|e| e.simd_fract())
879            }
880
881            #[inline(always)]
882            fn simd_abs(self) -> Self {
883                self.map(|e| e.simd_abs())
884            }
885
886            #[inline(always)]
887            fn simd_signum(self) -> Self {
888                self.map(|e| e.simd_signum())
889            }
890
891            #[inline(always)]
892            fn simd_mul_add(self, a: Self, b: Self) -> Self {
893                self.zip_zip_map(a, b, |x, y, z| x.simd_mul_add(y, z))
894            }
895
896            #[inline(always)]
897            fn simd_powi(self, n: i32) -> Self {
898                self.map(|e| e.simd_powi(n))
899            }
900
901            #[inline(always)]
902            fn simd_powf(self, n: Self) -> Self {
903                self.zip_map(n, |x, y| x.simd_powf(y))
904            }
905
906            #[inline(always)]
907            fn simd_powc(self, n: Self) -> Self {
908                self.zip_map(n, |x, y| x.simd_powc(y))
909            }
910
911            #[inline(always)]
912            fn simd_sqrt(self) -> Self {
913                self.map(|x| x.simd_sqrt())
914            }
915
916            #[inline(always)]
917            fn simd_exp(self) -> Self {
918                self.map(|x| x.simd_exp())
919            }
920
921            #[inline(always)]
922            fn simd_exp2(self) -> Self {
923                self.map(|x| x.simd_exp2())
924            }
925
926
927            #[inline(always)]
928            fn simd_exp_m1(self) -> Self {
929                self.map(|x| x.simd_exp_m1())
930            }
931
932            #[inline(always)]
933            fn simd_ln_1p(self) -> Self {
934                self.map(|x| x.simd_ln_1p())
935            }
936
937            #[inline(always)]
938            fn simd_ln(self) -> Self {
939                self.map(|x| x.simd_ln())
940            }
941
942            #[inline(always)]
943            fn simd_log(self, base: Self) -> Self {
944                self.zip_map(base, |x, y| x.simd_log(y))
945            }
946
947            #[inline(always)]
948            fn simd_log2(self) -> Self {
949                self.map(|x| x.simd_log2())
950            }
951
952            #[inline(always)]
953            fn simd_log10(self) -> Self {
954                self.map(|x| x.simd_log10())
955            }
956
957            #[inline(always)]
958            fn simd_cbrt(self) -> Self {
959                self.map(|x| x.simd_cbrt())
960            }
961
962            #[inline(always)]
963            fn simd_hypot(self, other: Self) -> Self::SimdRealField {
964                self.zip_map(other, |x, y| x.simd_hypot(y))
965            }
966
967            #[inline(always)]
968            fn simd_sin(self) -> Self {
969                self.map(|x| x.simd_sin())
970            }
971
972            #[inline(always)]
973            fn simd_cos(self) -> Self {
974                self.map(|x| x.simd_cos())
975            }
976
977            #[inline(always)]
978            fn simd_tan(self) -> Self {
979                self.map(|x| x.simd_tan())
980            }
981
982            #[inline(always)]
983            fn simd_asin(self) -> Self {
984                self.map(|x| x.simd_asin())
985            }
986
987            #[inline(always)]
988            fn simd_acos(self) -> Self {
989                self.map(|x| x.simd_acos())
990            }
991
992            #[inline(always)]
993            fn simd_atan(self) -> Self {
994                self.map(|x| x.simd_atan())
995            }
996
997            #[inline(always)]
998            fn simd_sin_cos(self) -> (Self, Self) {
999                (self.simd_sin(), self.simd_cos())
1000            }
1001
1002//            #[inline(always)]
1003//            fn simd_exp_m1(self) -> Self {
1004//                $libm::exp_m1(self)
1005//            }
1006//
1007//            #[inline(always)]
1008//            fn simd_ln_1p(self) -> Self {
1009//                $libm::ln_1p(self)
1010//            }
1011//
1012            #[inline(always)]
1013            fn simd_sinh(self) -> Self {
1014                self.map(|x| x.simd_sinh())
1015            }
1016
1017            #[inline(always)]
1018            fn simd_cosh(self) -> Self {
1019                self.map(|x| x.simd_cosh())
1020            }
1021
1022            #[inline(always)]
1023            fn simd_tanh(self) -> Self {
1024                self.map(|x| x.simd_tanh())
1025            }
1026
1027            #[inline(always)]
1028            fn simd_asinh(self) -> Self {
1029                self.map(|x| x.simd_asinh())
1030            }
1031
1032            #[inline(always)]
1033            fn simd_acosh(self) -> Self {
1034                self.map(|x| x.simd_acosh())
1035            }
1036
1037            #[inline(always)]
1038            fn simd_atanh(self) -> Self {
1039                self.map(|x| x.simd_atanh())
1040            }
1041        }
1042
1043        // NOTE: most of the impls in there are copy-paste from the implementation of
1044        // ComplexField for num_complex::Complex. Unfortunately, we can't reuse the implementations
1045        // so easily.
1046        #[cfg(any(feature = "std", feature = "libm", feature = "libm_force"))]
1047        impl SimdComplexField for num_complex::Complex<AutoSimd<$t>> {
1048            type SimdRealField = AutoSimd<$t>;
1049
1050            #[inline(always)]
1051            fn simd_horizontal_sum(self) -> Self::Element {
1052                num_complex::Complex::new(self.re.simd_horizontal_sum(), self.im.simd_horizontal_sum())
1053            }
1054
1055            #[inline(always)]
1056            fn simd_horizontal_product(self) -> Self::Element {
1057                let mut prod = self.extract(0);
1058                for ii in 1..$lanes {
1059                    prod *= self.extract(ii)
1060                }
1061                prod
1062            }
1063
1064            #[inline]
1065            fn from_simd_real(re: Self::SimdRealField) -> Self {
1066                Self::new(re, Self::SimdRealField::zero())
1067            }
1068
1069            #[inline]
1070            fn simd_real(self) -> Self::SimdRealField {
1071                self.re
1072            }
1073
1074            #[inline]
1075            fn simd_imaginary(self) -> Self::SimdRealField {
1076                self.im
1077            }
1078
1079            #[inline]
1080            fn simd_argument(self) -> Self::SimdRealField {
1081                self.im.simd_atan2(self.re)
1082            }
1083
1084            #[inline]
1085            fn simd_modulus(self) -> Self::SimdRealField {
1086                self.re.simd_hypot(self.im)
1087            }
1088
1089            #[inline]
1090            fn simd_modulus_squared(self) -> Self::SimdRealField {
1091                self.re * self.re + self.im * self.im
1092            }
1093
1094            #[inline]
1095            fn simd_norm1(self) -> Self::SimdRealField {
1096                self.re.simd_abs() + self.im.simd_abs()
1097            }
1098
1099            #[inline]
1100            fn simd_recip(self) -> Self {
1101                Self::one() / self
1102            }
1103
1104            #[inline]
1105            fn simd_conjugate(self) -> Self {
1106                self.conj()
1107            }
1108
1109            #[inline]
1110            fn simd_scale(self, factor: Self::SimdRealField) -> Self {
1111                self * factor
1112            }
1113
1114            #[inline]
1115            fn simd_unscale(self, factor: Self::SimdRealField) -> Self {
1116                self / factor
1117            }
1118
1119            #[inline]
1120            fn simd_floor(self) -> Self {
1121                Self::new(self.re.simd_floor(), self.im.simd_floor())
1122            }
1123
1124            #[inline]
1125            fn simd_ceil(self) -> Self {
1126                Self::new(self.re.simd_ceil(), self.im.simd_ceil())
1127            }
1128
1129            #[inline]
1130            fn simd_round(self) -> Self {
1131                Self::new(self.re.simd_round(), self.im.simd_round())
1132            }
1133
1134            #[inline]
1135            fn simd_trunc(self) -> Self {
1136                Self::new(self.re.simd_trunc(), self.im.simd_trunc())
1137            }
1138
1139            #[inline]
1140            fn simd_fract(self) -> Self {
1141                Self::new(self.re.simd_fract(), self.im.simd_fract())
1142            }
1143
1144            #[inline]
1145            fn simd_mul_add(self, a: Self, b: Self) -> Self {
1146                self * a + b
1147            }
1148
1149            #[inline]
1150            fn simd_abs(self) -> Self::SimdRealField {
1151                self.simd_modulus()
1152            }
1153
1154            #[inline]
1155            fn simd_exp2(self) -> Self {
1156                let _2 = AutoSimd::<$t>::one() + AutoSimd::<$t>::one();
1157                num_complex::Complex::new(_2, AutoSimd::<$t>::zero()).simd_powc(self)
1158            }
1159
1160            #[inline]
1161            fn simd_exp_m1(self) -> Self {
1162                self.simd_exp() - Self::one()
1163            }
1164
1165            #[inline]
1166            fn simd_ln_1p(self) -> Self {
1167                (Self::one() + self).simd_ln()
1168            }
1169
1170            #[inline]
1171            fn simd_log2(self) -> Self {
1172                let _2 = AutoSimd::<$t>::one() + AutoSimd::<$t>::one();
1173                self.simd_log(_2)
1174            }
1175
1176            #[inline]
1177            fn simd_log10(self) -> Self {
1178                let _10 = AutoSimd::<$t>::from_subset(&10.0f64);
1179                self.simd_log(_10)
1180            }
1181
1182            #[inline]
1183            fn simd_cbrt(self) -> Self {
1184                let one_third = AutoSimd::<$t>::from_subset(&(1.0 / 3.0));
1185                self.simd_powf(one_third)
1186            }
1187
1188            #[inline]
1189            fn simd_powi(self, n: i32) -> Self {
1190                // TODO: is there a more accurate solution?
1191                let n = AutoSimd::<$t>::from_subset(&(n as f64));
1192                self.simd_powf(n)
1193            }
1194
1195            /*
1196             *
1197             *
1198             * Unfortunately we are forced to copy-paste all
1199             * those impls from https://github.com/rust-num/num-complex/blob/master/src/lib.rs
1200             * to avoid requiring `std`.
1201             *
1202             *
1203             */
1204            /// Computes `e^(self)`, where `e` is the base of the natural logarithm.
1205            #[inline]
1206            fn simd_exp(self) -> Self {
1207                // formula: e^(a + bi) = e^a (cos(b) + i*sin(b))
1208                // = from_polar(e^a, b)
1209                simd_complex_from_polar(self.re.simd_exp(), self.im)
1210            }
1211
1212            /// Computes the principal value of natural logarithm of `self`.
1213            ///
1214            /// This function has one branch cut:
1215            ///
1216            /// * `(-∞, 0]`, continuous from above.
1217            ///
1218            /// The branch satisfies `-π ≤ arg(ln(z)) ≤ π`.
1219            #[inline]
1220            fn simd_ln(self) -> Self {
1221                // formula: ln(z) = ln|z| + i*arg(z)
1222                let (r, theta) = self.simd_to_polar();
1223                Self::new(r.simd_ln(), theta)
1224            }
1225
1226            /// Computes the principal value of the square root of `self`.
1227            ///
1228            /// This function has one branch cut:
1229            ///
1230            /// * `(-∞, 0)`, continuous from above.
1231            ///
1232            /// The branch satisfies `-π/2 ≤ arg(sqrt(z)) ≤ π/2`.
1233            #[inline]
1234            fn simd_sqrt(self) -> Self {
1235                // formula: sqrt(r e^(it)) = sqrt(r) e^(it/2)
1236                let two = AutoSimd::<$t>::one() + AutoSimd::<$t>::one();
1237                let (r, theta) = self.simd_to_polar();
1238                simd_complex_from_polar(r.simd_sqrt(), theta / two)
1239            }
1240
1241            #[inline]
1242            fn simd_hypot(self, b: Self) -> Self::SimdRealField {
1243                (self.simd_modulus_squared() + b.simd_modulus_squared()).simd_sqrt()
1244            }
1245
1246            /// Raises `self` to a floating point power.
1247            #[inline]
1248            fn simd_powf(self, exp: Self::SimdRealField) -> Self {
1249                // formula: x^y = (ρ e^(i θ))^y = ρ^y e^(i θ y)
1250                // = from_polar(ρ^y, θ y)
1251                let (r, theta) = self.simd_to_polar();
1252                simd_complex_from_polar(r.simd_powf(exp), theta * exp)
1253            }
1254
1255            /// Returns the logarithm of `self` with respect to an arbitrary base.
1256            #[inline]
1257            fn simd_log(self, base: AutoSimd<$t>) -> Self {
1258                // formula: log_y(x) = log_y(ρ e^(i θ))
1259                // = log_y(ρ) + log_y(e^(i θ)) = log_y(ρ) + ln(e^(i θ)) / ln(y)
1260                // = log_y(ρ) + i θ / ln(y)
1261                let (r, theta) = self.simd_to_polar();
1262                Self::new(r.simd_log(base), theta / base.simd_ln())
1263            }
1264
1265            /// Raises `self` to a complex power.
1266            #[inline]
1267            fn simd_powc(self, exp: Self) -> Self {
1268                // formula: x^y = (a + i b)^(c + i d)
1269                // = (ρ e^(i θ))^c (ρ e^(i θ))^(i d)
1270                //    where ρ=|x| and θ=arg(x)
1271                // = ρ^c e^(−d θ) e^(i c θ) ρ^(i d)
1272                // = p^c e^(−d θ) (cos(c θ)
1273                //   + i sin(c θ)) (cos(d ln(ρ)) + i sin(d ln(ρ)))
1274                // = p^c e^(−d θ) (
1275                //   cos(c θ) cos(d ln(ρ)) − sin(c θ) sin(d ln(ρ))
1276                //   + i(cos(c θ) sin(d ln(ρ)) + sin(c θ) cos(d ln(ρ))))
1277                // = p^c e^(−d θ) (cos(c θ + d ln(ρ)) + i sin(c θ + d ln(ρ)))
1278                // = from_polar(p^c e^(−d θ), c θ + d ln(ρ))
1279                let (r, theta) = self.simd_to_polar();
1280                simd_complex_from_polar(
1281                    r.simd_powf(exp.re) * (-exp.im * theta).simd_exp(),
1282                    exp.re * theta + exp.im * r.simd_ln(),
1283                )
1284            }
1285
1286            /*
1287            /// Raises a floating point number to the complex power `self`.
1288            #[inline]
1289            fn simd_expf(&self, base: T) -> Self {
1290                // formula: x^(a+bi) = x^a x^bi = x^a e^(b ln(x) i)
1291                // = from_polar(x^a, b ln(x))
1292                Self::from_polar(&base.powf(self.re), &(self.im * base.ln()))
1293            }
1294            */
1295
1296            /// Computes the sine of `self`.
1297            #[inline]
1298            fn simd_sin(self) -> Self {
1299                // formula: sin(a + bi) = sin(a)cosh(b) + i*cos(a)sinh(b)
1300                Self::new(
1301                    self.re.simd_sin() * self.im.simd_cosh(),
1302                    self.re.simd_cos() * self.im.simd_sinh(),
1303                )
1304            }
1305
1306            /// Computes the cosine of `self`.
1307            #[inline]
1308            fn simd_cos(self) -> Self {
1309                // formula: cos(a + bi) = cos(a)cosh(b) - i*sin(a)sinh(b)
1310                Self::new(
1311                    self.re.simd_cos() * self.im.simd_cosh(),
1312                    -self.re.simd_sin() * self.im.simd_sinh(),
1313                )
1314            }
1315
1316            #[inline]
1317            fn simd_sin_cos(self) -> (Self, Self) {
1318                let (rsin, rcos) = self.re.simd_sin_cos();
1319                let (isinh, icosh) = self.im.simd_sinh_cosh();
1320                let sin = Self::new(rsin * icosh, rcos * isinh);
1321                let cos = Self::new(rcos * icosh, -rsin * isinh);
1322
1323                (sin, cos)
1324            }
1325
1326            /// Computes the tangent of `self`.
1327            #[inline]
1328            fn simd_tan(self) -> Self {
1329                // formula: tan(a + bi) = (sin(2a) + i*sinh(2b))/(cos(2a) + cosh(2b))
1330                let (two_re, two_im) = (self.re + self.re, self.im + self.im);
1331                Self::new(two_re.simd_sin(), two_im.simd_sinh()).unscale(two_re.simd_cos() + two_im.simd_cosh())
1332            }
1333
1334            /// Computes the principal value of the inverse sine of `self`.
1335            ///
1336            /// This function has two branch cuts:
1337            ///
1338            /// * `(-∞, -1)`, continuous from above.
1339            /// * `(1, ∞)`, continuous from below.
1340            ///
1341            /// The branch satisfies `-π/2 ≤ Re(asin(z)) ≤ π/2`.
1342            #[inline]
1343            fn simd_asin(self) -> Self {
1344                // formula: arcsin(z) = -i ln(sqrt(1-z^2) + iz)
1345                let i = Self::i();
1346                -i * ((Self::one() - self * self).simd_sqrt() + i * self).simd_ln()
1347            }
1348
1349            /// Computes the principal value of the inverse cosine of `self`.
1350            ///
1351            /// This function has two branch cuts:
1352            ///
1353            /// * `(-∞, -1)`, continuous from above.
1354            /// * `(1, ∞)`, continuous from below.
1355            ///
1356            /// The branch satisfies `0 ≤ Re(acos(z)) ≤ π`.
1357            #[inline]
1358            fn simd_acos(self) -> Self {
1359                // formula: arccos(z) = -i ln(i sqrt(1-z^2) + z)
1360                let i = Self::i();
1361                -i * (i * (Self::one() - self * self).simd_sqrt() + self).simd_ln()
1362            }
1363
1364            /// Computes the principal value of the inverse tangent of `self`.
1365            ///
1366            /// This function has two branch cuts:
1367            ///
1368            /// * `(-∞i, -i]`, continuous from the left.
1369            /// * `[i, ∞i)`, continuous from the right.
1370            ///
1371            /// The branch satisfies `-π/2 ≤ Re(atan(z)) ≤ π/2`.
1372            #[inline]
1373            fn simd_atan(self) -> Self {
1374                // formula: arctan(z) = (ln(1+iz) - ln(1-iz))/(2i)
1375                let i = Self::i();
1376                let one = Self::one();
1377                let two = one + one;
1378
1379                if self == i {
1380                    return Self::new(AutoSimd::<$t>::zero(), AutoSimd::<$t>::one() / AutoSimd::<$t>::zero());
1381                } else if self == -i {
1382                    return Self::new(AutoSimd::<$t>::zero(), -AutoSimd::<$t>::one() / AutoSimd::<$t>::zero());
1383                }
1384
1385                ((one + i * self).simd_ln() - (one - i * self).simd_ln()) / (two * i)
1386            }
1387
1388            /// Computes the hyperbolic sine of `self`.
1389            #[inline]
1390            fn simd_sinh(self) -> Self {
1391                // formula: sinh(a + bi) = sinh(a)cos(b) + i*cosh(a)sin(b)
1392                Self::new(
1393                    self.re.simd_sinh() * self.im.simd_cos(),
1394                    self.re.simd_cosh() * self.im.simd_sin(),
1395                )
1396            }
1397
1398            /// Computes the hyperbolic cosine of `self`.
1399            #[inline]
1400            fn simd_cosh(self) -> Self {
1401                // formula: cosh(a + bi) = cosh(a)cos(b) + i*sinh(a)sin(b)
1402                Self::new(
1403                    self.re.simd_cosh() * self.im.simd_cos(),
1404                    self.re.simd_sinh() * self.im.simd_sin(),
1405                )
1406            }
1407
1408            #[inline]
1409            fn simd_sinh_cosh(self) -> (Self, Self) {
1410                let (rsinh, rcosh) = self.re.simd_sinh_cosh();
1411                let (isin, icos) = self.im.simd_sin_cos();
1412                let sin = Self::new(rsinh * icos, rcosh * isin);
1413                let cos = Self::new(rcosh * icos, rsinh * isin);
1414
1415                (sin, cos)
1416            }
1417
1418            /// Computes the hyperbolic tangent of `self`.
1419            #[inline]
1420            fn simd_tanh(self) -> Self {
1421                // formula: tanh(a + bi) = (sinh(2a) + i*sin(2b))/(cosh(2a) + cos(2b))
1422                let (two_re, two_im) = (self.re + self.re, self.im + self.im);
1423                Self::new(two_re.simd_sinh(), two_im.simd_sin()).unscale(two_re.simd_cosh() + two_im.simd_cos())
1424            }
1425
1426            /// Computes the principal value of inverse hyperbolic sine of `self`.
1427            ///
1428            /// This function has two branch cuts:
1429            ///
1430            /// * `(-∞i, -i)`, continuous from the left.
1431            /// * `(i, ∞i)`, continuous from the right.
1432            ///
1433            /// The branch satisfies `-π/2 ≤ Im(asinh(z)) ≤ π/2`.
1434            #[inline]
1435            fn simd_asinh(self) -> Self {
1436                // formula: arcsinh(z) = ln(z + sqrt(1+z^2))
1437                let one = Self::one();
1438                (self + (one + self * self).simd_sqrt()).simd_ln()
1439            }
1440
1441            /// Computes the principal value of inverse hyperbolic cosine of `self`.
1442            ///
1443            /// This function has one branch cut:
1444            ///
1445            /// * `(-∞, 1)`, continuous from above.
1446            ///
1447            /// The branch satisfies `-π ≤ Im(acosh(z)) ≤ π` and `0 ≤ Re(acosh(z)) < ∞`.
1448            #[inline]
1449            fn simd_acosh(self) -> Self {
1450                // formula: arccosh(z) = 2 ln(sqrt((z+1)/2) + sqrt((z-1)/2))
1451                let one = Self::one();
1452                let two = one + one;
1453                two * (((self + one) / two).simd_sqrt() + ((self - one) / two).simd_sqrt()).simd_ln()
1454            }
1455
1456            /// Computes the principal value of inverse hyperbolic tangent of `self`.
1457            ///
1458            /// This function has two branch cuts:
1459            ///
1460            /// * `(-∞, -1]`, continuous from above.
1461            /// * `[1, ∞)`, continuous from below.
1462            ///
1463            /// The branch satisfies `-π/2 ≤ Im(atanh(z)) ≤ π/2`.
1464            #[inline]
1465            fn simd_atanh(self) -> Self {
1466                // formula: arctanh(z) = (ln(1+z) - ln(1-z))/2
1467                let one = Self::one();
1468                let two = one + one;
1469                if self == one {
1470                    return Self::new(AutoSimd::<$t>::one() / AutoSimd::<$t>::zero(), AutoSimd::<$t>::zero());
1471                } else if self == -one {
1472                    return Self::new(-AutoSimd::<$t>::one() / AutoSimd::<$t>::zero(), AutoSimd::<$t>::zero());
1473                }
1474                ((one + self).simd_ln() - (one - self).simd_ln()) / two
1475            }
1476        }
1477    )*)
1478);
1479
1480#[inline]
1481fn simd_complex_from_polar<N: SimdRealField>(r: N, theta: N) -> num_complex::Complex<N> {
1482    num_complex::Complex::new(r.clone() * theta.clone().simd_cos(), r * theta.simd_sin())
1483}
1484
1485impl_float_simd!(
1486    [f32; 2], f32, 2, [i32; 2], AutoBoolx2, _0, _1;
1487    [f32; 4], f32, 4, [i32; 4], AutoBoolx4, _0, _1, _2, _3;
1488    [f32; 8], f32, 8, [i32; 8], AutoBoolx8, _0, _1, _2, _3, _4, _5, _6, _7;
1489    [f32; 16], f32, 16, [i32; 16], AutoBoolx16, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15;
1490    [f64; 2], f64, 2, [i64; 2], AutoBoolx2, _0, _1;
1491    [f64; 4], f64, 4, [i64; 4], AutoBoolx4, _0, _1, _2, _3;
1492    [f64; 8], f64, 8, [i64; 8], AutoBoolx8, _0, _1, _2, _3, _4, _5, _6, _7;
1493);
1494
1495impl_int_simd!(
1496    [i128; 1], i128, 1, AutoBoolx1, _0;
1497    [i128; 2], i128, 2, AutoBoolx2, _0, _1;
1498    [i128; 4], i128, 4, AutoBoolx4, _0, _1, _2, _3;
1499    [i16; 2], i16, 2, AutoBoolx2, _0, _1;
1500    [i16; 4], i16, 4, AutoBoolx4, _0, _1, _2, _3;
1501    [i16; 8], i16, 8, AutoBoolx8, _0, _1, _2, _3, _4, _5, _6, _7;
1502    [i16; 16], i16, 16, AutoBoolx16, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15;
1503    [i16; 32], i16, 32, AutoBoolx32, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31;
1504    [i32; 2], i32, 2, AutoBoolx2, _0, _1;
1505    [i32; 4], i32, 4, AutoBoolx4, _0, _1, _2, _3;
1506    [i32; 8], i32, 8, AutoBoolx8, _0, _1, _2, _3, _4, _5, _6, _7;
1507    [i32; 16], i32, 16, AutoBoolx16, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15;
1508    [i64; 2], i64, 2, AutoBoolx2, _0, _1;
1509    [i64; 4], i64, 4, AutoBoolx4, _0, _1, _2, _3;
1510    [i64; 8], i64, 8, AutoBoolx8, _0, _1, _2, _3, _4, _5, _6, _7;
1511    [i8; 2], i8, 2, AutoBoolx2, _0, _1;
1512    [i8; 4], i8, 4, AutoBoolx4, _0, _1, _2, _3;
1513    [i8; 8], i8, 8, AutoBoolx8, _0, _1, _2, _3, _4, _5, _6, _7;
1514    [i8; 16], i8, 16, AutoBoolx16, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15;
1515    [i8; 32], i8, 32, AutoBoolx32, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31;
1516    // [i8; 64], i8, 64, AutoBoolx64, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63;
1517    [isize; 2], isize, 2, AutoBoolx2, _0, _1;
1518    [isize; 4], isize, 4, AutoBoolx4, _0, _1, _2, _3;
1519    [isize; 8], isize, 8, AutoBoolx8, _0, _1, _2, _3, _4, _5, _6, _7;
1520);
1521
1522impl_uint_simd!(
1523    [u128; 1], u128, 1, AutoBoolx1, _0;
1524    [u128; 2], u128, 2, AutoBoolx2, _0, _1;
1525    [u128; 4], u128, 4, AutoBoolx4, _0, _1, _2, _3;
1526    [u16; 2], u16, 2, AutoBoolx2, _0, _1;
1527    [u16; 4], u16, 4, AutoBoolx4, _0, _1, _2, _3;
1528    [u16; 8], u16, 8, AutoBoolx8, _0, _1, _2, _3, _4, _5, _6, _7;
1529    [u16; 16], u16, 16, AutoBoolx16, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15;
1530    [u16; 32], u16, 32, AutoBoolx32, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31;
1531    [u32; 2], u32, 2, AutoBoolx2, _0, _1;
1532    [u32; 4], u32, 4, AutoBoolx4, _0, _1, _2, _3;
1533    [u32; 8], u32, 8, AutoBoolx8, _0, _1, _2, _3, _4, _5, _6, _7;
1534    [u32; 16], u32, 16, AutoBoolx16, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15;
1535    [u64; 2], u64, 2, AutoBoolx2, _0, _1;
1536    [u64; 4], u64, 4, AutoBoolx4, _0, _1, _2, _3;
1537    [u64; 8], u64, 8, AutoBoolx8, _0, _1, _2, _3, _4, _5, _6, _7;
1538    [u8; 2], u8, 2, AutoBoolx2, _0, _1;
1539    [u8; 4], u8, 4, AutoBoolx4, _0, _1, _2, _3;
1540    [u8; 8], u8, 8, AutoBoolx8, _0, _1, _2, _3, _4, _5, _6, _7;
1541    [u8; 16], u8, 16, AutoBoolx16, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15;
1542    [u8; 32], u8, 32, AutoBoolx32, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31;
1543    // [u8; 64], u8, 64, AutoBoolx64, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63;
1544    [usize; 2], usize, 2, AutoBoolx2, _0, _1;
1545    [usize; 4], usize, 4, AutoBoolx4, _0, _1, _2, _3;
1546    [usize; 8], usize, 8, AutoBoolx8, _0, _1, _2, _3, _4, _5, _6, _7;
1547);
1548
1549impl_bool_simd!(
1550    [bool; 1], 1, _0;
1551    [bool; 2], 2, _0, _1;
1552    [bool; 4], 4, _0, _1, _2, _3;
1553    [bool; 8], 8, _0, _1, _2, _3, _4, _5, _6, _7;
1554    [bool; 16], 16, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15;
1555    [bool; 32], 32, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31;
1556    // [bool; 64], 64, 0, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63;
1557);
1558
1559//
1560// NOTE: the following does not work because of the orphan rules.
1561//
1562//macro_rules! impl_simd_complex_from(
1563//    ($($t: ty, $elt: ty $(, $i: expr)*;)*) => ($(
1564//        impl From<[num_complex::Complex<$elt>; $lanes]> for num_complex::Complex<AutoSimd<$t>> {
1565//            #[inline(always)]
1566//            fn from(vals: [num_complex::Complex<$elt>; $lanes]) -> Self {
1567//                num_complex::Complex {
1568//                    re: <$t>::from([$(vals[$i].re),*]),
1569//                    im: <$t>::from([$(vals[$i].im),*]),
1570//                }
1571//            }
1572//        }
1573//    )*)
1574//);
1575//
1576//impl_simd_complex_from!(
1577//    [f32; 2], f32, 0, 1;
1578//    [f32; 4], f32, 0, 1, 2, 3;
1579//    [f32; 8], f32, 0, 1, 2, 3, 4, 5, 6, 7;
1580//    [f32; 16], f32, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15;
1581//);
1582
1583//////////////////////////////////////////
1584//               Aliases                //
1585//////////////////////////////////////////
1586
1587pub type AutoF32x2 = AutoSimd<[f32; 2]>;
1588pub type AutoF32x4 = AutoSimd<[f32; 4]>;
1589pub type AutoF32x8 = AutoSimd<[f32; 8]>;
1590pub type AutoF32x16 = AutoSimd<[f32; 16]>;
1591pub type AutoF64x2 = AutoSimd<[f64; 2]>;
1592pub type AutoF64x4 = AutoSimd<[f64; 4]>;
1593pub type AutoF64x8 = AutoSimd<[f64; 8]>;
1594pub type AutoI128x1 = AutoSimd<[i128; 1]>;
1595pub type AutoI128x2 = AutoSimd<[i128; 2]>;
1596pub type AutoI128x4 = AutoSimd<[i128; 4]>;
1597pub type AutoI16x2 = AutoSimd<[i16; 2]>;
1598pub type AutoI16x4 = AutoSimd<[i16; 4]>;
1599pub type AutoI16x8 = AutoSimd<[i16; 8]>;
1600pub type AutoI16x16 = AutoSimd<[i16; 16]>;
1601pub type AutoI16x32 = AutoSimd<[i16; 32]>;
1602pub type AutoI32x2 = AutoSimd<[i32; 2]>;
1603pub type AutoI32x4 = AutoSimd<[i32; 4]>;
1604pub type AutoI32x8 = AutoSimd<[i32; 8]>;
1605pub type AutoI32x16 = AutoSimd<[i32; 16]>;
1606pub type AutoI64x2 = AutoSimd<[i64; 2]>;
1607pub type AutoI64x4 = AutoSimd<[i64; 4]>;
1608pub type AutoI64x8 = AutoSimd<[i64; 8]>;
1609pub type AutoI8x2 = AutoSimd<[i8; 2]>;
1610pub type AutoI8x4 = AutoSimd<[i8; 4]>;
1611pub type AutoI8x8 = AutoSimd<[i8; 8]>;
1612pub type AutoI8x16 = AutoSimd<[i8; 16]>;
1613pub type AutoI8x32 = AutoSimd<[i8; 32]>;
1614// pub type AutoI8x64 = AutoSimd<[i8; 64]>;
1615pub type AutoIsizex2 = AutoSimd<[isize; 2]>;
1616pub type AutoIsizex4 = AutoSimd<[isize; 4]>;
1617pub type AutoIsizex8 = AutoSimd<[isize; 8]>;
1618pub type AutoU128x1 = AutoSimd<[u128; 1]>;
1619pub type AutoU128x2 = AutoSimd<[u128; 2]>;
1620pub type AutoU128x4 = AutoSimd<[u128; 4]>;
1621pub type AutoU16x2 = AutoSimd<[u16; 2]>;
1622pub type AutoU16x4 = AutoSimd<[u16; 4]>;
1623pub type AutoU16x8 = AutoSimd<[u16; 8]>;
1624pub type AutoU16x16 = AutoSimd<[u16; 16]>;
1625pub type AutoU16x32 = AutoSimd<[u16; 32]>;
1626pub type AutoU32x2 = AutoSimd<[u32; 2]>;
1627pub type AutoU32x4 = AutoSimd<[u32; 4]>;
1628pub type AutoU32x8 = AutoSimd<[u32; 8]>;
1629pub type AutoU32x16 = AutoSimd<[u32; 16]>;
1630pub type AutoU64x2 = AutoSimd<[u64; 2]>;
1631pub type AutoU64x4 = AutoSimd<[u64; 4]>;
1632pub type AutoU64x8 = AutoSimd<[u64; 8]>;
1633pub type AutoU8x2 = AutoSimd<[u8; 2]>;
1634pub type AutoU8x4 = AutoSimd<[u8; 4]>;
1635pub type AutoU8x8 = AutoSimd<[u8; 8]>;
1636pub type AutoU8x16 = AutoSimd<[u8; 16]>;
1637pub type AutoU8x32 = AutoSimd<[u8; 32]>;
1638// pub type AutoU8x64 = AutoSimd<[u8; 64]>;
1639pub type AutoUsizex2 = AutoSimd<[usize; 2]>;
1640pub type AutoUsizex4 = AutoSimd<[usize; 4]>;
1641pub type AutoUsizex8 = AutoSimd<[usize; 8]>;
1642
1643pub type AutoBoolx1 = AutoSimd<[bool; 1]>;
1644pub type AutoBoolx16 = AutoSimd<[bool; 16]>;
1645pub type AutoBoolx2 = AutoSimd<[bool; 2]>;
1646pub type AutoBoolx32 = AutoSimd<[bool; 32]>;
1647pub type AutoBoolx4 = AutoSimd<[bool; 4]>;
1648// pub type AutoBoolx64 = AutoSimd<[bool; 64]>;
1649pub type AutoBoolx8 = AutoSimd<[bool; 8]>;
1650
1651/*
1652 * Helper trait to transform an array.
1653 */
1654trait ArrTransform: SimdValue {
1655    fn map(self, f: impl Fn(Self::Element) -> Self::Element) -> Self;
1656    fn zip_map(
1657        self,
1658        other: Self,
1659        f: impl Fn(Self::Element, Self::Element) -> Self::Element,
1660    ) -> Self;
1661    fn zip_zip_map(
1662        self,
1663        b: Self,
1664        c: Self,
1665        f: impl Fn(Self::Element, Self::Element, Self::Element) -> Self::Element,
1666    ) -> Self;
1667    fn map_bool(self, f: impl Fn(Self::Element) -> bool) -> Self::SimdBool;
1668    fn zip_map_bool(
1669        self,
1670        other: Self,
1671        f: impl Fn(Self::Element, Self::Element) -> bool,
1672    ) -> Self::SimdBool;
1673}