ospf_rust_math/algebra/operator/comparison/
zero.rs1use 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}