use core::fmt;
use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use super::Float;
#[derive(Copy, Clone, Default, PartialEq)]
#[repr(C)]
pub struct Complex<T: Float> {
pub re: T,
pub im: T,
}
impl<T: Float> Complex<T> {
#[inline]
#[must_use]
pub const fn new(re: T, im: T) -> Self {
Self { re, im }
}
#[inline]
#[must_use]
pub fn zero() -> Self {
Self::new(T::ZERO, T::ZERO)
}
#[inline]
#[must_use]
pub fn one() -> Self {
Self::new(T::ONE, T::ZERO)
}
#[inline]
#[must_use]
pub fn i() -> Self {
Self::new(T::ZERO, T::ONE)
}
#[inline]
#[must_use]
pub fn from_polar(r: T, theta: T) -> Self {
let (sin, cos) = Float::sin_cos(theta);
Self::new(r * cos, r * sin)
}
#[inline]
#[must_use]
pub fn conj(self) -> Self {
Self::new(self.re, -self.im)
}
#[inline]
#[must_use]
pub fn norm_sqr(self) -> T {
self.re * self.re + self.im * self.im
}
#[inline]
#[must_use]
pub fn norm(self) -> T {
Float::sqrt(self.norm_sqr())
}
#[inline]
#[must_use]
pub fn arg(self) -> T {
num_traits::Float::atan2(self.im, self.re)
}
#[inline]
#[must_use]
pub fn inv(self) -> Self {
let norm_sq = self.norm_sqr();
Self::new(self.re / norm_sq, -self.im / norm_sq)
}
#[inline]
#[must_use]
pub fn cis(theta: T) -> Self {
let (sin, cos) = Float::sin_cos(theta);
Self::new(cos, sin)
}
#[inline]
#[must_use]
pub fn scale(self, s: T) -> Self {
Self::new(self.re * s, self.im * s)
}
}
impl<T: Float> fmt::Debug for Complex<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?} + {:?}i", self.re, self.im)
}
}
impl<T: Float> fmt::Display for Complex<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?} + {:?}i", self.re, self.im)
}
}
impl<T: Float> Add for Complex<T> {
type Output = Self;
#[inline]
fn add(self, rhs: Self) -> Self::Output {
Self::new(self.re + rhs.re, self.im + rhs.im)
}
}
impl<T: Float> AddAssign for Complex<T> {
#[inline]
fn add_assign(&mut self, rhs: Self) {
self.re += rhs.re;
self.im += rhs.im;
}
}
impl<T: Float> Sub for Complex<T> {
type Output = Self;
#[inline]
fn sub(self, rhs: Self) -> Self::Output {
Self::new(self.re - rhs.re, self.im - rhs.im)
}
}
impl<T: Float> SubAssign for Complex<T> {
#[inline]
fn sub_assign(&mut self, rhs: Self) {
self.re -= rhs.re;
self.im -= rhs.im;
}
}
impl<T: Float> Mul for Complex<T> {
type Output = Self;
#[inline]
fn mul(self, rhs: Self) -> Self::Output {
Self::new(
self.re * rhs.re - self.im * rhs.im,
self.re * rhs.im + self.im * rhs.re,
)
}
}
impl<T: Float> MulAssign for Complex<T> {
#[inline]
fn mul_assign(&mut self, rhs: Self) {
*self = *self * rhs;
}
}
impl<T: Float> Div for Complex<T> {
type Output = Self;
#[inline]
fn div(self, rhs: Self) -> Self::Output {
self * rhs.inv()
}
}
impl<T: Float> DivAssign for Complex<T> {
#[inline]
fn div_assign(&mut self, rhs: Self) {
*self = *self / rhs;
}
}
impl<T: Float> Neg for Complex<T> {
type Output = Self;
#[inline]
fn neg(self) -> Self::Output {
Self::new(-self.re, -self.im)
}
}
impl<T: Float> Mul<T> for Complex<T> {
type Output = Self;
#[inline]
fn mul(self, rhs: T) -> Self::Output {
Self::new(self.re * rhs, self.im * rhs)
}
}
impl<T: Float> Div<T> for Complex<T> {
type Output = Self;
#[inline]
fn div(self, rhs: T) -> Self::Output {
Self::new(self.re / rhs, self.im / rhs)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_complex_arithmetic() {
let a = Complex::new(1.0_f64, 2.0);
let b = Complex::new(3.0, 4.0);
let sum = a + b;
assert!((sum.re - 4.0).abs() < 1e-10);
assert!((sum.im - 6.0).abs() < 1e-10);
let prod = a * b;
assert!((prod.re - (-5.0)).abs() < 1e-10);
assert!((prod.im - 10.0).abs() < 1e-10);
}
#[test]
fn test_complex_conjugate() {
let z = Complex::new(3.0_f64, 4.0);
let conj = z.conj();
assert!((conj.re - 3.0).abs() < 1e-10);
assert!((conj.im - (-4.0)).abs() < 1e-10);
}
#[test]
fn test_complex_norm() {
let z = Complex::new(3.0_f64, 4.0);
assert!((z.norm() - 5.0).abs() < 1e-10);
}
}