use std::{
fmt::{Display, Formatter},
ops::{Add, AddAssign, Div, Mul, MulAssign, Neg, Sub},
};
use crate::{
traits::{Abs, Atan2, Cos, Exp, Hypot, Inv, One, Pow, Sin, Zero},
wrappers::CWrapper,
};
pub fn pulse<T: Hypot>(c: Complex<T>) -> T {
c.re.hypot(c.im)
}
pub fn damp<T>(c: Complex<T>) -> T
where
T: Div<Output = T> + Neg<Output = T> + Hypot + One + Zero,
{
let w = c.re.hypot(c.im);
if w.is_zero() {
-T::one()
} else {
-c.re / w
}
}
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
pub struct Complex<T> {
pub re: T,
pub im: T,
}
impl<T> From<(T, T)> for Complex<T> {
fn from((re, im): (T, T)) -> Self {
Complex::new(re, im)
}
}
impl<T> PartialEq<(T, T)> for Complex<T>
where
T: PartialEq,
{
fn eq(&self, other: &(T, T)) -> bool {
self.re == other.0 && self.im == other.1
}
}
impl<T> Complex<T> {
pub fn new(re: T, im: T) -> Self {
Self { re, im }
}
}
impl<T> Complex<T>
where
T: Clone + Cos + Mul<Output = T> + Sin,
{
pub(crate) fn from_polar(rho: T, theta: T) -> Self {
Self::new(rho.clone() * theta.cos(), rho * theta.sin())
}
}
impl<T> Complex<T>
where
T: Clone + Hypot,
{
pub fn norm(&self) -> T {
self.re.hypot(self.im.clone())
}
}
impl<T> Complex<T>
where
T: Atan2 + Clone,
{
pub fn arg(&self) -> T {
self.im.atan2(self.re.clone())
}
}
impl<T> Pow<T> for Complex<T>
where
T: Abs
+ Add<Output = T>
+ Atan2
+ Clone
+ Cos
+ Div<Output = T>
+ Hypot
+ Inv<Output = T>
+ Mul<Output = T>
+ Neg<Output = T>
+ One
+ PartialOrd
+ Pow<T>
+ Sin
+ Sub<Output = T>
+ Zero,
{
fn powf(&self, exp: T) -> Self {
let (rho, theta) = (self.norm(), self.arg());
Self::from_polar(rho.powf(exp.clone()), theta * exp)
}
#[allow(clippy::cast_sign_loss)]
fn powi(&self, exp: i32) -> Self {
let (mut z, mut n) = if exp < 0 {
(self.inv(), exp.wrapping_neg() as u32)
} else {
(self.clone(), exp as u32)
};
let mut y = Self::one();
while n > 0 {
if n % 2 == 1 {
y = &y * &z;
}
z = &z * &z;
n /= 2;
}
y
}
}
impl<T> Exp for Complex<T>
where
T: Clone + Cos + Exp + Mul<Output = T> + Sin,
{
fn exp(&self) -> Self {
Self::from_polar(self.re.exp(), self.im.clone())
}
}
impl<T> Zero for Complex<T>
where
T: Zero,
{
fn zero() -> Self {
Self::new(T::zero(), T::zero())
}
fn is_zero(&self) -> bool {
self.re.is_zero() && self.im.is_zero()
}
}
impl<T> One for Complex<T>
where
T: One + Zero,
{
fn one() -> Self {
Self::new(T::one(), T::zero())
}
fn is_one(&self) -> bool {
self.re.is_one() && self.im.is_zero()
}
}
impl<T> Add for Complex<T>
where
T: Add<Output = T>,
{
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self::Output::new(self.re + rhs.re, self.im + rhs.im)
}
}
impl<T> AddAssign for Complex<T>
where
T: Add<Output = T> + Clone,
{
fn add_assign(&mut self, rhs: Self) {
self.re = self.re.clone() + rhs.re;
self.im = self.im.clone() + rhs.im;
}
}
impl<'a, T> Add for &'a Complex<T>
where
T: Add<Output = T> + Clone,
{
type Output = Complex<T>;
fn add(self, rhs: Self) -> Self::Output {
Self::Output::new(
self.re.clone() + rhs.re.clone(),
self.im.clone() + rhs.im.clone(),
)
}
}
impl<T> Add<T> for Complex<T>
where
T: Add<Output = T>,
{
type Output = Self;
fn add(self, rhs: T) -> Self::Output {
Self::Output::new(self.re + rhs, self.im)
}
}
impl<T> Add<&T> for Complex<T>
where
T: Add<Output = T> + Clone,
{
type Output = Self;
fn add(self, rhs: &T) -> Self::Output {
Self::Output::new(self.re + rhs.clone(), self.im)
}
}
impl<T> Div for Complex<T>
where
T: Abs
+ Add<Output = T>
+ Clone
+ Div<Output = T>
+ Inv<Output = T>
+ Mul<Output = T>
+ Neg<Output = T>
+ PartialOrd
+ Sub<Output = T>
+ Zero,
{
type Output = Self;
fn div(self, rhs: Self) -> Self::Output {
let (re, im) = complex_division::compdiv(
CWrapper(self.re),
CWrapper(self.im),
CWrapper(rhs.re),
CWrapper(rhs.im),
);
Complex::new(re.0, im.0)
}
}
impl<T> Div<T> for Complex<T>
where
T: Clone + Div<Output = T>,
{
type Output = Self;
fn div(self, rhs: T) -> Self::Output {
Complex::new(self.re / rhs.clone(), self.im / rhs)
}
}
impl<T> Neg for Complex<T>
where
T: Neg<Output = T>,
{
type Output = Self;
fn neg(self) -> Self::Output {
Self::Output::new(-self.re, -self.im)
}
}
impl<T> Mul for Complex<T>
where
T: Add<Output = T> + Clone + Mul<Output = T> + Sub<Output = T>,
{
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
Self::Output::new(
self.re.clone() * rhs.re.clone() - self.im.clone() * rhs.im.clone(),
self.re * rhs.im + self.im * rhs.re,
)
}
}
impl<T> Mul<&Self> for Complex<T>
where
T: Add<Output = T> + Clone + Mul<Output = T> + Sub<Output = T>,
{
type Output = Self;
fn mul(self, rhs: &Self) -> Self::Output {
Self::Output::new(
self.re.clone() * rhs.re.clone() - self.im.clone() * rhs.im.clone(),
self.re * rhs.im.clone() + self.im * rhs.re.clone(),
)
}
}
impl<T> Mul for &Complex<T>
where
T: Add<Output = T> + Clone + Mul<Output = T> + Sub<Output = T>,
{
type Output = Complex<T>;
fn mul(self, rhs: Self) -> Self::Output {
Self::Output::new(
self.re.clone() * rhs.re.clone() - self.im.clone() * rhs.im.clone(),
self.re.clone() * rhs.im.clone() + self.im.clone() * rhs.re.clone(),
)
}
}
impl<T> Mul<T> for Complex<T>
where
T: Clone + Mul<Output = T>,
{
type Output = Self;
fn mul(self, rhs: T) -> Self::Output {
Self::Output::new(self.re * rhs.clone(), self.im * rhs)
}
}
impl<T> MulAssign for Complex<T>
where
T: Add<Output = T> + Clone + Mul<Output = T> + Sub<Output = T>,
{
fn mul_assign(&mut self, rhs: Self) {
let re = self.re.clone() * rhs.re.clone() - self.im.clone() * rhs.im.clone();
let im = self.re.clone() * rhs.im + self.im.clone() * rhs.re;
self.re = re;
self.im = im;
}
}
impl<T> Sub<T> for Complex<T>
where
T: Sub<Output = T>,
{
type Output = Self;
fn sub(self, rhs: T) -> Self::Output {
Self::Output::new(self.re - rhs, self.im)
}
}
impl<T> Inv for &Complex<T>
where
T: Abs
+ Add<Output = T>
+ Clone
+ Div<Output = T>
+ Inv<Output = T>
+ Mul<Output = T>
+ Neg<Output = T>
+ PartialOrd
+ Sub<Output = T>
+ Zero,
{
type Output = Complex<T>;
fn inv(self) -> Self::Output {
let (re, im) =
complex_division::compinv(CWrapper(self.re.clone()), CWrapper(self.im.clone()));
Complex::new(re.0, im.0)
}
}
impl<T> Display for Complex<T>
where
T: Display + PartialOrd + Zero,
{
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
self.re.fmt(f)?;
if !f.sign_plus() && self.im >= T::zero() {
write!(f, " +")?;
} else {
write!(f, " ")?;
}
self.im.fmt(f)?;
write!(f, "i")
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Complex;
#[test]
fn pulse_damp() {
let c = Complex::new(4., 3.);
assert_relative_eq!(5., pulse(c));
assert_relative_eq!(-0.8, damp(c));
let i = Complex::new(0., 1.);
assert_relative_eq!(1., pulse(i));
assert_relative_eq!(0., damp(i));
let zero = Complex::new(0., 0.);
assert_relative_eq!(0., pulse(zero));
assert_relative_eq!(-1., damp(zero));
}
#[test]
fn tuple_conversion() {
assert_eq!(Complex::new(1, 2), Complex::from((1, 2)));
}
#[test]
fn float_power() {
let c = Complex::new(-4., 0.).powf(0.5);
assert_relative_eq!(0., c.re);
assert_relative_eq!(2., c.im);
}
#[test]
fn positive_integer_power() {
assert_eq!(Complex::new(-0.25, 0.), Complex::new(0., 2.).powi(-2));
assert_eq!(Complex::new(0., -64.), Complex::new(0., 4.).powi(3));
}
#[test]
fn zero() {
assert!(Complex::<f32>::zero().is_zero());
}
#[test]
fn one() {
assert!(Complex::<f64>::one().is_one());
}
#[test]
fn add_assign() {
let mut c = Complex::new(3., -5.);
c += Complex::new(10., -38.);
assert_eq!(Complex::new(13., -43.), c);
}
#[test]
fn mul_assign() {
let mut c = Complex::new(3., 0.);
c *= Complex::new(0., -2.);
assert_eq!(Complex::new(0., -6.), c);
}
#[test]
fn display() {
assert_eq!("3 +4i", format!("{}", Complex::new(3., 4.)));
assert_eq!("-5.00 -0.10i", format!("{:0.2}", Complex::new(-5., -0.1)));
}
}