1use core::marker::PhantomData;
27use core::ops::{Add, Div, Mul, Rem, Sub};
28
29use num_traits::Bounded;
30
31use thermite::Swizzle;
32use thermite::element::{Element, FloatElement, SignedElement};
33use thermite::generic_array::{GenericArray, IntoArrayLength, typenum::Const};
34use thermite::mask::{GenericMask, GenericSelectable};
35use thermite::math::algorithms::reduce_in_place;
36use thermite::register::SwizzleIndices;
37use thermite::vector::ops::{AddSubExt, AddSubExtMasked, NegMasked, Square, SquareMasked};
38use thermite::vector::{NewConst, NewVector, SplatConst, SplatVector, VectorValue, const_new, const_splat};
39use thermite::{LargeInt, prelude::*};
40
41use crate::{Dual, DualValue};
42
43macro_rules! array_each {
48 ([$init:expr; $n:expr], |$j:ident| $body:expr) => {{
49 let mut out = [$init; $n];
50 let mut $j = 0usize;
51 while $j < $n {
52 out[$j] = $body;
53 $j += 1;
54 }
55 out
56 }};
57}
58
59pub trait DualFloatVector: DualValue + FloatVector<Element: DualValue> + CastVector<Self> + SwizzleVector {}
65impl<V> DualFloatVector for V where V: DualValue + FloatVector<Element: DualValue> + CastVector<V> + SwizzleVector {}
66
67impl<V: DualFloatVector, const N: usize> Swizzle<V::Lanes> for Dual<V, N> {
71 #[inline(always)]
72 fn swizzle(self, other: Self, indices: GenericArray<u32, V::Lanes>) -> Self {
73 let mut out = Self {
74 re: self.re.swizzle(other.re, indices.clone()),
75 dual: [V::ZERO; N],
76 };
77 let mut i = 0;
78 while i < N {
79 out.dual[i] = self.dual[i].swizzle(other.dual[i], indices.clone());
80 i += 1;
81 }
82 out
83 }
84
85 #[inline(always)]
86 fn permute(self, indices: GenericArray<u32, V::Lanes>) -> Self {
87 let mut out = Self {
88 re: self.re.permute(indices.clone()),
89 dual: [V::ZERO; N],
90 };
91 let mut i = 0;
92 while i < N {
93 out.dual[i] = self.dual[i].permute(indices.clone());
94 i += 1;
95 }
96 out
97 }
98
99 #[inline(always)]
104 fn swizzle_const<I: SwizzleIndices<V::Lanes>>(self, other: Self) -> Self {
105 let mut out = Self {
106 re: self.re.swizzle_const::<I>(other.re),
107 dual: [V::ZERO; N],
108 };
109 let mut i = 0;
110 while i < N {
111 out.dual[i] = self.dual[i].swizzle_const::<I>(other.dual[i]);
112 i += 1;
113 }
114 out
115 }
116
117 #[inline(always)]
118 fn permute_const<I: SwizzleIndices<V::Lanes>>(self) -> Self {
119 let mut out = Self {
120 re: self.re.permute_const::<I>(),
121 dual: [V::ZERO; N],
122 };
123 let mut i = 0;
124 while i < N {
125 out.dual[i] = self.dual[i].permute_const::<I>();
126 i += 1;
127 }
128 out
129 }
130}
131
132#[rustfmt::skip]
137impl<E: DualValue + Element, const N: usize> Element for Dual<E, N> {
138 type Signed = <E as Element>::Signed;
139 type Unsigned = <E as Element>::Unsigned;
140
141 const ZERO: Self = Self::ZERO;
142 const ONE: Self = Self::ONE;
143
144 const ORDER_MAX: Self = Self::constant(E::ORDER_MAX);
148 const ORDER_MIN: Self = Self::constant(E::ORDER_MIN);
149 const HAS_UNORDERED: bool = E::HAS_UNORDERED;
150 const IS_FLOAT: bool = E::IS_FLOAT;
151
152 #[inline(always)] fn from_i8(value: i8) -> Self { Self::constant(E::from_i8(value)) }
153 #[inline(always)] fn from_u8(value: u8) -> Self { Self::constant(E::from_u8(value)) }
154 #[inline(always)] fn from_u16(value: u16) -> Self { Self::constant(E::from_u16(value)) }
155}
156
157impl<E: DualValue + SignedElement, const N: usize> SignedElement for Dual<E, N> {
158 #[inline(always)]
159 fn abs(self) -> Self {
160 if self.re < E::ZERO { -self } else { self }
161 }
162
163 #[inline(always)]
164 fn signum(self) -> Self {
165 Self::constant(self.re.signum())
166 }
167}
168
169pub struct DualIntConst<E, const DN: usize, const VAL: LargeInt>(PhantomData<E>);
172
173pub struct DualRatioConst<E, const DN: usize, const NUM: LargeInt, const DEN: LargeInt>(PhantomData<E>);
176
177impl<E: DualValue + FloatElement, const DN: usize, const VAL: LargeInt> SplatConst<Dual<E, DN>>
178 for DualIntConst<E, DN, VAL>
179{
180 const VALUE: Dual<E, DN> = Dual::constant(<E::ConstInt<VAL> as SplatConst<E>>::VALUE);
181}
182
183impl<E: DualValue + FloatElement, const DN: usize, const NUM: LargeInt, const DEN: LargeInt> SplatConst<Dual<E, DN>>
184 for DualRatioConst<E, DN, NUM, DEN>
185{
186 const VALUE: Dual<E, DN> = Dual::constant(<E::ConstRatio<NUM, DEN> as SplatConst<E>>::VALUE);
187}
188
189#[rustfmt::skip]
190impl<E: DualValue + FloatElement, const N: usize> FloatElement for Dual<E, N> {
191 #[inline(always)]
192 fn sqrt(this: Self) -> Self {
193 let s = E::sqrt(this.re);
194 let factor = E::VAL_ONE / (s + s);
196 this.chain(s, factor)
197 }
198
199 #[inline(always)] fn floor(this: Self) -> Self { Self::constant(E::floor(this.re)) }
200 #[inline(always)] fn ceil(this: Self) -> Self { Self::constant(E::ceil(this.re)) }
201 #[inline(always)] fn round(this: Self) -> Self { Self::constant(E::round(this.re)) }
202 #[inline(always)] fn trunc(this: Self) -> Self { Self::constant(E::trunc(this.re)) }
203
204 #[inline(always)] fn next_up(this: Self) -> Self { Self { re: E::next_up(this.re), dual: this.dual } }
206 #[inline(always)] fn next_down(this: Self) -> Self { Self { re: E::next_down(this.re), dual: this.dual } }
207
208 #[inline(always)]
209 fn try_from_int(value: LargeInt) -> Option<Self> {
210 E::try_from_int(value).map(Self::constant)
211 }
212
213 #[inline(always)]
214 fn try_from_ratio(n: LargeInt, d: LargeInt) -> Option<Self> {
215 E::try_from_ratio(n, d).map(Self::constant)
216 }
217
218 const HAS_INFINITY: bool = E::HAS_INFINITY;
219 const HAS_SIGNED_ZERO: bool = E::HAS_SIGNED_ZERO;
220 const HAS_SUBNORMALS: bool = E::HAS_SUBNORMALS;
221
222 type ConstInt<const VAL: LargeInt> = DualIntConst<E, N, VAL>;
223 type ConstRatio<const NUM: LargeInt, const DEN: LargeInt> = DualRatioConst<E, N, NUM, DEN>;
224}
225
226impl<V: DualValue, const N: usize> thermite::const_default::ConstDefault for Dual<V, N> {
231 const DEFAULT: Self = Self::ZERO;
232}
233
234macro_rules! impl_float_consts {
235 ($($name:ident),* $(,)?) => {
236 impl<V: DualValue + thermite::math::FloatConsts, const N: usize> thermite::math::FloatConsts for Dual<V, N> {
237 $(const $name: Self = Self::constant(<V as thermite::math::FloatConsts>::$name);)*
238 }
239 };
240}
241
242impl_float_consts!(
243 NEG_ZERO,
244 E,
245 EULER_GAMMA,
246 PI_SQUARED,
247 PI_CUBED,
248 PI_FOURTH,
249 FRAC_1_PI,
250 FRAC_1_SQRT_2,
251 FRAC_1_SQRT_3,
252 FRAC_2_PI,
253 FRAC_1_SQRT_PI,
254 FRAC_2_SQRT_PI,
255 FRAC_SQRT_PI_2,
256 FRAC_1_SQRT_TAU,
257 FRAC_PI_2,
258 FRAC_PI_3,
259 FRAC_PI_4,
260 FRAC_PI_6,
261 FRAC_PI_8,
262 FRAC_PI_180,
263 FRAC_180_PI,
264 LN_2,
265 LN_10,
266 LN_PI,
267 FRAC_LN_PI_2,
268 LOG2_10,
269 LOG2_E,
270 LOG10_2,
271 LOG10_E,
272 PI,
273 SQRT_2,
274 SQRT_3,
275 SQRT_E,
276 EPSILON,
277 SQRT_EPSILON,
278 FOURTH_ROOT_EPSILON,
279 TAU,
280 SQRT_FRAC_PI_2,
281 SQRT_TAU,
282 PHI,
283 FRAC_1_3,
284 FRAC_2_3,
285 FRAC_1_4,
286 FRAC_1_6,
287 FRAC_NEG_1_E
288);
289
290impl<V: thermite::simd::HasIsa, const N: usize> thermite::simd::HasIsa for Dual<V, N> {
291 type Native = V::Native;
292
293 const ISA: thermite::isa::InstructionSet = V::ISA;
294}
295
296impl<V: DualFloatVector, const N: usize> GenericSelectable for Dual<V, N> {
297 type SelectableMask = <V as GenericSelectable>::SelectableMask;
298
299 #[inline(always)]
300 fn select<M>(mask: M, t: Self, f: Self) -> Self
301 where
302 Self::SelectableMask: CastMask<M>,
303 {
304 let mask = <Self::SelectableMask as CastMask<M>>::mask_from(mask);
305
306 let mut dual = t.dual;
309 let mut i = 0;
310 while i < N {
311 dual[i] = mask.select(t.dual[i], f.dual[i]);
312 i += 1;
313 }
314 Self {
315 re: mask.select(t.re, f.re),
316 dual,
317 }
318 }
319}
320
321#[rustfmt::skip]
322impl<V: DualFloatVector, const N: usize> Interleave for Dual<V, N> {
323 #[inline(always)]
324 fn interleave(self, other: Self) -> (Self, Self) {
325 let (re_lo, re_hi) = self.re.interleave(other.re);
326 let mut lo = Self { re: re_lo, dual: [V::ZERO; N] };
327 let mut hi = Self { re: re_hi, dual: [V::ZERO; N] };
328 for i in 0..N {
329 let (d_lo, d_hi) = self.dual[i].interleave(other.dual[i]);
330 lo.dual[i] = d_lo;
331 hi.dual[i] = d_hi;
332 }
333 (lo, hi)
334 }
335
336 #[inline(always)]
337 fn deinterleave(self, other: Self) -> (Self, Self) {
338 let (re_lo, re_hi) = self.re.deinterleave(other.re);
339 let mut lo = Self { re: re_lo, dual: [V::ZERO; N] };
340 let mut hi = Self { re: re_hi, dual: [V::ZERO; N] };
341 for i in 0..N {
342 let (d_lo, d_hi) = self.dual[i].deinterleave(other.dual[i]);
343 lo.dual[i] = d_lo;
344 hi.dual[i] = d_hi;
345 }
346 (lo, hi)
347 }
348}
349
350impl<V: DualFloatVector, const N: usize> thermite::sort::SortKey<Self> for Dual<V, N> {
354 #[inline(always)]
355 fn key_lt(a: Self, b: Self) -> V::Mask {
356 a.re.cmp_lt(b.re)
357 }
358}
359
360#[inline(always)]
364fn sort_lanes_scalar<V: NumericVector, O: thermite::sort::SortOrder>(v: V) -> V
365where
366 V::Element: PartialOrd,
367{
368 let mut out = v;
369 let mut i = 1;
370 while i < V::LANES {
371 let key = out.extractv(i);
372 let mut j = i;
373 while j > 0 {
374 let prev = out.extractv(j - 1);
375 let misplaced = if O::IS_ASCENDING { prev > key } else { prev < key };
376 if !misplaced {
377 break;
378 }
379 out = out.insertv(j, prev);
380 j -= 1;
381 }
382 out = out.insertv(j, key);
383 i += 1;
384 }
385 out
386}
387
388struct DualReSplat<E, V, const N: usize>(PhantomData<(E, V)>);
394
395impl<E, V: DualFloatVector, const N: usize> SplatConst<V::Element> for DualReSplat<E, V, N>
396where
397 E: SplatConst<Dual<V::Element, N>>,
398{
399 const VALUE: V::Element = <E as SplatConst<Dual<V::Element, N>>>::VALUE.re;
400}
401
402impl<V: DualFloatVector, const N: usize> SplatVector<Dual<V::Element, N>> for Dual<V, N> {
403 type Splat<T: SplatConst<Dual<V::Element, N>>> = Self;
404}
405
406impl<V: DualFloatVector, const N: usize, E: SplatConst<Dual<V::Element, N>>> VectorValue<E, Dual<V, N>> for Dual<V, N> {
407 const VALUE: Dual<V, N> = Dual {
408 re: const_splat::<V, DualReSplat<E, V, N>>(),
409 dual: [<V as NumericVector>::ZERO; N],
410 };
411}
412
413struct DualReNew<C, V, const N: usize>(PhantomData<(C, V)>);
415
416impl<C, V: DualFloatVector, const N: usize> NewConst<V::Element, V::Lanes> for DualReNew<C, V, N>
417where
418 C: NewConst<Dual<V::Element, N>, V::Lanes>,
419{
420 const VALUES: GenericArray<V::Element, V::Lanes> = const {
421 let c_vals = C::VALUES;
422 let src = c_vals.as_slice();
423 let mut out: GenericArray<V::Element, V::Lanes> = unsafe { core::mem::zeroed() };
424 let dst = out.as_mut_slice();
425 let mut i = 0;
426 while i < V::LANES {
427 dst[i] = src[i].re;
428 i += 1;
429 }
430 core::mem::forget(c_vals);
431 out
432 };
433}
434
435pub struct DualNewImpl;
437
438impl<T, V: DualFloatVector, const N: usize> VectorValue<T, Dual<V, N>> for DualNewImpl
439where
440 T: NewConst<Dual<V::Element, N>, V::Lanes>,
441{
442 const VALUE: Dual<V, N> = Dual {
443 re: const_new::<V, V::Lanes, DualReNew<T, V, N>>(),
444 dual: [<V as NumericVector>::ZERO; N],
445 };
446}
447
448impl<V: DualFloatVector, const N: usize> NewVector<Dual<V::Element, N>, V::Lanes> for Dual<V, N> {
449 type New<T: NewConst<Dual<V::Element, N>, V::Lanes>> = DualNewImpl;
450}
451
452impl<FROM, TO, const N: usize> CastVector<Dual<FROM, N>> for Dual<TO, N>
457where
458 FROM: DualFloatVector + CastVector<TO>,
459 TO: DualFloatVector + CastVector<FROM>,
460{
461 #[inline(always)]
462 fn cast_into(self) -> Dual<FROM, N> {
463 Dual::<FROM, N>::cast_from(self)
464 }
465
466 #[inline(always)]
467 fn cast_from(from: Dual<FROM, N>) -> Self {
468 Self {
469 re: TO::cast_from(from.re),
470 dual: array_each!([TO::ZERO; N], |i| TO::cast_from(from.dual[i])),
471 }
472 }
473}
474
475impl<V: DualFloatVector, const N: usize> GenericVector for Dual<V, N> {
480 type Element = Dual<V::Element, N>;
481
482 const EMPTY: Self = Self::ZERO;
483 const LANES: usize = V::LANES;
484
485 type Lanes = V::Lanes;
486
487 type Unsigned = V::Unsigned;
488 type Signed = V::Signed;
489 type Mask = V::Mask;
490
491 #[inline(always)]
492 fn new<const M: usize>(value: [Self::Element; M]) -> Self
493 where
494 Const<M>: IntoArrayLength<ArrayLength = Self::Lanes>,
495 {
496 Self {
497 re: V::new(array_each!([<V::Element as Element>::ZERO; M], |m| value[m].re)),
498 dual: array_each!([V::ZERO; N], |j| V::new(array_each!(
499 [<V::Element as Element>::ZERO; M],
500 |m| value[m].dual[j]
501 ))),
502 }
503 }
504
505 #[inline(always)]
506 fn into_array(self) -> GenericArray<Self::Element, Self::Lanes> {
507 let mut arr = GenericArray::default();
508 for i in 0..Self::LANES {
509 arr[i] = Dual {
510 re: self.re.extractv(i),
511 dual: array_each!([<V::Element as Element>::ZERO; N], |j| self.dual[j].extractv(i)),
512 };
513 }
514 arr
515 }
516
517 #[inline(always)]
518 fn splat(value: Self::Element) -> Self {
519 Self {
520 re: V::splat(value.re),
521 dual: array_each!([V::ZERO; N], |j| V::splat(value.dual[j])),
522 }
523 }
524
525 #[inline(always)]
526 fn single(value: Self::Element) -> Self {
527 Self {
528 re: V::single(value.re),
529 dual: array_each!([V::ZERO; N], |j| V::single(value.dual[j])),
530 }
531 }
532
533 #[inline(always)]
537 unsafe fn load(ptr: *const Self::Element) -> Self {
538 unsafe { Self::load_unaligned(ptr) }
539 }
540
541 #[inline(always)]
546 unsafe fn load_unaligned(ptr: *const Self::Element) -> Self {
547 let [out] = unsafe { Self::load_deinterleaved::<1>(ptr) };
548 out
549 }
550
551 #[inline(always)]
552 unsafe fn load_streaming(ptr: *const Self::Element) -> Self {
553 unsafe { Self::load(ptr) }
554 }
555
556 #[inline(always)]
564 unsafe fn load_deinterleaved<const M: usize>(ptr: *const Self::Element) -> [Self; M] {
565 let groups = unsafe { V::load_deinterleaved_grouped::<M, N>(ptr as *const V::Element) };
566
567 let mut out = [Self::EMPTY; M];
568 let mut j = 0;
569 while j < M {
570 out[j] = Dual {
571 re: groups[j].head,
572 dual: groups[j].tail,
573 };
574 j += 1;
575 }
576 out
577 }
578
579 #[inline(always)]
581 unsafe fn store_interleaved<const M: usize>(ptr: *mut Self::Element, values: [Self; M]) {
582 let mut groups = [StreamGroup {
583 head: V::ZERO,
584 tail: [V::ZERO; N],
585 }; M];
586 let mut j = 0;
587 while j < M {
588 groups[j] = StreamGroup {
589 head: values[j].re,
590 tail: values[j].dual,
591 };
592 j += 1;
593 }
594 unsafe { V::store_interleaved_grouped::<M, N>(ptr as *mut V::Element, groups) }
595 }
596
597 #[inline(always)]
598 unsafe fn load_m(src: Self, mask: Self::Mask, ptr: *const Self::Element) -> Self {
599 let flags = mask.select(<V::Signed as NumericVector>::ONE, <V::Signed as NumericVector>::ZERO);
600 let zero = <<V::Signed as GenericVector>::Element as Element>::ZERO;
601 let mut out = src;
602 for i in 0..Self::LANES {
603 if flags.extractv(i) != zero {
604 out = out.insertv(i, unsafe { ptr.add(i).read() });
605 }
606 }
607 out
608 }
609
610 #[inline(always)]
611 unsafe fn load_z(mask: Self::Mask, ptr: *const Self::Element) -> Self {
612 unsafe { Self::load_m(Self::EMPTY, mask, ptr) }
613 }
614
615 #[inline(always)]
617 unsafe fn store(self, ptr: *mut Self::Element) {
618 unsafe { self.store_unaligned(ptr) }
619 }
620
621 #[inline(always)]
622 unsafe fn store_unaligned(self, ptr: *mut Self::Element) {
623 unsafe { Self::store_interleaved::<1>(ptr, [self]) }
624 }
625
626 #[inline(always)]
627 unsafe fn store_streaming(self, ptr: *mut Self::Element) {
628 unsafe { self.store(ptr) }
629 }
630
631 #[inline(always)]
632 fn interleave_by<const GROUP: usize>(self, other: Self) -> (Self, Self) {
633 let (re_lo, re_hi) = self.re.interleave_by::<GROUP>(other.re);
634 let mut lo = Self {
635 re: re_lo,
636 dual: [V::ZERO; N],
637 };
638 let mut hi = Self {
639 re: re_hi,
640 dual: [V::ZERO; N],
641 };
642 for i in 0..N {
643 let (d_lo, d_hi) = self.dual[i].interleave_by::<GROUP>(other.dual[i]);
644 lo.dual[i] = d_lo;
645 hi.dual[i] = d_hi;
646 }
647 (lo, hi)
648 }
649
650 #[inline(always)]
651 fn deinterleave_by<const GROUP: usize>(self, other: Self) -> (Self, Self) {
652 let (re_lo, re_hi) = self.re.deinterleave_by::<GROUP>(other.re);
653 let mut lo = Self {
654 re: re_lo,
655 dual: [V::ZERO; N],
656 };
657 let mut hi = Self {
658 re: re_hi,
659 dual: [V::ZERO; N],
660 };
661 for i in 0..N {
662 let (d_lo, d_hi) = self.dual[i].deinterleave_by::<GROUP>(other.dual[i]);
663 lo.dual[i] = d_lo;
664 hi.dual[i] = d_hi;
665 }
666 (lo, hi)
667 }
668
669 #[inline(always)]
673 fn interleave_radix<const M: usize>(inputs: [Self; M]) -> [Self; M] {
674 let mut re = [V::EMPTY; M];
675 for i in 0..M {
676 re[i] = inputs[i].re;
677 }
678 let re = V::interleave_radix::<M>(re);
679
680 let mut out = [Self::EMPTY; M];
681 for i in 0..M {
682 out[i].re = re[i];
683 }
684 for d in 0..N {
685 let mut comp = [V::EMPTY; M];
686 for i in 0..M {
687 comp[i] = inputs[i].dual[d];
688 }
689 let comp = V::interleave_radix::<M>(comp);
690 for i in 0..M {
691 out[i].dual[d] = comp[i];
692 }
693 }
694 out
695 }
696
697 #[inline(always)]
698 fn deinterleave_radix<const M: usize>(inputs: [Self; M]) -> [Self; M] {
699 let mut re = [V::EMPTY; M];
700 for i in 0..M {
701 re[i] = inputs[i].re;
702 }
703 let re = V::deinterleave_radix::<M>(re);
704
705 let mut out = [Self::EMPTY; M];
706 for i in 0..M {
707 out[i].re = re[i];
708 }
709 for d in 0..N {
710 let mut comp = [V::EMPTY; M];
711 for i in 0..M {
712 comp[i] = inputs[i].dual[d];
713 }
714 let comp = V::deinterleave_radix::<M>(comp);
715 for i in 0..M {
716 out[i].dual[d] = comp[i];
717 }
718 }
719 out
720 }
721
722 #[inline(always)]
723 fn deinterleave_radix_by<const M: usize, const GROUP: usize>(inputs: [Self; M]) -> [Self; M] {
724 let mut re = [V::EMPTY; M];
725 for i in 0..M {
726 re[i] = inputs[i].re;
727 }
728 let re = V::deinterleave_radix_by::<M, GROUP>(re);
729
730 let mut out = [Self::EMPTY; M];
731 for i in 0..M {
732 out[i].re = re[i];
733 }
734 for d in 0..N {
735 let mut comp = [V::EMPTY; M];
736 for i in 0..M {
737 comp[i] = inputs[i].dual[d];
738 }
739 let comp = V::deinterleave_radix_by::<M, GROUP>(comp);
740 for i in 0..M {
741 out[i].dual[d] = comp[i];
742 }
743 }
744 out
745 }
746
747 #[inline(always)]
748 fn interleave_radix_by<const M: usize, const GROUP: usize>(inputs: [Self; M]) -> [Self; M] {
749 let mut re = [V::EMPTY; M];
750 for i in 0..M {
751 re[i] = inputs[i].re;
752 }
753 let re = V::interleave_radix_by::<M, GROUP>(re);
754
755 let mut out = [Self::EMPTY; M];
756 for i in 0..M {
757 out[i].re = re[i];
758 }
759 for d in 0..N {
760 let mut comp = [V::EMPTY; M];
761 for i in 0..M {
762 comp[i] = inputs[i].dual[d];
763 }
764 let comp = V::interleave_radix_by::<M, GROUP>(comp);
765 for i in 0..M {
766 out[i].dual[d] = comp[i];
767 }
768 }
769 out
770 }
771
772 #[inline(always)]
773 unsafe fn store_masked(self, mask: Self::Mask, ptr: *mut Self::Element) {
774 let flags = mask.select(<V::Signed as NumericVector>::ONE, <V::Signed as NumericVector>::ZERO);
775 let zero = <<V::Signed as GenericVector>::Element as Element>::ZERO;
776 for i in 0..Self::LANES {
777 if flags.extractv(i) != zero {
778 unsafe { ptr.add(i).write(self.extractv(i)) };
779 }
780 }
781 }
782
783 #[inline(always)]
784 unsafe fn lookup_unchecked(values: &[Self::Element], indices: Self::Unsigned) -> Self {
785 let mut res = Self::EMPTY;
786 for i in 0..Self::LANES {
787 let Ok(idx) = indices.extractv(i).try_into() else {
788 panic!("Index out of bounds for usize");
789 };
790 res = res.insertv(i, values[idx]);
791 }
792 res
793 }
794
795 #[inline(always)]
796 fn broadcast<const I: usize>(self) -> Self {
797 Self {
798 re: V::broadcast::<I>(self.re),
799 dual: array_each!([V::ZERO; N], |j| V::broadcast::<I>(self.dual[j])),
800 }
801 }
802
803 #[inline(always)]
804 fn broadcastv(self, idx: usize) -> Self {
805 Self {
806 re: self.re.broadcastv(idx),
807 dual: array_each!([V::ZERO; N], |j| self.dual[j].broadcastv(idx)),
808 }
809 }
810
811 #[inline(always)]
812 fn extract<const I: usize>(self) -> Self::Element {
813 Dual {
814 re: V::extract::<I>(self.re),
815 dual: array_each!([<V::Element as Element>::ZERO; N], |j| V::extract::<I>(self.dual[j])),
816 }
817 }
818
819 #[inline(always)]
820 fn extractv(self, idx: usize) -> Self::Element {
821 Dual {
822 re: self.re.extractv(idx),
823 dual: array_each!([<V::Element as Element>::ZERO; N], |j| self.dual[j].extractv(idx)),
824 }
825 }
826
827 #[inline(always)]
828 fn insert<const I: usize>(self, value: Self::Element) -> Self {
829 Self {
830 re: V::insert::<I>(self.re, value.re),
831 dual: array_each!([V::ZERO; N], |j| V::insert::<I>(self.dual[j], value.dual[j])),
832 }
833 }
834
835 #[inline(always)]
836 fn insertv(self, idx: usize, value: Self::Element) -> Self {
837 Self {
838 re: self.re.insertv(idx, value.re),
839 dual: array_each!([V::ZERO; N], |j| self.dual[j].insertv(idx, value.dual[j])),
840 }
841 }
842
843 #[inline(always)]
844 fn reverse(self) -> Self {
845 Self {
846 re: self.re.reverse(),
847 dual: array_each!([V::ZERO; N], |j| self.dual[j].reverse()),
848 }
849 }
850
851 #[inline(always)]
852 fn swap_bytes(self) -> Self {
853 Self {
854 re: self.re.swap_bytes(),
855 dual: array_each!([V::ZERO; N], |j| self.dual[j].swap_bytes()),
856 }
857 }
858
859 #[inline(always)]
860 fn zz(self, mask: Self::Mask) -> Self {
861 Self {
862 re: self.re.zz(mask),
863 dual: array_each!([V::ZERO; N], |j| self.dual[j].zz(mask)),
864 }
865 }
866
867 #[inline(always)]
868 fn nz(self, mask: Self::Mask) -> Self {
869 Self {
870 re: self.re.nz(mask),
871 dual: array_each!([V::ZERO; N], |j| self.dual[j].nz(mask)),
872 }
873 }
874
875 #[inline(always)]
876 fn compress(self, mask: Self::Mask) -> Self {
877 Self {
878 re: self.re.compress(mask),
879 dual: array_each!([V::ZERO; N], |j| self.dual[j].compress(mask)),
880 }
881 }
882
883 #[inline(always)]
884 fn compress_z(self, mask: Self::Mask) -> Self {
885 Self {
886 re: self.re.compress_z(mask),
887 dual: array_each!([V::ZERO; N], |j| self.dual[j].compress_z(mask)),
888 }
889 }
890
891 #[inline(always)]
896 fn compress_m(self, src: Self, mask: Self::Mask) -> Self {
897 Self {
898 re: self.re.compress_m(src.re, mask),
899 dual: array_each!([V::ZERO; N], |j| self.dual[j].compress_m(src.dual[j], mask)),
900 }
901 }
902
903 #[inline(always)]
904 fn expand(self, mask: Self::Mask) -> Self {
905 Self {
906 re: self.re.expand(mask),
907 dual: array_each!([V::ZERO; N], |j| self.dual[j].expand(mask)),
908 }
909 }
910
911 #[inline(always)]
912 fn expand_z(self, mask: Self::Mask) -> Self {
913 Self {
914 re: self.re.expand_z(mask),
915 dual: array_each!([V::ZERO; N], |j| self.dual[j].expand_z(mask)),
916 }
917 }
918
919 #[inline(always)]
920 fn expand_m(self, src: Self, mask: Self::Mask) -> Self {
921 Self {
922 re: self.re.expand_m(src.re, mask),
923 dual: array_each!([V::ZERO; N], |j| self.dual[j].expand_m(src.dual[j], mask)),
924 }
925 }
926
927 #[inline(always)]
928 fn align<const OFFSET: usize>(self, other: Self) -> Self {
929 Self {
930 re: self.re.align::<OFFSET>(other.re),
931 dual: array_each!([V::ZERO; N], |j| self.dual[j].align::<OFFSET>(other.dual[j])),
932 }
933 }
934
935 const HAS_NATIVE_ALIGN: bool = V::HAS_NATIVE_ALIGN;
937
938 #[inline(always)]
939 fn map<F>(mut self, f: F) -> Self
940 where
941 F: Fn(Self::Element) -> Self::Element,
942 {
943 for i in 0..Self::LANES {
944 self = self.insertv(i, f(self.extractv(i)));
945 }
946 self
947 }
948
949 #[inline(always)]
950 fn fold<F>(self, mut init: Self::Element, f: F) -> Self::Element
951 where
952 F: Fn(Self::Element, Self::Element) -> Self::Element,
953 {
954 for i in 0..Self::LANES {
955 init = f(init, self.extractv(i));
956 }
957 init
958 }
959
960 #[inline(always)]
961 fn reduce<F>(self, f: F) -> Self::Element
962 where
963 F: Fn(Self::Element, Self::Element) -> Self::Element,
964 {
965 let mut result = self.extractv(0);
966 for i in 1..Self::LANES {
967 result = f(result, self.extractv(i));
968 }
969 result
970 }
971
972 #[inline(always)]
973 fn splat_m(src: Self, mask: Self::Mask, value: Self::Element) -> Self {
974 mask.select(Self::splat(value), src)
975 }
976 #[inline(always)]
977 fn splat_z(mask: Self::Mask, value: Self::Element) -> Self {
978 mask.select(Self::splat(value), Self::EMPTY)
979 }
980 #[inline(always)]
981 fn broadcast_c<const I: usize>(self, mask: Self::Mask) -> Self {
982 mask.select(self.broadcast::<I>(), self)
983 }
984 #[inline(always)]
985 fn broadcast_m<const I: usize>(self, src: Self, mask: Self::Mask) -> Self {
986 mask.select(self.broadcast::<I>(), src)
987 }
988 #[inline(always)]
989 fn broadcast_z<const I: usize>(self, mask: Self::Mask) -> Self {
990 mask.select(self.broadcast::<I>(), Self::EMPTY)
991 }
992 #[inline(always)]
993 fn broadcastv_c(self, mask: Self::Mask, idx: usize) -> Self {
994 mask.select(self.broadcastv(idx), self)
995 }
996 #[inline(always)]
997 fn broadcastv_m(self, src: Self, mask: Self::Mask, idx: usize) -> Self {
998 mask.select(self.broadcastv(idx), src)
999 }
1000 #[inline(always)]
1001 fn broadcastv_z(self, mask: Self::Mask, idx: usize) -> Self {
1002 mask.select(self.broadcastv(idx), Self::EMPTY)
1003 }
1004 #[inline(always)]
1005 fn reverse_c(self, mask: Self::Mask) -> Self {
1006 mask.select(self.reverse(), self)
1007 }
1008 #[inline(always)]
1009 fn reverse_m(self, src: Self, mask: Self::Mask) -> Self {
1010 mask.select(self.reverse(), src)
1011 }
1012 #[inline(always)]
1013 fn reverse_z(self, mask: Self::Mask) -> Self {
1014 mask.select(self.reverse(), Self::EMPTY)
1015 }
1016 #[inline(always)]
1017 fn swap_bytes_c(self, mask: Self::Mask) -> Self {
1018 mask.select(self.swap_bytes(), self)
1019 }
1020 #[inline(always)]
1021 fn swap_bytes_m(self, src: Self, mask: Self::Mask) -> Self {
1022 mask.select(self.swap_bytes(), src)
1023 }
1024 #[inline(always)]
1025 fn swap_bytes_z(self, mask: Self::Mask) -> Self {
1026 mask.select(self.swap_bytes(), Self::EMPTY)
1027 }
1028}
1029
1030#[rustfmt::skip]
1035impl<V: DualFloatVector, const N: usize> PartialOrdVector for Dual<V, N> {
1036 #[inline(always)] fn cmp_eq(self, other: Self) -> Self::Mask { self.re.cmp_eq(other.re) }
1037 #[inline(always)] fn cmp_ne(self, other: Self) -> Self::Mask { self.re.cmp_ne(other.re) }
1038 #[inline(always)] fn cmp_lt(self, other: Self) -> Self::Mask { self.re.cmp_lt(other.re) }
1039 #[inline(always)] fn cmp_gt(self, other: Self) -> Self::Mask { self.re.cmp_gt(other.re) }
1040 #[inline(always)] fn cmp_le(self, other: Self) -> Self::Mask { self.re.cmp_le(other.re) }
1041 #[inline(always)] fn cmp_ge(self, other: Self) -> Self::Mask { self.re.cmp_ge(other.re) }
1042}
1043
1044impl<V: DualValue, const N: usize> core::iter::Sum for Dual<V, N> {
1049 #[inline]
1050 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
1051 iter.fold(Self::ZERO, |a, b| a + b)
1052 }
1053}
1054
1055impl<V: DualValue, const N: usize> core::iter::Product for Dual<V, N> {
1056 #[inline]
1057 fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
1058 iter.fold(Self::ONE, |a, b| a * b)
1059 }
1060}
1061
1062#[rustfmt::skip]
1063impl<V: DualFloatVector, const N: usize> Bounded for Dual<V, N> {
1064 #[inline(always)] fn min_value() -> Self { Self::constant(V::MIN) }
1065 #[inline(always)] fn max_value() -> Self { Self::constant(V::MAX) }
1066}
1067
1068impl<V: DualFloatVector, const N: usize> SquareMasked<V::Mask> for Dual<V, N> {
1073 #[inline(always)]
1074 fn square_c(self, mask: V::Mask) -> Self::Output {
1075 mask.select(self.square(), self)
1076 }
1077
1078 #[inline(always)]
1079 fn square_m(self, src: Self, mask: V::Mask) -> Self::Output {
1080 mask.select(self.square(), src)
1081 }
1082
1083 #[inline(always)]
1084 fn square_z(self, mask: V::Mask) -> Self::Output {
1085 mask.select(self.square(), Self::ZERO)
1086 }
1087}
1088
1089macro_rules! impl_masked {
1094 (MUL_ADD: $($method:ident),*) => {paste::paste! {
1095 impl<V: DualFloatVector, const N: usize, A, B> thermite::vector::ops::MulAddExtMasked<V::Mask, A, B> for Dual<V, N>
1096 where
1097 Dual<V, N>: thermite::vector::ops::MulAddExt<A, B, Output = Self>,
1098 {
1099 $(
1100 #[inline(always)]
1101 fn [<$method _c>](self, mask: V::Mask, a: A, b: B) -> Self {
1102 mask.select(self.$method(a, b), self)
1103 }
1104 #[inline(always)]
1105 fn [<$method _m>](self, src: Self, mask: V::Mask, a: A, b: B) -> Self {
1106 mask.select(self.$method(a, b), src)
1107 }
1108 #[inline(always)]
1109 fn [<$method _z>](self, mask: V::Mask, a: A, b: B) -> Self {
1110 mask.select(self.$method(a, b), Self::EMPTY)
1111 }
1112 )*
1113 }
1114
1115 impl<V: DualFloatVector, const N: usize, A, B> thermite::vector::ops::MulAddAssignExtMasked<V::Mask, A, B> for Dual<V, N>
1116 where
1117 Dual<V, N>: thermite::vector::ops::MulAddExt<A, B, Output = Self>,
1118 {
1119 $(
1120 #[inline(always)]
1121 fn [<$method _assign_c>](&mut self, mask: V::Mask, a: A, b: B) {
1122 *self = mask.select(self.$method(a, b), *self);
1123 }
1124 #[inline(always)]
1125 fn [<$method _assign_m>](&mut self, src: Self, mask: V::Mask, a: A, b: B) {
1126 *self = mask.select(self.$method(a, b), src);
1127 }
1128 #[inline(always)]
1129 fn [<$method _assign_z>](&mut self, mask: V::Mask, a: A, b: B) {
1130 *self = mask.select(self.$method(a, b), Self::EMPTY);
1131 }
1132 )*
1133 }
1134 }};
1135
1136 ($trait:ident::$method:ident) => {paste::paste! {
1137 impl<V: DualFloatVector, const N: usize, Rhs> thermite::vector::ops::[<$trait Masked>]<V::Mask, Rhs> for Dual<V, N>
1138 where
1139 Dual<V, N>: core::ops::$trait<Rhs, Output = Self>,
1140 {
1141 #[inline(always)]
1142 fn [<$method _c>](self, mask: V::Mask, rhs: Rhs) -> Self {
1143 mask.select(self.$method(rhs), self)
1144 }
1145 #[inline(always)]
1146 fn [<$method _m>](self, src: Self, mask: V::Mask, rhs: Rhs) -> Self {
1147 mask.select(self.$method(rhs), src)
1148 }
1149 #[inline(always)]
1150 fn [<$method _z>](self, mask: V::Mask, rhs: Rhs) -> Self {
1151 mask.select(self.$method(rhs), Self::EMPTY)
1152 }
1153 }
1154
1155 impl<V: DualFloatVector, const N: usize, Rhs> thermite::vector::ops::[<$trait AssignMasked>]<V::Mask, Rhs> for Dual<V, N>
1156 where
1157 Dual<V, N>: core::ops::$trait<Rhs, Output = Self>,
1158 {
1159 #[inline(always)]
1160 fn [<$method _assign_c>](&mut self, mask: V::Mask, rhs: Rhs) {
1161 *self = mask.select(self.$method(rhs), *self);
1162 }
1163 #[inline(always)]
1164 fn [<$method _assign_m>](&mut self, src: Self, mask: V::Mask, rhs: Rhs) {
1165 *self = mask.select(self.$method(rhs), src);
1166 }
1167 #[inline(always)]
1168 fn [<$method _assign_z>](&mut self, mask: V::Mask, rhs: Rhs) {
1169 *self = mask.select(self.$method(rhs), Self::EMPTY);
1170 }
1171 }
1172 }};
1173}
1174
1175impl_masked!(MUL_ADD: mul_add, mul_sub, nmul_add, nmul_sub, mul_adde, mul_sube, nmul_adde, nmul_sube);
1176impl_masked!(Add::add);
1177impl_masked!(Sub::sub);
1178impl_masked!(Mul::mul);
1179impl_masked!(Div::div);
1180impl_masked!(Rem::rem);
1181
1182#[inline(always)]
1193fn neg_even_dual<V: DualFloatVector, const N: usize>(x: Dual<V, N>) -> Dual<V, N> {
1194 let mut dual = x.dual;
1195 let mut i = 0;
1196 while i < N {
1197 dual[i] = V::ZERO.addsub(dual[i]);
1198 i += 1;
1199 }
1200 Dual {
1201 re: V::ZERO.addsub(x.re),
1202 dual,
1203 }
1204}
1205
1206impl<V: DualFloatVector, const N: usize> AddSubExt for Dual<V, N> {
1207 type Output = Self;
1208
1209 #[inline(always)]
1210 fn addsub(self, b: Self) -> Self {
1211 self + neg_even_dual(b)
1212 }
1213 #[inline(always)]
1214 fn fmaddsub(self, b: Self, c: Self) -> Self {
1215 self.mul_adde(b, neg_even_dual(c))
1216 }
1217 #[inline(always)]
1218 fn fmsubadd(self, b: Self, c: Self) -> Self {
1219 self.mul_sube(b, neg_even_dual(c))
1220 }
1221}
1222
1223impl<V: DualFloatVector, const N: usize> AddSubExtMasked<V::Mask> for Dual<V, N> {
1224 #[inline(always)]
1225 fn addsub_c(self, mask: V::Mask, b: Self) -> Self {
1226 mask.select(self.addsub(b), self)
1227 }
1228 #[inline(always)]
1229 fn addsub_m(self, src: Self, mask: V::Mask, b: Self) -> Self {
1230 mask.select(self.addsub(b), src)
1231 }
1232 #[inline(always)]
1233 fn addsub_z(self, mask: V::Mask, b: Self) -> Self {
1234 mask.select(self.addsub(b), Self::EMPTY)
1235 }
1236
1237 #[inline(always)]
1238 fn fmaddsub_c(self, mask: V::Mask, b: Self, c: Self) -> Self {
1239 mask.select(self.fmaddsub(b, c), self)
1240 }
1241 #[inline(always)]
1242 fn fmaddsub_m(self, src: Self, mask: V::Mask, b: Self, c: Self) -> Self {
1243 mask.select(self.fmaddsub(b, c), src)
1244 }
1245 #[inline(always)]
1246 fn fmaddsub_z(self, mask: V::Mask, b: Self, c: Self) -> Self {
1247 mask.select(self.fmaddsub(b, c), Self::EMPTY)
1248 }
1249
1250 #[inline(always)]
1251 fn fmsubadd_c(self, mask: V::Mask, b: Self, c: Self) -> Self {
1252 mask.select(self.fmsubadd(b, c), self)
1253 }
1254 #[inline(always)]
1255 fn fmsubadd_m(self, src: Self, mask: V::Mask, b: Self, c: Self) -> Self {
1256 mask.select(self.fmsubadd(b, c), src)
1257 }
1258 #[inline(always)]
1259 fn fmsubadd_z(self, mask: V::Mask, b: Self, c: Self) -> Self {
1260 mask.select(self.fmsubadd(b, c), Self::EMPTY)
1261 }
1262}
1263
1264macro_rules! dual_masked {
1269 (unary: $($m:ident),* $(,)?) => { paste::paste! {
1270 $(
1271 #[inline(always)] fn [<$m _c>](self, mask: Self::Mask) -> Self { mask.select(self.$m(), self) }
1272 #[inline(always)] fn [<$m _m>](self, src: Self, mask: Self::Mask) -> Self { mask.select(self.$m(), src) }
1273 #[inline(always)] fn [<$m _z>](self, mask: Self::Mask) -> Self { mask.select(self.$m(), Self::ZERO) }
1274 )*
1275 }};
1276 (binary: $($m:ident),* $(,)?) => { paste::paste! {
1277 $(
1278 #[inline(always)] fn [<$m _c>](self, mask: Self::Mask, rhs: Self) -> Self { mask.select(self.$m(rhs), self) }
1279 #[inline(always)] fn [<$m _m>](self, src: Self, mask: Self::Mask, rhs: Self) -> Self { mask.select(self.$m(rhs), src) }
1280 #[inline(always)] fn [<$m _z>](self, mask: Self::Mask, rhs: Self) -> Self { mask.select(self.$m(rhs), Self::ZERO) }
1281 )*
1282 }};
1283}
1284
1285#[rustfmt::skip]
1290impl<V: DualFloatVector, const N: usize> NumericVector for Dual<V, N> {
1291 #[inline(always)]
1295 fn to_signed_integer(self) -> Self::Signed {
1296 self.re.to_signed_integer()
1297 }
1298
1299 #[inline(always)]
1300 fn from_signed_integer(v: Self::Signed) -> Self {
1301 Self::constant(V::from_signed_integer(v))
1302 }
1303
1304 #[inline(always)]
1305 fn to_unsigned_integer(self) -> Self::Unsigned {
1306 self.re.to_unsigned_integer()
1307 }
1308
1309 #[inline(always)]
1310 fn from_unsigned_integer(v: Self::Unsigned) -> Self {
1311 Self::constant(V::from_unsigned_integer(v))
1312 }
1313
1314 const ZERO: Self = <Self as crate::DualValue>::VAL_ZERO;
1315 const ONE: Self = <Self as crate::DualValue>::VAL_ONE;
1316 const TWO: Self = Self::constant(V::TWO);
1317 const MIN: Self = Self::constant(V::MIN);
1318 const MAX: Self = Self::constant(V::MAX);
1319
1320 #[inline(always)] fn is_zero(self) -> Self::Mask { self.re.is_zero() }
1321 #[inline(always)] fn is_all_zero(self) -> bool { self.re.is_all_zero() }
1322
1323 #[inline(always)] fn min(self, other: Self) -> Self { self.cmp_lt(other).select(self, other) }
1324 #[inline(always)] fn max(self, other: Self) -> Self { self.cmp_gt(other).select(self, other) }
1325
1326 #[inline(always)]
1333 fn sort_by<O: thermite::sort::SortOrder>(self) -> Self {
1334 if const { Self::LANES <= 16 && Self::LANES.is_power_of_two() } {
1335 thermite::sort::sort_lanes_by_key::<Self, O, Self>(self)
1336 } else {
1337 sort_lanes_scalar::<Self, O>(self)
1338 }
1339 }
1340
1341 #[inline(always)]
1342 fn bitonic_clean_by<O: thermite::sort::SortOrder>(self) -> Self {
1343 if const { Self::LANES <= 16 && Self::LANES.is_power_of_two() } {
1344 thermite::sort::bitonic_clean_lanes_by_key::<Self, O, Self>(self)
1345 } else {
1346 sort_lanes_scalar::<Self, O>(self)
1348 }
1349 }
1350
1351 #[inline(always)]
1354 fn clamp(self, min: Self, max: Self) -> Self {
1355 let is_lt = self.re.cmp_lt(min.re);
1356 let is_gt = self.re.cmp_gt(max.re);
1357
1358 let re = is_lt.select(min.re, is_gt.select(max.re, self.re));
1359 let mut dual = self.dual;
1360 let mut i = 0;
1361 while i < N {
1362 dual[i] = is_lt.select(min.dual[i], is_gt.select(max.dual[i], self.dual[i]));
1363 i += 1;
1364 }
1365 Self { re, dual }
1366 }
1367
1368 #[inline(always)]
1372 fn min_element(self) -> Self::Element {
1373 let (lo, _) = self.re.arg_minmax();
1374 self.extractv(lo)
1375 }
1376
1377 #[inline(always)]
1378 fn max_element(self) -> Self::Element {
1379 let (_, hi) = self.re.arg_minmax();
1380 self.extractv(hi)
1381 }
1382
1383 #[inline(always)]
1385 fn min_max_element(self) -> (Self::Element, Self::Element) {
1386 let (lo, hi) = self.re.arg_minmax();
1387 (self.extractv(lo), self.extractv(hi))
1388 }
1389
1390 #[inline(always)]
1394 fn sum_elements(self) -> Self::Element {
1395 let mut dual = [<V::Element as Element>::ZERO; N];
1396 let mut j = 0;
1397 while j < N {
1398 dual[j] = self.dual[j].sum_elements();
1399 j += 1;
1400 }
1401 Dual { re: self.re.sum_elements(), dual }
1402 }
1403
1404 #[inline(always)]
1407 fn prefix_sum(self) -> Self {
1408 Self {
1409 re: self.re.prefix_sum(),
1410 dual: array_each!([V::ZERO; N], |j| self.dual[j].prefix_sum()),
1411 }
1412 }
1413
1414 #[inline(always)]
1415 fn reverse_prefix_sum(self) -> Self {
1416 Self {
1417 re: self.re.reverse_prefix_sum(),
1418 dual: array_each!([V::ZERO; N], |j| self.dual[j].reverse_prefix_sum()),
1419 }
1420 }
1421
1422 #[inline(always)]
1427 fn prefix_min(self) -> Self {
1428 thermite::scan_ladder!(forward, self, self.broadcast::<0>(), Self::min)
1429 }
1430
1431 #[inline(always)]
1432 fn prefix_max(self) -> Self {
1433 thermite::scan_ladder!(forward, self, self.broadcast::<0>(), Self::max)
1434 }
1435
1436 #[inline(always)]
1437 fn reverse_prefix_min(self) -> Self {
1438 thermite::scan_ladder!(reverse, self, self.reverse().broadcast::<0>(), Self::min)
1439 }
1440
1441 #[inline(always)]
1442 fn reverse_prefix_max(self) -> Self {
1443 thermite::scan_ladder!(reverse, self, self.reverse().broadcast::<0>(), Self::max)
1444 }
1445
1446 #[inline(always)]
1450 fn prod_elements(self) -> Self::Element {
1451 let mut arr = self.into_array();
1452 reduce_in_place(&mut arr, |a, b| a * b);
1453 arr[0]
1454 }
1455
1456 #[inline(always)] fn offset() -> Self { Self::constant(V::offset()) }
1457 #[inline(always)] fn indexed() -> Self { Self::constant(V::indexed()) }
1458
1459 #[inline(always)] fn arg_minmax(self) -> (usize, usize) { self.re.arg_minmax() }
1460
1461 #[inline(always)]
1465 fn scale(self, factor: Self::Element) -> Self {
1466 let fr = V::splat(factor.re);
1467 let mut dual = self.dual;
1468 let mut i = 0;
1469 while i < N {
1470 dual[i] = self.re.mul_adde(V::splat(factor.dual[i]), self.dual[i] * fr);
1472 i += 1;
1473 }
1474 Self { re: self.re * fr, dual }
1475 }
1476
1477 #[inline(always)] fn scale_c(self, mask: Self::Mask, factor: Self::Element) -> Self { mask.select(self.scale(factor), self) }
1478 #[inline(always)] fn scale_m(self, src: Self, mask: Self::Mask, factor: Self::Element) -> Self { mask.select(self.scale(factor), src) }
1479 #[inline(always)] fn scale_z(self, mask: Self::Mask, factor: Self::Element) -> Self { mask.select(self.scale(factor), Self::ZERO) }
1480 dual_masked!(binary: min, max);
1481
1482 #[inline(always)]
1485 fn pairwise_sum(lo: Self, hi: Self) -> Self {
1486 let mut dual = lo.dual;
1487 let mut i = 0;
1488 while i < N {
1489 dual[i] = V::pairwise_sum(lo.dual[i], hi.dual[i]);
1490 i += 1;
1491 }
1492 Self { re: V::pairwise_sum(lo.re, hi.re), dual }
1493 }
1494
1495 #[inline(always)]
1496 fn relaxed_pairwise_sum(lo: Self, hi: Self) -> Self {
1497 let mut dual = lo.dual;
1498 let mut i = 0;
1499 while i < N {
1500 dual[i] = V::relaxed_pairwise_sum(lo.dual[i], hi.dual[i]);
1501 i += 1;
1502 }
1503 Self { re: V::relaxed_pairwise_sum(lo.re, hi.re), dual }
1504 }
1505}
1506
1507impl<V: DualFloatVector, const N: usize> NegMasked<V::Mask> for Dual<V, N> {
1512 #[inline(always)]
1515 fn neg_c(self, mask: V::Mask) -> Self {
1516 let re = mask.select(-self.re, self.re);
1517 let mut dual = self.dual;
1518 let mut i = 0;
1519 while i < N {
1520 dual[i] = mask.select(-dual[i], dual[i]);
1521 i += 1;
1522 }
1523 Self { re, dual }
1524 }
1525
1526 #[inline(always)]
1527 fn neg_m(self, src: Self, mask: V::Mask) -> Self {
1528 let re = mask.select(-self.re, src.re);
1529 let mut dual = self.dual;
1530 let mut i = 0;
1531 while i < N {
1532 dual[i] = mask.select(-dual[i], src.dual[i]);
1533 i += 1;
1534 }
1535 Self { re, dual }
1536 }
1537
1538 #[inline(always)]
1539 fn neg_z(self, mask: V::Mask) -> Self {
1540 let re = mask.select(-self.re, V::ZERO);
1541 let mut dual = self.dual;
1542 let mut i = 0;
1543 while i < N {
1544 dual[i] = mask.select(-dual[i], V::ZERO);
1545 i += 1;
1546 }
1547 Self { re, dual }
1548 }
1549}
1550
1551#[rustfmt::skip]
1552impl<V: DualFloatVector, const N: usize> SignedVector for Dual<V, N> {
1553 const NEG_ONE: Self = Self::constant(V::NEG_ONE);
1554 const MIN_POSITIVE: Self = Self::constant(V::MIN_POSITIVE);
1555
1556 #[inline(always)]
1557 fn abs(self) -> Self {
1558 self.neg_c(self.re.cmp_lt(V::ZERO))
1560 }
1561
1562 #[inline(always)] fn signum(self) -> Self { Self::constant(self.re.signum()) }
1563 #[inline(always)] fn is_positive(self) -> Self::Mask { self.re.is_positive() }
1564 #[inline(always)] fn is_negative(self) -> Self::Mask { self.re.is_negative() }
1565 #[inline(always)] fn select_negative(self, if_neg: Self, if_pos: Self) -> Self { self.is_negative().select(if_neg, if_pos) }
1566
1567 #[inline(always)]
1568 fn copysign(self, sign: Self) -> Self {
1569 self.neg_c(self.is_negative() ^ sign.is_negative())
1570 }
1571
1572 dual_masked!(unary: abs);
1573 dual_masked!(binary: copysign);
1574}
1575
1576#[rustfmt::skip]
1581impl<V: DualFloatVector, const N: usize> FloatVector for Dual<V, N> {
1582 const HALF: Self = Self::constant(<V as FloatVector>::HALF);
1583 const NEG_ZERO: Self = Self::constant(<V as FloatVector>::NEG_ZERO);
1584 const INFINITY: Self = Self::constant(<V as FloatVector>::INFINITY);
1585 const NEG_INFINITY: Self = Self::constant(<V as FloatVector>::NEG_INFINITY);
1586 const NAN: Self = Self::constant(<V as FloatVector>::NAN);
1587 const EPSILON: Self = Self::constant(<V as FloatVector>::EPSILON);
1588
1589 type ExtendedPrecision = Self;
1590
1591 const HAS_APPROX_RCP: bool = V::HAS_APPROX_RCP;
1594 const HAS_APPROX_RSQRT: bool = V::HAS_APPROX_RSQRT;
1595
1596 #[inline(always)] fn is_infinite(self) -> Self::Mask { self.re.is_infinite() }
1597 #[inline(always)] fn is_finite(self) -> Self::Mask { self.re.is_finite() }
1598 #[inline(always)] fn is_nan(self) -> Self::Mask { self.re.is_nan() }
1599 #[inline(always)] fn is_zero_or_subnormal(self) -> Self::Mask { self.re.is_zero_or_subnormal() }
1600 #[inline(always)] fn is_normal(self) -> Self::Mask { self.re.is_normal() }
1601 #[inline(always)] fn is_subnormal(self) -> Self::Mask { self.re.is_subnormal() }
1602
1603 #[inline(always)]
1604 fn sqrt(self) -> Self {
1605 let s = self.re.sqrt();
1606 self.chain(s, V::HALF / s)
1608 }
1609
1610 #[inline(always)]
1611 fn rcp(self) -> Self {
1612 let r = self.re.rcp();
1613 self.chain(r, -(r * r))
1615 }
1616
1617 #[inline(always)]
1618 fn rsqrt(self) -> Self {
1619 let r = self.re.rsqrt();
1620 self.chain(r, (V::HALF * r * r * r).neg())
1622 }
1623
1624 #[inline(always)] fn floor(self) -> Self { Self::constant(self.re.floor()) }
1625 #[inline(always)] fn ceil(self) -> Self { Self::constant(self.re.ceil()) }
1626 #[inline(always)] fn round(self) -> Self { Self::constant(self.re.round()) }
1627 #[inline(always)] fn trunc(self) -> Self { Self::constant(self.re.trunc()) }
1628 #[inline(always)] fn fract(self) -> Self { Self { re: self.re.fract(), dual: self.dual } }
1631
1632 #[inline(always)]
1633 fn mul_sign(self, sign: Self) -> Self {
1634 Self {
1635 re: self.re.mul_sign(sign.re),
1636 dual: array_each!([V::ZERO; N], |i| self.dual[i].mul_sign(sign.re)),
1637 }
1638 }
1639
1640 #[inline(always)] fn signed_zero(self) -> Self { Self::constant(self.re.signed_zero()) }
1641
1642 #[inline(always)] fn next_up(self) -> Self { Self { re: self.re.next_up(), dual: self.dual } }
1643 #[inline(always)] fn next_down(self) -> Self { Self { re: self.re.next_down(), dual: self.dual } }
1644
1645 #[inline(always)] unsafe fn block_autovectorization(&mut self) {
1646 unsafe {
1647 self.re.block_autovectorization();
1648 for i in 0..N {
1649 self.dual[i].block_autovectorization();
1650 }
1651 }
1652 }
1653
1654 #[inline(always)] fn mix(self, a: Self, b: Self) -> Self { a + (b - a) * self }
1656
1657 dual_masked!(unary: sqrt, rsqrt, rcp, floor, ceil, round, trunc, fract, signed_zero, next_up, next_down);
1658 dual_masked!(binary: mul_sign);
1659}