pub struct ConfigHnsw {
num_neighbors_per_vec: usize,
ef_construction: usize,
ef_search: usize,
}
pub struct ConfigHnswBuilder {
num_neighbors: Option<usize>,
ef_construction: Option<usize>,
ef_search: Option<usize>,
check_relative_distance: Option<bool>,
}
impl ConfigHnsw {
pub fn new() -> ConfigHnswBuilder {
ConfigHnswBuilder {
num_neighbors: None,
ef_construction: None,
ef_search: None,
check_relative_distance: None,
}
}
pub fn set_ef_search(&mut self, ef_search: usize) {
assert!(ef_search > 0, "The ef_search must be at least 1");
self.ef_search = ef_search;
}
pub fn get_ef_search(&self) -> usize {
self.ef_search
}
pub fn get_num_neighbors_per_vec(&self) -> usize {
self.num_neighbors_per_vec
}
pub fn get_ef_construction(&self) -> usize {
self.ef_construction
}
}
impl ConfigHnswBuilder {
pub fn num_neighbors(&mut self, num_neighbors: usize) -> &mut Self {
assert!(
num_neighbors >= 2,
"The number of neighbors must be at least 2"
);
self.num_neighbors = Some(num_neighbors);
self
}
pub fn ef_construction(&mut self, ef_construction: usize) -> &mut Self {
assert!(
ef_construction > 0,
"The ef_construction must be at least 1"
);
self.ef_construction = Some(ef_construction);
self
}
pub fn ef_search(&mut self, ef_search: usize) -> &mut Self {
assert!(ef_search > 0, "The ef_search must be at least 1");
self.ef_search = Some(ef_search);
self
}
pub fn check_relative_distance(&mut self, check_relative_distance: bool) -> &mut Self {
self.check_relative_distance = Some(check_relative_distance);
self
}
pub fn build(&mut self) -> ConfigHnsw {
ConfigHnsw {
num_neighbors_per_vec: self.num_neighbors.unwrap_or(32),
ef_construction: self.ef_construction.unwrap_or(40),
ef_search: self.ef_search.unwrap_or(16),
}
}
}
#[cfg(test)]
mod tests_confighsnw {
use super::*;
#[test]
fn test_partial_config_build() {
let config = ConfigHnsw::new()
.num_neighbors(15)
.ef_construction(100)
.build();
assert_eq!(config.get_num_neighbors_per_vec(), 15);
assert_eq!(config.get_ef_construction(), 100);
assert_eq!(config.get_ef_search(), 16); }
#[test]
fn test_multiple_set_operations() {
let mut config = ConfigHnsw::new()
.num_neighbors(32)
.ef_construction(200)
.build();
config.set_ef_search(60);
assert_eq!(config.get_num_neighbors_per_vec(), 32);
assert_eq!(config.get_ef_construction(), 200);
assert_eq!(config.get_ef_search(), 60);
}
#[test]
fn test_minimum_valid_values() {
let config = ConfigHnsw::new()
.num_neighbors(2) .ef_construction(1) .ef_search(1) .build();
assert_eq!(config.get_num_neighbors_per_vec(), 2);
assert_eq!(config.get_ef_construction(), 1);
assert_eq!(config.get_ef_search(), 1);
}
#[test]
#[should_panic(expected = "The number of neighbors must be at least 2")]
fn test_num_neighbors_panic() {
let _config = ConfigHnsw::new().num_neighbors(1).build(); }
#[test]
#[should_panic(expected = "The ef_construction must be at least 1")]
fn test_ef_construction_panic() {
let _config = ConfigHnsw::new().ef_construction(0).build(); }
#[test]
fn test_extreme_values() {
let config = ConfigHnsw::new()
.num_neighbors(usize::MAX)
.ef_construction(usize::MAX)
.ef_search(usize::MAX)
.build();
assert_eq!(config.get_num_neighbors_per_vec(), usize::MAX);
assert_eq!(config.get_ef_construction(), usize::MAX);
assert_eq!(config.get_ef_search(), usize::MAX);
}
}