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