concision_math/traits/
num.rs

1/*
2   Appellation: num <traits>
3   Contrib: FL03 <jo3mccain@icloud.com>
4*/
5use ndarray::{Array, Dimension};
6use num::complex::Complex;
7use num::{Float, Num, Signed, Zero};
8
9pub trait ComplexNum<T = f64> {
10    type Real: Sized;
11}
12/// Trait for converting a type into a complex number.
13pub trait AsComplex<T> {
14    type Complex: ComplexNum<T>;
15
16    fn as_complex(&self, real: bool) -> Self::Complex;
17
18    fn as_re(&self) -> Self::Complex {
19        self.as_complex(true)
20    }
21
22    fn as_im(&self) -> Self::Complex {
23        self.as_complex(false)
24    }
25}
26/// Trait for converting a type into a complex number.
27pub trait IntoComplex<T> {
28    type Complex: ComplexNum<T>;
29
30    fn into_complex(self, real: bool) -> Self::Complex
31    where
32        Self: Sized;
33
34    fn into_re(self) -> Self::Complex
35    where
36        Self: Sized,
37    {
38        self.into_complex(true)
39    }
40
41    fn into_im(self) -> Self::Complex
42    where
43        Self: Sized,
44    {
45        self.into_complex(false)
46    }
47}
48
49pub trait Conjugate {
50    type Output;
51
52    fn conj(&self) -> Self::Output;
53}
54
55pub trait FloorDiv<Rhs = Self> {
56    type Output;
57
58    fn floor_div(self, rhs: Rhs) -> Self::Output;
59}
60
61pub trait RoundTo {
62    fn round_to(&self, places: usize) -> Self;
63}
64
65/*
66 ********* Implementations *********
67*/
68impl<T> ComplexNum<T> for Complex<T>
69where
70    T: Num,
71{
72    type Real = T;
73}
74
75impl<T> ComplexNum<T> for T
76where
77    T: Num,
78{
79    type Real = T;
80}
81
82impl<T> AsComplex<T> for T
83where
84    T: Clone + Num,
85{
86    type Complex = Complex<T>;
87
88    fn as_complex(&self, real: bool) -> Complex<T> {
89        match real {
90            true => Complex::new(self.clone(), Self::zero()),
91            false => Complex::new(Self::zero(), self.clone()),
92        }
93    }
94}
95
96impl<T> IntoComplex<T> for T
97where
98    T: Num,
99{
100    type Complex = Complex<T>;
101
102    fn into_complex(self, real: bool) -> Self::Complex
103    where
104        Self: Sized,
105    {
106        match real {
107            true => Complex::new(self, T::zero()),
108            false => Complex::new(T::zero(), self),
109        }
110    }
111}
112
113impl<T> FloorDiv for T
114where
115    T: Copy + Num,
116{
117    type Output = T;
118
119    fn floor_div(self, rhs: Self) -> Self::Output {
120        crate::floor_div(self, rhs)
121    }
122}
123
124impl<T> RoundTo for T
125where
126    T: Float,
127{
128    fn round_to(&self, places: usize) -> Self {
129        crate::round_to(*self, places)
130    }
131}
132
133/*
134 ************* macro implementations *************
135*/
136
137macro_rules! impl_conj {
138    ($($t:ident<$res:ident>),*) => {
139        $(
140            impl_conj!(@impl $t<$res>);
141        )*
142    };
143    (@impl $t:ident<$res:ident>) => {
144        impl Conjugate for $t {
145            type Output = $res<$t>;
146
147            fn conj(&self) -> Self::Output {
148                Complex { re: *self, im: -$t::zero() }
149            }
150        }
151    };
152}
153
154impl_conj!(f32<Complex>, f64<Complex>);
155
156impl<T> Conjugate for Complex<T>
157where
158    T: Clone + Signed,
159{
160    type Output = Complex<T>;
161
162    fn conj(&self) -> Self {
163        Complex::<T>::conj(self)
164    }
165}
166
167impl<T, D> Conjugate for Array<T, D>
168where
169    D: Dimension,
170    T: Clone + num::complex::ComplexFloat,
171{
172    type Output = Array<T, D>;
173    fn conj(&self) -> Self::Output {
174        self.mapv(|x| x.conj())
175    }
176}