use num_complex::{Complex32, Complex64};
pub type C32 = Complex32;
pub type C64 = Complex64;
#[inline]
pub const fn c64(re: f64, im: f64) -> C64 {
Complex64::new(re, im)
}
#[inline]
pub const fn c32(re: f32, im: f32) -> C32 {
Complex32::new(re, im)
}
pub const I64: C64 = Complex64::new(0.0, 1.0);
pub const I32: C32 = Complex32::new(0.0, 1.0);
#[inline]
pub const fn imag_unit() -> C64 {
I64
}
#[inline]
pub const fn imag_unit32() -> C32 {
I32
}
#[inline]
pub const fn imag(im: f64) -> C64 {
Complex64::new(0.0, im)
}
#[inline]
pub const fn imag32(im: f32) -> C32 {
Complex32::new(0.0, im)
}
#[inline]
pub const fn real(re: f64) -> C64 {
Complex64::new(re, 0.0)
}
#[inline]
pub const fn real32(re: f32) -> C32 {
Complex32::new(re, 0.0)
}
#[inline]
pub fn from_polar(r: f64, theta: f64) -> C64 {
Complex64::from_polar(r, theta)
}
#[inline]
pub fn from_polar32(r: f32, theta: f32) -> C32 {
Complex32::from_polar(r, theta)
}
pub trait ComplexExt: Sized {
type Real;
#[allow(clippy::wrong_self_convention)] fn is_purely_real(self, tolerance: Self::Real) -> bool;
#[allow(clippy::wrong_self_convention)] fn is_purely_imaginary(self, tolerance: Self::Real) -> bool;
fn rotate(self, angle: Self::Real) -> Self;
fn scale_magnitude(self, factor: Self::Real) -> Self;
fn normalize(self) -> Self;
fn reflect_real(self) -> Self;
fn reflect_imag(self) -> Self;
fn distance(self, other: Self) -> Self::Real;
}
impl ComplexExt for C64 {
type Real = f64;
#[inline]
fn is_purely_real(self, tolerance: f64) -> bool {
self.im.abs() <= tolerance
}
#[inline]
fn is_purely_imaginary(self, tolerance: f64) -> bool {
self.re.abs() <= tolerance
}
#[inline]
fn rotate(self, angle: f64) -> Self {
self * Complex64::from_polar(1.0, angle)
}
#[inline]
fn scale_magnitude(self, factor: f64) -> Self {
let (r, theta) = self.to_polar();
Complex64::from_polar(r * factor, theta)
}
#[inline]
fn normalize(self) -> Self {
let norm = self.norm();
if norm == 0.0 {
Complex64::new(0.0, 0.0)
} else {
self / norm
}
}
#[inline]
fn reflect_real(self) -> Self {
self.conj()
}
#[inline]
fn reflect_imag(self) -> Self {
Complex64::new(-self.re, self.im)
}
#[inline]
fn distance(self, other: Self) -> f64 {
(self - other).norm()
}
}
impl ComplexExt for C32 {
type Real = f32;
#[inline]
fn is_purely_real(self, tolerance: f32) -> bool {
self.im.abs() <= tolerance
}
#[inline]
fn is_purely_imaginary(self, tolerance: f32) -> bool {
self.re.abs() <= tolerance
}
#[inline]
fn rotate(self, angle: f32) -> Self {
self * Complex32::from_polar(1.0, angle)
}
#[inline]
fn scale_magnitude(self, factor: f32) -> Self {
let (r, theta) = self.to_polar();
Complex32::from_polar(r * factor, theta)
}
#[inline]
fn normalize(self) -> Self {
let norm = self.norm();
if norm == 0.0 {
Complex32::new(0.0, 0.0)
} else {
self / norm
}
}
#[inline]
fn reflect_real(self) -> Self {
self.conj()
}
#[inline]
fn reflect_imag(self) -> Self {
Complex32::new(-self.re, self.im)
}
#[inline]
fn distance(self, other: Self) -> f32 {
(self - other).norm()
}
}
pub trait ToComplex<C> {
fn to_complex(self) -> C;
fn with_imag(self, im: Self) -> C;
}
impl ToComplex<C64> for f64 {
#[inline]
fn to_complex(self) -> C64 {
Complex64::new(self, 0.0)
}
#[inline]
fn with_imag(self, im: f64) -> C64 {
Complex64::new(self, im)
}
}
impl ToComplex<C32> for f32 {
#[inline]
fn to_complex(self) -> C32 {
Complex32::new(self, 0.0)
}
#[inline]
fn with_imag(self, im: f32) -> C32 {
Complex32::new(self, im)
}
}