use core::f32;
const MMAP_ALIGNMENT: usize = 8;
pub fn rabitq_quantize(data: &[f32]) -> Box<[u64]> {
let num_blocks = data.len().div_ceil(64);
let mut packed = vec![0u64; num_blocks];
for (i, &val) in data.iter().enumerate() {
if val > 0.0 {
let block = i / 64;
let bit = i % 64;
packed[block] |= 1 << bit;
}
}
packed.into_boxed_slice()
}
pub fn rabitq_similarity(a: &[u64], b: &[u64]) -> f32 {
let mut xor_sum = 0;
for (va, vb) in a.iter().zip(b.iter()) {
xor_sum += (va ^ vb).count_ones();
}
let total_bits = (a.len() * 64) as f32;
1.0 - (xor_sum as f32 / total_bits)
}
pub fn turbo_quant_quantize(data: &[f32]) -> (Box<[u8]>, f32) {
let mut max_abs = 0.0_f32;
for &val in data {
let abs = val.abs();
if abs > max_abs {
max_abs = abs;
}
}
if max_abs < f32::EPSILON {
max_abs = 1.0;
}
let scale = 7.0 / max_abs;
let num_bytes = data.len().div_ceil(2);
let mut packed = vec![0u8; num_bytes];
for (i, &val) in data.iter().enumerate() {
let scaled = (val * scale).round();
let clamped = scaled.clamp(-8.0, 7.0) as i8;
let q = (clamped as u8) & 0x0F;
let byte_pos = i / 2;
if i % 2 == 0 {
packed[byte_pos] |= q << 4;
} else {
packed[byte_pos] |= q;
}
}
let aligned_len = (num_bytes + MMAP_ALIGNMENT - 1) & !(MMAP_ALIGNMENT - 1);
packed.resize(aligned_len, 0u8);
(packed.into_boxed_slice(), max_abs)
}
pub fn turbo_quant_similarity(
a_packed: &[u8],
a_max_abs: f32,
b_packed: &[u8],
b_max_abs: f32,
) -> f32 {
debug_assert!(
(a_packed.as_ptr() as usize).is_multiple_of(std::mem::align_of::<u8>()),
"turbo_quant_similarity: a_packed pointer is misaligned"
);
let mut dot = 0_i32;
for (va, vb) in a_packed.iter().zip(b_packed.iter()) {
let a_high = (*va >> 4) as i8;
let a_high = if a_high & 8 != 0 { a_high | -8 } else { a_high };
let a_low = (*va & 0x0F) as i8;
let a_low = if a_low & 8 != 0 { a_low | -8 } else { a_low };
let b_high = (*vb >> 4) as i8;
let b_high = if b_high & 8 != 0 { b_high | -8 } else { b_high };
let b_low = (*vb & 0x0F) as i8;
let b_low = if b_low & 8 != 0 { b_low | -8 } else { b_low };
dot += (a_high as i32 * b_high as i32) + (a_low as i32 * b_low as i32);
}
dot as f32 * (a_max_abs * b_max_abs) / 49.0
}
pub fn sq8_quantize(data: &[f32]) -> (Box<[i8]>, f32) {
let mut max_abs = 0.0_f32;
for &val in data {
let abs = val.abs();
if abs > max_abs {
max_abs = abs;
}
}
if max_abs < f32::EPSILON {
max_abs = 1.0;
}
let scale = 127.0 / max_abs;
let quantized: Vec<i8> = data
.iter()
.map(|&v| {
let scaled = (v * scale).round().clamp(-127.0, 127.0) as i8;
scaled
})
.collect();
(quantized.into_boxed_slice(), max_abs)
}
pub fn sq8_similarity(a: &[i8], a_max_abs: f32, b: &[i8], b_max_abs: f32) -> f32 {
let mut dot = 0_i32;
for (va, vb) in a.iter().zip(b.iter()) {
dot += *va as i32 * *vb as i32;
}
let scale = (a_max_abs / 127.0) * (b_max_abs / 127.0);
dot as f32 * scale
}