#![cfg_attr(coverage_nightly, coverage(off))]
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests_distance_metrics {
use super::super::engine::ClusteringEngine;
use super::super::types::Linkage;
use crate::services::semantic::TursoVectorDB;
use std::collections::HashMap;
use std::sync::Arc;
async fn create_test_engine() -> ClusteringEngine {
let db = TursoVectorDB::new_local(":memory:")
.await
.expect("Failed to create test database");
ClusteringEngine::new(Arc::new(db))
}
#[tokio::test]
async fn test_cluster_distance_single_linkage() {
let engine = create_test_engine().await;
let vectors = vec![
vec![0.0, 0.0],
vec![1.0, 0.0],
vec![10.0, 0.0],
vec![11.0, 0.0],
];
let mut distances = HashMap::new();
for i in 0..4 {
for j in (i + 1)..4 {
let dist = engine.euclidean_distance(&vectors[i], &vectors[j]);
distances.insert((i, j), dist);
}
}
let cluster1 = vec![0, 1]; let cluster2 = vec![2, 3];
let dist =
engine.cluster_distance(&cluster1, &cluster2, &distances, &vectors, Linkage::Single);
assert!((dist - 9.0).abs() < 1e-6);
}
#[tokio::test]
async fn test_cluster_distance_complete_linkage() {
let engine = create_test_engine().await;
let vectors = vec![
vec![0.0, 0.0],
vec![1.0, 0.0],
vec![10.0, 0.0],
vec![11.0, 0.0],
];
let mut distances = HashMap::new();
for i in 0..4 {
for j in (i + 1)..4 {
let dist = engine.euclidean_distance(&vectors[i], &vectors[j]);
distances.insert((i, j), dist);
}
}
let cluster1 = vec![0, 1];
let cluster2 = vec![2, 3];
let dist = engine.cluster_distance(
&cluster1,
&cluster2,
&distances,
&vectors,
Linkage::Complete,
);
assert!((dist - 11.0).abs() < 1e-6);
}
#[tokio::test]
async fn test_cluster_distance_average_linkage() {
let engine = create_test_engine().await;
let vectors = vec![
vec![0.0, 0.0],
vec![1.0, 0.0],
vec![10.0, 0.0],
vec![11.0, 0.0],
];
let mut distances = HashMap::new();
for i in 0..4 {
for j in (i + 1)..4 {
let dist = engine.euclidean_distance(&vectors[i], &vectors[j]);
distances.insert((i, j), dist);
}
}
let cluster1 = vec![0, 1];
let cluster2 = vec![2, 3];
let dist =
engine.cluster_distance(&cluster1, &cluster2, &distances, &vectors, Linkage::Average);
assert!((dist - 10.0).abs() < 1e-6);
}
#[tokio::test]
async fn test_cluster_distance_empty_result() {
let engine = create_test_engine().await;
let vectors = vec![vec![0.0, 0.0]];
let distances = HashMap::new();
let cluster1 = vec![0];
let cluster2 = vec![1];
let dist =
engine.cluster_distance(&cluster1, &cluster2, &distances, &vectors, Linkage::Single);
assert_eq!(dist, f64::MAX);
}
#[tokio::test]
async fn test_intra_cluster_distance_basic() {
let engine = create_test_engine().await;
let vectors = vec![vec![0.0, 0.0], vec![2.0, 0.0], vec![4.0, 0.0]];
let labels = vec![0, 0, 0];
let dist = engine.intra_cluster_distance(&vectors, &labels, 1);
assert!((dist - 2.0).abs() < 1e-6);
}
#[tokio::test]
async fn test_intra_cluster_distance_single_point() {
let engine = create_test_engine().await;
let vectors = vec![vec![0.0, 0.0], vec![10.0, 0.0]];
let labels = vec![0, 1];
let dist = engine.intra_cluster_distance(&vectors, &labels, 0);
assert_eq!(dist, 0.0);
}
#[tokio::test]
async fn test_nearest_cluster_distance_basic() {
let engine = create_test_engine().await;
let vectors = vec![
vec![0.0, 0.0],
vec![1.0, 0.0],
vec![10.0, 0.0],
vec![11.0, 0.0],
];
let labels = vec![0, 0, 1, 1];
let dist = engine.nearest_cluster_distance(&vectors, &labels, 0);
assert!((dist - 10.5).abs() < 1e-6);
}
#[tokio::test]
async fn test_nearest_cluster_distance_single_cluster() {
let engine = create_test_engine().await;
let vectors = vec![vec![0.0, 0.0], vec![1.0, 0.0], vec![2.0, 0.0]];
let labels = vec![0, 0, 0];
let dist = engine.nearest_cluster_distance(&vectors, &labels, 0);
assert_eq!(dist, f64::MAX);
}
}