use rand::{
Rng,
distributions::{
Distribution,
uniform::{SampleBorrow, SampleUniform, Uniform, UniformSampler},
},
};
use crate::number::{
instances::{integer::Integer, ratio::Rational},
traits::{
floating::Floating,
fractional::Fractional,
number::Number,
one::One,
realfloat::RealFloat,
zero::Zero,
},
};
#[derive(Clone, PartialEq, Eq)]
pub struct Complex<F: RealFloat> {
pub real: F,
pub imaginary: F,
}
impl<F: RealFloat> Complex<F> {
pub const fn of(real: F, imaginary: F) -> Self { Self { real, imaginary } }
pub fn of_str(complex_number: &str) -> Option<Self> {
std::str::FromStr::from_str(complex_number).ok()
}
pub fn unit_i() -> Self {
Complex {
real: F::zero(),
imaginary: F::one(),
}
}
pub fn conjugate(self) -> Self {
Self {
real: self.real,
imaginary: -self.imaginary,
}
}
pub fn norm(self) -> F {
(self.real.clone() * self.real + self.imaginary.clone() * self.imaginary).square_root()
}
}
impl<F: RealFloat> Zero for Complex<F> {
fn zero() -> Self {
Self {
real: F::zero(),
imaginary: F::zero(),
}
}
fn is_zero(&self) -> bool { self.real.is_zero() && self.imaginary.is_zero() }
}
impl<F: RealFloat> One for Complex<F> {
fn one() -> Self {
Self {
real: F::one(),
imaginary: F::zero(),
}
}
fn is_one(&self) -> bool { self.real.is_one() && self.imaginary.is_zero() }
}
impl<F: RealFloat> std::default::Default for Complex<F> {
fn default() -> Self { Self::zero() }
}
impl<F: RealFloat> std::ops::Neg for Complex<F> {
type Output = Self;
fn neg(self) -> Self::Output {
Self {
real: -self.real,
imaginary: -self.imaginary,
}
}
}
impl<F: RealFloat> std::ops::Add for Complex<F> {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self {
real: self.real + rhs.real,
imaginary: self.imaginary + rhs.imaginary,
}
}
}
impl<F: RealFloat> std::ops::Sub for Complex<F> {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self {
real: self.real - rhs.real,
imaginary: self.imaginary - rhs.imaginary,
}
}
}
impl<F: RealFloat> std::ops::Mul for Complex<F> {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
Self {
real: self.real.clone() * rhs.real.clone()
- self.imaginary.clone() * rhs.imaginary.clone(),
imaginary: self.real * rhs.imaginary + self.imaginary * rhs.real,
}
}
}
impl<F: RealFloat> std::ops::Div for Complex<F> {
type Output = Self;
fn div(self, rhs: Self) -> Self::Output {
let denominator =
rhs.real.clone() * rhs.real.clone() + rhs.imaginary.clone() * rhs.imaginary.clone();
let numerator = self * rhs.conjugate();
Self {
real: numerator.real / denominator.clone(),
imaginary: numerator.imaginary / denominator,
}
}
}
impl<F: RealFloat> Number for Complex<F> {
fn absolute_value(&self) -> Self {
Self {
real: self.clone().norm(),
imaginary: F::zero(),
}
}
fn sign_number(&self) -> Self {
if self.is_zero() {
Self::zero()
} else {
let n = self.clone().norm();
Self {
real: self.real.clone() / n.clone(),
imaginary: self.imaginary.clone() / n,
}
}
}
fn from_integer(integer_number: Integer) -> Self {
if integer_number.is_zero() {
Self::zero()
} else {
Self {
real: F::from_integer(integer_number),
imaginary: F::zero(),
}
}
}
}
impl<F: RealFloat> Floating for Complex<F> {
const PI: Self = Self {
real: F::PI,
imaginary: F::ZERO,
};
const ZERO: Self = Self {
real: F::ZERO,
imaginary: F::ZERO,
};
fn exponential(self) -> Self {
Self {
real: self.real.clone().exponential() * self.imaginary.clone().cosine(),
imaginary: self.real.exponential() * self.imaginary.sine(),
}
}
fn logarithmic(self) -> Self {
Self {
real: self.clone().norm().logarithmic(),
imaginary: F::arc_tangent_2(self.imaginary, self.real),
}
}
fn sine(self) -> Self {
Self {
real: self.real.clone().sine() * self.imaginary.clone().hyperbolic_cosine(),
imaginary: self.real.cosine() * self.imaginary.hyperbolic_sine(),
}
}
fn cosine(self) -> Self {
Self {
real: self.real.clone().cosine() * self.imaginary.clone().hyperbolic_cosine(),
imaginary: -self.real.sine() * self.imaginary.hyperbolic_sine(),
}
}
fn arc_sine(self) -> Self {
let i = Self {
real: F::zero(),
imaginary: F::one(),
};
-i.clone()
* (i * self.clone() + (Self::one() - self.clone() * self).square_root())
.logarithmic()
}
fn arc_cosine(self) -> Self {
let i = Self {
real: F::zero(),
imaginary: F::one(),
};
-i.clone()
* (self.clone() + i * (Self::one() - self.clone() * self).square_root())
.logarithmic()
}
fn arc_tangent(self) -> Self {
let i = Self {
real: F::zero(),
imaginary: F::one(),
};
let two = Self::one() + Self::one();
Self::one() / (two * i.clone())
* ((Self::one() + i.clone() * self.clone()) / (Self::one() - i * self))
.logarithmic()
}
fn hyperbolic_sine(self) -> Self {
(self.clone().exponential() - (-self).exponential()) / (Self::one() + Self::one())
}
fn hyperbolic_cosine(self) -> Self {
(self.clone().exponential() + (-self).exponential()) / (Self::one() + Self::one())
}
fn arc_hyperbolic_sine(self) -> Self {
(self.clone() + (Self::one() + self.clone() * self).square_root()).logarithmic()
}
fn arc_hyperbolic_cosine(self) -> Self {
(self.clone() + (self.clone() * self - Self::one()).square_root()).logarithmic()
}
fn arc_hyperbolic_tangent(self) -> Self {
Self::half() * ((Self::one() + self.clone()) / (Self::one() - self)).logarithmic()
}
}
impl<F: RealFloat> Fractional for Complex<F> {
fn half() -> Self {
Self {
real: F::half(),
imaginary: F::zero(),
}
}
fn reciprocal(self) -> Self {
let n = self.clone().norm();
let conj = self.conjugate();
Self {
real: conj.real / n.clone(),
imaginary: conj.imaginary / n,
}
}
fn from_rational(rational_number: Rational) -> Self {
Self::from_integer(rational_number.numerator)
/ Self::from_integer(rational_number.denominator)
}
}
impl<F: RealFloat> std::cmp::PartialOrd for Complex<F> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
if self.imaginary.is_zero() && other.imaginary.is_zero() {
self.real.partial_cmp(&other.real)
} else {
None
}
}
}
impl<F: RealFloat> std::fmt::Display for Complex<F> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} :+ {}", self.real, self.imaginary)
}
}
impl<F: RealFloat> std::fmt::Debug for Complex<F> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:+} :+ {:+}", self.real, self.imaginary)
}
}
impl<F: RealFloat> std::str::FromStr for Complex<F> {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
let trimmed_s = s.split(":+").map(|p| p.trim()).collect::<Vec<_>>();
if trimmed_s.len() != 2 {
eprintln!(
"Error[Complex::from_str]: ({}) is not a valid Complex literal.",
s
);
Err(())
} else {
let real = F::from_str(trimmed_s[0])?;
let imaginary = F::from_str(trimmed_s[1])?;
Ok(Self { real, imaginary })
}
}
}
pub struct UniformComplex<F: RealFloat + SampleUniform>(Uniform<F>, Uniform<F>);
impl<F: RealFloat + SampleUniform> UniformSampler for UniformComplex<F> {
type X = Complex<F>;
fn new<B1, B2>(low: B1, high: B2) -> Self
where
B1: SampleBorrow<Self::X> + Sized,
B2: SampleBorrow<Self::X> + Sized,
{
Self(
Uniform::<F>::new(low.borrow().real.clone(), high.borrow().real.clone()),
Uniform::<F>::new(
low.borrow().imaginary.clone(),
high.borrow().imaginary.clone(),
),
)
}
fn new_inclusive<B1, B2>(low: B1, high: B2) -> Self
where
B1: SampleBorrow<Self::X> + Sized,
B2: SampleBorrow<Self::X> + Sized,
{
Self(
Uniform::<F>::new_inclusive(low.borrow().real.clone(), high.borrow().real.clone()),
Uniform::<F>::new_inclusive(
low.borrow().imaginary.clone(),
high.borrow().imaginary.clone(),
),
)
}
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
Self::X::of(self.0.sample(rng), self.1.sample(rng))
}
}
impl<F: RealFloat + SampleUniform> SampleUniform for Complex<F> {
type Sampler = UniformComplex<F>;
}