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