weavatrix_search_vector/
config.rs1use crate::error::SearchError;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
5#[non_exhaustive]
6pub enum DistanceMetric {
7 #[default]
9 Cosine,
10 Dot,
12 SquaredEuclidean,
14}
15
16#[derive(Debug, Clone, PartialEq, Eq)]
18pub struct IndexConfig {
19 pub dimensions: usize,
21 pub metric: DistanceMetric,
23 pub connectivity: usize,
26 pub expansion_build: usize,
28 pub expansion_query: usize,
30 pub replicas: usize,
32 pub build_threads: usize,
34 pub query_threads: usize,
36 pub seed: u64,
38}
39
40impl IndexConfig {
41 #[must_use]
43 pub fn new(dimensions: usize) -> Self {
44 let workers = std::thread::available_parallelism()
45 .map_or(1, std::num::NonZeroUsize::get)
46 .min(16);
47 Self {
48 dimensions,
49 metric: DistanceMetric::Cosine,
50 connectivity: 12,
51 expansion_build: 48,
52 expansion_query: 24,
53 replicas: 1,
54 build_threads: workers,
55 query_threads: workers,
56 seed: 0x6a09_e667_f3bc_c909,
57 }
58 }
59
60 pub fn validate(&self) -> Result<(), SearchError> {
67 if self.dimensions == 0 {
68 return Err(SearchError::InvalidConfig("dimensions must be non-zero"));
69 }
70 if self.connectivity < 2 {
71 return Err(SearchError::InvalidConfig(
72 "connectivity must be at least two",
73 ));
74 }
75 if self.expansion_build < self.connectivity {
76 return Err(SearchError::InvalidConfig(
77 "expansion_build must be at least connectivity",
78 ));
79 }
80 if self.expansion_query == 0 {
81 return Err(SearchError::InvalidConfig(
82 "expansion_query must be non-zero",
83 ));
84 }
85 if self.replicas == 0 {
86 return Err(SearchError::InvalidConfig("replicas must be non-zero"));
87 }
88 if self.build_threads == 0 {
89 return Err(SearchError::InvalidConfig("build_threads must be non-zero"));
90 }
91 if self.query_threads == 0 {
92 return Err(SearchError::InvalidConfig("query_threads must be non-zero"));
93 }
94 self.connectivity
95 .checked_mul(2)
96 .ok_or(SearchError::CapacityOverflow)?;
97 Ok(())
98 }
99}