use crate::probe_select::DiversityConfig;
use crate::vector_ops::DistanceMetric;
use core::fmt;
#[derive(Clone, PartialEq)]
pub struct IndexConfig {
pub dim: u32,
pub num_clusters: u32,
pub num_subvectors: u32,
pub num_codewords: u16,
pub metric: DistanceMetric,
pub store_raw_vectors: bool,
pub default_nprobe: u32,
pub(crate) state: u8,
pub num_vectors: u64,
}
pub const STATE_UNTRAINED: u8 = 0;
pub const STATE_TRAINED: u8 = 1;
impl IndexConfig {
pub fn state(&self) -> u8 {
self.state
}
pub fn sub_dim(&self) -> usize {
if self.num_subvectors == 0 {
return 0;
}
self.dim as usize / self.num_subvectors as usize
}
pub fn metric_byte(&self) -> u8 {
match self.metric {
DistanceMetric::Cosine => 0,
DistanceMetric::EuclideanSq => 1,
DistanceMetric::DotProduct => 2,
DistanceMetric::Manhattan => 3,
}
}
}
impl fmt::Debug for IndexConfig {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("IndexConfig")
.field("dim", &self.dim)
.field("num_clusters", &self.num_clusters)
.field("num_subvectors", &self.num_subvectors)
.field("num_codewords", &self.num_codewords)
.field("metric", &self.metric)
.field("store_raw", &self.store_raw_vectors)
.field("nprobe", &self.default_nprobe)
.field("state", &self.state)
.field("num_vectors", &self.num_vectors)
.finish()
}
}
#[derive(Debug, Clone)]
pub struct SearchParams {
pub nprobe: u32,
pub candidates: usize,
pub k: usize,
pub rerank: bool,
pub diversity: DiversityConfig,
}
impl SearchParams {
pub fn top_k(k: usize) -> Self {
Self {
nprobe: 10,
candidates: k.saturating_mul(10).max(100),
k,
rerank: true,
diversity: DiversityConfig { lambda: 0.0 },
}
}
#[must_use]
pub fn with_diversity(mut self, lambda: f32) -> Self {
self.diversity = DiversityConfig {
lambda: lambda.clamp(0.0, 1.0),
};
self
}
}
pub struct IvfPqIndexDefinition {
name: &'static str,
dim: u32,
num_clusters: u32,
num_subvectors: u32,
metric: DistanceMetric,
store_raw_vectors: bool,
default_nprobe: u32,
}
impl IvfPqIndexDefinition {
pub const fn new(
name: &'static str,
dim: u32,
num_clusters: u32,
num_subvectors: u32,
metric: DistanceMetric,
) -> Self {
Self {
name,
dim,
num_clusters,
num_subvectors,
metric,
store_raw_vectors: false,
default_nprobe: 10,
}
}
#[must_use]
pub const fn with_raw_vectors(mut self) -> Self {
self.store_raw_vectors = true;
self
}
#[must_use]
pub const fn with_nprobe(mut self, nprobe: u32) -> Self {
self.default_nprobe = nprobe;
self
}
pub const fn name(&self) -> &'static str {
self.name
}
pub const fn num_clusters(&self) -> u32 {
self.num_clusters
}
pub fn to_config(&self) -> IndexConfig {
IndexConfig {
dim: self.dim,
num_clusters: self.num_clusters,
num_subvectors: self.num_subvectors,
num_codewords: 256,
metric: self.metric,
store_raw_vectors: self.store_raw_vectors,
default_nprobe: self.default_nprobe,
state: STATE_UNTRAINED,
num_vectors: 0,
}
}
}
impl fmt::Debug for IvfPqIndexDefinition {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"IvfPqIndexDefinition({:?}, dim={}, clusters={}, subvecs={}, {:?})",
self.name, self.dim, self.num_clusters, self.num_subvectors, self.metric,
)
}
}