use std::fmt;
use bytemuck::{Pod, Zeroable};
use crate::distance::Distance;
use crate::node::Item;
use crate::spaces::simple::dot_product_binary_quantized;
use crate::unaligned_vector::{self, BinaryQuantized, UnalignedVector};
#[derive(Debug, Clone)]
pub enum BinaryQuantizedEuclidean {}
#[repr(C)]
#[derive(Pod, Zeroable, Clone, Copy)]
pub struct NodeHeaderBinaryQuantizedEuclidean {
bias: f32,
}
impl fmt::Debug for NodeHeaderBinaryQuantizedEuclidean {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("NodeHeaderBinaryQuantizedEuclidean")
.field("bias", &format!("{:.4}", self.bias))
.finish()
}
}
impl Distance for BinaryQuantizedEuclidean {
type Header = NodeHeaderBinaryQuantizedEuclidean;
type VectorCodec = unaligned_vector::BinaryQuantized;
fn name() -> &'static str {
"binary quantized euclidean"
}
fn new_header(_vector: &UnalignedVector<Self::VectorCodec>) -> Self::Header {
NodeHeaderBinaryQuantizedEuclidean { bias: 0.0 }
}
fn distance(p: &Item<Self>, q: &Item<Self>) -> f32 {
squared_euclidean_distance_binary_quantized(&p.vector, &q.vector)
}
fn norm_no_header(v: &UnalignedVector<Self::VectorCodec>) -> f32 {
dot_product_binary_quantized(v, v).sqrt()
}
}
fn squared_euclidean_distance_binary_quantized(
u: &UnalignedVector<BinaryQuantized>,
v: &UnalignedVector<BinaryQuantized>,
) -> f32 {
let ret =
u.as_bytes().iter().zip(v.as_bytes()).map(|(u, v)| (u ^ v).count_ones()).sum::<u32>() * 4;
ret as f32
}