/// Cosine similarity between two embedding vectors. /// Returns value in [-1, 1] range; higher = more similar. pub fn cosine_similarity(a: &[f32], b: &[f32]) -> f32 { debug_assert_eq!(a.len(), b.len(), "embedding dimensions must match"); let dot: f32 = a.iter().zip(b).map(|(x, y)| x * y).sum(); let norm_a: f32 = a.iter().map(|x| x * x).sum::().sqrt(); let norm_b: f32 = b.iter().map(|x| x * x).sum::().sqrt(); if norm_a == 0.0 || norm_b == 0.0 { return 0.0; } dot / (norm_a * norm_b) } #[cfg(test)] mod tests { use super::*; #[test] fn test_cosine_similarity_identical() { let v = [1.0, 2.0, 3.0]; let sim = cosine_similarity(&v, &v); assert!((sim - 1.0).abs() < 1e-6); } #[test] fn test_cosine_similarity_orthogonal() { let a = [1.0, 0.0, 0.0]; let b = [0.0, 1.0, 0.0]; let sim = cosine_similarity(&a, &b); assert!(sim.abs() < 1e-6); } #[test] fn test_cosine_similarity_zero_vector() { let a = [1.0, 2.0, 3.0]; let b = [0.0, 0.0, 0.0]; let sim = cosine_similarity(&a, &b); assert!((sim - 0.0).abs() < 1e-6); } #[test] fn test_cosine_similarity_opposite() { let a = [1.0, 2.0, 3.0]; let b = [-1.0, -2.0, -3.0]; let sim = cosine_similarity(&a, &b); assert!((sim - (-1.0)).abs() < 1e-6); } }