Wire hybrid search (FTS5 + vector + RRF) to CLI search command. Enhance robot-docs with quick_start guide and example_output. Fill data gaps in issue detail (references, note counts, closed_at). Add lore drift command for discussion divergence detection. Rewrite agent skills to mandate lore for reads, glab for writes. Closes: bd-1ksf, bd-91j1, bd-2g50, bd-1cjx, bd-kvij
49 lines
1.4 KiB
Rust
49 lines
1.4 KiB
Rust
/// 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::<f32>().sqrt();
|
|
let norm_b: f32 = b.iter().map(|x| x * x).sum::<f32>().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);
|
|
}
|
|
}
|