use std::ops::*;
use std::fmt::Debug;
use std::iter::Sum;
use num_complex::Complex;
use num_traits::*;
use rand::Rng;
use rand::distributions::*;
use ndarray::LinalgScalar;
use super::lapack_traits::LapackScalar;
pub use num_complex::Complex32 as c32;
pub use num_complex::Complex64 as c64;
macro_rules! trait_alias {
($name:ident: $($t:ident),*) => {
pub trait $name : $($t +)* {}
impl<T> $name for T where T: $($t +)* {}
}}
trait_alias!(Field: LapackScalar,
LinalgScalar,
AssociatedReal,
AssociatedComplex,
Absolute,
SquareRoot,
Conjugate,
RandNormal,
Sum,
Debug);
trait_alias!(RealField: Field, Float);
pub trait AssociatedReal: Sized {
type Real: Float + Mul<Self, Output = Self>;
}
pub trait AssociatedComplex: Sized {
type Complex;
}
pub trait Absolute {
type Output: RealField;
fn squared(&self) -> Self::Output;
fn abs(&self) -> Self::Output {
self.squared().sqrt()
}
}
pub trait SquareRoot {
fn sqrt(&self) -> Self;
}
pub trait Conjugate: Copy {
fn conj(self) -> Self;
}
pub trait RandNormal {
fn randn<R: Rng>(&mut R) -> Self;
}
macro_rules! impl_traits {
($real:ty, $complex:ty) => {
impl AssociatedReal for $real {
type Real = $real;
}
impl AssociatedReal for $complex {
type Real = $real;
}
impl AssociatedComplex for $real {
type Complex = $complex;
}
impl AssociatedComplex for $complex {
type Complex = $complex;
}
impl Absolute for $real {
type Output = Self;
fn squared(&self) -> Self::Output {
*self * *self
}
fn abs(&self) -> Self::Output {
Float::abs(*self)
}
}
impl Absolute for $complex {
type Output = $real;
fn squared(&self) -> Self::Output {
self.norm_sqr()
}
fn abs(&self) -> Self::Output {
self.norm()
}
}
impl SquareRoot for $real {
fn sqrt(&self) -> Self {
Float::sqrt(*self)
}
}
impl SquareRoot for $complex {
fn sqrt(&self) -> Self {
Complex::sqrt(self)
}
}
impl Conjugate for $real {
fn conj(self) -> Self {
self
}
}
impl Conjugate for $complex {
fn conj(self) -> Self {
Complex::conj(&self)
}
}
impl RandNormal for $real {
fn randn<R: Rng>(rng: &mut R) -> Self {
let dist = Normal::new(0., 1.);
dist.ind_sample(rng) as $real
}
}
impl RandNormal for $complex {
fn randn<R: Rng>(rng: &mut R) -> Self {
let dist = Normal::new(0., 1.);
let re = dist.ind_sample(rng) as $real;
let im = dist.ind_sample(rng) as $real;
Self::new(re, im)
}
}
}}
impl_traits!(f64, c64);
impl_traits!(f32, c32);