cauchy/
lib.rs

1//! Scalar trait for generic algorithm
2//!
3//! Examples
4//! --------
5//!
6//! Basic arithmetics with real/complex
7//!
8//! ```
9//! use cauchy::Scalar;
10//!
11//! fn add_int<A: Scalar>(a: A) -> A {
12//!     a + A::from(1).unwrap()  // A::from is inhereted from num_traits::NumCast
13//! }
14//!
15//! fn add_float<A: Scalar>(a: A) -> A {
16//!     a + A::from(1.0).unwrap()
17//! }
18//!
19//! fn add_real<A: Scalar>(a: A) -> A::Real {
20//!     a.re() + A::real(1.0)
21//! }
22//!
23//! fn add_complex<A: Scalar>(a: A) -> A::Complex {
24//!     a.as_c() + A::complex(1.0, 1.0)  // upcast to complex if real
25//! }
26//! ```
27//!
28//! Random number generation
29//!
30//! ```
31//! use cauchy::Scalar;
32//! use rand::prelude::*;
33//!
34//! fn random_algorithm<A: Scalar>() {
35//!     let mut rng = StdRng::from_entropy();
36//!     let a = A::rand(&mut rng);
37//! }
38//! ```
39
40use num_complex::Complex;
41use num_traits::{Float, FromPrimitive, NumAssign, NumCast, NumOps, ToPrimitive, Zero};
42use rand::{distributions::Standard, prelude::*};
43use serde::{Deserialize, Serialize};
44use std::fmt::{Debug, Display, LowerExp, UpperExp};
45use std::iter::{Product, Sum};
46use std::ops::Neg;
47
48pub use num_complex::Complex32 as c32;
49pub use num_complex::Complex64 as c64;
50
51pub trait Scalar:
52    NumAssign
53    + FromPrimitive
54    + NumCast
55    + Neg<Output = Self>
56    + Copy
57    + Clone
58    + Display
59    + Debug
60    + LowerExp
61    + UpperExp
62    + Sum
63    + Product
64    + Serialize
65    + for<'de> Deserialize<'de>
66    + 'static
67{
68    type Real: Scalar<Real = Self::Real, Complex = Self::Complex>
69        + NumOps<Self::Real, Self::Real>
70        + Float;
71    type Complex: Scalar<Real = Self::Real, Complex = Self::Complex>
72        + NumOps<Self::Real, Self::Complex>
73        + NumOps<Self::Complex, Self::Complex>;
74
75    /// Create a new real number
76    fn real<T: ToPrimitive>(re: T) -> Self::Real;
77    /// Create a new complex number
78    fn complex<T: ToPrimitive>(re: T, im: T) -> Self::Complex;
79
80    fn from_real(re: Self::Real) -> Self;
81
82    fn add_real(self, re: Self::Real) -> Self;
83    fn sub_real(self, re: Self::Real) -> Self;
84    fn mul_real(self, re: Self::Real) -> Self;
85    fn div_real(self, re: Self::Real) -> Self;
86
87    fn add_complex(self, im: Self::Complex) -> Self::Complex;
88    fn sub_complex(self, im: Self::Complex) -> Self::Complex;
89    fn mul_complex(self, im: Self::Complex) -> Self::Complex;
90    fn div_complex(self, im: Self::Complex) -> Self::Complex;
91
92    fn pow(self, n: Self) -> Self;
93    fn powi(self, n: i32) -> Self;
94    fn powf(self, n: Self::Real) -> Self;
95    fn powc(self, n: Self::Complex) -> Self::Complex;
96
97    /// Real part
98    fn re(&self) -> Self::Real;
99    /// Imaginary part
100    fn im(&self) -> Self::Real;
101    /// As a complex number
102    fn as_c(&self) -> Self::Complex;
103    /// Complex conjugate
104    fn conj(&self) -> Self;
105
106    /// Absolute value
107    fn abs(self) -> Self::Real;
108    /// Sqaure of absolute value
109    fn square(self) -> Self::Real;
110
111    fn sqrt(self) -> Self;
112    fn exp(self) -> Self;
113    fn ln(self) -> Self;
114    fn sin(self) -> Self;
115    fn cos(self) -> Self;
116    fn tan(self) -> Self;
117    fn asin(self) -> Self;
118    fn acos(self) -> Self;
119    fn atan(self) -> Self;
120    fn sinh(self) -> Self;
121    fn cosh(self) -> Self;
122    fn tanh(self) -> Self;
123    fn asinh(self) -> Self;
124    fn acosh(self) -> Self;
125    fn atanh(self) -> Self;
126
127    /// Generate an random number from
128    /// [rand::distributions::Standard](https://docs.rs/rand/0.7.2/rand/distributions/struct.Standard.html)
129    fn rand(rng: &mut impl Rng) -> Self;
130}
131
132macro_rules! impl_float {
133    ($name:ident) => {
134        #[inline]
135        fn $name(self) -> Self {
136            Float::$name(self)
137        }
138    };
139}
140
141macro_rules! impl_complex {
142    ($name:ident) => {
143        #[inline]
144        fn $name(self) -> Self {
145            Complex::$name(self)
146        }
147    };
148}
149
150macro_rules! impl_with_real {
151    ($name:ident, $op:tt) => {
152        #[inline]
153        fn $name(self, re: Self::Real) -> Self {
154            self $op re
155        }
156    }
157}
158
159macro_rules! impl_with_complex {
160    ($name:ident, $op:tt) => {
161        #[inline]
162        fn $name(self, im: Self::Complex) -> Self::Complex {
163            self $op im
164        }
165    }
166}
167
168macro_rules! impl_scalar {
169    ($real:ty, $complex:ty) => {
170        impl Scalar for $real {
171            type Real = $real;
172            type Complex = $complex;
173
174            #[inline]
175            fn re(&self) -> Self::Real {
176                *self
177            }
178            #[inline]
179            fn im(&self) -> Self::Real {
180                0.0
181            }
182
183            #[inline]
184            fn from_real(re: Self::Real) -> Self {
185                re
186            }
187
188            fn pow(self, n: Self) -> Self {
189                self.powf(n)
190            }
191            fn powi(self, n: i32) -> Self {
192                Float::powi(self, n)
193            }
194            fn powf(self, n: Self::Real) -> Self {
195                Float::powf(self, n)
196            }
197            fn powc(self, n: Self::Complex) -> Self::Complex {
198                self.as_c().powc(n)
199            }
200
201            #[inline]
202            fn real<T: ToPrimitive>(re: T) -> Self::Real {
203                NumCast::from(re).unwrap()
204            }
205            #[inline]
206            fn complex<T: ToPrimitive>(re: T, im: T) -> Self::Complex {
207                Complex {
208                    re: NumCast::from(re).unwrap(),
209                    im: NumCast::from(im).unwrap(),
210                }
211            }
212            #[inline]
213            fn as_c(&self) -> Self::Complex {
214                Complex::new(*self, 0.0)
215            }
216            #[inline]
217            fn conj(&self) -> Self {
218                *self
219            }
220            #[inline]
221            fn square(self) -> Self::Real {
222                self * self
223            }
224
225            fn rand(rng: &mut impl Rng) -> Self {
226                rng.sample(Standard)
227            }
228
229            impl_with_real!(add_real, +);
230            impl_with_real!(sub_real, -);
231            impl_with_real!(mul_real, *);
232            impl_with_real!(div_real, /);
233            impl_with_complex!(add_complex, +);
234            impl_with_complex!(sub_complex, -);
235            impl_with_complex!(mul_complex, *);
236            impl_with_complex!(div_complex, /);
237
238            impl_float!(sqrt);
239            impl_float!(abs);
240            impl_float!(exp);
241            impl_float!(ln);
242            impl_float!(sin);
243            impl_float!(cos);
244            impl_float!(tan);
245            impl_float!(sinh);
246            impl_float!(cosh);
247            impl_float!(tanh);
248            impl_float!(asin);
249            impl_float!(acos);
250            impl_float!(atan);
251            impl_float!(asinh);
252            impl_float!(acosh);
253            impl_float!(atanh);
254        }
255
256        impl Scalar for $complex {
257            type Real = $real;
258            type Complex = $complex;
259
260            #[inline]
261            fn re(&self) -> Self::Real {
262                self.re
263            }
264            #[inline]
265            fn im(&self) -> Self::Real {
266                self.im
267            }
268
269            #[inline]
270            fn from_real(re: Self::Real) -> Self {
271                Self::new(re, Zero::zero())
272            }
273
274            fn pow(self, n: Self) -> Self {
275                self.powc(n)
276            }
277            fn powi(self, n: i32) -> Self {
278                self.powf(n as Self::Real)
279            }
280            fn powf(self, n: Self::Real) -> Self {
281                self.powf(n)
282            }
283            fn powc(self, n: Self::Complex) -> Self::Complex {
284                self.powc(n)
285            }
286
287            #[inline]
288            fn real<T: ToPrimitive>(re: T) -> Self::Real {
289                NumCast::from(re).unwrap()
290            }
291            #[inline]
292            fn complex<T: ToPrimitive>(re: T, im: T) -> Self::Complex {
293                Complex {
294                    re: NumCast::from(re).unwrap(),
295                    im: NumCast::from(im).unwrap(),
296                }
297            }
298            #[inline]
299            fn as_c(&self) -> Self::Complex {
300                *self
301            }
302            #[inline]
303            fn conj(&self) -> Self {
304                Complex::conj(self)
305            }
306            #[inline]
307            fn square(self) -> Self::Real {
308                Complex::norm_sqr(&self)
309            }
310            #[inline]
311            fn abs(self) -> Self::Real {
312                Complex::norm(self)
313            }
314
315            fn rand(rng: &mut impl Rng) -> Self {
316                rng.sample(Standard)
317            }
318
319            impl_with_real!(add_real, +);
320            impl_with_real!(sub_real, -);
321            impl_with_real!(mul_real, *);
322            impl_with_real!(div_real, /);
323            impl_with_complex!(add_complex, +);
324            impl_with_complex!(sub_complex, -);
325            impl_with_complex!(mul_complex, *);
326            impl_with_complex!(div_complex, /);
327
328            impl_complex!(sqrt);
329            impl_complex!(exp);
330            impl_complex!(ln);
331            impl_complex!(sin);
332            impl_complex!(cos);
333            impl_complex!(tan);
334            impl_complex!(sinh);
335            impl_complex!(cosh);
336            impl_complex!(tanh);
337            impl_complex!(asin);
338            impl_complex!(acos);
339            impl_complex!(atan);
340            impl_complex!(asinh);
341            impl_complex!(acosh);
342            impl_complex!(atanh);
343        }
344    }
345}
346
347impl_scalar!(f32, c32);
348impl_scalar!(f64, c64);