pub mod ops;
pub mod product_quantize;
pub mod quantize;
pub mod simd;
use crate::{RagError, Result};
pub use ops::{approx_equal, cosine_similarity, dot_product, l2_distance, normalize};
pub use simd::{
cosine_distance_prenorm, cosine_similarity_simd, dot_product_simd, l2_distance_simd, norm_simd,
};
#[inline]
pub fn cosine_similarity_auto(a: &[f32], b: &[f32]) -> Result<f32> {
if a.len() != b.len() {
return Err(RagError::DimensionMismatch {
expected: a.len(),
actual: b.len(),
});
}
Ok(simd::cosine_similarity_simd(a, b))
}
#[inline]
pub fn l2_distance_auto(a: &[f32], b: &[f32]) -> Result<f32> {
if a.len() != b.len() {
return Err(RagError::DimensionMismatch {
expected: a.len(),
actual: b.len(),
});
}
Ok(simd::l2_distance_simd(a, b))
}
#[inline]
pub fn dot_product_auto(a: &[f32], b: &[f32]) -> Result<f32> {
if a.len() != b.len() {
return Err(RagError::DimensionMismatch {
expected: a.len(),
actual: b.len(),
});
}
Ok(simd::dot_product_simd(a, b))
}
#[cfg(test)]
mod tests {
use super::*;
const EPSILON: f32 = 1e-5;
#[test]
fn test_auto_functions_match_scalar() {
let a = vec![1.0, 2.0, 3.0, 4.0, 5.0];
let b = vec![5.0, 4.0, 3.0, 2.0, 1.0];
let auto_sim = cosine_similarity_auto(&a, &b).unwrap();
let scalar_sim = cosine_similarity(&a, &b).unwrap();
assert!((auto_sim - scalar_sim).abs() < EPSILON);
let auto_dist = l2_distance_auto(&a, &b).unwrap();
let scalar_dist = l2_distance(&a, &b).unwrap();
assert!((auto_dist - scalar_dist).abs() < EPSILON);
let auto_dot = dot_product_auto(&a, &b).unwrap();
let scalar_dot = dot_product(&a, &b).unwrap();
assert!((auto_dot - scalar_dot).abs() < EPSILON);
}
#[test]
fn test_auto_functions_dimension_mismatch() {
let a = vec![1.0, 2.0];
let b = vec![1.0, 2.0, 3.0];
assert!(matches!(
cosine_similarity_auto(&a, &b),
Err(RagError::DimensionMismatch { .. })
));
assert!(matches!(
l2_distance_auto(&a, &b),
Err(RagError::DimensionMismatch { .. })
));
assert!(matches!(
dot_product_auto(&a, &b),
Err(RagError::DimensionMismatch { .. })
));
}
#[test]
fn test_auto_functions_typical_embeddings() {
for size in [384, 768, 1024] {
let a: Vec<f32> = (0..size).map(|i| (i as f32) / (size as f32)).collect();
let b: Vec<f32> = (0..size)
.map(|i| 1.0 - (i as f32) / (size as f32))
.collect();
let auto_sim = cosine_similarity_auto(&a, &b).unwrap();
let scalar_sim = cosine_similarity(&a, &b).unwrap();
assert!(
(auto_sim - scalar_sim).abs() < 1e-4, "Size {}: auto={}, scalar={}",
size,
auto_sim,
scalar_sim
);
let auto_dist = l2_distance_auto(&a, &b).unwrap();
let scalar_dist = l2_distance(&a, &b).unwrap();
let epsilon = scalar_dist.abs() * 1e-5;
assert!(
(auto_dist - scalar_dist).abs() < epsilon,
"Size {}: auto={}, scalar={}",
size,
auto_dist,
scalar_dist
);
}
}
}