pub(crate) fn quantize(v: &[f32]) -> (f32, Vec<i8>) {
let mut maxabs = 0.0f32;
for &x in v {
let a = x.abs();
if a > maxabs {
maxabs = a;
}
}
if maxabs == 0.0 || !maxabs.is_finite() {
return (0.0, vec![0i8; v.len()]);
}
let s = 127.0f32 / maxabs;
let codes = v
.iter()
.map(|&x| {
((x * s).round() as i32).clamp(-127, 127) as i8
})
.collect();
(maxabs, codes)
}
pub(crate) fn dequantize(scale: f32, codes: &[i8]) -> Vec<f32> {
codes.iter().map(|&c| c as f32 * scale / 127.0).collect()
}
pub(crate) fn is_zero(codes: &[i8]) -> bool {
codes.iter().all(|&c| c == 0)
}
pub(crate) fn cosine_q(a: &[i8], b: &[i8]) -> Option<f32> {
let (mut dot, mut na, mut nb) = (0i64, 0i64, 0i64);
for (&x, &y) in a.iter().zip(b) {
let (x, y) = (i64::from(x), i64::from(y));
dot += x * y;
na += x * x;
nb += y * y;
}
if na == 0 || nb == 0 {
return None;
}
Some(dot as f32 / ((na as f32).sqrt() * (nb as f32).sqrt()))
}
#[cfg(test)]
mod tests {
use super::*;
use proptest::prelude::*;
fn cosine_f32(a: &[f32], b: &[f32]) -> Option<f32> {
let (mut dot, mut na, mut nb) = (0.0f32, 0.0f32, 0.0f32);
for (x, y) in a.iter().zip(b) {
dot += x * y;
na += x * x;
nb += y * y;
}
if na == 0.0 || nb == 0.0 {
return None;
}
Some(dot / (na.sqrt() * nb.sqrt()))
}
#[test]
fn zero_vector_codes_are_all_zero_and_scale_zero() {
let (scale, codes) = quantize(&[0.0; 5]);
assert_eq!(scale, 0.0);
assert!(is_zero(&codes));
assert_eq!(codes.len(), 5);
assert!(cosine_q(&codes, &codes).is_none());
}
#[test]
fn empty_slice_edge() {
assert_eq!(quantize(&[]), (0.0, vec![]));
assert!(is_zero(&[]));
assert!(cosine_q(&[], &[]).is_none());
}
#[test]
fn nonzero_vector_max_component_hits_127() {
let (scale, codes) = quantize(&[0.5, -2.0, 1.0]);
assert_eq!(scale, 2.0);
assert_eq!(codes, vec![32, -127, 64]); assert!(!is_zero(&codes));
}
#[test]
fn nan_component_codes_to_zero_deterministically() {
let (scale, codes) = quantize(&[f32::NAN, 1.0]);
assert_eq!(scale, 1.0);
assert_eq!(codes, vec![0, 127]);
}
#[test]
fn all_nonfinite_input_degrades_to_zero_encoding() {
let (scale, codes) = quantize(&[f32::INFINITY, f32::NAN]);
assert_eq!(scale, 0.0);
assert!(is_zero(&codes));
}
#[test]
fn cosine_q_identical_codes_is_one() {
let (_, codes) = quantize(&[0.1, 0.2, -0.3]);
let c = cosine_q(&codes, &codes).unwrap();
assert!((c - 1.0).abs() < 1e-6, "self-cosine {c}");
}
#[test]
fn cosine_q_zero_side_is_none() {
let (_, a) = quantize(&[1.0, 0.0]);
assert!(cosine_q(&a, &[0, 0]).is_none());
assert!(cosine_q(&[0, 0], &a).is_none());
}
proptest! {
#[test]
fn round_trip_codes_are_exactly_stable(
v in proptest::collection::vec(-1.0f32..1.0, 4..256)
) {
let (s1, c1) = quantize(&v);
prop_assume!(s1 != 0.0);
let back = dequantize(s1, &c1);
let (s2, c2) = quantize(&back);
prop_assert_eq!(&c1, &c2);
prop_assert!(((s2 - s1) / s1).abs() < 1e-5, "scale drifted {} -> {}", s1, s2);
}
#[test]
fn cosine_q_tracks_f32_cosine(
a in proptest::collection::vec(-1.0f32..1.0, 8..256),
b in proptest::collection::vec(-1.0f32..1.0, 8..256),
) {
let n = a.len().min(b.len());
let (a, b) = (&a[..n], &b[..n]);
let (fa, fb) = (cosine_f32(a, b), {
let (_, qa) = quantize(a);
let (_, qb) = quantize(b);
cosine_q(&qa, &qb)
});
match (fa, fb) {
(Some(f), Some(q)) => prop_assert!((f - q).abs() < 0.05, "f32 {} vs q {}", f, q),
(None, None) => {}
(f, q) => prop_assert!(false, "zero-norm disagreement: {:?} vs {:?}", f, q),
}
}
#[test]
fn i64_accumulators_never_overflow(dim in 1usize..100_000) {
let a = vec![127i8; dim];
let b = vec![-127i8; dim];
let c = cosine_q(&a, &b).unwrap();
prop_assert!((c + 1.0).abs() < 1e-5);
}
}
}