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