ospf_rust_math/algebra/operator/comparison/
less.rs

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