complex-number 0.1.2

A basic implementation of complex numbers in rust.
Documentation
//! `complex_number` A basic implementation of complex numbers in rust.

use std::ops;

pub mod consts {
    use super::Complex;
    #[allow(unused)] 
    ///The imaginary unit i. Equivalent to `0+1i`.
    pub const I: Complex = Complex {real: 0.0, imag: 1.0};
}

use consts::I;

/// Complex Exponentiation Function
#[allow(unused)] 
pub fn pow(a: Complex, b: Complex) -> Complex {
    let amod2 = a.real*a.real + a.imag*a.imag;
    amod2.powf(b.real/2.0) * (-b.imag*a.arg()).exp() * Complex::from_polar(1.0, b.real*a.arg() + 0.5*b.imag*(amod2.ln()))
}

/// Complex Exponential Function
#[allow(unused)] 
pub fn exp(z: Complex) -> Complex {
    z.real.exp()*Complex::from_polar(1.0, z.imag)
}

/// Complex Natural Logarithm Function
#[allow(unused)]
pub fn ln(z: Complex) -> Complex {
    z.modulus().ln() + z.arg()*I
}


#[allow(unused)] 
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Complex {
    pub real: f32,
    pub imag: f32,
}


impl Complex {

    /// Constructs a complex number from polar coordinates.
    pub fn from_polar(r: f32, th: f32) -> Self {
        Complex {
            real: r * f32::cos(th),
            imag: r * f32::sin(th),
        }
    }

    /// Computes the complex conjugate of a complex number.
    pub fn conj(self) -> Self {
        Complex {
            real: self.real,
            imag: - self.imag,
        }
    }

    /// Computes the argument of a complex number.
    pub fn arg(self) -> f32 {
        self.imag.atan2(self.real)
    }

    /// Computes the modulus of a complex number.
    pub fn modulus(self) -> f32 {
        (self.conj() * self).real.sqrt()
    }


}

impl ops::Add for Complex {
    type Output = Self;

    fn add(self, rhs: Self) -> Self::Output {
        Complex {
            real: self.real + rhs.real,
            imag: self.imag + rhs.imag,
        }
    }
}

impl ops::Sub for Complex {
    type Output = Self; 
    fn sub(self, rhs: Self) -> Self::Output {
        Complex {
            real: self.real - rhs.real,
            imag: self.imag - rhs.imag,
        }
    }
}

impl ops::Mul for Complex {
    type Output = Self;

    fn mul(self, rhs: Self) -> Self::Output {
        Complex {
            real: (self.real * rhs.real) - (self.imag * rhs.imag),
            imag: (self.real * rhs.imag) + (self.imag * rhs.real),
        }
    }
}

impl ops::Div for Complex {
    type Output = Self;

    fn div(self, rhs: Self) -> Self::Output {
        if rhs.real == 0_f32 && rhs.imag == 0_f32 {
            panic!("Cannot divide by 0!");
        }
        let s = rhs.real*rhs.real + rhs.imag*rhs.imag;
        Complex {
            real: (self.real*rhs.real + self.imag*rhs.imag)/s,
            imag: (self.imag*rhs.real - self.real*rhs.imag)/s,
        }
    }
}

impl ops::Add<f32> for Complex {
    type Output = Complex;

    fn add(self, rhs: f32) -> Self::Output {
        Complex {
            real: self.real + rhs,
            imag: self.imag,
        }
    }
}

impl ops::Sub<f32> for Complex {
    type Output = Complex;

    fn sub(self, rhs: f32) -> Self::Output {
        Complex {
            real: self.real - rhs,
            imag: self.imag,
        }
    }
}

impl ops::Mul<f32> for Complex {
    type Output = Complex;

    fn mul(self, rhs: f32) -> Self::Output {
        Complex {
            real: self.real * rhs,
            imag: self.imag * rhs,
        }
    }
}

impl ops::Div<f32> for Complex {
    type Output = Complex;

    fn div(self, rhs: f32) -> Self::Output {
        assert_eq!(rhs, 0_f32, "Cannot divide by 0!");
        Complex {
            real: self.real / rhs,
            imag: self.imag / rhs,
        }
    }
}

impl ops::Add<Complex> for f32 {
    type Output = Complex;
    fn add(self, rhs: Complex) -> Self::Output {
        rhs + self
    }
}

impl ops::Sub<Complex> for f32 {
    type Output = Complex;
    fn sub(self, rhs: Complex) -> Self::Output {
        rhs + self
    }
}

impl ops::Mul<Complex> for f32 {
    type Output = Complex;
    fn mul(self, rhs: Complex) -> Self::Output {
        rhs * self
    }
}

impl ops::Div<Complex> for f32 {
    type Output = Complex;
    fn div(self, rhs: Complex) -> Self::Output {
        rhs / self
    }
}

impl std::fmt::Display for Complex {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let sign = if self.imag < 0.0 { "-" } else { "+" };
        write!(f, "{}{}{}i", self.real, sign, self.imag*self.imag.signum())
    }
}


#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_addition() {
        let a = Complex { real: 1.0, imag: 2.0 };
        let b = Complex { real: 3.0, imag: 4.0 };
        let result = a + b;
        assert_eq!(result, Complex { real: 4.0, imag: 6.0 });
    }

    #[test]
    fn test_subtraction() {
        let a = Complex { real: 5.0, imag: 6.0 };
        let b = Complex { real: 3.0, imag: 4.0 };
        let result = a - b;
        assert_eq!(result, Complex { real: 2.0, imag: 2.0 });
    }

    #[test]
    fn test_multiplication() {
        let a = Complex { real: 1.0, imag: 2.0 };
        let b = Complex { real: 3.0, imag: 4.0 };
        let result = a * b;
        assert_eq!(result, Complex { real: -5.0, imag: 10.0 });
    }

    #[test]
    fn test_division() {
        let a = Complex { real: 1.0, imag: 2.0 };
        let b = Complex { real: 3.0, imag: 4.0 };
        let result = a / b;
        assert_eq!(result, Complex { real: 0.44, imag: 0.08 });
    }

    #[test]
    #[should_panic(expected = "Cannot divide by 0!")]
    fn test_division_by_zero() {
        let a = Complex { real: 1.0, imag: 2.0 };
        let b = Complex { real: 0.0, imag: 0.0 };
        let _ = a / b;
    }

    #[test]
    fn test_conjugate() {
        let a = Complex { real: 1.0, imag: 2.0 };
        let result = a.conj();
        assert_eq!(result, Complex { real: 1.0, imag: -2.0 });
    }

    #[test]
    fn test_modulus() {
        let a = Complex { real: 3.0, imag: 4.0 };
        let result = a.modulus();
        assert_eq!(result, 5.0);
    }

    #[test]
    fn test_argument() {
        let a = Complex { real: 1.0, imag: 1.0 };
        let result = a.arg();
        assert!((result - std::f32::consts::FRAC_PI_4).abs() < 1e-6);
    }

    #[test]
    fn test_from_polar() {
        let r = 2.0;
        let theta = std::f32::consts::PI / 4.0;
        let result = Complex::from_polar(r, theta);
        assert!((result.real - 1.4142).abs() < 1e-4);
        assert!((result.imag - 1.4142).abs() < 1e-4);
    }

    #[test]
    fn test_display_format() {
        let a = Complex { real: 1.0, imag: -2.0 };
        assert_eq!(a.to_string(), "1-2i");

        let b = Complex { real: 3.5, imag: 4.0 };
        assert_eq!(b.to_string(), "3.5+4i");
    }
}