Skip to main content

thermite_complex/
vector.rs

1//! Element and vector-trait integration for [`Complex`].
2//!
3//! `Complex<E>` over a scalar float element implements
4//! [`Element`]/[`SignedElement`]/[`FloatElement`], so it can be the element of a
5//! complex vector; `Complex<V>` over a real [`FloatVector`] implements the
6//! [`GenericVector`] -> [`FloatVector`] stack, with `Element = Complex<V::Element>`
7//! and the mask and lanes of `V`.
8//!
9//! The ordering, sign and rounding semantics are in the [crate docs](crate).
10
11use core::marker::PhantomData;
12use core::ops::{Add, Div, Mul, Rem, Sub};
13
14use num_traits::Bounded;
15
16use thermite::Swizzle;
17use thermite::element::{Element, FloatElement, SignedElement};
18use thermite::generic_array::{GenericArray, IntoArrayLength, typenum::Const};
19use thermite::mask::{GenericMask, GenericSelectable};
20use thermite::math::RealMathWithPolicy;
21use thermite::math::algorithms::reduce_in_place;
22use thermite::math::policy::DefaultPolicy;
23use thermite::register::SwizzleIndices;
24use thermite::vector::ops::{AddSubExt, AddSubExtMasked, NegMasked, Square, SquareMasked};
25use thermite::vector::{NewConst, NewVector, SplatConst, SplatVector, VectorValue, const_new, const_splat};
26use thermite::{LargeInt, features, prelude::*};
27
28use crate::{Complex, RealValue};
29
30/// A real [`FloatVector`] usable as the inner storage of a [`Complex`] vector.
31///
32/// The complex primitives (`sqrt`, `abs`, `signum`, `rcp`, ...) are built out of
33/// the inner vector's `hypot`/`reciprocal`, so the policy math library is required
34/// here. `Dual`/`Compensated` split theirs into a separate tier; there is no useful
35/// math-free tier to split out of this one.
36pub trait RealFloatVector:
37    RealValue + FloatVector<Element: RealValue> + CastVector<Self> + RealMathWithPolicy + SwizzleVector
38{
39}
40
41impl<V> RealFloatVector for V where
42    V: RealValue + FloatVector<Element: RealValue> + CastVector<V> + RealMathWithPolicy + SwizzleVector
43{
44}
45
46// Lane swizzles apply to both components: re and im move through the same
47// permutation, so a swizzled complex vector is the complex of the swizzled
48// inputs.
49impl<V: RealFloatVector> Swizzle<V::Lanes> for Complex<V> {
50    #[inline(always)]
51    fn swizzle(self, other: Self, indices: GenericArray<u32, V::Lanes>) -> Self {
52        Self {
53            re: self.re.swizzle(other.re, indices.clone()),
54            im: self.im.swizzle(other.im, indices),
55        }
56    }
57
58    #[inline(always)]
59    fn permute(self, indices: GenericArray<u32, V::Lanes>) -> Self {
60        Self {
61            re: self.re.permute(indices.clone()),
62            im: self.im.permute(indices),
63        }
64    }
65
66    // Forward the `_const` forms per component - the trait defaults route
67    // through the runtime-index methods and lose the immediate-encoded
68    // shuffles.
69    #[inline(always)]
70    fn swizzle_const<I: SwizzleIndices<V::Lanes>>(self, other: Self) -> Self {
71        Self {
72            re: self.re.swizzle_const::<I>(other.re),
73            im: self.im.swizzle_const::<I>(other.im),
74        }
75    }
76
77    #[inline(always)]
78    fn permute_const<I: SwizzleIndices<V::Lanes>>(self) -> Self {
79        Self {
80            re: self.re.permute_const::<I>(),
81            im: self.im.permute_const::<I>(),
82        }
83    }
84}
85
86// --- Element stack: Complex<E> as a scalar element ---
87
88#[rustfmt::skip]
89impl<E: RealValue + Element> Element for Complex<E> {
90    type Signed = <E as Element>::Signed;
91    type Unsigned = <E as Element>::Unsigned;
92
93    const ZERO: Self = Self::ZERO;
94    const ONE: Self = Self::ONE;
95
96    // The (documented, if artificial) order on complex numbers here is
97    // lexicographic (re, im) - see `PartialOrdVector for Complex` - so the
98    // order extremes are extreme in both components, and unordered values
99    // (NaN in either part) exist exactly when the component type has them.
100    const ORDER_MAX: Self = Self { re: E::ORDER_MAX, im: E::ORDER_MAX };
101    const ORDER_MIN: Self = Self { re: E::ORDER_MIN, im: E::ORDER_MIN };
102    const HAS_UNORDERED: bool = E::HAS_UNORDERED;
103
104    #[inline(always)] fn from_i8(value: i8) -> Self { Self::real(E::from_i8(value)) }
105    #[inline(always)] fn from_u8(value: u8) -> Self { Self::real(E::from_u8(value)) }
106    #[inline(always)] fn from_u16(value: u16) -> Self { Self::real(E::from_u16(value)) }
107}
108
109impl<E: RealValue + FloatElement> Complex<E> {
110    /// The modulus `$|z|$` of a complex element, the vector math library not being
111    /// available at the element level.
112    #[inline(always)]
113    fn elem_modulus(self) -> E {
114        E::sqrt(self.re.mul_add(self.re, self.im * self.im))
115    }
116}
117
118impl<E: RealValue + FloatElement> SignedElement for Complex<E> {
119    /// The modulus `$|z|$`, as a real complex number.
120    #[inline(always)]
121    fn abs(self) -> Self {
122        Self::real(self.elem_modulus())
123    }
124
125    /// `$z/|z|$`, the unit complex number along `z`, and zero at the origin.
126    #[inline(always)]
127    fn signum(self) -> Self {
128        let m = self.elem_modulus();
129
130        if m == E::ZERO {
131            return Self::ZERO;
132        }
133
134        Self::new(self.re / m, self.im / m)
135    }
136}
137
138/// Splats a compile-time integer constant as a real `Complex<E>`.
139pub struct ComplexIntConst<E, const VAL: LargeInt>(PhantomData<E>);
140
141/// Splats a compile-time rational constant `N/D` as a real `Complex<E>`.
142pub struct ComplexRatioConst<E, const NUM: LargeInt, const DEN: LargeInt>(PhantomData<E>);
143
144impl<E: RealValue + FloatElement, const VAL: LargeInt> SplatConst<Complex<E>> for ComplexIntConst<E, VAL> {
145    const VALUE: Complex<E> = Complex::real(<E::ConstInt<VAL> as SplatConst<E>>::VALUE);
146}
147
148impl<E: RealValue + FloatElement, const NUM: LargeInt, const DEN: LargeInt> SplatConst<Complex<E>>
149    for ComplexRatioConst<E, NUM, DEN>
150{
151    const VALUE: Complex<E> = Complex::real(<E::ConstRatio<NUM, DEN> as SplatConst<E>>::VALUE);
152}
153
154#[rustfmt::skip]
155impl<E: RealValue + FloatElement> FloatElement for Complex<E> {
156    /// The principal square root, in Kahan's form; see `FloatVector::sqrt` below for
157    /// why the symmetric formula is unusable.
158    #[inline(always)]
159    fn sqrt(this: Self) -> Self {
160        let half = E::from_ratio(1, 2);
161
162        let t = E::sqrt((SignedElement::abs(this.re) + this.elem_modulus()) * half);
163
164        if t == E::ZERO {
165            return Self::ZERO;
166        }
167
168        let half_im = this.im * half;
169
170        if this.re >= E::ZERO {
171            Self::new(t, half_im / t)
172        } else {
173            let i = if this.im < E::ZERO { -t } else { t };
174
175            Self::new(SignedElement::abs(half_im) / t, i)
176        }
177    }
178
179    // Rounding is componentwise; see the crate docs.
180    #[inline(always)] fn floor(this: Self) -> Self { Self::new(E::floor(this.re), E::floor(this.im)) }
181    #[inline(always)] fn ceil(this: Self) -> Self { Self::new(E::ceil(this.re), E::ceil(this.im)) }
182    #[inline(always)] fn round(this: Self) -> Self { Self::new(E::round(this.re), E::round(this.im)) }
183    #[inline(always)] fn trunc(this: Self) -> Self { Self::new(E::trunc(this.re), E::trunc(this.im)) }
184
185    #[inline(always)] fn next_up(this: Self) -> Self { Self::new(E::next_up(this.re), E::next_up(this.im)) }
186    #[inline(always)] fn next_down(this: Self) -> Self { Self::new(E::next_down(this.re), E::next_down(this.im)) }
187
188    #[inline(always)]
189    fn try_from_int(value: LargeInt) -> Option<Self> {
190        E::try_from_int(value).map(Self::real)
191    }
192
193    #[inline(always)]
194    fn try_from_ratio(n: LargeInt, d: LargeInt) -> Option<Self> {
195        E::try_from_ratio(n, d).map(Self::real)
196    }
197
198    const HAS_INFINITY: bool = E::HAS_INFINITY;
199    const HAS_SIGNED_ZERO: bool = E::HAS_SIGNED_ZERO;
200    const HAS_SUBNORMALS: bool = E::HAS_SUBNORMALS;
201
202    type ConstInt<const VAL: LargeInt> = ComplexIntConst<E, VAL>;
203    type ConstRatio<const NUM: LargeInt, const DEN: LargeInt> = ComplexRatioConst<E, NUM, DEN>;
204}
205
206// --- HasIsa / Selectable / Interleave ---
207
208impl<V: thermite::simd::HasIsa> thermite::simd::HasIsa for Complex<V> {
209    type Native = V::Native;
210
211    const ISA: thermite::isa::InstructionSet = V::ISA;
212}
213
214impl<V: RealFloatVector> GenericSelectable for Complex<V> {
215    type SelectableMask = <V as GenericSelectable>::SelectableMask;
216
217    #[inline(always)]
218    fn select<M>(mask: M, t: Self, f: Self) -> Self
219    where
220        Self::SelectableMask: CastMask<M>,
221    {
222        let mask = <Self::SelectableMask as CastMask<M>>::mask_from(mask);
223
224        Self::new(mask.select(t.re, f.re), mask.select(t.im, f.im))
225    }
226}
227
228#[rustfmt::skip]
229impl<V: RealFloatVector> Interleave for Complex<V> {
230    #[inline(always)]
231    fn interleave(self, other: Self) -> (Self, Self) {
232        let (re_lo, re_hi) = self.re.interleave(other.re);
233        let (im_lo, im_hi) = self.im.interleave(other.im);
234
235        (Self::new(re_lo, im_lo), Self::new(re_hi, im_hi))
236    }
237
238    #[inline(always)]
239    fn deinterleave(self, other: Self) -> (Self, Self) {
240        let (re_lo, re_hi) = self.re.deinterleave(other.re);
241        let (im_lo, im_hi) = self.im.deinterleave(other.im);
242
243        (Self::new(re_lo, im_lo), Self::new(re_hi, im_hi))
244    }
245}
246
247// --- Compile-time splat / new machinery ---
248
249/// Carriers extracting one component of a `Complex` element constant.
250struct ComplexReSplat<E, V>(PhantomData<(E, V)>);
251struct ComplexImSplat<E, V>(PhantomData<(E, V)>);
252
253impl<E, V: RealFloatVector> SplatConst<V::Element> for ComplexReSplat<E, V>
254where
255    E: SplatConst<Complex<V::Element>>,
256{
257    const VALUE: V::Element = <E as SplatConst<Complex<V::Element>>>::VALUE.re;
258}
259
260impl<E, V: RealFloatVector> SplatConst<V::Element> for ComplexImSplat<E, V>
261where
262    E: SplatConst<Complex<V::Element>>,
263{
264    const VALUE: V::Element = <E as SplatConst<Complex<V::Element>>>::VALUE.im;
265}
266
267impl<V: RealFloatVector> SplatVector<Complex<V::Element>> for Complex<V> {
268    type Splat<T: SplatConst<Complex<V::Element>>> = Self;
269}
270
271impl<V: RealFloatVector, E: SplatConst<Complex<V::Element>>> VectorValue<E, Complex<V>> for Complex<V> {
272    const VALUE: Complex<V> = Complex {
273        re: const_splat::<V, ComplexReSplat<E, V>>(),
274        im: const_splat::<V, ComplexImSplat<E, V>>(),
275    };
276}
277
278/// Carriers extracting the per-lane components of a `Complex` element array.
279struct ComplexReNew<C, V>(PhantomData<(C, V)>);
280struct ComplexImNew<C, V>(PhantomData<(C, V)>);
281
282macro_rules! impl_new_const {
283    ($($carrier:ident => $field:ident),* $(,)?) => {$(
284        impl<C, V: RealFloatVector> NewConst<V::Element, V::Lanes> for $carrier<C, V>
285        where
286            C: NewConst<Complex<V::Element>, V::Lanes>,
287        {
288            const VALUES: GenericArray<V::Element, V::Lanes> = const {
289                let c_vals = C::VALUES;
290                let src = c_vals.as_slice();
291                let mut out: GenericArray<V::Element, V::Lanes> = unsafe { core::mem::zeroed() };
292                let dst = out.as_mut_slice();
293                let mut i = 0;
294                while i < V::LANES {
295                    dst[i] = src[i].$field;
296                    i += 1;
297                }
298                core::mem::forget(c_vals);
299                out
300            };
301        }
302    )*};
303}
304
305impl_new_const!(ComplexReNew => re, ComplexImNew => im);
306
307/// `VectorValue` implementor for per-lane (`new`) construction of `Complex` vectors.
308pub struct ComplexNewImpl;
309
310impl<T, V: RealFloatVector> VectorValue<T, Complex<V>> for ComplexNewImpl
311where
312    T: NewConst<Complex<V::Element>, V::Lanes>,
313{
314    const VALUE: Complex<V> = Complex {
315        re: const_new::<V, V::Lanes, ComplexReNew<T, V>>(),
316        im: const_new::<V, V::Lanes, ComplexImNew<T, V>>(),
317    };
318}
319
320impl<V: RealFloatVector> NewVector<Complex<V::Element>, V::Lanes> for Complex<V> {
321    type New<T: NewConst<Complex<V::Element>, V::Lanes>> = ComplexNewImpl;
322}
323
324// --- CastVector ---
325
326impl<FROM, TO> CastVector<Complex<FROM>> for Complex<TO>
327where
328    FROM: RealFloatVector + CastVector<TO>,
329    TO: RealFloatVector + CastVector<FROM>,
330{
331    #[inline(always)]
332    fn cast_into(self) -> Complex<FROM> {
333        Complex::<FROM>::cast_from(self)
334    }
335
336    #[inline(always)]
337    fn cast_from(from: Complex<FROM>) -> Self {
338        Complex::new(TO::cast_from(from.re), TO::cast_from(from.im))
339    }
340}
341
342// --- ComplexVector ---
343
344#[rustfmt::skip]
345impl<V: RealFloatVector> crate::math::specialized::ComplexVector for Complex<V> {
346    type Real = V;
347
348    #[inline(always)] fn re(self) -> V { self.re }
349    #[inline(always)] fn im(self) -> V { self.im }
350    #[inline(always)] fn from_parts(re: V, im: V) -> Self { Complex::new(re, im) }
351
352    #[inline(always)]
353    unsafe fn store_streaming_block(self, ptr: *mut Self) {
354        // Stream each half with the real per-vector NT store (`_mm256_stream_ps` on AVX2; a
355        // plain store where the backend has no NT). `&raw mut (*ptr).re/.im` are the true field
356        // addresses, so no `repr` assumption; a `[Self]` slot is `Self`-aligned, `re` sits at
357        // offset 0 and `im` at `size_of::<V>()`, both aligned for the vector NT store. Preserves
358        // the planar `[re | im]` block layout (NO interleave - see the trait doc).
359        unsafe {
360            self.re.store_streaming((&raw mut (*ptr).re).cast());
361            self.im.store_streaming((&raw mut (*ptr).im).cast());
362        }
363    }
364
365    // Policy-free, so these are inherent on Complex<V> as well, where they also
366    // serve the element-level Complex<f32>. The trait methods forward.
367    #[inline(always)] fn conj(self) -> Self { Complex::conj(self) }
368    #[inline(always)] fn norm_sqr(self) -> V { Complex::norm_sqr(self) }
369    #[inline(always)] fn inv(self) -> Self { Complex::inv(self) }
370
371    #[inline(always)] fn norm_l1(self) -> V { self.re.abs() + self.im.abs() }
372}
373
374// --- GenericVector ---
375
376/// Applies one of the inner vector's radix (de)interleaves to both components.
377///
378/// The four `*_radix*` members differ only in which inner routine they call, so they
379/// share this: split the planar parts out, permute each, weave them back. `f` is a
380/// monomorphized fn item (`V::interleave_radix::<N>` and friends), not a closure over
381/// runtime state, so nothing survives inlining but the permutation itself.
382#[inline(always)]
383fn radix_per_component<V: RealFloatVector, const N: usize>(
384    inputs: [Complex<V>; N],
385    f: impl Fn([V; N]) -> [V; N],
386) -> [Complex<V>; N] {
387    let (mut re, mut im) = ([V::EMPTY; N], [V::EMPTY; N]);
388
389    let mut i = 0;
390    while i < N {
391        re[i] = inputs[i].re;
392        im[i] = inputs[i].im;
393        i += 1;
394    }
395
396    let re = f(re);
397    let im = f(im);
398
399    let mut out = [Complex::<V>::EMPTY; N];
400
401    let mut i = 0;
402    while i < N {
403        out[i] = Complex::new(re[i], im[i]);
404        i += 1;
405    }
406
407    out
408}
409
410impl<V: RealFloatVector> Complex<V> {
411    /// Splat a real and imaginary part across every lane.
412    #[inline(always)]
413    pub fn splat_parts(re: V::Element, im: V::Element) -> Self {
414        Self::new(V::splat(re), V::splat(im))
415    }
416}
417
418impl<V: RealFloatVector> GenericVector for Complex<V> {
419    type Element = Complex<V::Element>;
420
421    const EMPTY: Self = Self::ZERO;
422    const LANES: usize = V::LANES;
423
424    type Lanes = V::Lanes;
425
426    type Unsigned = V::Unsigned;
427    type Signed = V::Signed;
428    type Mask = V::Mask;
429
430    #[inline(always)]
431    fn new<const N: usize>(value: [Self::Element; N]) -> Self
432    where
433        Const<N>: IntoArrayLength<ArrayLength = Self::Lanes>,
434    {
435        let mut re = [<V::Element as Element>::ZERO; N];
436        let mut im = [<V::Element as Element>::ZERO; N];
437
438        let mut i = 0;
439        while i < N {
440            re[i] = value[i].re;
441            im[i] = value[i].im;
442            i += 1;
443        }
444
445        Complex::new(V::new(re), V::new(im))
446    }
447
448    #[inline(always)]
449    fn into_array(self) -> GenericArray<Self::Element, Self::Lanes> {
450        let mut arr = GenericArray::default();
451
452        for i in 0..Self::LANES {
453            arr[i] = Complex::new(self.re.extractv(i), self.im.extractv(i));
454        }
455
456        arr
457    }
458
459    #[inline(always)]
460    fn splat(value: Self::Element) -> Self {
461        Self::splat_parts(value.re, value.im)
462    }
463
464    #[inline(always)]
465    fn single(value: Self::Element) -> Self {
466        Complex::new(V::single(value.re), V::single(value.im))
467    }
468
469    // A Complex element only guarantees the alignment of one V::Element. The aligned
470    // load/store have no fast path to take and forward to the unaligned one.
471    #[inline(always)]
472    unsafe fn load(ptr: *const Self::Element) -> Self {
473        unsafe { Self::load_unaligned(ptr) }
474    }
475
476    /// A `Complex` element is `#[repr(C)]` over two floats, so one element is
477    /// [`load_deinterleaved::<1>`](Self::load_deinterleaved), which routes through the
478    /// inner vector's register engine and not a lane-by-lane loop.
479    #[inline(always)]
480    unsafe fn load_unaligned(ptr: *const Self::Element) -> Self {
481        let [out] = unsafe { Self::load_deinterleaved::<1>(ptr) };
482        out
483    }
484
485    #[inline(always)]
486    unsafe fn load_streaming(ptr: *const Self::Element) -> Self {
487        unsafe { Self::load(ptr) }
488    }
489
490    #[inline(always)]
491    fn interleave_by<const GROUP: usize>(self, other: Self) -> (Self, Self) {
492        let (re_lo, re_hi) = self.re.interleave_by::<GROUP>(other.re);
493        let (im_lo, im_hi) = self.im.interleave_by::<GROUP>(other.im);
494        (Self::new(re_lo, im_lo), Self::new(re_hi, im_hi))
495    }
496
497    #[inline(always)]
498    fn deinterleave_by<const GROUP: usize>(self, other: Self) -> (Self, Self) {
499        let (re_lo, re_hi) = self.re.deinterleave_by::<GROUP>(other.re);
500        let (im_lo, im_hi) = self.im.deinterleave_by::<GROUP>(other.im);
501        (Self::new(re_lo, im_lo), Self::new(re_hi, im_hi))
502    }
503
504    #[inline(always)]
505    fn interleave_radix<const N: usize>(inputs: [Self; N]) -> [Self; N] {
506        radix_per_component::<V, N>(inputs, V::interleave_radix::<N>)
507    }
508
509    #[inline(always)]
510    fn deinterleave_radix<const N: usize>(inputs: [Self; N]) -> [Self; N] {
511        radix_per_component::<V, N>(inputs, V::deinterleave_radix::<N>)
512    }
513
514    #[inline(always)]
515    fn deinterleave_radix_by<const N: usize, const GROUP: usize>(inputs: [Self; N]) -> [Self; N] {
516        radix_per_component::<V, N>(inputs, V::deinterleave_radix_by::<N, GROUP>)
517    }
518
519    #[inline(always)]
520    fn interleave_radix_by<const N: usize, const GROUP: usize>(inputs: [Self; N]) -> [Self; N] {
521        radix_per_component::<V, N>(inputs, V::interleave_radix_by::<N, GROUP>)
522    }
523
524    /// `M` interleaved `Complex` streams are `2 * M` interleaved float streams, i.e.
525    /// a grouped problem with `TAIL = 1` (see [`StreamGroup`]). `M` goes straight to
526    /// the inner vector's [`GenericVector::load_deinterleaved_grouped`] - a NEON
527    /// `LD2`/`LD4`, or a shuffle network on x86 - for any `M`.
528    #[inline(always)]
529    unsafe fn load_deinterleaved<const M: usize>(ptr: *const Self::Element) -> [Self; M] {
530        let groups = unsafe { V::load_deinterleaved_grouped::<M, 1>(ptr as *const V::Element) };
531
532        let mut out = [Self::EMPTY; M];
533        let mut j = 0;
534        while j < M {
535            out[j] = Complex::new(groups[j].head, groups[j].tail[0]);
536            j += 1;
537        }
538        out
539    }
540
541    /// The exact inverse of [`load_deinterleaved`](Self::load_deinterleaved).
542    #[inline(always)]
543    unsafe fn store_interleaved<const M: usize>(ptr: *mut Self::Element, values: [Self; M]) {
544        let mut groups = [StreamGroup {
545            head: V::ZERO,
546            tail: [V::ZERO; 1],
547        }; M];
548
549        let mut j = 0;
550        while j < M {
551            groups[j] = StreamGroup {
552                head: values[j].re,
553                tail: [values[j].im],
554            };
555            j += 1;
556        }
557
558        unsafe { V::store_interleaved_grouped::<M, 1>(ptr as *mut V::Element, groups) }
559    }
560
561    #[inline(always)]
562    unsafe fn load_m(src: Self, mask: Self::Mask, ptr: *const Self::Element) -> Self {
563        let ptr = ptr as *const V::Element;
564
565        // A Complex lane is two consecutive floats, so lane i of the mask covers
566        // positions 2i and 2i+1 of the interleaved layout.
567        let (a_mask, b_mask) = mask.interleave(mask);
568        let (src_a, src_b) = src.re.interleave(src.im);
569
570        let a = unsafe { V::load_m(src_a, a_mask, ptr) };
571        let b = unsafe { V::load_m(src_b, b_mask, ptr.add(V::LANES)) };
572
573        let (re, im) = a.deinterleave(b);
574        Complex::new(re, im)
575    }
576
577    #[inline(always)]
578    unsafe fn load_z(mask: Self::Mask, ptr: *const Self::Element) -> Self {
579        unsafe { Self::load_m(Self::EMPTY, mask, ptr) }
580    }
581
582    // See the note on `load` above: the aligned store forwards to unaligned.
583    #[inline(always)]
584    unsafe fn store(self, ptr: *mut Self::Element) {
585        unsafe { self.store_unaligned(ptr) }
586    }
587
588    #[inline(always)]
589    unsafe fn store_unaligned(self, ptr: *mut Self::Element) {
590        unsafe { Self::store_interleaved::<1>(ptr, [self]) }
591    }
592
593    #[inline(always)]
594    unsafe fn store_streaming(self, ptr: *mut Self::Element) {
595        unsafe { self.store(ptr) }
596    }
597
598    #[inline(always)]
599    unsafe fn store_masked(self, mask: Self::Mask, ptr: *mut Self::Element) {
600        let ptr = ptr as *mut V::Element;
601
602        let (a_mask, b_mask) = mask.interleave(mask);
603        let (a, b) = self.re.interleave(self.im);
604
605        unsafe {
606            a.store_masked(a_mask, ptr);
607            b.store_masked(b_mask, ptr.add(V::LANES));
608        }
609    }
610
611    #[inline(always)]
612    unsafe fn lookup_unchecked(values: &[Self::Element], indices: Self::Unsigned) -> Self {
613        // The table reinterpreted as its interleaved [re, im, re, im, ...] floats:
614        // element i lives at float positions 2i and 2i+1, so each component is one
615        // gather through the inner vector's engine.
616        let floats = unsafe { core::slice::from_raw_parts(values.as_ptr() as *const V::Element, values.len() * 2) };
617
618        let re_idx = indices << 1;
619        let im_idx = re_idx + Self::Unsigned::ONE;
620
621        let re = unsafe { V::lookup_unchecked(floats, re_idx) };
622        let im = unsafe { V::lookup_unchecked(floats, im_idx) };
623
624        Complex::new(re, im)
625    }
626
627    #[inline(always)]
628    fn broadcast<const I: usize>(self) -> Self {
629        Complex::new(V::broadcast::<I>(self.re), V::broadcast::<I>(self.im))
630    }
631
632    #[inline(always)]
633    fn broadcastv(self, idx: usize) -> Self {
634        Complex::new(self.re.broadcastv(idx), self.im.broadcastv(idx))
635    }
636
637    #[inline(always)]
638    fn extract<const I: usize>(self) -> Self::Element {
639        Complex::new(V::extract::<I>(self.re), V::extract::<I>(self.im))
640    }
641
642    #[inline(always)]
643    fn extractv(self, idx: usize) -> Self::Element {
644        Complex::new(self.re.extractv(idx), self.im.extractv(idx))
645    }
646
647    #[inline(always)]
648    fn insert<const I: usize>(self, value: Self::Element) -> Self {
649        Complex::new(V::insert::<I>(self.re, value.re), V::insert::<I>(self.im, value.im))
650    }
651
652    #[inline(always)]
653    fn insertv(self, idx: usize, value: Self::Element) -> Self {
654        Complex::new(self.re.insertv(idx, value.re), self.im.insertv(idx, value.im))
655    }
656
657    #[inline(always)]
658    fn reverse(self) -> Self {
659        Complex::new(self.re.reverse(), self.im.reverse())
660    }
661
662    #[inline(always)]
663    fn swap_bytes(self) -> Self {
664        Complex::new(self.re.swap_bytes(), self.im.swap_bytes())
665    }
666
667    #[inline(always)]
668    fn zz(self, mask: Self::Mask) -> Self {
669        Complex::new(self.re.zz(mask), self.im.zz(mask))
670    }
671
672    #[inline(always)]
673    fn nz(self, mask: Self::Mask) -> Self {
674        Complex::new(self.re.nz(mask), self.im.nz(mask))
675    }
676
677    #[inline(always)]
678    fn compress(self, mask: Self::Mask) -> Self {
679        Complex::new(self.re.compress(mask), self.im.compress(mask))
680    }
681
682    #[inline(always)]
683    fn compress_z(self, mask: Self::Mask) -> Self {
684        Complex::new(self.re.compress_z(mask), self.im.compress_z(mask))
685    }
686
687    // Pure lane movement driven by `mask` alone, so both parts take the same
688    // permutation and no lane ends up with a re/im pair from different sources.
689    // `compress_m` too: its keep-lanes come from the population count of the shared
690    // mask, so they land at the same positions in each part.
691    #[inline(always)]
692    fn compress_m(self, src: Self, mask: Self::Mask) -> Self {
693        Complex::new(self.re.compress_m(src.re, mask), self.im.compress_m(src.im, mask))
694    }
695
696    #[inline(always)]
697    fn expand(self, mask: Self::Mask) -> Self {
698        Complex::new(self.re.expand(mask), self.im.expand(mask))
699    }
700
701    #[inline(always)]
702    fn expand_z(self, mask: Self::Mask) -> Self {
703        Complex::new(self.re.expand_z(mask), self.im.expand_z(mask))
704    }
705
706    #[inline(always)]
707    fn expand_m(self, src: Self, mask: Self::Mask) -> Self {
708        Complex::new(self.re.expand_m(src.re, mask), self.im.expand_m(src.im, mask))
709    }
710
711    #[inline(always)]
712    fn align<const OFFSET: usize>(self, other: Self) -> Self {
713        Complex::new(self.re.align::<OFFSET>(other.re), self.im.align::<OFFSET>(other.im))
714    }
715
716    // Both parts align through `V`, so this is only as native as `V` is.
717    const HAS_NATIVE_ALIGN: bool = V::HAS_NATIVE_ALIGN;
718
719    #[inline(always)]
720    fn map<F>(mut self, f: F) -> Self
721    where
722        F: Fn(Self::Element) -> Self::Element,
723    {
724        for i in 0..Self::LANES {
725            self = self.insertv(i, f(self.extractv(i)));
726        }
727        self
728    }
729
730    #[inline(always)]
731    fn fold<F>(self, mut init: Self::Element, f: F) -> Self::Element
732    where
733        F: Fn(Self::Element, Self::Element) -> Self::Element,
734    {
735        for i in 0..Self::LANES {
736            init = f(init, self.extractv(i));
737        }
738        init
739    }
740
741    #[inline(always)]
742    fn reduce<F>(self, f: F) -> Self::Element
743    where
744        F: Fn(Self::Element, Self::Element) -> Self::Element,
745    {
746        let mut result = self.extractv(0);
747        for i in 1..Self::LANES {
748            result = f(result, self.extractv(i));
749        }
750        result
751    }
752
753    #[rustfmt::skip]
754    #[inline(always)]    fn splat_m(src: Self, mask: Self::Mask, value: Self::Element) -> Self { mask.select(Self::splat(value), src) }
755    #[rustfmt::skip]
756    #[inline(always)]    fn splat_z(mask: Self::Mask, value: Self::Element) -> Self { mask.select(Self::splat(value), Self::EMPTY) }
757    #[rustfmt::skip]
758    #[inline(always)]    fn broadcast_c<const I: usize>(self, mask: Self::Mask) -> Self { mask.select(self.broadcast::<I>(), self) }
759    #[rustfmt::skip]
760    #[inline(always)]    fn broadcast_m<const I: usize>(self, src: Self, mask: Self::Mask) -> Self { mask.select(self.broadcast::<I>(), src) }
761    #[rustfmt::skip]
762    #[inline(always)]    fn broadcast_z<const I: usize>(self, mask: Self::Mask) -> Self { mask.select(self.broadcast::<I>(), Self::EMPTY) }
763    #[rustfmt::skip]
764    #[inline(always)]    fn broadcastv_c(self, mask: Self::Mask, idx: usize) -> Self { mask.select(self.broadcastv(idx), self) }
765    #[rustfmt::skip]
766    #[inline(always)]    fn broadcastv_m(self, src: Self, mask: Self::Mask, idx: usize) -> Self { mask.select(self.broadcastv(idx), src) }
767    #[rustfmt::skip]
768    #[inline(always)]    fn broadcastv_z(self, mask: Self::Mask, idx: usize) -> Self { mask.select(self.broadcastv(idx), Self::EMPTY) }
769    #[rustfmt::skip]
770    #[inline(always)]    fn reverse_c(self, mask: Self::Mask) -> Self { mask.select(self.reverse(), self) }
771    #[rustfmt::skip]
772    #[inline(always)]    fn reverse_m(self, src: Self, mask: Self::Mask) -> Self { mask.select(self.reverse(), src) }
773    #[rustfmt::skip]
774    #[inline(always)]    fn reverse_z(self, mask: Self::Mask) -> Self { mask.select(self.reverse(), Self::EMPTY) }
775    #[rustfmt::skip]
776    #[inline(always)]    fn swap_bytes_c(self, mask: Self::Mask) -> Self { mask.select(self.swap_bytes(), self) }
777    #[rustfmt::skip]
778    #[inline(always)]    fn swap_bytes_m(self, src: Self, mask: Self::Mask) -> Self { mask.select(self.swap_bytes(), src) }
779    #[rustfmt::skip]
780    #[inline(always)]    fn swap_bytes_z(self, mask: Self::Mask) -> Self { mask.select(self.swap_bytes(), Self::EMPTY) }
781}
782
783// --- PartialOrdVector: lexicographic by (re, im) ---
784
785#[rustfmt::skip]
786impl<V: RealFloatVector> PartialOrdVector for Complex<V> {
787    #[inline(always)]
788    fn cmp_eq(self, other: Self) -> Self::Mask {
789        self.re.cmp_eq(other.re) & self.im.cmp_eq(other.im)
790    }
791
792    #[inline(always)]
793    fn cmp_ne(self, other: Self) -> Self::Mask {
794        self.re.cmp_ne(other.re) | self.im.cmp_ne(other.im)
795    }
796
797    // (re < other.re) | (re == other.re & im <op> other.im), in one ternlog.
798    #[inline(always)]
799    fn cmp_lt(self, other: Self) -> Self::Mask {
800        let re_lt = self.re.cmp_lt(other.re);
801        let re_eq = self.re.cmp_eq(other.re);
802        let im_lt = self.im.cmp_lt(other.im);
803
804        GenericMask::ternlog::<{ thermite::ternlog_imm!(A | (B & C)) }>(re_lt, re_eq, im_lt)
805    }
806
807    #[inline(always)]
808    fn cmp_gt(self, other: Self) -> Self::Mask {
809        let re_gt = self.re.cmp_gt(other.re);
810        let re_eq = self.re.cmp_eq(other.re);
811        let im_gt = self.im.cmp_gt(other.im);
812
813        GenericMask::ternlog::<{ thermite::ternlog_imm!(A | (B & C)) }>(re_gt, re_eq, im_gt)
814    }
815
816    #[inline(always)]
817    fn cmp_le(self, other: Self) -> Self::Mask {
818        let re_lt = self.re.cmp_lt(other.re);
819        let re_eq = self.re.cmp_eq(other.re);
820        let im_le = self.im.cmp_le(other.im);
821
822        GenericMask::ternlog::<{ thermite::ternlog_imm!(A | (B & C)) }>(re_lt, re_eq, im_le)
823    }
824
825    #[inline(always)]
826    fn cmp_ge(self, other: Self) -> Self::Mask {
827        let re_gt = self.re.cmp_gt(other.re);
828        let re_eq = self.re.cmp_eq(other.re);
829        let im_ge = self.im.cmp_ge(other.im);
830
831        GenericMask::ternlog::<{ thermite::ternlog_imm!(A | (B & C)) }>(re_gt, re_eq, im_ge)
832    }
833}
834
835// --- Masked ops ---
836
837macro_rules! impl_masked {
838    (MUL_ADD: $($method:ident),*) => {paste::paste! {
839        impl<V: RealFloatVector, A, B> thermite::vector::ops::MulAddExtMasked<V::Mask, A, B> for Complex<V>
840        where
841            Complex<V>: thermite::vector::ops::MulAddExt<A, B, Output = Self>,
842        {
843            $(
844                #[inline(always)]
845                fn [<$method _c>](self, mask: V::Mask, a: A, b: B) -> Self {
846                    mask.select(self.$method(a, b), self)
847                }
848                #[inline(always)]
849                fn [<$method _m>](self, src: Self, mask: V::Mask, a: A, b: B) -> Self {
850                    mask.select(self.$method(a, b), src)
851                }
852                #[inline(always)]
853                fn [<$method _z>](self, mask: V::Mask, a: A, b: B) -> Self {
854                    mask.select(self.$method(a, b), Self::EMPTY)
855                }
856            )*
857        }
858
859        impl<V: RealFloatVector, A, B> thermite::vector::ops::MulAddAssignExtMasked<V::Mask, A, B> for Complex<V>
860        where
861            Complex<V>: thermite::vector::ops::MulAddExt<A, B, Output = Self>,
862        {
863            $(
864                #[inline(always)]
865                fn [<$method _assign_c>](&mut self, mask: V::Mask, a: A, b: B) {
866                    *self = mask.select(self.$method(a, b), *self);
867                }
868                #[inline(always)]
869                fn [<$method _assign_m>](&mut self, src: Self, mask: V::Mask, a: A, b: B) {
870                    *self = mask.select(self.$method(a, b), src);
871                }
872                #[inline(always)]
873                fn [<$method _assign_z>](&mut self, mask: V::Mask, a: A, b: B) {
874                    *self = mask.select(self.$method(a, b), Self::EMPTY);
875                }
876            )*
877        }
878    }};
879
880    ($trait:ident::$method:ident) => {paste::paste! {
881        impl<V: RealFloatVector, Rhs> thermite::vector::ops::[<$trait Masked>]<V::Mask, Rhs> for Complex<V>
882        where
883            Complex<V>: core::ops::$trait<Rhs, Output = Self>,
884        {
885            #[inline(always)]
886            fn [<$method _c>](self, mask: V::Mask, rhs: Rhs) -> Self {
887                mask.select(self.$method(rhs), self)
888            }
889            #[inline(always)]
890            fn [<$method _m>](self, src: Self, mask: V::Mask, rhs: Rhs) -> Self {
891                mask.select(self.$method(rhs), src)
892            }
893            #[inline(always)]
894            fn [<$method _z>](self, mask: V::Mask, rhs: Rhs) -> Self {
895                mask.select(self.$method(rhs), Self::EMPTY)
896            }
897        }
898
899        impl<V: RealFloatVector, Rhs> thermite::vector::ops::[<$trait AssignMasked>]<V::Mask, Rhs> for Complex<V>
900        where
901            Complex<V>: core::ops::$trait<Rhs, Output = Self>,
902        {
903            #[inline(always)]
904            fn [<$method _assign_c>](&mut self, mask: V::Mask, rhs: Rhs) {
905                *self = mask.select(self.$method(rhs), *self);
906            }
907            #[inline(always)]
908            fn [<$method _assign_m>](&mut self, src: Self, mask: V::Mask, rhs: Rhs) {
909                *self = mask.select(self.$method(rhs), src);
910            }
911            #[inline(always)]
912            fn [<$method _assign_z>](&mut self, mask: V::Mask, rhs: Rhs) {
913                *self = mask.select(self.$method(rhs), Self::EMPTY);
914            }
915        }
916    }};
917}
918
919impl_masked!(MUL_ADD: mul_add, mul_sub, nmul_add, nmul_sub, mul_adde, mul_sube, nmul_adde, nmul_sube);
920impl_masked!(Add::add);
921impl_masked!(Sub::sub);
922impl_masked!(Mul::mul);
923impl_masked!(Div::div);
924impl_masked!(Rem::rem);
925
926// =====================================================================================
927// Lane-alternating add/sub (`AddSubExt`), over the *inner vector's* lanes - so the
928// even/odd parity applies per complex number. `Add`/`Sub` are component-wise on
929// `re`/`im`, so this is exact: `neg_even` flips the even-lane signs of both parts,
930// then:
931//   addsub(a, b)      = a + neg_even(b)
932//   fmaddsub(a, b, c) = a*b + neg_even(c)   (via the complex product-rule mul_adde)
933//   fmsubadd(a, b, c) = a*b - neg_even(c)
934// =====================================================================================
935
936#[inline(always)]
937fn neg_even_complex<V: RealFloatVector>(x: Complex<V>) -> Complex<V> {
938    // `addsub(0, w) = [-w0, w1, -w2, ...]` flips the even lanes exactly.
939    Complex::new(V::ZERO.addsub(x.re), V::ZERO.addsub(x.im))
940}
941
942impl<V: RealFloatVector> AddSubExt for Complex<V> {
943    type Output = Self;
944
945    #[inline(always)]
946    fn addsub(self, b: Self) -> Self {
947        self + neg_even_complex(b)
948    }
949    #[inline(always)]
950    fn fmaddsub(self, b: Self, c: Self) -> Self {
951        self.mul_adde(b, neg_even_complex(c))
952    }
953    #[inline(always)]
954    fn fmsubadd(self, b: Self, c: Self) -> Self {
955        self.mul_sube(b, neg_even_complex(c))
956    }
957}
958
959impl<V: RealFloatVector> AddSubExtMasked<V::Mask> for Complex<V> {
960    #[inline(always)]
961    fn addsub_c(self, mask: V::Mask, b: Self) -> Self {
962        mask.select(self.addsub(b), self)
963    }
964    #[inline(always)]
965    fn addsub_m(self, src: Self, mask: V::Mask, b: Self) -> Self {
966        mask.select(self.addsub(b), src)
967    }
968    #[inline(always)]
969    fn addsub_z(self, mask: V::Mask, b: Self) -> Self {
970        mask.select(self.addsub(b), Self::EMPTY)
971    }
972
973    #[inline(always)]
974    fn fmaddsub_c(self, mask: V::Mask, b: Self, c: Self) -> Self {
975        mask.select(self.fmaddsub(b, c), self)
976    }
977    #[inline(always)]
978    fn fmaddsub_m(self, src: Self, mask: V::Mask, b: Self, c: Self) -> Self {
979        mask.select(self.fmaddsub(b, c), src)
980    }
981    #[inline(always)]
982    fn fmaddsub_z(self, mask: V::Mask, b: Self, c: Self) -> Self {
983        mask.select(self.fmaddsub(b, c), Self::EMPTY)
984    }
985
986    #[inline(always)]
987    fn fmsubadd_c(self, mask: V::Mask, b: Self, c: Self) -> Self {
988        mask.select(self.fmsubadd(b, c), self)
989    }
990    #[inline(always)]
991    fn fmsubadd_m(self, src: Self, mask: V::Mask, b: Self, c: Self) -> Self {
992        mask.select(self.fmsubadd(b, c), src)
993    }
994    #[inline(always)]
995    fn fmsubadd_z(self, mask: V::Mask, b: Self, c: Self) -> Self {
996        mask.select(self.fmsubadd(b, c), Self::EMPTY)
997    }
998}
999
1000impl<V: RealFloatVector> SquareMasked<V::Mask> for Complex<V> {
1001    #[inline(always)]
1002    fn square_c(self, mask: V::Mask) -> Self::Output {
1003        mask.select(self.square(), self)
1004    }
1005
1006    #[inline(always)]
1007    fn square_m(self, src: Self, mask: V::Mask) -> Self::Output {
1008        mask.select(self.square(), src)
1009    }
1010
1011    #[inline(always)]
1012    fn square_z(self, mask: V::Mask) -> Self::Output {
1013        mask.select(self.square(), Self::ZERO)
1014    }
1015}
1016
1017// The _c/_m/_z variants of the unary (fn m(self) -> Self) and binary
1018// (fn m(self, Self) -> Self) ops, as plain blends, like impl_masked! above.
1019macro_rules! complex_masked {
1020    (unary: $($m:ident),* $(,)?) => { paste::paste! {
1021        $(
1022            #[inline(always)] fn [<$m _c>](self, mask: Self::Mask) -> Self { mask.select(self.$m(), self) }
1023            #[inline(always)] fn [<$m _m>](self, src: Self, mask: Self::Mask) -> Self { mask.select(self.$m(), src) }
1024            #[inline(always)] fn [<$m _z>](self, mask: Self::Mask) -> Self { mask.select(self.$m(), Self::ZERO) }
1025        )*
1026    }};
1027    (binary: $($m:ident),* $(,)?) => { paste::paste! {
1028        $(
1029            #[inline(always)] fn [<$m _c>](self, mask: Self::Mask, rhs: Self) -> Self { mask.select(self.$m(rhs), self) }
1030            #[inline(always)] fn [<$m _m>](self, src: Self, mask: Self::Mask, rhs: Self) -> Self { mask.select(self.$m(rhs), src) }
1031            #[inline(always)] fn [<$m _z>](self, mask: Self::Mask, rhs: Self) -> Self { mask.select(self.$m(rhs), Self::ZERO) }
1032        )*
1033    }};
1034}
1035
1036// --- NumericVector ---
1037
1038#[rustfmt::skip]
1039impl<V: RealFloatVector> Bounded for Complex<V> {
1040    #[inline(always)] fn min_value() -> Self { Complex::new(V::MIN, V::MIN) }
1041    #[inline(always)] fn max_value() -> Self { Complex::new(V::MAX, V::MAX) }
1042}
1043
1044#[rustfmt::skip]
1045/// The lane-sort key: strictly-before under the lexicographic (re, im)
1046/// order, i.e. `cmp_lt`. See `thermite::sort::SortKey` for why this is a
1047/// static trait method and not a closure.
1048impl<V: RealFloatVector> thermite::sort::SortKey<Self> for Complex<V> {
1049    #[inline(always)]
1050    fn key_lt(a: Self, b: Self) -> V::Mask {
1051        a.cmp_lt(b)
1052    }
1053}
1054
1055/// Scalar insertion walk over whole lanes, for widths past the network ladder.
1056/// Quadratic, like core's `sort_any`; compares composite elements through
1057/// `PartialOrd` (lexicographic, matching the vector comparisons).
1058#[inline(always)]
1059fn sort_lanes_scalar<V: NumericVector, O: thermite::sort::SortOrder>(v: V) -> V
1060where
1061    V::Element: PartialOrd,
1062{
1063    let mut out = v;
1064    let mut i = 1;
1065    while i < V::LANES {
1066        let key = out.extractv(i);
1067        let mut j = i;
1068        while j > 0 {
1069            let prev = out.extractv(j - 1);
1070            let misplaced = if O::IS_ASCENDING { prev > key } else { prev < key };
1071            if !misplaced {
1072                break;
1073            }
1074            out = out.insertv(j, prev);
1075            j -= 1;
1076        }
1077        out = out.insertv(j, key);
1078        i += 1;
1079    }
1080    out
1081}
1082
1083impl<V: RealFloatVector> NumericVector for Complex<V> {
1084    // The integer conversions are real/value-only in both directions: an integer has no
1085    // derivative, no imaginary part and no error term, so converting one in yields a
1086    // constant, and converting out is the value part alone.
1087    #[inline(always)]
1088    fn to_signed_integer(self) -> Self::Signed {
1089        self.re.to_signed_integer()
1090    }
1091
1092    #[inline(always)]
1093    fn from_signed_integer(v: Self::Signed) -> Self {
1094        Self::real(V::from_signed_integer(v))
1095    }
1096
1097    #[inline(always)]
1098    fn to_unsigned_integer(self) -> Self::Unsigned {
1099        self.re.to_unsigned_integer()
1100    }
1101
1102    #[inline(always)]
1103    fn from_unsigned_integer(v: Self::Unsigned) -> Self {
1104        Self::real(V::from_unsigned_integer(v))
1105    }
1106
1107    const ZERO: Self = Complex::new(V::ZERO, V::ZERO);
1108    const ONE: Self = Complex::new(V::ONE, V::ZERO);
1109    const TWO: Self = Self::real(V::TWO);
1110
1111    // The lexicographic extremes, consistent with the ordering above.
1112    const MIN: Self = Complex::new(V::MIN, V::MIN);
1113    const MAX: Self = Complex::new(V::MAX, V::MAX);
1114
1115    #[inline(always)]
1116    fn is_zero(self) -> Self::Mask {
1117        self.re.is_zero() & self.im.is_zero()
1118    }
1119    #[inline(always)]
1120    fn is_all_zero(self) -> bool {
1121        self.re.is_all_zero() && self.im.is_all_zero()
1122    }
1123
1124    // Lane sorts are keyed on the lexicographic (re, im) order - which is exactly
1125    // `cmp_lt` here, so the key IS the comparison. Each compare-exchange derives one
1126    // routing mask from it and moves both components through the same permutation
1127    // and select (`thermite::sort::sort_lanes_by_key`).
1128    #[inline(always)]
1129    fn sort_by<O: thermite::sort::SortOrder>(self) -> Self {
1130        if const { Self::LANES <= 16 && Self::LANES.is_power_of_two() } {
1131            thermite::sort::sort_lanes_by_key::<Self, O, Self>(self)
1132        } else {
1133            sort_lanes_scalar::<Self, O>(self)
1134        }
1135    }
1136
1137    #[inline(always)]
1138    fn bitonic_clean_by<O: thermite::sort::SortOrder>(self) -> Self {
1139        if const { Self::LANES <= 16 && Self::LANES.is_power_of_two() } {
1140            thermite::sort::bitonic_clean_lanes_by_key::<Self, O, Self>(self)
1141        } else {
1142            // A full sort trivially cleans a bitonic input.
1143            sort_lanes_scalar::<Self, O>(self)
1144        }
1145    }
1146
1147    #[inline(always)]
1148    fn min(self, other: Self) -> Self {
1149        self.cmp_lt(other).select(self, other)
1150    }
1151    #[inline(always)]
1152    fn max(self, other: Self) -> Self {
1153        self.cmp_gt(other).select(self, other)
1154    }
1155
1156    // Compare against both bounds once, then blend per component.
1157    #[inline(always)]
1158    fn clamp(self, min: Self, max: Self) -> Self {
1159        let is_lt = self.cmp_lt(min);
1160        let is_gt = self.cmp_gt(max);
1161
1162        Complex::new(
1163            is_lt.select(min.re, is_gt.select(max.re, self.re)),
1164            is_lt.select(min.im, is_gt.select(max.im, self.im)),
1165        )
1166    }
1167
1168    // Lexicographic order spans both components: there is no single inner vector to
1169    // hand to arg_minmax. Reduce the extracted elements in log2(LANES) steps with the
1170    // derived PartialOrd.
1171    #[inline(always)]
1172    fn min_element(self) -> Self::Element {
1173        let mut arr = self.into_array();
1174        reduce_in_place(&mut arr, |a, b| if b < a { b } else { a });
1175        arr[0]
1176    }
1177
1178    #[inline(always)]
1179    fn max_element(self) -> Self::Element {
1180        let mut arr = self.into_array();
1181        reduce_in_place(&mut arr, |a, b| if b > a { b } else { a });
1182        arr[0]
1183    }
1184
1185    #[inline(always)]
1186    fn min_max_element(self) -> (Self::Element, Self::Element) {
1187        (self.min_element(), self.max_element())
1188    }
1189
1190    #[inline(always)]
1191    fn arg_minmax(self) -> (usize, usize) {
1192        let arr = self.into_array();
1193
1194        let (mut lo, mut hi) = (0, 0);
1195
1196        for i in 1..Self::LANES {
1197            if arr[i] < arr[lo] {
1198                lo = i;
1199            }
1200            if arr[i] > arr[hi] {
1201                hi = i;
1202            }
1203        }
1204
1205        (lo, hi)
1206    }
1207
1208    // Sum is linear and commutes with the re/im split: each component reduces through
1209    // the inner vector's horizontal sum. No extracting and folding LANES scalar
1210    // complex numbers.
1211    #[inline(always)]
1212    fn sum_elements(self) -> Self::Element {
1213        Complex::new(self.re.sum_elements(), self.im.sum_elements())
1214    }
1215
1216    // Complex addition is componentwise, so the scan is too - the same argument as
1217    // `sum_elements`, one step at a time instead of all the way down.
1218    #[inline(always)]
1219    fn prefix_sum(self) -> Self {
1220        Complex::new(self.re.prefix_sum(), self.im.prefix_sum())
1221    }
1222
1223    #[inline(always)]
1224    fn reverse_prefix_sum(self) -> Self {
1225        Complex::new(self.re.reverse_prefix_sum(), self.im.reverse_prefix_sum())
1226    }
1227
1228    // min/max are lexicographic over both parts (see the ordering above), so there is
1229    // no per-component scan to delegate to: scanning `re` and `im` separately would
1230    // pair a real part from one lane with an imaginary part from another. The ladder
1231    // runs on whole complex values through `Self::min`/`Self::max`.
1232    #[inline(always)]
1233    fn prefix_min(self) -> Self {
1234        thermite::scan_ladder!(forward, self, self.broadcast::<0>(), Self::min)
1235    }
1236
1237    #[inline(always)]
1238    fn prefix_max(self) -> Self {
1239        thermite::scan_ladder!(forward, self, self.broadcast::<0>(), Self::max)
1240    }
1241
1242    #[inline(always)]
1243    fn reverse_prefix_min(self) -> Self {
1244        thermite::scan_ladder!(reverse, self, self.reverse().broadcast::<0>(), Self::min)
1245    }
1246
1247    #[inline(always)]
1248    fn reverse_prefix_max(self) -> Self {
1249        thermite::scan_ladder!(reverse, self, self.reverse().broadcast::<0>(), Self::max)
1250    }
1251
1252    // Product is not componentwise (the parts cross-multiply) and needs complex
1253    // multiplies across lanes. The tree reduction keeps the dependency chain at log
1254    // depth.
1255    #[inline(always)]
1256    fn prod_elements(self) -> Self::Element {
1257        let mut arr = self.into_array();
1258        reduce_in_place(&mut arr, |a, b| a * b);
1259        arr[0]
1260    }
1261
1262    #[inline(always)]
1263    fn offset() -> Self {
1264        Self::real(V::offset())
1265    }
1266    #[inline(always)]
1267    fn indexed() -> Self {
1268        Self::real(V::indexed())
1269    }
1270
1271    #[inline(always)]
1272    fn scale(self, factor: Self::Element) -> Self {
1273        self * Self::splat(factor)
1274    }
1275
1276    #[inline(always)]
1277    fn scale_c(self, mask: Self::Mask, factor: Self::Element) -> Self {
1278        mask.select(<Self as NumericVector>::scale(self, factor), self)
1279    }
1280    #[inline(always)]
1281    fn scale_m(self, src: Self, mask: Self::Mask, factor: Self::Element) -> Self {
1282        mask.select(<Self as NumericVector>::scale(self, factor), src)
1283    }
1284    #[inline(always)]
1285    fn scale_z(self, mask: Self::Mask, factor: Self::Element) -> Self {
1286        mask.select(<Self as NumericVector>::scale(self, factor), Self::ZERO)
1287    }
1288    complex_masked!(binary: min, max);
1289
1290    // pairwise_sum is a lane rearrange-and-add, and a lane's components sit at the
1291    // same index in re and im, so it applies componentwise.
1292    #[inline(always)]
1293    fn pairwise_sum(lo: Self, hi: Self) -> Self {
1294        Complex::new(V::pairwise_sum(lo.re, hi.re), V::pairwise_sum(lo.im, hi.im))
1295    }
1296
1297    #[inline(always)]
1298    fn relaxed_pairwise_sum(lo: Self, hi: Self) -> Self {
1299        Complex::new(
1300            V::relaxed_pairwise_sum(lo.re, hi.re),
1301            V::relaxed_pairwise_sum(lo.im, hi.im),
1302        )
1303    }
1304}
1305
1306// --- SignedVector ---
1307
1308impl<V: RealFloatVector> NegMasked<V::Mask> for Complex<V> {
1309    #[inline(always)]
1310    fn neg_c(self, mask: V::Mask) -> Self {
1311        Complex::new(self.re.neg_c(mask), self.im.neg_c(mask))
1312    }
1313
1314    #[inline(always)]
1315    fn neg_m(self, src: Self, mask: V::Mask) -> Self {
1316        Complex::new(self.re.neg_m(src.re, mask), self.im.neg_m(src.im, mask))
1317    }
1318
1319    #[inline(always)]
1320    fn neg_z(self, mask: V::Mask) -> Self {
1321        Complex::new(self.re.neg_z(mask), self.im.neg_z(mask))
1322    }
1323}
1324
1325impl<V: RealFloatVector> Complex<V> {
1326    /// The modulus `$|z|$` under the default policy, for the vector-trait methods
1327    /// that take no policy. The policy-aware form is
1328    /// [`norm_p`](crate::math::ComplexMathWithPolicy::norm_p).
1329    #[inline(always)]
1330    pub(crate) fn modulus(self) -> V {
1331        self.re.hypot_p::<DefaultPolicy>(self.im)
1332    }
1333}
1334
1335#[rustfmt::skip]
1336impl<V: RealFloatVector> SignedVector for Complex<V> {
1337    const NEG_ONE: Self = Self::real(V::NEG_ONE);
1338    const MIN_POSITIVE: Self = Self::real(V::MIN_POSITIVE);
1339
1340    /// The modulus `$|z|$`, as a real complex number.
1341    #[inline(always)]
1342    fn abs(self) -> Self {
1343        Self::real(self.modulus())
1344    }
1345
1346    /// `$z/|z|$`, the unit complex number along `z`, and zero at the origin.
1347    ///
1348    /// Preserves the real identity `abs(z) * signum(z) == z`.
1349    #[inline(always)]
1350    fn signum(self) -> Self {
1351        let m = self.modulus();
1352        let is_zero = m.is_zero();
1353        let inv = m.reciprocal_p::<DefaultPolicy>();
1354
1355        // nz() zeroes where the mask is set, pinning signum(0) to 0; the division
1356        // there gives 0 * inf = NaN.
1357        Complex::new((self.re * inv).nz(is_zero), (self.im * inv).nz(is_zero))
1358    }
1359
1360    // Sign-bit ops are componentwise. A mask has one bit per lane, and the sign
1361    // predicates report the sign of the real part. See the crate docs.
1362    #[inline(always)] fn is_positive(self) -> Self::Mask { self.re.is_positive() }
1363    #[inline(always)] fn is_negative(self) -> Self::Mask { self.re.is_negative() }
1364    #[inline(always)] fn select_negative(self, if_neg: Self, if_pos: Self) -> Self { self.is_negative().select(if_neg, if_pos) }
1365
1366    #[inline(always)]
1367    fn copysign(self, sign: Self) -> Self {
1368        Complex::new(self.re.copysign(sign.re), self.im.copysign(sign.im))
1369    }
1370
1371    complex_masked!(unary: abs);
1372    complex_masked!(binary: copysign);
1373}
1374
1375// --- FloatVector ---
1376
1377/// Kahan's principal square root, plus a mask of the lanes that degenerated.
1378///
1379/// Split out so those lanes can re-enter it on a rescaled argument; see
1380/// [`sqrt_rescaled`]. Both `t` and the modulus have to be tested, and which one fires
1381/// depends on how the build handles denormals - see the mask's own comment.
1382#[inline(always)]
1383fn sqrt_kahan<V: RealFloatVector>(z: Complex<V>) -> (Complex<V>, V::Mask) {
1384    let half = <V as FloatVector>::HALF;
1385
1386    let m = z.modulus();
1387
1388    // Halving each term before the sum, not after: `|re| + |z|` overflows for a `re`
1389    // near the top of the range even though `sqrt(z)` is comfortably representable
1390    // there (`sqrt(1.7e308)` gave `inf` for a true 1.3e154). Scaling by a power of two
1391    // is exact, so this is the same value at no extra instruction - the multiply folds
1392    // into the FMA.
1393    let t = z.re.abs().mul_adde(half, m * half).sqrt(); // sqrt((|re| + |z|)/2)
1394    let half_im = z.im * half;
1395
1396    // One quotient serves both branches: t >= 0, so |im/2|/t is |im/2t| exactly.
1397    let q = half_im / t;
1398
1399    // re >= 0: (t, im/2t).   re < 0: (|im|/2t, sign(im)*t).
1400    let re_pos = z.re.is_positive();
1401
1402    // *Which* of the two goes to zero depends on how the build handles denormals, and
1403    // neither implies the other - so the flag picks the test, at one instruction either
1404    // way. Testing only one unconditionally returns silent garbage in the other
1405    // configuration, which is exactly how this was found.
1406    //
1407    // - Flushing (the default): `hypot` drops a subnormal `|z|` to zero while the
1408    //   `|re|` beside it survives, so `m == 0` while `t == sqrt(|re|/2)` is non-zero -
1409    //   and a factor of sqrt(2) below the answer. A normal `|z|` keeps `t >= sqrt(m/2)`
1410    //   positive, so `m` alone decides.
1411    // - Preserving or ignoring: `m` keeps the subnormal, so it is zero only for a true
1412    //   zero - but halving the *smallest* subnormals underflows, leaving `t == 0` with
1413    //   `m != 0`. A true zero sets `t` too, so `t` alone decides.
1414    let degenerate = if const { features::PRESERVE_DENORMALS || features::IGNORE_DENORMALS } {
1415        t.is_zero()
1416    } else {
1417        m.is_zero()
1418    };
1419
1420    (
1421        Complex::new(re_pos.select(t, q.abs()), re_pos.select(q, t.mul_sign(z.im))),
1422        degenerate,
1423    )
1424}
1425
1426/// The degenerate lanes of [`sqrt_kahan`].
1427///
1428/// That means one of two things. Either `z` is genuinely zero, where the root is zero
1429/// and both quotients were `0/0`; or `|z|` is subnormal, and either `hypot` flushed it
1430/// even though the *answer* is an entirely ordinary number - `sqrt(5e-324)` is 2.2e-162,
1431/// a perfectly normal double. Denormal flushing exists to avoid hardware stalls on
1432/// denormal intermediates and results; here there are none, only a denormal input, so
1433/// preserving it costs nothing at runtime and buys back 160 orders of magnitude.
1434///
1435/// Scaling into the normal range recovers it. `1/MIN_POSITIVE` is an exact power of two
1436/// whose exponent is even in both binary formats (2^1022 for f64, 2^126 for f32), so
1437/// `sqrt(MIN_POSITIVE)` is exact as well and undoing the scale introduces no rounding of
1438/// its own.
1439#[inline(always)]
1440fn sqrt_rescaled<V: RealFloatVector>(z: Complex<V>) -> Complex<V> {
1441    let up = V::ONE / <V as SignedVector>::MIN_POSITIVE;
1442    let down = <V as SignedVector>::MIN_POSITIVE.sqrt();
1443
1444    let (r, _) = sqrt_kahan(Complex::new(z.re * up, z.im * up));
1445
1446    let is_zero = z.is_zero();
1447
1448    Complex::new((r.re * down).nz(is_zero), (r.im * down).nz(is_zero))
1449}
1450
1451#[rustfmt::skip]
1452impl<V: RealFloatVector> FloatVector for Complex<V> {
1453    const HALF: Self = Self::real(<V as FloatVector>::HALF);
1454    const NEG_ZERO: Self = Self::real(<V as FloatVector>::NEG_ZERO);
1455    const EPSILON: Self = Self::real(<V as FloatVector>::EPSILON);
1456
1457    // Directed along the real axis. A NaN in either component makes the whole
1458    // number NaN.
1459    const INFINITY: Self = Self::real(<V as FloatVector>::INFINITY);
1460    const NEG_INFINITY: Self = Self::real(<V as FloatVector>::NEG_INFINITY);
1461    const NAN: Self = Complex::new(<V as FloatVector>::NAN, <V as FloatVector>::NAN);
1462
1463    type ExtendedPrecision = Self;
1464
1465    // rcp/rsqrt go through the inner vector's reciprocal, and are approximate exactly
1466    // when it is.
1467    const HAS_APPROX_RCP: bool = V::HAS_APPROX_RCP;
1468    const HAS_APPROX_RSQRT: bool = V::HAS_APPROX_RCP;
1469
1470    #[inline(always)] fn is_nan(self) -> Self::Mask { self.re.is_nan() | self.im.is_nan() }
1471    #[inline(always)] fn is_infinite(self) -> Self::Mask { self.re.is_infinite() | self.im.is_infinite() }
1472    #[inline(always)] fn is_finite(self) -> Self::Mask { self.re.is_finite() & self.im.is_finite() }
1473
1474    // |z| is negligible only if both components are, and z is normal if either
1475    // component is and the other is finite.
1476    #[inline(always)] fn is_zero_or_subnormal(self) -> Self::Mask { self.re.is_zero_or_subnormal() & self.im.is_zero_or_subnormal() }
1477    #[inline(always)] fn is_normal(self) -> Self::Mask { (self.re.is_normal() | self.im.is_normal()) & self.is_finite() }
1478    #[inline(always)] fn is_subnormal(self) -> Self::Mask { (self.re.is_subnormal() | self.im.is_subnormal()) & self.is_zero_or_subnormal() }
1479
1480    /// The principal square root, with a branch cut on the negative real axis.
1481    #[inline(always)]
1482    fn sqrt(self) -> Self {
1483        // Kahan's formulation. The symmetric form
1484        //
1485        //     sqrt((|z| + re)/2) + i*sign(im)*sqrt((|z| - re)/2)
1486        //
1487        // is only safe on one side: for a nearly-real z the smaller of |z| +- re is a
1488        // difference of nearly equal numbers, so it cancels to noise and the small
1489        // component has no correct digits left (asin/acos/asinh feed in arguments of
1490        // exactly that shape). Take the large component from the modulus, always
1491        // adding, and recover the small one from re*im_out = im/2. One division, no
1492        // cancellation.
1493        let (res, degenerate) = sqrt_kahan(self);
1494
1495        // Branching rather than blending costs the common path nothing: it trades the two
1496        // unconditional `nz` this used to end with for a test the predictor will call
1497        // correctly essentially always, and takes them off the dependency chain.
1498        if thermite::unlikely(degenerate.any()) {
1499            return degenerate.select(sqrt_rescaled(self), res);
1500        }
1501
1502        res
1503    }
1504
1505    /// `$1/z = \bar{z}/|z|^2$`
1506    #[inline(always)]
1507    fn rcp(self) -> Self {
1508        let inv = self.norm_sqr().rcp();
1509
1510        Complex::new(self.re * inv, -(self.im * inv))
1511    }
1512
1513    /// `$1/\sqrt{z} = \overline{\sqrt{z}}/|z|$`, since `$|\sqrt{z}|^2 = |z|$`.
1514    #[inline(always)]
1515    fn rsqrt(self) -> Self {
1516        let s = self.sqrt();
1517        let inv = self.modulus().rcp();
1518
1519        Complex::new(s.re * inv, -(s.im * inv))
1520    }
1521
1522    // Rounding is componentwise; see the crate docs.
1523    #[inline(always)] fn floor(self) -> Self { Complex::new(self.re.floor(), self.im.floor()) }
1524    #[inline(always)] fn ceil(self) -> Self { Complex::new(self.re.ceil(), self.im.ceil()) }
1525    #[inline(always)] fn round(self) -> Self { Complex::new(self.re.round(), self.im.round()) }
1526    #[inline(always)] fn trunc(self) -> Self { Complex::new(self.re.trunc(), self.im.trunc()) }
1527    #[inline(always)] fn fract(self) -> Self { Complex::new(self.re.fract(), self.im.fract()) }
1528
1529    #[inline(always)] fn mul_sign(self, sign: Self) -> Self { Complex::new(self.re.mul_sign(sign.re), self.im.mul_sign(sign.im)) }
1530    #[inline(always)] fn signed_zero(self) -> Self { Complex::new(self.re.signed_zero(), self.im.signed_zero()) }
1531
1532    #[inline(always)] fn next_up(self) -> Self { Complex::new(self.re.next_up(), self.im.next_up()) }
1533    #[inline(always)] fn next_down(self) -> Self { Complex::new(self.re.next_down(), self.im.next_down()) }
1534
1535    #[inline(always)]
1536    unsafe fn block_autovectorization(&mut self) {
1537        unsafe {
1538            self.re.block_autovectorization();
1539            self.im.block_autovectorization();
1540        }
1541    }
1542
1543    // mix(t) = a*(1 - t) + b*t = (b - a)*t + a, one complex FMA (four inner FMAs)
1544    // rather than a complex multiply and a complex add.
1545    #[inline(always)] fn mix(self, a: Self, b: Self) -> Self { (b - a).mul_adde(self, a) }
1546
1547    complex_masked!(unary: sqrt, rsqrt, rcp, floor, ceil, round, trunc, fract, signed_zero, next_up, next_down);
1548    complex_masked!(binary: mul_sign);
1549}