1mod usearch;
7
8use crate::error::Result;
9
10use crate::serde::centroid_chunk::CentroidEntry;
11use crate::serde::collection_meta::DistanceMetric;
12
13pub use usearch::UsearchCentroidGraph;
15
16pub trait CentroidGraph: Send + Sync {
21 fn search(&self, query: &[f32], k: usize) -> Vec<u64>;
30
31 fn add_centroid(&self, entry: &CentroidEntry) -> Result<()>;
35
36 fn remove_centroid(&self, centroid_id: u64) -> Result<()>;
40
41 fn get_centroid_vector(&self, centroid_id: u64) -> Option<Vec<f32>>;
45
46 fn len(&self) -> usize;
48
49 fn is_empty(&self) -> bool {
51 self.len() == 0
52 }
53}
54
55pub fn build_centroid_graph(
57 centroids: Vec<CentroidEntry>,
58 distance_metric: DistanceMetric,
59) -> Result<Box<dyn CentroidGraph>> {
60 let graph = UsearchCentroidGraph::build(centroids, distance_metric)?;
61 Ok(Box::new(graph))
62}
63
64#[cfg(test)]
65mod tests {
66 use super::*;
67
68 #[test]
69 fn should_work_through_trait_interface() {
70 let centroids = vec![
72 CentroidEntry::new(1, vec![1.0, 0.0, 0.0]),
73 CentroidEntry::new(2, vec![0.0, 1.0, 0.0]),
74 CentroidEntry::new(3, vec![0.0, 0.0, 1.0]),
75 ];
76 let graph: Box<dyn CentroidGraph> =
77 Box::new(UsearchCentroidGraph::build(centroids, DistanceMetric::L2).unwrap());
78
79 assert_eq!(graph.len(), 3);
81 assert!(!graph.is_empty());
82
83 let results = graph.search(&[0.9, 0.1, 0.1], 1);
84 assert_eq!(results.len(), 1);
85 assert_eq!(results[0], 1);
86 }
87
88 #[test]
89 fn should_build_with_default_function() {
90 let centroids = vec![
92 CentroidEntry::new(1, vec![1.0, 0.0]),
93 CentroidEntry::new(2, vec![0.0, 1.0]),
94 ];
95
96 let graph = build_centroid_graph(centroids, DistanceMetric::L2).unwrap();
98
99 assert_eq!(graph.len(), 2);
101
102 let results = graph.search(&[0.9, 0.1], 1);
103 assert_eq!(results.len(), 1);
104 assert_eq!(results[0], 1);
105 }
106}