#![allow(clippy::cast_precision_loss)]
use super::{hamming_distance_native, jaccard_similarity_native};
const DIMS: &[usize] = &[3, 4, 8, 16, 17, 64, 520, 1030];
fn pair(dim: usize) -> (Vec<f32>, Vec<f32>) {
(
(0..dim).map(|i| (i % 3) as f32 * 0.4).collect(),
(0..dim).map(|i| ((i + 1) % 3) as f32 * 0.4).collect(),
)
}
#[test]
fn jaccard_is_asymmetric_under_a_nan_which_is_why_nan_is_refused_at_the_edge() {
let mut split_seen = false;
for &dim in DIMS {
let (base_a, base_b) = pair(dim);
let mut a = base_a.clone();
a[0] = f32::NAN;
let nan_in_a = jaccard_similarity_native(&a, &base_b);
let mut b = base_b.clone();
b[0] = f32::NAN;
let nan_in_b = jaccard_similarity_native(&base_a, &b);
assert!(
!nan_in_a.is_nan(),
"dim {dim}: NaN in the first argument produced {nan_in_a}; if this \
ever starts propagating, the guard's rationale has changed"
);
if nan_in_b.is_nan() {
split_seen = true;
assert!(
dim >= 8,
"dim {dim}: the split is expected only once the AVX2 kernel \
takes over at 8 lanes, but it appeared here"
);
}
}
assert!(
split_seen,
"no dimension propagated a NaN from the second argument. Either the \
kernels were fixed — in which case delete this test and say so — or \
the dispatch no longer reaches the AVX2 Jaccard kernel at all, which \
is a coverage regression worth knowing about."
);
}
#[test]
fn hamming_absorbs_a_nan_in_either_argument() {
for &dim in DIMS {
let (base_a, base_b) = pair(dim);
let mut a = base_a.clone();
a[0] = f32::NAN;
let mut b = base_b.clone();
b[0] = f32::NAN;
assert!(
!hamming_distance_native(&a, &base_b).is_nan(),
"dim {dim}, a"
);
assert!(
!hamming_distance_native(&base_a, &b).is_nan(),
"dim {dim}, b"
);
}
}