use super::vector_index::{l2_squared, VectorIndex};
pub struct FlatVectorIndex {
entries: Vec<(u128, Vec<f32>)>,
}
impl FlatVectorIndex {
pub fn new() -> Self {
Self { entries: vec![] }
}
}
impl Default for FlatVectorIndex {
fn default() -> Self {
Self::new()
}
}
impl VectorIndex for FlatVectorIndex {
fn len(&self) -> usize {
self.entries.len()
}
fn insert(&mut self, id: u128, vector: &[f32]) -> Result<(), String> {
if let Some(pos) = self.entries.iter().position(|(eid, _)| *eid == id) {
self.entries[pos] = (id, vector.to_vec());
} else {
self.entries.push((id, vector.to_vec()));
}
Ok(())
}
fn search(&self, query: &[f32], k: usize) -> Result<Vec<(u128, f32)>, String> {
if self.entries.is_empty() || k == 0 {
return Ok(vec![]);
}
let mut scored: Vec<(u128, f32)> = self
.entries
.iter()
.map(|(id, vec)| (*id, l2_squared(query, vec)))
.collect();
scored.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap_or(std::cmp::Ordering::Equal));
let limit = k.min(scored.len());
Ok(scored[..limit].to_vec())
}
fn remove(&mut self, id: u128) -> Result<(), String> {
self.entries.retain(|(eid, _)| *eid != id);
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn insert_and_search() {
let mut idx = FlatVectorIndex::new();
idx.insert(1, &[1.0, 0.0]).unwrap();
idx.insert(2, &[0.0, 1.0]).unwrap();
idx.insert(3, &[0.5, 0.5]).unwrap();
let results = idx.search(&[1.0, 0.1], 2).unwrap();
assert_eq!(results.len(), 2);
assert_eq!(results[0].0, 1); }
#[test]
fn remove_entry() {
let mut idx = FlatVectorIndex::new();
idx.insert(1, &[1.0, 0.0]).unwrap();
idx.remove(1).unwrap();
assert_eq!(idx.len(), 0);
}
}