hipparchus_metrics/
point.rs

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 distance, equivalent to Minkowski distance with p=1
9    Manhattan = 1,
10
11    /// Euclidean distance, equivalent to Minkowski distance with p=2
12    Euclidean = 2,
13
14    /// Chebyshev distance, equivalent to Minkowski distance with p=Inf
15    Chebyshev = 3,
16
17    /// Minkowski distance where p=1, 2, ..., Inf
18    Minkowski(T) = 4,
19
20    /// Canberra distance, d=∑|Pi−Qi|/(|Pi|+|Qi|)
21    Canberra = 11,
22
23    /// Gower distance, d=∑|Pi−Qi|/n
24    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}