Skip to main content

VecqIndex

Struct VecqIndex 

Source
pub struct VecqIndex { /* private fields */ }
Expand description

A quantized vector database in memory.

Each vector is stored as padded_dim / 2 bytes of 4-bit Lloyd-Max codes (computed after RHDH rotation) plus one f32 correction factor. The score against an f32 query is an unbiased estimate of the cosine similarity after undoing the per-vector quantization scale.

Vectors can be stored anonymously via VecqIndex::add or under a caller-chosen u64 key via VecqIndex::add_keyed. Keyed vectors can be removed in place (tombstoned); tombstoned slots keep their storage but are skipped by searches and dropped by VecqIndex::compact and by VecqIndex::to_bytes. Slot indices stay stable until a compaction, so integrators can treat a slot as a transient handle while keys are the durable identity.

Implementations§

Source§

impl VecqIndex

Source

pub fn to_bytes(&self) -> Vec<u8>

Serialize the index to bytes (format version 1.1, f16 scales).

Tombstoned slots are skipped: the output always holds the live vectors in slot order, so a round-trip through bytes has the same effect as VecqIndex::compact on disk without disturbing in-memory slot indices. Keys are not part of the file format; persist a key→slot table alongside (e.g. in SQLite) if you need keyed access across a reload.

Source

pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error>

Parse an index from bytes produced by [to_bytes] (or a v1 file).

Source§

impl VecqIndex

Source

pub fn new(dim: usize, seed: u64) -> Self

Create an empty index for dim-dimensional unit vectors. seed must be persisted with the index for cross-platform determinism.

Source

pub fn len(&self) -> usize

Number of live (searchable) vectors.

Source

pub fn is_empty(&self) -> bool

Source

pub fn slots(&self) -> usize

Total slots in use, including tombstoned ones (slots() == len() + tombstones()).

Source

pub fn tombstones(&self) -> usize

Number of tombstoned slots awaiting VecqIndex::compact.

Source

pub fn dim(&self) -> usize

Source

pub fn seed(&self) -> u64

Source

pub fn add(&mut self, v: &[f32]) -> usize

Quantize and add one vector (any norm; normalized internally).

Returns the slot index holding the vector (stable until compaction).

Source

pub fn add_keyed(&mut self, key: u64, v: &[f32]) -> usize

Quantize and add one vector under a caller-chosen u64 key.

If key already exists, the vector is replaced in place (the slot index is preserved, matching usearch’s insert semantics). Otherwise a new slot is appended. Returns the slot index holding the vector.

Source

pub fn remove_keyed(&mut self, key: u64) -> bool

Remove a keyed vector. The slot becomes a tombstone: its storage is kept (slot indices stay stable) but searches skip it until VecqIndex::compact. Returns false if the key is unknown.

Source

pub fn key_of(&self, slot: usize) -> Option<u64>

Look up the key stored at slot (None for anonymous slots, tombstones, or out-of-range indices).

Source

pub fn contains_key(&self, key: u64) -> bool

Whether key currently identifies a live vector.

Source

pub fn compact(&mut self)

Rebuild the index in place, dropping tombstoned slots.

All remaining vectors keep their keys; slot indices shift to become dense (0..len). Search results are unchanged.

Source

pub fn prepare_query(&self, q: &[f32]) -> PreparedQuery

Prepare an f32 query in rotated space (call once per query).

Source

pub fn score(&self, pq: &PreparedQuery, idx: usize) -> f32

Asymmetric score of vector idx against a prepared query. Returns estimated cosine similarity in [-1, 1].

Dispatches to the explicit NEON path on aarch64, the explicit AVX2 path on x86_64 when the host supports it (runtime detection), and the fixed 8-bucket scalar path otherwise. All use the identical association order (per code byte: mul, mul, add, then add into bucket j; final pairwise tree), so they produce the same f32 bits — guarded by neon_matches_scalar_bitwise / avx2_matches_scalar_bitwise in tests.

Source

pub fn search(&self, q: &[f32], k: usize) -> Vec<(usize, f32)>

Brute-force top-k search. Returns (slot index, score) sorted by score desc. Tombstoned slots are skipped.

Uses a bounded min-heap of size k (no O(n log n) sort, no O(n) allocation per query): push while the heap is not full, then only push-and-pop when the candidate beats the current k-th score.

Source

pub fn search_keyed(&self, q: &[f32], k: usize) -> Vec<(u64, f32)>

Keyed variant of VecqIndex::search: returns (key, score) sorted by score desc, restricted to live keyed vectors.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.