Skip to main content

tensor4all_tcicore/matrixluci/
scalar.rs

1//! Scalar trait shared by matrixluci implementations.
2
3use num_complex::{Complex32, Complex64};
4use num_traits::{Float, One, Zero};
5
6/// Common scalar trait for matrix LUCI operations.
7pub trait Scalar:
8    Clone
9    + Copy
10    + Zero
11    + One
12    + std::ops::Add<Output = Self>
13    + std::ops::Sub<Output = Self>
14    + std::ops::Mul<Output = Self>
15    + std::ops::Div<Output = Self>
16    + std::ops::Neg<Output = Self>
17    + Default
18    + Send
19    + Sync
20    + 'static
21{
22    /// Complex conjugate.
23    fn conj(self) -> Self;
24
25    /// Squared absolute value.
26    fn abs_sq(self) -> f64;
27
28    /// Absolute value as same scalar type.
29    fn abs(self) -> Self;
30
31    /// Absolute value as f64.
32    fn abs_val(self) -> f64 {
33        self.abs_sq().sqrt()
34    }
35
36    /// Construct from f64.
37    fn from_f64(val: f64) -> Self;
38
39    /// Whether value is NaN.
40    fn is_nan(self) -> bool;
41
42    /// Machine epsilon.
43    fn epsilon() -> f64 {
44        f64::EPSILON
45    }
46}
47
48impl Scalar for f64 {
49    fn conj(self) -> Self {
50        self
51    }
52
53    fn abs_sq(self) -> f64 {
54        self * self
55    }
56
57    fn abs(self) -> Self {
58        Float::abs(self)
59    }
60
61    fn abs_val(self) -> f64 {
62        Float::abs(self)
63    }
64
65    fn from_f64(val: f64) -> Self {
66        val
67    }
68
69    fn is_nan(self) -> bool {
70        Float::is_nan(self)
71    }
72}
73
74impl Scalar for f32 {
75    fn conj(self) -> Self {
76        self
77    }
78
79    fn abs_sq(self) -> f64 {
80        (self * self) as f64
81    }
82
83    fn abs(self) -> Self {
84        Float::abs(self)
85    }
86
87    fn abs_val(self) -> f64 {
88        Float::abs(self) as f64
89    }
90
91    fn from_f64(val: f64) -> Self {
92        val as f32
93    }
94
95    fn is_nan(self) -> bool {
96        Float::is_nan(self)
97    }
98}
99
100impl Scalar for Complex64 {
101    fn conj(self) -> Self {
102        Complex64::conj(&self)
103    }
104
105    fn abs_sq(self) -> f64 {
106        self.norm_sqr()
107    }
108
109    fn abs(self) -> Self {
110        Complex64::new(self.norm(), 0.0)
111    }
112
113    fn abs_val(self) -> f64 {
114        self.norm()
115    }
116
117    fn from_f64(val: f64) -> Self {
118        Complex64::new(val, 0.0)
119    }
120
121    fn is_nan(self) -> bool {
122        self.re.is_nan() || self.im.is_nan()
123    }
124}
125
126impl Scalar for Complex32 {
127    fn conj(self) -> Self {
128        Complex32::conj(&self)
129    }
130
131    fn abs_sq(self) -> f64 {
132        self.norm_sqr() as f64
133    }
134
135    fn abs(self) -> Self {
136        Complex32::new(self.norm(), 0.0)
137    }
138
139    fn abs_val(self) -> f64 {
140        self.norm() as f64
141    }
142
143    fn from_f64(val: f64) -> Self {
144        Complex32::new(val as f32, 0.0)
145    }
146
147    fn is_nan(self) -> bool {
148        self.re.is_nan() || self.im.is_nan()
149    }
150}
151
152#[cfg(test)]
153mod tests;