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