#![deny(unsafe_op_in_unsafe_fn)]
use std::fmt;
mod bitmap;
mod fastscan;
#[cfg(feature = "experimental")]
mod multi_bucket;
mod quant;
mod quant_kernels;
pub mod rank;
pub mod rank_io;
pub mod sign_bitmap;
mod util;
pub use bitmap::Bitmap;
pub use quant::{rankquant_eval_search, RankQuant, TwoStageCandidatePolicy};
pub use rank::Rank;
pub use rank_io::{probe_index_metadata, IndexKind, IndexMetadata, IndexParams};
pub use sign_bitmap::SignBitmap;
#[doc(hidden)]
pub use quant::search_asymmetric_byte_lut;
#[cfg(feature = "experimental")]
pub use multi_bucket::MultiBucketBitmap;
#[doc(hidden)]
pub use fastscan::RankQuantFastscan;
#[deprecated(since = "0.2.0", note = "renamed to `Rank`")]
pub type RankIndex = Rank;
#[deprecated(since = "0.2.0", note = "renamed to `RankQuant`")]
pub type RankQuantIndex = RankQuant;
#[deprecated(since = "0.2.0", note = "renamed to `Bitmap`")]
pub type BitmapIndex = Bitmap;
#[deprecated(since = "0.2.0", note = "renamed to `SignBitmap`")]
pub type SignBitmapIndex = SignBitmap;
#[cfg(feature = "experimental")]
#[deprecated(since = "0.2.0", note = "renamed to `MultiBucketBitmap`")]
pub type MultiBucketBitmapIndex = MultiBucketBitmap;
#[doc(hidden)]
#[deprecated(since = "0.2.0", note = "renamed to `RankQuantFastscan`")]
pub type RankQuantFastscanIndex = RankQuantFastscan;
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum OrdvecError {
InvalidParameter {
name: &'static str,
message: String,
},
InvalidLength {
name: &'static str,
len: usize,
dim: usize,
},
InvalidVectorLength {
name: &'static str,
len: usize,
expected: usize,
},
CandidateIdOutOfRange {
id: u32,
n_vectors: usize,
},
}
impl fmt::Display for OrdvecError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidParameter { name, message } => {
write!(f, "invalid {name}: {message}")
}
Self::InvalidLength { name, len, dim } => {
write!(f, "{name} length {len} must be a multiple of dim {dim}")
}
Self::InvalidVectorLength {
name,
len,
expected,
} => {
write!(f, "{name} length {len} must equal dim {expected}")
}
Self::CandidateIdOutOfRange { id, n_vectors } => {
write!(
f,
"candidate id {id} out of range for n_vectors {n_vectors}"
)
}
}
}
}
impl std::error::Error for OrdvecError {}
pub fn validate_flat_vectors_len(len: usize, dim: usize) -> Result<usize, OrdvecError> {
if dim == 0 {
return Err(OrdvecError::InvalidParameter {
name: "dim",
message: "must be > 0".to_string(),
});
}
if !len.is_multiple_of(dim) {
return Err(OrdvecError::InvalidLength {
name: "vectors",
len,
dim,
});
}
Ok(len / dim)
}
pub fn validate_candidate_ids(candidates: &[u32], n_vectors: usize) -> Result<(), OrdvecError> {
if let Some(&id) = candidates.iter().find(|&&id| (id as usize) >= n_vectors) {
return Err(OrdvecError::CandidateIdOutOfRange { id, n_vectors });
}
Ok(())
}
#[must_use = "search runs the full scan to produce these results; dropping them discards that work"]
pub struct SearchResults {
pub scores: Vec<f32>,
pub indices: Vec<i64>,
pub nq: usize,
pub k: usize,
}
impl SearchResults {
pub fn scores_for_query(&self, qi: usize) -> &[f32] {
&self.scores[qi * self.k..(qi + 1) * self.k]
}
pub fn indices_for_query(&self, qi: usize) -> &[i64] {
&self.indices[qi * self.k..(qi + 1) * self.k]
}
}