use approx::{AbsDiffEq, RelativeEq, UlpsEq};
use num_traits::{Float, Num, NumCast, One, ToPrimitive, Zero};
use std::fmt::{Debug, Display};
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct Complex<T: Float> {
pub re: T,
pub im: T,
}
impl<T: Float> Complex<T> {
pub fn new(re: T, im: T) -> Self {
Self { re, im }
}
pub fn from_real(re: T) -> Self {
Self::new(re, T::zero())
}
pub fn from_imag(im: T) -> Self {
Self::new(T::zero(), im)
}
pub fn real(&self) -> T {
self.re
}
pub fn imag(&self) -> T {
self.im
}
pub fn conj(&self) -> Self {
Self::new(self.re, -self.im)
}
pub fn abs(&self) -> T {
(self.re * self.re + self.im * self.im).sqrt()
}
pub fn abs_sq(&self) -> T {
self.re * self.re + self.im * self.im
}
pub fn arg(&self) -> T {
self.im.atan2(self.re)
}
pub fn to_polar(&self) -> (T, T) {
(self.abs(), self.arg())
}
pub fn from_polar(r: T, theta: T) -> Self {
Self::new(r * theta.cos(), r * theta.sin())
}
pub fn is_finite(&self) -> bool {
self.re.is_finite() && self.im.is_finite()
}
pub fn is_infinite(&self) -> bool {
self.re.is_infinite() || self.im.is_infinite()
}
pub fn is_nan(&self) -> bool {
self.re.is_nan() || self.im.is_nan()
}
pub fn is_real(&self) -> bool {
self.im == T::zero()
}
pub fn is_imag(&self) -> bool {
self.re == T::zero()
}
}
impl<T: Float> Complex<T> {
pub fn zero_const() -> Self {
Self {
re: T::zero(),
im: T::zero(),
}
}
pub fn one_const() -> Self {
Self {
re: T::one(),
im: T::zero(),
}
}
pub fn i() -> Self {
Self {
re: T::zero(),
im: T::one(),
}
}
}
impl<T: Float> Zero for Complex<T> {
fn zero() -> Self {
Self::new(T::zero(), T::zero())
}
fn is_zero(&self) -> bool {
self.re.is_zero() && self.im.is_zero()
}
}
impl<T: Float> One for Complex<T> {
fn one() -> Self {
Self::new(T::one(), T::zero())
}
}
impl<T: Float> PartialOrd for Complex<T> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
let self_mag = self.re * self.re + self.im * self.im;
let other_mag = other.re * other.re + other.im * other.im;
self_mag.partial_cmp(&other_mag)
}
}
impl<T: Float> Num for Complex<T> {
type FromStrRadixErr = <T as Num>::FromStrRadixErr;
fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
let val = T::from_str_radix(str, radix)?;
Ok(Self::from_real(val))
}
}
impl<T: Float + ToPrimitive> ToPrimitive for Complex<T> {
fn to_i64(&self) -> Option<i64> {
self.abs().to_i64()
}
fn to_u64(&self) -> Option<u64> {
self.abs().to_u64()
}
fn to_f64(&self) -> Option<f64> {
self.abs().to_f64()
}
fn to_f32(&self) -> Option<f32> {
self.abs().to_f32()
}
}
impl<T: Float + NumCast> NumCast for Complex<T> {
fn from<N: ToPrimitive>(n: N) -> Option<Self> {
T::from(n).map(|t| Self::from_real(t))
}
}
impl<T: Float + AbsDiffEq> AbsDiffEq for Complex<T>
where
T::Epsilon: Clone,
{
type Epsilon = T::Epsilon;
fn default_epsilon() -> Self::Epsilon {
T::default_epsilon()
}
fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
self.re.abs_diff_eq(&other.re, epsilon.clone()) && self.im.abs_diff_eq(&other.im, epsilon)
}
}
impl<T: Float + RelativeEq> RelativeEq for Complex<T>
where
T::Epsilon: Clone,
{
fn default_max_relative() -> Self::Epsilon {
T::default_max_relative()
}
fn relative_eq(
&self,
other: &Self,
epsilon: Self::Epsilon,
max_relative: Self::Epsilon,
) -> bool {
self.re
.relative_eq(&other.re, epsilon.clone(), max_relative.clone())
&& self.im.relative_eq(&other.im, epsilon, max_relative)
}
}
impl<T: Float + UlpsEq> UlpsEq for Complex<T>
where
T::Epsilon: Clone,
{
fn default_max_ulps() -> u32 {
T::default_max_ulps()
}
fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
self.re.ulps_eq(&other.re, epsilon.clone(), max_ulps)
&& self.im.ulps_eq(&other.im, epsilon, max_ulps)
}
}
impl<T: Float + Display> Display for Complex<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.im >= T::zero() {
write!(f, "{}+{}i", self.re, self.im)
} else {
write!(f, "{}{}i", self.re, self.im)
}
}
}
impl<T: Float> From<T> for Complex<T> {
fn from(re: T) -> Self {
Self::from_real(re)
}
}
impl<T: Float> From<(T, T)> for Complex<T> {
fn from((re, im): (T, T)) -> Self {
Self::new(re, im)
}
}
impl<T: Float> From<Complex<T>> for (T, T) {
fn from(z: Complex<T>) -> Self {
(z.re, z.im)
}
}