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§
Sourcetype Real: RealFloatVector
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§
Sourcefn from_parts(re: Self::Real, im: Self::Real) -> Self
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.
Sourcefn norm_sqr(self) -> Self::Real
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.
Sourcefn inv(self) -> Self
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§
Sourceunsafe fn store_streaming_block(self, ptr: *mut Self)
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).
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".