hipparchus_metrics/
vector.rs1use hipparchus_mean::Fp;
2use crate::metrics::Metrics;
3
4#[repr(i32)]
6#[derive(Clone,PartialEq,Debug)]
7pub enum VectorMetrics
8{
9 DotProduct = 1,
11
12 Cosine = 2,
14}
15
16impl<T:Fp> Metrics<&[T], T> for VectorMetrics
17{
18 fn measure(self, x:&[T], y:&[T]) -> T
19 {
20 let it = x.iter().zip(y.iter());
21 match self
22 {
23 VectorMetrics::DotProduct => it.fold( T::zero(), | agg, (&a, &b) | agg + a * b),
24 VectorMetrics::Cosine =>
25 {
26 let mut aa = T::zero();
27 let mut bb = T::zero();
28 let ab = it.fold( T::zero(), | agg, (&a, &b) |
29 {
30 aa = aa + a * a;
31 bb = bb + b * b;
32 agg + a * b
33 });
34 ab / (aa.sqrt() * bb.sqrt())
35 },
36 }
37 }
38}
39
40#[cfg(test)]
41mod tests
42{
43 use super::*;
44 use float_cmp::assert_approx_eq;
45 use hipparchus_mean::LpNorm;
46
47 #[test]
48 fn test_dotproduct_overlap()
49 {
50 let v = 1.0;
51 let x = [v, v];
52 let y = [2.0 * v, 2.0 * v];
53 let l2x = x.iter().l2norm().unwrap();
54 let l2y = y.iter().l2norm().unwrap();
55 let expected = l2x * l2y;
56 assert_approx_eq!(f32, expected, VectorMetrics::DotProduct.measure(&x, &y));
57 assert_approx_eq!(f32, expected, VectorMetrics::DotProduct.measure(&y, &x));
58 }
59
60 #[test]
61 fn test_dotproduct_orthogonal()
62 {
63 let v = 1.0;
64 let x = [v, v];
65 let y = [v, -v];
66 let expected = 0.0;
67 assert_approx_eq!(f32, expected, VectorMetrics::DotProduct.measure(&x, &y));
68 assert_approx_eq!(f32, expected, VectorMetrics::DotProduct.measure(&y, &x));
69 }
70
71 #[test]
72 fn test_cosine_opposite()
73 {
74 let v = 1.0;
75 let x = [v, v];
76 let y = [-v, -v];
77 let expected = f32::cos(180.0f32.to_radians());
78 assert_approx_eq!(f32, expected, VectorMetrics::Cosine.measure(&x, &y));
79 assert_approx_eq!(f32, expected, VectorMetrics::Cosine.measure(&x, &y));
80 }
81
82 #[test]
83 fn test_cosine_overlap()
84 {
85 let v = 1.0;
86 let x = [v, v];
87 let y = [2.0 * v, 2.0 * v];
88 let expected = f32::cos(0.0f32.to_radians());
89 assert_approx_eq!(f32, expected, VectorMetrics::Cosine.measure(&x, &y));
90 assert_approx_eq!(f32, expected, VectorMetrics::Cosine.measure(&y, &x));
91 }
92
93 #[test]
94 fn test_cosine_eq()
95 {
96 let x = [1.0, 2.0];
97 let expected = f32::cos(0.0f32.to_radians());
98 assert_approx_eq!(f32, expected, VectorMetrics::Cosine.measure(&x, &x));
99 }
100}