Skip to main content

selene_core/
vector_index.rs

1//! Durable vector-index configuration payloads.
2
3use serde::{Deserialize, Serialize};
4
5/// HNSW construction parameters for native vector indexes.
6///
7/// `max_neighbors` is the HNSW `M` fanout. Layer zero may store up to
8/// `2 * max_neighbors` links, while upper layers store up to `max_neighbors`.
9/// `ef_construction` is the candidate beam width used while inserting vectors.
10#[derive(
11    Clone,
12    Copy,
13    Debug,
14    Deserialize,
15    Eq,
16    Hash,
17    PartialEq,
18    rkyv::Archive,
19    rkyv::Deserialize,
20    rkyv::Serialize,
21    Serialize,
22)]
23pub struct HnswIndexConfig {
24    /// HNSW `M` fanout for upper-layer neighbor lists.
25    pub max_neighbors: u16,
26    /// Candidate beam width used when constructing HNSW links.
27    pub ef_construction: u16,
28}
29
30impl HnswIndexConfig {
31    /// Default HNSW `M` fanout.
32    pub const DEFAULT_MAX_NEIGHBORS: u16 = 18;
33    /// Default HNSW construction beam width.
34    pub const DEFAULT_EF_CONSTRUCTION: u16 = 64;
35    /// Default HNSW construction configuration.
36    pub const DEFAULT: Self = Self {
37        max_neighbors: Self::DEFAULT_MAX_NEIGHBORS,
38        ef_construction: Self::DEFAULT_EF_CONSTRUCTION,
39    };
40
41    /// Construct a configuration without validation.
42    ///
43    /// The graph layer validates bounds because it owns index memory policy.
44    #[must_use]
45    pub const fn new(max_neighbors: u16, ef_construction: u16) -> Self {
46        Self {
47            max_neighbors,
48            ef_construction,
49        }
50    }
51
52    /// Return true when this config is the engine default.
53    #[must_use]
54    pub const fn is_default(self) -> bool {
55        self.max_neighbors == Self::DEFAULT_MAX_NEIGHBORS
56            && self.ef_construction == Self::DEFAULT_EF_CONSTRUCTION
57    }
58}
59
60impl Default for HnswIndexConfig {
61    fn default() -> Self {
62        Self::DEFAULT
63    }
64}
65
66/// IVF construction parameters for native vector indexes.
67///
68/// `target_centroids` is the requested inverted-list count used during bulk
69/// training and rebuild. The graph layer validates the upper bound and caps the
70/// effective count to the number of live vectors being trained, so explicit
71/// configuration never creates empty centroids beyond the current corpus.
72#[derive(
73    Clone,
74    Copy,
75    Debug,
76    Deserialize,
77    Eq,
78    Hash,
79    PartialEq,
80    rkyv::Archive,
81    rkyv::Deserialize,
82    rkyv::Serialize,
83    Serialize,
84)]
85pub struct IvfIndexConfig {
86    /// Requested IVF centroid/list count.
87    pub target_centroids: u16,
88}
89
90impl IvfIndexConfig {
91    /// Construct a configuration without validation.
92    ///
93    /// The graph layer validates bounds because it owns index memory policy.
94    #[must_use]
95    pub const fn new(target_centroids: u16) -> Self {
96        Self { target_centroids }
97    }
98}