bbqvec 0.0.10

Scalable, embeddable, vector storage for approximate K-nearest-neighbors (AKNN)
Documentation
use crate::{vector::distance, Vector};
use anyhow::Result;
use half::{bf16, vec::HalfFloatVecExt};

pub trait Quantization: Default {
    type Lower: Clone;
    fn similarity(x: &Self::Lower, y: &Self::Lower) -> Result<f32>;
    fn compare(x: &Vector, y: &Self::Lower) -> Result<f32>;
    fn lower(vec: Vector) -> Result<Self::Lower>;
    fn vector_size(dimensions: usize) -> usize;
    fn marshal(v: &Self::Lower, array: &mut [u8]) -> Result<()>;
    fn unmarshal(array: &[u8]) -> Result<Self::Lower>;
    fn name() -> &'static str;
}

#[derive(Default)]
pub struct NoQuantization {}

impl Quantization for NoQuantization {
    type Lower = Vector;

    fn similarity(x: &Self::Lower, y: &Self::Lower) -> Result<f32> {
        Ok(distance(x, y))
    }

    fn compare(x: &Vector, y: &Self::Lower) -> Result<f32> {
        Ok(distance(x, y))
    }

    fn lower(vec: Vector) -> Result<Self::Lower> {
        Ok(vec)
    }

    fn name() -> &'static str {
        "none"
    }

    fn vector_size(dimensions: usize) -> usize {
        4 * dimensions
    }

    fn marshal(v: &Self::Lower, array: &mut [u8]) -> Result<()> {
        for (i, f) in v.iter().enumerate() {
            let bytes = f.to_le_bytes();
            let _ = &array[i * 4..i * 4 + 4].copy_from_slice(&bytes);
        }
        Ok(())
    }

    fn unmarshal(array: &[u8]) -> Result<Self::Lower> {
        let mut vec = Vec::new();
        for i in (0..array.len()).step_by(4) {
            let bytes = &array[i..i + 4];
            let f: f32 = f32::from_le_bytes(bytes.try_into().unwrap());
            vec.push(f);
        }
        Ok(vec)
    }
}

#[derive(Default)]
pub struct BF16Quantization {}

impl Quantization for BF16Quantization {
    type Lower = Vec<half::bf16>;

    fn similarity(x: &Self::Lower, y: &Self::Lower) -> Result<f32> {
        let fx = x.iter().map(|v| v.to_f32()).collect();
        let fy = y.iter().map(|v| v.to_f32()).collect();
        Ok(distance(&fx, &fy))
    }

    fn compare(x: &Vector, y: &Self::Lower) -> Result<f32> {
        let fy = y.iter().map(|v| v.to_f32()).collect();
        Ok(distance(x, &fy))
    }

    fn lower(vec: Vector) -> Result<Self::Lower> {
        Ok(Vec::from_f32_slice(vec.as_slice()))
    }

    fn name() -> &'static str {
        "bf16"
    }

    fn vector_size(dimensions: usize) -> usize {
        2 * dimensions
    }

    fn marshal(v: &Self::Lower, array: &mut [u8]) -> Result<()> {
        for (i, f) in v.iter().enumerate() {
            let bytes = f.to_le_bytes();
            let _ = &array[i * 2..i * 2 + 2].copy_from_slice(&bytes);
        }
        Ok(())
    }

    fn unmarshal(array: &[u8]) -> Result<Self::Lower> {
        let mut vec = Vec::new();
        for i in (0..array.len()).step_by(2) {
            let bytes = &array[i..i + 2];
            let f: bf16 = bf16::from_le_bytes(bytes.try_into().unwrap());
            vec.push(f);
        }
        Ok(vec)
    }
}