Skip to main content

ComplexVector

Trait ComplexVector 

Source
pub trait ComplexVector:
    FloatVector
    + Add<Self::Real, Output = Self>
    + Sub<Self::Real, Output = Self>
    + Mul<Self::Real, Output = Self>
    + Div<Self::Real, Output = Self>
    + Rem<Self::Real, Output = Self>
    + AddAssign<Self::Real>
    + SubAssign<Self::Real>
    + MulAssign<Self::Real>
    + DivAssign<Self::Real>
    + RemAssign<Self::Real>
    + MulAddExt<Self::Real, Self, Output = Self>
    + MulAddAssignExt<Self::Real, Self>
    + AddMasked<Self::Mask, Self::Real, Output = Self>
    + SubMasked<Self::Mask, Self::Real, Output = Self>
    + MulMasked<Self::Mask, Self::Real, Output = Self>
    + DivMasked<Self::Mask, Self::Real, Output = Self>
    + MulAddExtMasked<Self::Mask, Self::Real, Self, Output = Self> {
    type Real: RealFloatVector;

    // Required methods
    fn re(self) -> Self::Real;
    fn im(self) -> Self::Real;
    fn from_parts(re: Self::Real, im: Self::Real) -> Self;
    fn conj(self) -> Self;
    fn norm_sqr(self) -> Self::Real;
    fn norm_l1(self) -> Self::Real;
    fn inv(self) -> Self;

    // Provided methods
    unsafe fn store_streaming_block(self, ptr: *mut Self) { ... }
    fn real(re: Self::Real) -> Self { ... }
}
Expand description

A vector of complex numbers over a real vector type.

The structural half of the complex math family: it names the underlying real vector (Real) and the operations that take no Policy. The policy-dependent ones (modulus, argument, polar form, …) are in ComplexMath.

§Mixed complex/real arithmetic

The supertraits promise the binary operators against Real, so generic code can scale, offset and fuse by a real vector without widening it into a complex one:

use thermite::prelude::*;
use thermite_complex::prelude::*;

// Horner evaluation of a real-coefficient polynomial at a complex point.
fn horner<T: ComplexVector>(z: T, coeffs: &[T::Real]) -> T {
    let mut acc = T::real(coeffs[0]);

    for &c in &coeffs[1..] {
        acc = acc * z + c; // Complex * Complex, then Complex + Real
    }

    acc
}

type V = Vector<f64>;

// z^2 + 3 at z = 1 + 2i is -3 + 4i + 3 = 4i
let z = Complex::new(V::splat(1.0), V::splat(2.0));
let r = horner(z, &[V::ONE, V::ZERO, V::splat(3.0)]);

assert_eq!((r.re.extract::<0>(), r.im.extract::<0>()), (0.0, 4.0));

Mul/Div by a real cost two real multiplies, versus the four multiplies and two adds of a complex multiply by Complex::real(r), which the compiler cannot recover from the widened form. MulAddExt<Self::Real, Self> is promised for the same reason, and is a true single-rounding FMA (one fused op per component) where the complex-by-complex FMA cannot be.

Required Associated Types§

Source

type Real: RealFloatVector

The real vector type of each component, in which a modulus or an argument is measured.

The core SpatialMath family has no such associated type, so its norms must return Self and come back as real-valued complex numbers. ComplexMath::norm returns this instead.

Required Methods§

Source

fn re(self) -> Self::Real

The real part.

Source

fn im(self) -> Self::Real

The imaginary part.

Source

fn from_parts(re: Self::Real, im: Self::Real) -> Self

Builds a complex vector from its real and imaginary parts.

Not spelled new, tempting as it is to match the inherent Complex::new: GenericVector::new is already in scope on every implementor and takes a lane array, so a second new is ambiguous (E0034) in precisely the generic code this trait exists for. real has no such clash and does match its inherent twin.

Source

fn conj(self) -> Self

The complex conjugate re - im*i.

Source

fn norm_sqr(self) -> Self::Real

The squared modulus $|z|^2 = re^2 + im^2$.

Cheaper than norm (no square root), but it squares the range, so it overflows or underflows near the limits of the format.

Source

fn norm_l1(self) -> Self::Real

The L1 (“Manhattan”) norm |re| + |im|, a real value.

Source

fn inv(self) -> Self

The multiplicative inverse $1/z = \bar{z}/|z|^2$.

Inherits the range limits of norm_sqr; the scaled form is ComplexMath::finv.

Provided Methods§

Source

unsafe fn store_streaming_block(self, ptr: *mut Self)

Non-temporal store of the whole block to ptr, in Self’s own memory layout (the planar/SoA [re | im] layout for Complex<V>), bypassing the cache. This is for relocating blocks within a [Self] buffer - e.g. an FFT transpose whose output is too large to cache - NOT the AoS boundary (that is store / store_streaming, which interleave re/im).

Weakly ordered: a non-temporal store is not guaranteed visible to a later load until an sfence, so the caller must fence before reading the result. Use it only when the destination clearly exceeds last-level cache (NT forfeits cache reuse, so it loses below a few MB).

The default is a plain store (correct everywhere, no NT benefit). Complex<V> overrides it to stream each half with the real store_streaming of its component vector (_mm256_stream_ps on AVX2; a plain store on backends without NT).

§Safety

ptr must be valid for writes and aligned to Self (a [Self] slot satisfies this).

Source

fn real(re: Self::Real) -> Self

Builds a complex vector from a real part, with zero imaginary part.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§