use lattice_embed::simd::{
QuantizedVector, batch_cosine_similarity, batch_dot_product, cosine_similarity, dot_product,
euclidean_distance, normalize,
};
#[test]
fn test_dot_product_zero_vectors() {
let zero = vec![0.0f32; 384];
let nonzero = vec![1.0f32; 384];
assert_eq!(dot_product(&zero, &zero), 0.0);
assert_eq!(dot_product(&zero, &nonzero), 0.0);
}
#[test]
fn test_cosine_similarity_zero_vector() {
let zero = vec![0.0f32; 384];
let nonzero: Vec<f32> = (0..384).map(|i| (i as f32 * 0.1).sin()).collect();
let sim = cosine_similarity(&zero, &nonzero);
assert_eq!(sim, 0.0, "Cosine with zero vector should be 0");
let sim_zero = cosine_similarity(&zero, &zero);
assert_eq!(sim_zero, 0.0, "Cosine of two zero vectors should be 0");
}
#[test]
fn test_normalize_zero_vector() {
let mut zero = vec![0.0f32; 384];
normalize(&mut zero);
for val in &zero {
assert!(val.is_finite(), "Normalized zero vector should be finite");
assert_eq!(*val, 0.0, "Zero vector should remain zero after normalize");
}
}
#[test]
fn test_euclidean_distance_zero_vectors() {
let zero = vec![0.0f32; 384];
let nonzero = vec![1.0f32; 384];
assert_eq!(euclidean_distance(&zero, &zero), 0.0);
let expected = (384.0f32).sqrt();
let dist = euclidean_distance(&zero, &nonzero);
assert!(
(dist - expected).abs() < 1e-4,
"Expected {expected}, got {dist}"
);
}
#[test]
fn test_unit_vectors_cosine_similarity() {
let e1: Vec<f32> = (0..384).map(|i| if i == 0 { 1.0 } else { 0.0 }).collect();
let e2: Vec<f32> = (0..384).map(|i| if i == 1 { 1.0 } else { 0.0 }).collect();
let e1_neg: Vec<f32> = (0..384).map(|i| if i == 0 { -1.0 } else { 0.0 }).collect();
let sim = cosine_similarity(&e1, &e1);
assert!(
(sim - 1.0).abs() < 1e-5,
"Identical unit vectors should have similarity 1.0, got {sim}"
);
let sim_ortho = cosine_similarity(&e1, &e2);
assert!(
sim_ortho.abs() < 1e-5,
"Orthogonal unit vectors should have similarity 0.0, got {sim_ortho}"
);
let sim_opp = cosine_similarity(&e1, &e1_neg);
assert!(
(sim_opp + 1.0).abs() < 1e-5,
"Opposite unit vectors should have similarity -1.0, got {sim_opp}"
);
}
#[test]
fn test_normalized_dot_product_equals_cosine() {
let mut a: Vec<f32> = (0..384).map(|i| (i as f32 * 0.1).sin()).collect();
let mut b: Vec<f32> = (0..384).map(|i| (i as f32 * 0.2).cos()).collect();
normalize(&mut a);
normalize(&mut b);
let dot = dot_product(&a, &b);
let cos = cosine_similarity(&a, &b);
assert!(
(dot - cos).abs() < 1e-5,
"For normalized vectors, dot product ({dot}) should equal cosine similarity ({cos})"
);
}
#[test]
fn test_very_small_values() {
let tiny = vec![1e-15f32; 384];
let also_tiny = vec![2e-15f32; 384];
let dot = dot_product(&tiny, &also_tiny);
let expected: f32 = (1e-15 * 2e-15) * 384.0;
let abs_error = (dot - expected).abs();
assert!(
abs_error < 1e-28,
"Dot product of tiny values: expected {expected:.2e}, got {dot:.2e}, error {abs_error:.2e}"
);
let cos = cosine_similarity(&tiny, &also_tiny);
assert!(
(cos - 1.0).abs() < 1e-5,
"Parallel tiny vectors should have cosine 1.0, got {cos}"
);
}
#[test]
fn test_underflow_detection() {
let extreme_tiny = vec![1e-30f32; 384];
let also_extreme = vec![2e-30f32; 384];
let dot = dot_product(&extreme_tiny, &also_extreme);
assert_eq!(dot, 0.0, "Extreme small values should underflow to 0");
let cos = cosine_similarity(&extreme_tiny, &also_extreme);
assert!(
cos == 0.0 || cos.is_finite(),
"Underflow case should not produce unexpected value, got {cos}"
);
}
#[test]
fn test_moderately_large_values() {
let large = vec![1e15f32; 384];
let also_large = vec![1e15f32; 384];
let cos = cosine_similarity(&large, &also_large);
assert!(
(cos - 1.0).abs() < 1e-4,
"Identical large vectors should have cosine 1.0, got {cos}"
);
}
#[test]
fn test_overflow_detection() {
let extreme_large = vec![1e30f32; 384];
let also_extreme = vec![1e30f32; 384];
let dot = dot_product(&extreme_large, &also_extreme);
assert!(
dot.is_infinite(),
"Extreme large values should overflow to infinity, got {dot}"
);
let cos = cosine_similarity(&extreme_large, &also_extreme);
assert!(
cos.is_nan(),
"Overflow case produces NaN (inf/inf), got {cos}"
);
}
#[test]
fn test_mixed_magnitude_values() {
let mut mixed: Vec<f32> = (0..384)
.map(|i| if i % 2 == 0 { 1e-10 } else { 1e10 })
.collect();
let original = mixed.clone();
normalize(&mut mixed);
let norm: f32 = mixed.iter().map(|x| x * x).sum::<f32>().sqrt();
assert!(
(norm - 1.0).abs() < 1e-5,
"Mixed magnitude vector should normalize to unit length, got {norm}"
);
for (i, val) in mixed.iter().enumerate() {
assert!(
val.is_finite(),
"Value at index {i} should be finite, got {val} (original: {})",
original[i]
);
}
}
#[test]
fn test_nan_handling_dot_product() {
let normal: Vec<f32> = (0..384).map(|i| (i as f32 * 0.1).sin()).collect();
let mut with_nan = normal.clone();
with_nan[100] = f32::NAN;
let result = dot_product(&with_nan, &normal);
assert!(result.is_nan(), "Dot product with NaN should produce NaN");
}
#[test]
fn test_nan_handling_cosine() {
let normal: Vec<f32> = (0..384).map(|i| (i as f32 * 0.1).sin()).collect();
let mut with_nan = normal.clone();
with_nan[100] = f32::NAN;
let result = cosine_similarity(&with_nan, &normal);
assert!(
result.is_nan(),
"Cosine similarity with NaN should produce NaN"
);
}
#[test]
fn test_infinity_handling() {
let normal: Vec<f32> = (0..384).map(|i| (i as f32 * 0.1).sin()).collect();
let mut with_inf = normal.clone();
with_inf[100] = f32::INFINITY;
let dot = dot_product(&with_inf, &normal);
assert!(
dot.is_infinite() || dot.is_nan(),
"Dot product with infinity should be infinite or NaN"
);
}
#[test]
fn test_empty_vectors() {
let empty: Vec<f32> = vec![];
let dot = dot_product(&empty, &empty);
assert_eq!(dot, 0.0, "Dot product of empty vectors should be 0");
let cos = cosine_similarity(&empty, &empty);
assert_eq!(cos, 0.0, "Cosine of empty vectors should be 0");
let dist = euclidean_distance(&empty, &empty);
assert_eq!(dist, 0.0, "Euclidean distance of empty vectors should be 0");
}
#[test]
fn test_single_element_vectors() {
let a = vec![3.0f32];
let b = vec![4.0f32];
let dot = dot_product(&a, &b);
assert!((dot - 12.0).abs() < 1e-5, "Expected 12.0, got {dot}");
let cos = cosine_similarity(&a, &b);
assert!(
(cos - 1.0).abs() < 1e-5,
"Parallel 1D vectors should have cosine 1.0"
);
let dist = euclidean_distance(&a, &b);
assert!(
(dist - 1.0).abs() < 1e-5,
"Expected distance 1.0, got {dist}"
);
}
#[test]
fn test_mismatched_length_vectors() {
let a = vec![1.0f32; 384];
let b = vec![1.0f32; 256];
let dot = dot_product(&a, &b);
assert_eq!(
dot, 0.0,
"Mismatched lengths should return 0 for dot product"
);
let cos = cosine_similarity(&a, &b);
assert_eq!(cos, 0.0, "Mismatched lengths should return 0 for cosine");
let dist = euclidean_distance(&a, &b);
assert_eq!(
dist,
f32::MAX,
"Mismatched lengths should return MAX for distance"
);
}
#[test]
fn test_simd_alignment_boundaries() {
let test_dims = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 15, 16, 17, 31, 32, 33, 63, 64, 65, 127, 128, 129, 383, 384, 385, 511, 512, 513, 767, 768, 769, 1023, 1024, 1025, ];
for &dim in &test_dims {
let a: Vec<f32> = (0..dim).map(|i| (i as f32 * 0.17).sin()).collect();
let b: Vec<f32> = (0..dim).map(|i| (i as f32 * 0.23).cos()).collect();
let dot_expected: f32 = a.iter().zip(b.iter()).map(|(x, y)| x * y).sum();
let norm_a: f32 = a.iter().map(|x| x * x).sum::<f32>().sqrt();
let norm_b: f32 = b.iter().map(|x| x * x).sum::<f32>().sqrt();
let cos_expected = if norm_a > 0.0 && norm_b > 0.0 {
dot_expected / (norm_a * norm_b)
} else {
0.0
};
let dot = dot_product(&a, &b);
assert!(
(dot - dot_expected).abs() < 1e-3 * dot_expected.abs().max(1.0),
"Dim {dim}: dot product mismatch: {dot} vs {dot_expected}"
);
let cos = cosine_similarity(&a, &b);
assert!(
(cos - cos_expected).abs() < 1e-4,
"Dim {dim}: cosine mismatch: {cos} vs {cos_expected}"
);
let mut v = a.clone();
normalize(&mut v);
let norm_after: f32 = v.iter().map(|x| x * x).sum::<f32>().sqrt();
if norm_a > 1e-10 {
assert!(
(norm_after - 1.0).abs() < 1e-5,
"Dim {dim}: normalize failed, got norm {norm_after}"
);
}
}
}
#[test]
fn test_unaligned_offset_dot_product_matches_scalar() {
#[repr(align(64))]
struct AlignedBuffer<const N: usize>([f32; N]);
const DIM: usize = 384;
let mut a_storage = AlignedBuffer([0.0; DIM + 1]);
let mut b_storage = AlignedBuffer([0.0; DIM + 1]);
for i in 0..=DIM {
a_storage.0[i] = (i as f32 * 0.17).sin() * 0.5;
b_storage.0[i] = (i as f32 * 0.11).cos() * 0.25;
}
let a = &a_storage.0[1..];
let b = &b_storage.0[1..];
assert_ne!((a.as_ptr() as usize) % 64, 0);
assert_ne!((b.as_ptr() as usize) % 64, 0);
let expected: f32 = a.iter().zip(b.iter()).map(|(x, y)| x * y).sum();
let actual = dot_product(a, b);
let tolerance = 1e-4 * expected.abs().max(1.0);
assert!(
(actual - expected).abs() <= tolerance,
"unaligned offset dot product mismatch: actual={actual}, expected={expected}"
);
}
#[test]
fn test_all_negative_values() {
let neg: Vec<f32> = (0..384)
.map(|i| -((i as f32 * 0.1).sin().abs() + 0.1))
.collect();
let cos = cosine_similarity(&neg, &neg);
assert!(
(cos - 1.0).abs() < 1e-5,
"Negative vector cosine with itself should be 1.0, got {cos}"
);
let mut normalized = neg.clone();
normalize(&mut normalized);
let norm: f32 = normalized.iter().map(|x| x * x).sum::<f32>().sqrt();
assert!(
(norm - 1.0).abs() < 1e-5,
"Normalized negative vector should have unit length"
);
}
#[test]
fn test_opposite_vectors() {
let pos: Vec<f32> = (0..384).map(|i| (i as f32 * 0.1).sin()).collect();
let neg: Vec<f32> = pos.iter().map(|x| -x).collect();
let cos = cosine_similarity(&pos, &neg);
assert!(
(cos + 1.0).abs() < 1e-5,
"Opposite vectors should have cosine -1.0, got {cos}"
);
let dist = euclidean_distance(&pos, &neg);
let norm_pos: f32 = pos.iter().map(|x| x * x).sum::<f32>().sqrt();
let expected_dist = 2.0 * norm_pos;
assert!(
(dist - expected_dist).abs() < 1e-3,
"Distance between opposite vectors: expected {expected_dist}, got {dist}"
);
}
#[test]
fn test_batch_empty() {
let pairs: Vec<(&[f32], &[f32])> = vec![];
let cos_results = batch_cosine_similarity(&pairs);
assert!(cos_results.is_empty());
let dot_results = batch_dot_product(&pairs);
assert!(dot_results.is_empty());
}
#[test]
fn test_batch_single_pair() {
let a = vec![1.0f32, 2.0, 3.0];
let b = vec![4.0f32, 5.0, 6.0];
let pairs: Vec<(&[f32], &[f32])> = vec![(&a, &b)];
let cos_results = batch_cosine_similarity(&pairs);
assert_eq!(cos_results.len(), 1);
assert!((cos_results[0] - cosine_similarity(&a, &b)).abs() < 1e-6);
let dot_results = batch_dot_product(&pairs);
assert_eq!(dot_results.len(), 1);
assert!((dot_results[0] - dot_product(&a, &b)).abs() < 1e-6);
}
#[test]
fn test_batch_with_varying_lengths() {
let a1 = vec![1.0f32; 10];
let b1 = vec![2.0f32; 10];
let a2 = vec![1.0f32; 20];
let b2 = vec![2.0f32; 15];
let pairs: Vec<(&[f32], &[f32])> = vec![(&a1, &b1), (&a2, &b2)];
let results = batch_cosine_similarity(&pairs);
assert_eq!(results.len(), 2);
assert!((results[0] - 1.0).abs() < 1e-5, "Parallel vectors");
assert_eq!(results[1], 0.0, "Mismatched lengths should return 0");
}
#[test]
fn test_quantization_zero_vector() {
let zero = vec![0.0f32; 384];
let quantized = QuantizedVector::from_f32(&zero);
for val in &quantized.data {
assert_eq!(*val, 0, "Zero vector should quantize to all zeros");
}
assert_eq!(quantized.norm, 0.0, "Zero vector norm should be 0");
let dequantized = quantized.to_f32();
for val in &dequantized {
assert_eq!(*val, 0.0);
}
}
#[test]
fn test_quantization_single_value_vector() {
let uniform = vec![0.5f32; 384];
let quantized = QuantizedVector::from_f32(&uniform);
let first = quantized.data[0];
for val in &quantized.data {
assert_eq!(*val, first, "Uniform vector should quantize uniformly");
}
}
#[test]
fn test_quantization_max_values() {
let max_val = vec![1.0f32; 384];
let quantized = QuantizedVector::from_f32(&max_val);
for val in &quantized.data {
assert_eq!(*val, 127, "Max values should quantize to 127");
}
}
#[test]
fn test_quantization_min_values() {
let min_val = vec![-1.0f32; 384];
let quantized = QuantizedVector::from_f32(&min_val);
for val in &quantized.data {
assert_eq!(*val, -127, "Min values should quantize to -127");
}
}
#[test]
fn test_quantization_with_nan() {
let mut with_nan = vec![0.5f32; 384];
with_nan[100] = f32::NAN;
let quantized = QuantizedVector::from_f32(&with_nan);
assert_eq!(quantized.data[100], 0, "NaN should quantize to 0");
assert!(
quantized.norm.is_finite(),
"Norm should be finite even with NaN input"
);
}
#[test]
fn test_quantization_with_infinity() {
let mut with_inf = vec![0.5f32; 384];
with_inf[100] = f32::INFINITY;
let quantized = QuantizedVector::from_f32(&with_inf);
assert_eq!(quantized.data[100], 0, "Infinity should quantize to 0");
}
#[test]
fn test_quantized_dot_product_zero_vectors() {
let zero = vec![0.0f32; 384];
let nonzero: Vec<f32> = (0..384).map(|i| (i as f32 * 0.1).sin()).collect();
let q_zero = QuantizedVector::from_f32(&zero);
let q_nonzero = QuantizedVector::from_f32(&nonzero);
let dot = q_zero.dot_product(&q_nonzero);
assert_eq!(dot, 0.0, "Dot product with quantized zero should be 0");
}
#[test]
fn test_quantized_cosine_zero_norm() {
let zero = vec![0.0f32; 384];
let nonzero: Vec<f32> = (0..384).map(|i| (i as f32 * 0.1).sin()).collect();
let q_zero = QuantizedVector::from_f32(&zero);
let q_nonzero = QuantizedVector::from_f32(&nonzero);
let cos = q_zero.cosine_similarity(&q_nonzero);
assert_eq!(cos, 0.0, "Cosine with zero quantized vector should be 0");
}
#[test]
fn test_quantized_mismatched_lengths() {
let a: Vec<f32> = (0..384).map(|i| (i as f32 * 0.1).sin()).collect();
let b: Vec<f32> = (0..256).map(|i| (i as f32 * 0.1).sin()).collect();
let q_a = QuantizedVector::from_f32(&a);
let q_b = QuantizedVector::from_f32(&b);
let dot = q_a.dot_product(&q_b);
assert_eq!(
dot, 0.0,
"Mismatched quantized vector lengths should return 0"
);
}