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}