pub mod cosine;
pub mod euclidean;
pub use cosine::{cosine_distance, cosine_similarity, dot_product};
pub use euclidean::euclidean_distance;
pub trait DistanceMetric: Send + Sync {
fn distance(&self, a: &[f32], b: &[f32]) -> f32;
}
#[derive(Debug, Clone, Copy)]
pub struct Euclidean;
impl DistanceMetric for Euclidean {
#[inline]
fn distance(&self, a: &[f32], b: &[f32]) -> f32 {
euclidean_distance(a, b)
}
}
#[derive(Debug, Clone, Copy)]
pub struct Cosine;
impl DistanceMetric for Cosine {
#[inline]
fn distance(&self, a: &[f32], b: &[f32]) -> f32 {
cosine_distance(a, b)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DistanceKind {
Euclidean,
Cosine,
}
impl DistanceKind {
#[inline]
pub fn distance(&self, a: &[f32], b: &[f32]) -> f32 {
match self {
DistanceKind::Euclidean => euclidean_distance(a, b),
DistanceKind::Cosine => cosine_distance(a, b),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_euclidean_metric() {
let metric = Euclidean;
let a = vec![1.0, 2.0, 3.0];
let b = vec![4.0, 5.0, 6.0];
let dist = metric.distance(&a, &b);
assert!((dist - 5.196152).abs() < 0.001);
}
#[test]
fn test_cosine_metric() {
let metric = Cosine;
let a = vec![1.0, 0.0, 0.0];
let b = vec![1.0, 0.0, 0.0];
let dist = metric.distance(&a, &b);
assert!(dist < 0.01); }
#[test]
fn test_dot_product() {
let a = vec![1.0, 0.0];
let b = vec![0.0, 1.0];
assert!(dot_product(&a, &b).abs() < 1e-6);
let a = vec![3.0, 4.0];
assert!((dot_product(&a, &a) - 25.0).abs() < 1e-5);
let a = vec![1.0, 2.0, 3.0];
let b = vec![4.0, 5.0, 6.0];
assert!((dot_product(&a, &b) - 32.0).abs() < 1e-5);
let a: Vec<f32> = (0..100).map(|i| i as f32).collect();
let b: Vec<f32> = (0..100).map(|i| (i + 1) as f32).collect();
let expected: f32 = a.iter().zip(b.iter()).map(|(x, y)| x * y).sum();
assert!((dot_product(&a, &b) - expected).abs() < 1e-2);
}
}