use symagen::random_data; use test_case::test_case; use distances::{ simd, vectors::{cosine, euclidean, euclidean_sq}, }; #[test_case(euclidean_sq, simd::euclidean_sq_f32, 10_f32; "euclidean_sq_f32")] #[test_case(euclidean, simd::euclidean_f32, 10_f32; "euclidean_f32")] #[test_case(cosine, simd::cosine_f32, 1_f32; "cosine_f32")] fn simd_distances_f32(naive: fn(&[f32], &[f32]) -> f32, simd: fn(&[f32], &[f32]) -> f32, limit: f32) { let (cardinality, dimensionality) = (100, 2_usize.pow(12)); let limit = limit.abs(); let (min_val, max_val) = (-limit, limit); let mut rng = rand::thread_rng(); let data_x = random_data::random_tabular(cardinality, dimensionality, min_val, max_val, &mut rng); let data_y = random_data::random_tabular(cardinality, dimensionality, min_val, max_val, &mut rng); let mut failures = Vec::new(); for (i, x) in data_x.iter().enumerate() { for (j, y) in data_y.iter().enumerate() { let expected = naive(x, y); let actual = simd(x, y); let delta = (expected - actual).abs(); let threshold = f32::EPSILON.sqrt() * actual; if delta > threshold { failures.push((i, j, delta, threshold, actual, expected)); } } } assert!( failures.is_empty(), "{} non-empty failures, {:?} ...", failures.len(), &failures[..5] ); } #[test_case(euclidean_sq, simd::euclidean_sq_f64, 10_f64; "euclidean_sq_f64")] #[test_case(euclidean, simd::euclidean_f64, 10_f64; "euclidean_f64")] #[test_case(cosine, simd::cosine_f64, 1_f64; "cosine_f64")] fn simd_distances_f64(naive: fn(&[f64], &[f64]) -> f64, simd: fn(&[f64], &[f64]) -> f64, limit: f64) { let (cardinality, dimensionality) = (100, 2_usize.pow(12)); let limit = limit.abs(); let (min_val, max_val) = (-limit, limit); let mut rng = rand::thread_rng(); let data_x = random_data::random_tabular(cardinality, dimensionality, min_val, max_val, &mut rng); let data_y = random_data::random_tabular(cardinality, dimensionality, min_val, max_val, &mut rng); let mut failures = Vec::new(); for (i, x) in data_x.iter().enumerate() { for (j, y) in data_y.iter().enumerate() { let expected = naive(x, y); let actual = simd(x, y); let delta = (expected - actual).abs(); let threshold = f64::EPSILON.sqrt() * actual; if delta > threshold { failures.push((i, j, delta, threshold, actual, expected)); } } } assert!( failures.is_empty(), "{} non-empty failures, {:?} ...", failures.len(), &failures[..5] ); }