1pub fn dot(a: &[f32], b: &[f32]) -> f32 {
5 a.iter().zip(b).map(|(x, y)| x * y).sum()
6}
7
8pub fn norm(a: &[f32]) -> f32 {
10 dot(a, a).sqrt()
11}
12
13pub fn cosine(a: &[f32], b: &[f32]) -> f32 {
15 let na = norm(a);
16 let nb = norm(b);
17 if na == 0.0 || nb == 0.0 {
18 0.0
19 } else {
20 dot(a, b) / (na * nb)
21 }
22}
23
24pub fn normalize(v: &mut [f32]) {
26 let n = norm(v);
27 if n > 0.0 {
28 for x in v.iter_mut() {
29 *x /= n;
30 }
31 }
32}
33
34pub fn to_bytes(v: &[f32]) -> Vec<u8> {
36 let mut out = Vec::with_capacity(v.len() * 4);
37 for x in v {
38 out.extend_from_slice(&x.to_le_bytes());
39 }
40 out
41}
42
43pub fn from_bytes(bytes: &[u8]) -> Vec<f32> {
45 bytes
46 .chunks_exact(4)
47 .map(|c| f32::from_le_bytes([c[0], c[1], c[2], c[3]]))
48 .collect()
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54
55 #[test]
56 fn cosine_basics() {
57 assert!((cosine(&[1.0, 0.0], &[1.0, 0.0]) - 1.0).abs() < 1e-6);
58 assert!(cosine(&[1.0, 0.0], &[0.0, 1.0]).abs() < 1e-6);
59 assert_eq!(cosine(&[0.0, 0.0], &[1.0, 1.0]), 0.0);
60 }
61
62 #[test]
63 fn normalize_makes_unit_length() {
64 let mut v = vec![3.0, 4.0];
65 normalize(&mut v);
66 assert!((norm(&v) - 1.0).abs() < 1e-6);
67 }
68
69 #[test]
70 fn bytes_roundtrip() {
71 let v = vec![1.5f32, -2.25, 0.0, 1024.5];
72 assert_eq!(from_bytes(&to_bytes(&v)), v);
73 }
74}