use crate::c32;
use crate::c64;
use crate::memory::Memorable;
use faer_traits::ComplexField;
use faer_traits::RealField;
use num::FromPrimitive;
use num::Signed;
use num::ToPrimitive;
use num::bigint::BigInt;
use num::complex::ComplexFloat;
use num::rational::Ratio;
use num_traits::AsPrimitive;
use num_traits::ConstOne;
use num_traits::ConstZero;
use num_traits::Float;
use num_traits::FloatConst;
use num_traits::NumAssign;
use num_traits::NumAssignOps;
use num_traits::NumAssignRef;
use num_traits::NumOps;
use rand_distr::{Distribution, StandardNormal, Uniform};
use crate::bitwidth::BitWidthConvertible;
pub trait RealScalar:
Clone
+ Copy
+ Sync
+ Send
+ Sized
+ std::any::Any
+ std::fmt::Debug
+ std::fmt::Display
+ std::iter::Sum
+ std::iter::Product
+ Float
+ FloatConst
+ FromPrimitive
+ ToPrimitive
+ AsPrimitive<f32>
+ AsPrimitive<f64>
+ NumAssign
+ NumAssignRef
+ Default
+ Signed
+ 'static
+ RealField
+ ConstOne
+ ConstZero
+ Memorable
+ BitWidthConvertible<Width32 = f32, Width64 = f64>
{
type C: ComplexScalar<R = Self>;
fn into_ratio(self) -> Option<Ratio<BigInt>>;
fn from_ratio(ratio: Ratio<BigInt>) -> Option<Self>;
fn standard_random() -> Self;
fn uniform_random(min: Self, max: Self) -> Self;
fn is_close(self, other: impl RealScalar) -> bool;
fn is_close_with_tolerance(self, other: impl RealScalar, rtol: Self, atol: Self) -> bool;
}
impl RealScalar for f32 {
type C = c32;
fn into_ratio(self) -> Option<Ratio<BigInt>> {
Ratio::from_float(self as f64)
}
fn from_ratio(ratio: Ratio<BigInt>) -> Option<Self> {
ratio.to_f32()
}
fn standard_random() -> Self {
let mut rng = rand::rng();
StandardNormal.sample(&mut rng)
}
fn uniform_random(min: Self, max: Self) -> Self {
let mut rng = rand::rng();
Uniform::new(min, max).unwrap().sample(&mut rng)
}
fn is_close(self, other: impl RealScalar) -> bool {
self.is_close_with_tolerance(other, 1e-5, 1e-8)
}
fn is_close_with_tolerance(self, other: impl RealScalar, rtol: Self, atol: Self) -> bool {
(self - other.to32()).abs() <= (atol + rtol * other.to32().abs())
}
}
impl RealScalar for f64 {
type C = c64;
fn into_ratio(self) -> Option<Ratio<BigInt>> {
Ratio::from_float(self)
}
fn from_ratio(ratio: Ratio<BigInt>) -> Option<Self> {
ratio.to_f64()
}
fn standard_random() -> Self {
let mut rng = rand::rng();
StandardNormal.sample(&mut rng)
}
fn uniform_random(min: Self, max: Self) -> Self {
let mut rng = rand::rng();
Uniform::new(min, max).unwrap().sample(&mut rng)
}
fn is_close(self, other: impl RealScalar) -> bool {
self.is_close_with_tolerance(other, 1e-9, 1e-12)
}
fn is_close_with_tolerance(self, other: impl RealScalar, rtol: Self, atol: Self) -> bool {
(self - other.to64()).abs() <= (atol + rtol * other.to64().abs())
}
}
pub trait ComplexScalar:
Clone
+ Copy
+ Sync
+ Send
+ Sized
+ std::any::Any
+ std::fmt::Debug
+ std::fmt::Display
+ std::iter::Sum
+ std::iter::Product
+ NumAssign
+ NumAssignRef
+ NumOps<Self::R>
+ NumAssignOps<Self::R>
+ Default
+ 'static
+ ConstOne
+ ConstZero
+ ComplexField<Real = Self::R>
+ ComplexFloat<Real = Self::R>
+ Memorable
+ BitWidthConvertible<Width32 = c32, Width64 = c64>
{
type R: RealScalar<C = Self>;
fn new(real: impl RealScalar, imag: impl RealScalar) -> Self;
fn from_real(real: impl RealScalar) -> Self;
fn real(&self) -> Self::R;
fn imag(&self) -> Self::R;
fn standard_random() -> Self;
fn uniform_random(
real_min: Self::R,
real_max: Self::R,
imag_min: Self::R,
imag_max: Self::R,
) -> Self;
#[inline(always)]
fn norm_squared(self) -> Self::R {
self.re() * self.re() + self.im() * self.im()
}
}
impl ComplexScalar for c32 {
type R = f32;
fn new(real: impl RealScalar, imag: impl RealScalar) -> Self {
c32::new(real.to32(), imag.to32())
}
fn from_real(real: impl RealScalar) -> Self {
c32::new(real.to32(), 0.0)
}
#[inline(always)]
fn real(&self) -> Self::R {
self.re
}
#[inline(always)]
fn imag(&self) -> Self::R {
self.im
}
fn standard_random() -> Self {
c32::new(f32::standard_random(), f32::standard_random())
}
fn uniform_random(
real_min: Self::R,
real_max: Self::R,
imag_min: Self::R,
imag_max: Self::R,
) -> Self {
c32::new(
f32::uniform_random(real_min, real_max),
f32::uniform_random(imag_min, imag_max),
)
}
}
impl ComplexScalar for c64 {
type R = f64;
fn new(real: impl RealScalar, imag: impl RealScalar) -> Self {
c64::new(real.to64(), imag.to64())
}
fn from_real(real: impl RealScalar) -> Self {
c64::new(real.to64(), 0.0)
}
#[inline(always)]
fn real(&self) -> Self::R {
self.re
}
#[inline(always)]
fn imag(&self) -> Self::R {
self.im
}
fn standard_random() -> Self {
c64::new(f64::standard_random(), f64::standard_random())
}
fn uniform_random(
real_min: Self::R,
real_max: Self::R,
imag_min: Self::R,
imag_max: Self::R,
) -> Self {
c64::new(
f64::uniform_random(real_min, real_max),
f64::uniform_random(imag_min, imag_max),
)
}
}