use crate::float::Float;
use num_complex::Complex;
#[inline]
pub fn complex_zero<F: Float>() -> Complex<F> {
Complex {
re: F::ZERO,
im: F::ZERO,
}
}
#[inline]
pub fn complex_from_re<F: Float>(re: F) -> Complex<F> {
Complex { re, im: F::ZERO }
}
#[inline]
pub fn norm_sq<F: Float>(z: Complex<F>) -> F {
z.re * z.re + z.im * z.im
}
#[inline]
pub fn i_times<F: Float>(z: Complex<F>) -> Complex<F> {
Complex {
re: -z.im,
im: z.re,
}
}
#[inline]
pub fn complex_mul<F: Float>(a: Complex<F>, b: Complex<F>) -> Complex<F> {
Complex {
re: a.re * b.re - a.im * b.im,
im: a.re * b.im + a.im * b.re,
}
}
#[inline]
pub fn complex_scale<F: Float>(z: Complex<F>, s: F) -> Complex<F> {
Complex {
re: z.re * s,
im: z.im * s,
}
}
#[inline]
pub fn complex_exp<F: Float>(z: Complex<F>) -> Complex<F> {
let ea = z.re.exp();
let (sb, cb) = z.im.sin_cos();
Complex {
re: ea * cb,
im: ea * sb,
}
}
#[inline]
pub fn complex_div<F: Float>(a: Complex<F>, b: Complex<F>) -> Complex<F> {
let denom = b.re * b.re + b.im * b.im;
Complex {
re: (a.re * b.re + a.im * b.im) / denom,
im: (a.im * b.re - a.re * b.im) / denom,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn complex_zero_one() {
let z: Complex<f64> = complex_zero();
assert_eq!(z.re, 0.0);
assert_eq!(z.im, 0.0);
let o: Complex<f64> = complex_from_re(1.0);
assert_eq!(o.re, 1.0);
assert_eq!(o.im, 0.0);
}
#[test]
fn complex_norm_sq() {
let z = Complex {
re: 3.0_f64,
im: 4.0,
};
assert!((norm_sq(z) - 25.0).abs() < 1e-14);
}
#[test]
fn complex_i_times() {
let z = Complex {
re: 3.0_f64,
im: 4.0,
};
let iz = i_times(z);
assert!((iz.re - (-4.0)).abs() < 1e-14);
assert!((iz.im - 3.0).abs() < 1e-14);
}
}