ospf_rust_math/algebra/operator/comparison/
zero.rs

1use crate::algebra::concept::*;
2use crate::algebra::operator::Abs;
3
4pub trait ZeroOpr<T> {
5    fn precision(&self) -> Option<&T> {
6        None
7    }
8
9    fn is_zero(&self, x: &T) -> bool;
10}
11
12impl<T> FnOnce<(&T,)> for &dyn ZeroOpr<T> {
13    type Output = bool;
14
15    extern "rust-call" fn call_once(self, (x,): (&T,)) -> Self::Output {
16        self.is_zero(x)
17    }
18}
19
20impl<T> FnMut<(&T,)> for &dyn ZeroOpr<T> {
21    extern "rust-call" fn call_mut(&mut self, (x,): (&T,)) -> bool {
22        self.is_zero(x)
23    }
24}
25
26impl<T> Fn<(&T,)> for &dyn ZeroOpr<T> {
27    extern "rust-call" fn call(&self, (x,): (&T,)) -> Self::Output {
28        self.is_zero(x)
29    }
30}
31
32impl<T> FnOnce<(&T,)> for Box<dyn ZeroOpr<T>> {
33    type Output = bool;
34
35    extern "rust-call" fn call_once(self, (x,): (&T,)) -> Self::Output {
36        self.is_zero(x)
37    }
38}
39
40impl<T> FnMut<(&T,)> for Box<dyn ZeroOpr<T>> {
41    extern "rust-call" fn call_mut(&mut self, (x,): (&T,)) -> bool {
42        self.is_zero(x)
43    }
44}
45
46impl<T> Fn<(&T,)> for Box<dyn ZeroOpr<T>> {
47    extern "rust-call" fn call(&self, (x,): (&T,)) -> Self::Output {
48        self.is_zero(x)
49    }
50}
51
52#[derive(Clone, Copy, Debug)]
53pub struct ZeroInt {}
54
55impl ZeroInt {
56    pub fn new() -> Self {
57        Self {}
58    }
59}
60
61impl<T: SemiArithmetic + PartialEq> ZeroOpr<T> for ZeroInt {
62    fn precision(&self) -> Option<&T> {
63        return Some(T::ZERO);
64    }
65
66    fn is_zero(&self, x: &T) -> bool {
67        x == T::ZERO
68    }
69}
70
71#[derive(Clone, Copy, Debug)]
72pub struct ZeroFlt<T> {
73    pub(self) precision: T,
74}
75
76impl<T> From<T> for ZeroFlt<T> {
77    default fn from(precision: T) -> Self {
78        Self { precision }
79    }
80}
81
82impl<T: Signed> From<&T> for ZeroFlt<T>
83where
84    for<'a> &'a T: Abs<Output = T>,
85{
86    fn from(precision: &T) -> Self {
87        Self {
88            precision: precision.abs(),
89        }
90    }
91}
92
93impl<T: Signed + Copy + Abs<Output = T>> From<T> for ZeroFlt<T> {
94    fn from(precision: T) -> Self {
95        Self {
96            precision: precision.abs(),
97        }
98    }
99}
100
101impl<T> ZeroFlt<T> {
102    pub fn new() -> Self
103    where
104        T: Precision + Clone,
105    {
106        Self {
107            precision: <T as Precision>::DECIMAL_PRECISION.clone(),
108        }
109    }
110
111    pub fn new_with(precision: T) -> Self
112    where
113        Self: From<T>,
114    {
115        Self::from(precision)
116    }
117}
118
119impl<T: PartialOrd> ZeroOpr<T> for ZeroFlt<T>
120where
121    for<'a> &'a T: Abs,
122    for<'a> <&'a T as Abs>::Output: PartialOrd<T>,
123{
124    fn precision(&self) -> Option<&T> {
125        Some(&self.precision)
126    }
127
128    fn is_zero(&self, x: &T) -> bool {
129        return x.abs() < self.precision;
130    }
131}
132
133pub trait ZeroOprBuilder<T> {
134    fn new() -> Box<dyn ZeroOpr<T>>;
135    fn new_with(precision: T) -> Box<dyn ZeroOpr<T>>;
136}
137
138pub struct Zero<T> {
139    _marker: std::marker::PhantomData<T>,
140}
141
142impl<T: SemiArithmetic> ZeroOprBuilder<T> for Zero<T> {
143    default fn new() -> Box<dyn ZeroOpr<T>> {
144        Box::new(ZeroInt::new())
145    }
146
147    default fn new_with(precision: T) -> Box<dyn ZeroOpr<T>> {
148        Box::new(ZeroInt::new())
149    }
150}
151
152impl<T: 'static + SemiArithmetic> ZeroOprBuilder<T> for Zero<T>
153where
154    for<'a> &'a T: Abs,
155    for<'a> <&'a T as Abs>::Output: PartialOrd<T>,
156{
157    default fn new() -> Box<dyn ZeroOpr<T>> {
158        Box::new(ZeroInt::new())
159    }
160
161    default fn new_with(precision: T) -> Box<dyn ZeroOpr<T>> {
162        Box::new(ZeroFlt::new_with(precision))
163    }
164}
165
166impl<T: FloatingNumber> ZeroOprBuilder<T> for Zero<T>
167where
168    for<'a> &'a T: Abs,
169    for<'a> <&'a T as Abs>::Output: PartialOrd<T>,
170{
171    fn new() -> Box<dyn ZeroOpr<T>> {
172        Box::new(ZeroFlt::new())
173    }
174
175    fn new_with(precision: T) -> Box<dyn ZeroOpr<T>> {
176        Box::new(ZeroFlt::new_with(precision))
177    }
178}
179
180#[cfg(test)]
181mod tests {
182    use super::*;
183
184    #[test]
185    fn test_zero_int() {
186        let zero = Zero::new();
187        assert_eq!(zero(&0), true);
188        assert_eq!(zero(&1), false);
189    }
190
191    #[test]
192    fn test_zero_flt() {
193        let zero = Zero::new();
194        assert_eq!(zero(&0.0), true);
195        assert_eq!(zero(&1e-6), false);
196
197        let zero = Zero::new_with(1e-5);
198        assert_eq!(zero(&0.0), true);
199        assert_eq!(zero(&1e-6), true);
200    }
201}