1use hipparchus_mean::Fp;
2use crate::metrics::Metrics;
3
4#[repr(i32)]
5#[derive(Clone,PartialEq,Debug)]
6pub enum PointMetrics<T:Fp>
7{
8 Manhattan = 1,
10
11 Euclidean = 2,
13
14 Chebyshev = 3,
16
17 Minkowski(T) = 4,
19
20 Canberra = 11,
22
23 Gower = 12,
25}
26
27impl<T:Fp> Metrics<&[T], T> for PointMetrics<T>
28{
29 fn measure(self, x:&[T], y:&[T]) -> T
30 {
31 let it = x.iter().zip(y.iter());
32 match self
33 {
34 PointMetrics::Manhattan => it.fold( T::zero(), | agg, (&a, &b) |
35 {
36 let d = a.sub(b).abs();
37 agg + d
38 }),
39 PointMetrics::Euclidean => it.fold( T::zero(), | agg, (&a, &b) |
40 {
41 let d = a.sub(b);
42 agg + d * d
43 }).sqrt(),
44 PointMetrics::Chebyshev => it.fold( T::zero(), | agg, (&a, &b) |
45 {
46 let d = a.sub(b).abs();
47 agg.max(d)
48 }),
49 PointMetrics::Minkowski(p) => it.fold( T::zero(), | agg, (&a, &b) |
50 {
51 let d = a.sub(b).abs();
52 agg + d.powf(p)
53 }).powf(p.inv()),
54 PointMetrics::Canberra => it.fold( T::zero(), | agg, (&a, &b) |
55 {
56 let d = a.sub(b).abs();
57 let s = a.abs() + b.abs();
58 agg + d / s
59 }),
60 PointMetrics::Gower =>
61 {
62 let mut total = 0;
63 it.fold( T::zero(), | agg, (&a, &b) |
64 {
65 let d = a.sub(b).abs();
66 total += 1;
67 agg + d
68 }) / T::from(total).unwrap()
69 },
70 }
71 }
72}
73
74#[cfg(test)]
75mod tests
76{
77 use super::*;
78 use float_cmp::assert_approx_eq;
79
80 #[test]
81 fn test_manhattan()
82 {
83 let x = [0.0, 1.0];
84 let y = [1.0, -1.0];
85 let expected = 3.0;
86
87 assert_approx_eq!(f32, expected, PointMetrics::Manhattan.measure(&x, &y));
88 assert_approx_eq!(f32, expected, PointMetrics::Manhattan.measure(&y, &x));
89 }
90
91 #[test]
92 fn test_euclidean()
93 {
94 let x = [0.0, 1.0];
95 let y = [1.0, -1.0];
96 let expected = 5.0;
97
98 assert_approx_eq!(f32, expected, PointMetrics::Euclidean::<f32>.measure(&x, &y).powi(2));
99 assert_approx_eq!(f32, expected, PointMetrics::Euclidean::<f32>.measure(&y, &x).powi(2));
100 }
101
102 #[test]
103 fn test_chebyshev()
104 {
105 let x = [0.0, 1.0];
106 let y = [1.0, -1.0];
107 let expected = 2.0;
108
109 assert_approx_eq!(f32, expected, PointMetrics::Chebyshev.measure(&x, &y));
110 assert_approx_eq!(f32, expected, PointMetrics::Chebyshev.measure(&y, &x));
111 }
112
113 #[test]
114 fn test_minkowski()
115 {
116 let x = [0.0, 1.0];
117 let y = [1.0, -1.0];
118
119 assert_approx_eq!(f32, 3.0, PointMetrics::Minkowski(1.0f32).measure(&x, &y));
120 assert_approx_eq!(f32, 3.0, PointMetrics::Minkowski(1.0f32).measure(&y, &x));
121 assert_approx_eq!(f32, 5.0, PointMetrics::Minkowski(2.0f32).measure(&x, &y).powi(2));
122 assert_approx_eq!(f32, 5.0, PointMetrics::Minkowski(2.0f32).measure(&y, &x).powi(2));
123 assert_approx_eq!(f32, 9.0, PointMetrics::Minkowski(3.0f32).measure(&x, &y).powi(3));
124 assert_approx_eq!(f32, 9.0, PointMetrics::Minkowski(3.0f32).measure(&y, &x).powi(3));
125 }
126
127 #[test]
128 fn test_canberra()
129 {
130 let x = [0.0, 1.0];
131 let y = [1.0, -1.0];
132 let expected = 2.0;
133
134 assert_approx_eq!(f32, expected, PointMetrics::Canberra.measure(&x, &y));
135 assert_approx_eq!(f32, expected, PointMetrics::Canberra.measure(&y, &x));
136 }
137
138 #[test]
139 fn test_gower()
140 {
141 let x = [0.0, 1.0];
142 let y = [1.0, -1.0];
143 let expected = 1.5;
144
145 assert_approx_eq!(f32, expected, PointMetrics::Gower.measure(&x, &y));
146 assert_approx_eq!(f32, expected, PointMetrics::Gower.measure(&y, &x));
147 }
148
149 #[test]
150 fn test_measure_eq()
151 {
152 let x = [1.0, 2.0];
153
154 assert_approx_eq!(f32, 0.0, PointMetrics::Manhattan.measure(&x, &x));
155 assert_approx_eq!(f32, 0.0, PointMetrics::Euclidean.measure(&x, &x));
156 assert_approx_eq!(f32, 0.0, PointMetrics::Chebyshev.measure(&x, &x));
157 assert_approx_eq!(f32, 0.0, PointMetrics::Minkowski(1.0).measure(&x, &x));
158 assert_approx_eq!(f32, 0.0, PointMetrics::Canberra.measure(&x, &x));
159 assert_approx_eq!(f32, 0.0, PointMetrics::Gower.measure(&x, &x));
160 }
161}