use crate::error::Result;
use crate::quantized::{QuantizedVector, QuerySketch};
use crate::SQuaJL;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct ScoredIndex {
pub index: usize,
pub score: f32,
}
#[derive(Debug, Clone)]
pub struct FlatIndex {
codec: SQuaJL,
items: Vec<QuantizedVector>,
}
impl FlatIndex {
pub fn new(codec: SQuaJL) -> Self {
Self {
codec,
items: Vec::new(),
}
}
pub fn from_encoded(codec: SQuaJL, items: Vec<QuantizedVector>) -> Result<Self> {
for item in &items {
codec.validate_code(item)?;
}
Ok(Self { codec, items })
}
pub fn codec(&self) -> &SQuaJL {
&self.codec
}
pub fn len(&self) -> usize {
self.items.len()
}
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
pub fn get(&self, index: usize) -> Option<&QuantizedVector> {
self.items.get(index)
}
pub fn add_encoded(&mut self, item: QuantizedVector) -> Result<usize> {
self.codec.validate_code(&item)?;
self.items.push(item);
Ok(self.items.len() - 1)
}
pub fn add_vector(&mut self, vector: &[f32]) -> Result<usize> {
let item = self.codec.encode(vector)?;
self.add_encoded(item)
}
pub fn extend_vectors<'a, I>(&mut self, vectors: I) -> Result<()>
where
I: IntoIterator<Item = &'a [f32]>,
{
for vector in vectors {
self.add_vector(vector)?;
}
Ok(())
}
pub fn search(&self, query: &[f32], k: usize) -> Result<Vec<ScoredIndex>> {
let prepared = self.codec.sketch_query(query)?;
self.search_prepared(&prepared, k)
}
pub fn search_prepared(&self, query: &QuerySketch, k: usize) -> Result<Vec<ScoredIndex>> {
let mut hits = Vec::with_capacity(self.items.len());
for (index, item) in self.items.iter().enumerate() {
hits.push(ScoredIndex {
index,
score: self.codec.score(query, item)?,
});
}
hits.sort_by(|left, right| right.score.total_cmp(&left.score));
hits.truncate(k.min(hits.len()));
Ok(hits)
}
}