use std::cmp;
use std::fmt;
use std::ops;
use crate::fraction::{Fraction, ZERO};
use crate::matrix::matrix2x2::Matrix2x2;
pub struct Complex {
pub real: Fraction,
pub imaginary: Fraction,
}
impl Complex {
pub fn new(real: Fraction, imaginary: Fraction) -> Complex {
Complex { real, imaginary }
}
pub fn conjugate(self) -> Complex {
Complex::new(self.real, -self.imaginary)
}
pub fn norm(self) -> Fraction {
(self.real * self.real + self.imaginary * self.imaginary).sqrt()
}
pub fn angle(self) -> Fraction {
Fraction::arc_tangent(self.imaginary / self.real)
}
pub fn as_matrix2x2(self) -> Matrix2x2 {
use crate::matrix::Matrix;
let values: [Fraction; 4] = [self.real, -self.imaginary, self.imaginary, self.real];
Matrix2x2::from_slice(&values)
}
}
impl PartialEq for Complex {
fn eq(&self, other: &Complex) -> bool {
self.real == other.real && self.imaginary == other.imaginary
}
}
impl Eq for Complex {}
impl PartialOrd for Complex {
fn partial_cmp(&self, other: &Complex) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Complex {
fn cmp(&self, other: &Complex) -> cmp::Ordering {
if self.norm() > other.norm() {
return cmp::Ordering::Greater;
} else if self.norm() < other.norm() {
return cmp::Ordering::Less;
}
cmp::Ordering::Equal
}
}
impl fmt::Debug for Complex {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut string = String::from("[");
if self.real != ZERO {
string.push_str(&self.real.to_string());
}
if self.imaginary != ZERO {
string.push_str(&self.imaginary.to_string());
string.push('i');
}
string.push(']');
write!(f, "{}", string)
}
}
impl fmt::Display for Complex {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut string = String::from("(");
if self.real != ZERO {
string.push_str(&self.real.to_string());
}
if self.imaginary != ZERO {
string.push_str(&self.imaginary.to_string());
string.push('i');
}
string.push(')');
write!(f, "{}", string)
}
}
impl ops::Add for Complex {
type Output = Complex;
fn add(self, other: Complex) -> Complex {
Complex::new(self.real + other.real, self.imaginary + other.imaginary)
}
}
impl ops::AddAssign for Complex {
fn add_assign(&mut self, other: Complex) {
self.real += other.real;
self.imaginary += other.imaginary;
}
}
impl ops::Sub for Complex {
type Output = Complex;
fn sub(self, other: Complex) -> Complex {
Complex::new(self.real - other.real, self.imaginary - other.imaginary)
}
}
impl ops::SubAssign for Complex {
fn sub_assign(&mut self, other: Complex) {
self.real -= other.real;
self.imaginary -= other.imaginary;
}
}
impl ops::Mul for Complex {
type Output = Complex;
fn mul(self, other: Complex) -> Complex {
Complex::new(
self.real * other.real - self.imaginary * other.imaginary,
self.real * other.imaginary + self.imaginary * other.real,
)
}
}
impl ops::Div for Complex {
type Output = Complex;
fn div(self, other: Complex) -> Complex {
Complex::new(
(self.real * other.real + self.imaginary * other.imaginary)
/ (other.real * other.real + other.imaginary * other.imaginary),
-(self.real * other.imaginary - self.imaginary * other.real)
/ (other.real * other.real + other.imaginary * other.imaginary),
)
}
}
impl ops::Neg for Complex {
type Output = Complex;
fn neg(self) -> Complex {
Complex::new(-self.real, -self.imaginary)
}
}
impl Copy for Complex {}
impl Clone for Complex {
fn clone(&self) -> Complex {
*self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_test() {
let complex1 = Complex {
real: Fraction::new_denom(7, 1),
imaginary: Fraction::new_denom(5, 1),
};
let complex2 = Complex::new(Fraction::new_denom(7, 1), Fraction::new_denom(5, 1));
assert_eq!(complex1, complex2);
}
#[test]
fn addition_test() {
let complex1 = Complex::new(Fraction::new_denom(7, 1), Fraction::new_denom(5, 1));
let complex2 = Complex::new(Fraction::new_denom(3, 1), Fraction::new_denom(2, 1));
let result_complex = Complex::new(Fraction::new_denom(10, 1), Fraction::new_denom(7, 1));
assert_eq!(result_complex, complex1 + complex2);
assert_eq!(result_complex, complex2 + complex1);
}
#[test]
fn subtraction_test() {
let complex1 = Complex::new(Fraction::new_denom(7, 1), Fraction::new_denom(5, 1));
let complex2 = Complex::new(Fraction::new_denom(3, 1), Fraction::new_denom(2, 1));
let result_complex1 = Complex::new(Fraction::new_denom(4, 1), Fraction::new_denom(3, 1));
let result_complex2 = Complex::new(Fraction::new_denom(-4, 1), Fraction::new_denom(-3, 1));
assert_eq!(result_complex1, complex1 - complex2);
assert_eq!(result_complex2, complex2 - complex1);
}
#[test]
fn multiplication_test() {
let complex1 = Complex::new(Fraction::new_denom(7, 1), Fraction::new_denom(5, 1));
let complex2 = Complex::new(Fraction::new_denom(3, 1), Fraction::new_denom(2, 1));
let result_complex1 = Complex::new(Fraction::new_denom(11, 1), Fraction::new_denom(29, 1));
assert_eq!(result_complex1, complex1 * complex2);
}
#[test]
fn division_test() {
let complex1 = Complex::new(Fraction::new_denom(7, 1), Fraction::new_denom(5, 1));
let complex2 = Complex::new(Fraction::new_denom(3, 1), Fraction::new_denom(2, 1));
let result_complex1 = Complex::new(Fraction::new_denom(31, 13), Fraction::new_denom(1, 13));
let result_complex2 =
Complex::new(Fraction::new_denom(31, 74), Fraction::new_denom(-1, 74));
assert_eq!(result_complex1, complex1 / complex2);
assert_eq!(result_complex2, complex2 / complex1);
}
#[test]
fn conjugate_test() {
let complex = Complex::new(Fraction::new_denom(3, 1), Fraction::new_denom(4, 1));
let result_complex = Complex::new(Fraction::new_denom(3, 1), Fraction::new_denom(-4, 1));
assert_eq!(result_complex, complex.conjugate());
}
#[test]
fn norm_test() {
let complex = Complex::new(Fraction::new_denom(3, 1), Fraction::new_denom(4, 1));
let result = Fraction::new_denom(5, 1);
assert_eq!(result, complex.norm());
}
#[test]
fn angle_test() {
let complex = Complex::new(Fraction::new_denom(3, 1), Fraction::new_denom(4, 1));
let result = Fraction::new_denom(9273, 10000);
assert_eq!(result, complex.angle());
}
#[test]
fn as_matrix2x2_test() {
use crate::matrix::Matrix;
let complex = Complex::new(Fraction::new_denom(3, 1), Fraction::new_denom(4, 1));
let values: [Fraction; 4] = [
Fraction::new_denom(3, 1),
Fraction::new_denom(-4, 1),
Fraction::new_denom(4, 1),
Fraction::new_denom(3, 1),
];
let result_matrix = Matrix2x2::from_slice(&values);
assert_eq!(result_matrix, complex.as_matrix2x2());
}
}