1#[cfg(target_arch = "aarch64")]
7use diskann_wide::arch::aarch64::Neon;
8#[cfg(target_arch = "x86_64")]
9use diskann_wide::arch::x86_64::{V3, V4};
10use diskann_wide::{
11 arch::{Dispatched2, FTarget2, Scalar},
12 Architecture,
13};
14use half::f16;
15
16use super::{implementations::Specialize, Cosine, CosineNormalized, InnerProduct, SquaredL2};
17use crate::{distance::Metric, AsUnaligned, UnalignedSlice};
18
19pub trait DistanceProvider<T>: Sized + 'static {
45 fn distance_comparer(metric: Metric, dimension: Option<usize>) -> Distance<Self, T>;
46}
47
48#[derive(Debug)]
49struct Unaligned<T>(std::marker::PhantomData<T>);
50
51impl<T> diskann_wide::lifetime::AddLifetime for Unaligned<T>
52where
53 T: 'static,
54{
55 type Of<'a> = UnalignedSlice<'a, T>;
56}
57
58#[derive(Debug, Clone, Copy)]
62pub struct Distance<T, U>
63where
64 T: 'static,
65 U: 'static,
66{
67 f: Dispatched2<f32, Unaligned<T>, Unaligned<U>>,
68}
69
70impl<T, U> Distance<T, U>
71where
72 T: 'static,
73 U: 'static,
74{
75 fn new(f: Dispatched2<f32, Unaligned<T>, Unaligned<U>>) -> Self {
76 Self { f }
77 }
78
79 #[inline]
86 pub fn call(&self, x: &[T], y: &[U]) -> f32 {
87 self.call_unaligned(x.as_unaligned(), y.as_unaligned())
88 }
89
90 #[inline]
97 pub fn call_unaligned(&self, x: UnalignedSlice<'_, T>, y: UnalignedSlice<'_, U>) -> f32 {
98 self.f.call(x, y)
99 }
100}
101
102impl<T, U> crate::DistanceFunction<&[T], &[U], f32> for Distance<T, U>
103where
104 T: 'static,
105 U: 'static,
106{
107 fn evaluate_similarity(&self, x: &[T], y: &[U]) -> f32 {
108 self.call(x, y)
109 }
110}
111
112impl<T, U> crate::DistanceFunction<UnalignedSlice<'_, T>, UnalignedSlice<'_, U>, f32>
113 for Distance<T, U>
114where
115 T: 'static,
116 U: 'static,
117{
118 fn evaluate_similarity(&self, x: UnalignedSlice<'_, T>, y: UnalignedSlice<'_, U>) -> f32 {
119 self.f.call(x, y)
120 }
121}
122
123macro_rules! provider {
176 ($T:ty, $U:ty) => {
177 impl DistanceProvider<$U> for $T {
178 fn distance_comparer(metric: Metric, dimension: Option<usize>) -> Distance<$T, $U> {
179 diskann_wide::arch::dispatch2_no_features(
184 ArgumentTypes::<$T, $U>::new(),
185 metric,
186 dimension,
187 )
188 }
189 }
190 };
191}
192
193provider!(f32, f32);
194provider!(f16, f16);
195provider!(f32, f16);
196provider!(i8, i8);
197provider!(u8, u8);
198
199macro_rules! spec_list {
204 ($($Ns:literal),* $(,)?) => {
205 spec_list!(@value, $($Ns,)*)
206 };
207 (@value $(,)?) => {
208 Cons::new(Null, Null)
209 };
210 (@value, $N0:literal $(,)?) => {
211 Cons::new(Spec::<$N0>, Null)
212 };
213 (@value, $N0:literal, $N1:literal $(,)?) => {
214 Cons::new(Spec::<$N0>, Spec::<$N1>)
215 };
216 (@value, $N0:literal, $N1:literal, $($Ns:literal),+ $(,)?) => {
217 Cons::new(Spec::<$N0>, spec_list!(@value, $N1, $($Ns,)+))
218 };
219}
220
221struct ArgumentTypes<T: 'static, U: 'static>(std::marker::PhantomData<(T, U)>);
222
223impl<T, U> ArgumentTypes<T, U>
224where
225 T: 'static,
226 U: 'static,
227{
228 fn new() -> Self {
229 Self(std::marker::PhantomData)
230 }
231}
232
233macro_rules! specialize {
234 ($arch:ty, $T:ty, $U:ty, $($Ns:literal),* $(,)?) => {
235 impl diskann_wide::arch::Target2<
236 $arch,
237 Distance<$T, $U>,
238 Metric,
239 Option<usize>,
240 > for ArgumentTypes<$T, $U> {
241 fn run(
242 self,
243 arch: $arch,
244 metric: Metric,
245 dim: Option<usize>,
246 ) -> Distance<$T, $U> {
247 let spec = spec_list!($($Ns),*);
248 match metric {
249 Metric::L2 => spec.specialize(arch, SquaredL2 {}, dim),
250 Metric::Cosine => spec.specialize(arch, Cosine {}, dim),
251 Metric::CosineNormalized => spec.specialize(arch, CosineNormalized {}, dim),
252 Metric::InnerProduct => spec.specialize(arch, InnerProduct {}, dim),
253 }
254 }
255 }
256 };
257 (@integer, $arch:ty, $T:ty, $U:ty, $($Ns:literal),* $(,)?) => {
259 impl diskann_wide::arch::Target2<
260 $arch,
261 Distance<$T, $U>,
262 Metric,
263 Option<usize>,
264 > for ArgumentTypes<$T, $U> {
265 fn run(
266 self,
267 arch: $arch,
268 metric: Metric,
269 dim: Option<usize>,
270 ) -> Distance<$T, $U> {
271 let spec = spec_list!($($Ns),*);
272 match metric {
273 Metric::L2 => spec.specialize(arch, SquaredL2 {}, dim),
274 Metric::Cosine | Metric::CosineNormalized => {
275 spec.specialize(arch, Cosine {}, dim)
276 },
277 Metric::InnerProduct => spec.specialize(arch, InnerProduct {}, dim),
278 }
279 }
280 }
281 };
282}
283
284specialize!(Scalar, f32, f32,);
285specialize!(Scalar, f32, f16,);
286specialize!(Scalar, f16, f16,);
287specialize!(@integer, Scalar, u8, u8,);
288specialize!(@integer, Scalar, i8, i8,);
289
290#[cfg(target_arch = "x86_64")]
291mod x86_64 {
292 use super::*;
293
294 specialize!(V3, f32, f32, 768, 384, 128, 100);
295 specialize!(V4, f32, f32, 768, 384, 128, 100);
296
297 specialize!(V3, f32, f16, 768, 384, 128, 100);
298 specialize!(V4, f32, f16, 768, 384, 128, 100);
299
300 specialize!(V3, f16, f16, 768, 384, 128, 100);
301 specialize!(V4, f16, f16, 768, 384, 128, 100);
302
303 specialize!(@integer, V3, u8, u8, 128);
304 specialize!(@integer, V4, u8, u8, 128);
305
306 specialize!(@integer, V3, i8, i8, 128, 100);
307 specialize!(@integer, V4, i8, i8, 128, 100);
308}
309
310#[cfg(target_arch = "aarch64")]
311mod aarch64 {
312 use super::*;
313
314 specialize!(Neon, f32, f32, 768, 384, 128, 100);
315 specialize!(Neon, f32, f16, 768, 384, 128, 100);
316 specialize!(Neon, f16, f16, 768, 384, 128, 100);
317
318 specialize!(@integer, Neon, u8, u8, 128);
319 specialize!(@integer, Neon, i8, i8, 128, 100);
320}
321
322trait TrySpecialize<A, F, T, U>
325where
326 A: Architecture,
327 T: 'static,
328 U: 'static,
329{
330 fn try_specialize(&self, arch: A, dim: Option<usize>) -> Option<Distance<T, U>>;
331}
332
333struct Spec<const N: usize>;
335
336impl<A, F, const N: usize, T, U> TrySpecialize<A, F, T, U> for Spec<N>
337where
338 A: Architecture,
339 Specialize<N, F>: for<'a, 'b> FTarget2<A, f32, UnalignedSlice<'a, T>, UnalignedSlice<'b, U>>,
340 T: 'static,
341 U: 'static,
342{
343 fn try_specialize(&self, arch: A, dim: Option<usize>) -> Option<Distance<T, U>> {
344 if let Some(d) = dim {
345 if d == N {
346 return Some(Distance::new(
347 arch.dispatch2::<Specialize<N, F>, f32, Unaligned<T>, Unaligned<U>>(),
349 ));
350 }
351 }
352 None
353 }
354}
355
356struct Null;
358
359impl<A, F, T, U> TrySpecialize<A, F, T, U> for Null
360where
361 A: Architecture,
362 T: 'static,
363 U: 'static,
364{
365 fn try_specialize(&self, _arch: A, _dim: Option<usize>) -> Option<Distance<T, U>> {
366 None
367 }
368}
369
370struct Cons<Head, Tail> {
372 head: Head,
373 tail: Tail,
374}
375
376impl<Head, Tail> Cons<Head, Tail> {
377 const fn new(head: Head, tail: Tail) -> Self {
378 Self { head, tail }
379 }
380
381 fn specialize<A, F, T, U>(&self, arch: A, _f: F, dim: Option<usize>) -> Distance<T, U>
384 where
385 A: Architecture,
386 F: for<'a, 'b> FTarget2<A, f32, UnalignedSlice<'a, T>, UnalignedSlice<'b, U>>,
387 Head: TrySpecialize<A, F, T, U>,
388 Tail: TrySpecialize<A, F, T, U>,
389 T: 'static,
390 U: 'static,
391 {
392 if let Some(f) = self.try_specialize(arch, dim) {
393 f
394 } else {
395 Distance::new(arch.dispatch2::<F, f32, Unaligned<T>, Unaligned<U>>())
396 }
397 }
398}
399
400impl<A, Head, Tail, F, T, U> TrySpecialize<A, F, T, U> for Cons<Head, Tail>
402where
403 A: Architecture,
404 Head: TrySpecialize<A, F, T, U>,
405 Tail: TrySpecialize<A, F, T, U>,
406 T: 'static,
407 U: 'static,
408{
409 fn try_specialize(&self, arch: A, dim: Option<usize>) -> Option<Distance<T, U>> {
410 if let Some(f) = self.head.try_specialize(arch, dim) {
411 Some(f)
412 } else {
413 self.tail.try_specialize(arch, dim)
414 }
415 }
416}
417
418#[cfg(test)]
423mod test_unaligned_distance_provider {
424 use approx::assert_relative_eq;
425 use rand::{self, SeedableRng};
426
427 use super::*;
428 use crate::{
429 distance::{reference::ReferenceProvider, Metric},
430 test_util, SimilarityScore,
431 };
432
433 struct EpsilonAndRelative {
435 epsilon: f32,
436 max_relative: f32,
437 }
438
439 fn get_float_bounds(metric: Metric) -> EpsilonAndRelative {
449 match metric {
450 Metric::L2 => EpsilonAndRelative {
451 epsilon: 1e-5,
452 max_relative: 1e-5,
453 },
454 Metric::InnerProduct => EpsilonAndRelative {
455 epsilon: 1e-4,
456 max_relative: 1e-4,
457 },
458 Metric::Cosine => EpsilonAndRelative {
459 epsilon: 1e-4,
460 max_relative: 1e-4,
461 },
462 Metric::CosineNormalized => EpsilonAndRelative {
463 epsilon: 1e-4,
464 max_relative: 1e-4,
465 },
466 }
467 }
468
469 fn get_int_bounds(metric: Metric) -> EpsilonAndRelative {
470 match metric {
471 Metric::Cosine | Metric::CosineNormalized => EpsilonAndRelative {
473 epsilon: 1e-6,
474 max_relative: 1e-6,
475 },
476 Metric::L2 | Metric::InnerProduct => EpsilonAndRelative {
478 epsilon: 0.0,
479 max_relative: 0.0,
480 },
481 }
482 }
483
484 fn do_test<T, Distribution>(
485 under_test: Distance<T, T>,
486 reference: fn(&[T], &[T]) -> SimilarityScore<f32>,
487 bounds: EpsilonAndRelative,
488 dim: usize,
489 distribution: Distribution,
490 ) where
491 T: test_util::CornerCases,
492 Distribution: test_util::GenerateRandomArguments<T> + Clone,
493 {
494 let mut rng = rand::rngs::StdRng::seed_from_u64(0xef0053c);
495
496 let converted = |a: &[T], b: &[T]| -> f32 { reference(a, b).into_inner() };
498
499 let mut checker = test_util::Checker::<T, T, f32>::new(
500 |a, b| under_test.call(a, b),
501 converted,
502 |got: f32, expected: f32| {
503 assert_relative_eq!(
504 got,
505 expected,
506 epsilon = bounds.epsilon,
507 max_relative = bounds.max_relative
508 );
509 },
510 );
511
512 test_util::test_distance_function(
513 &mut checker,
514 distribution.clone(),
515 distribution.clone(),
516 dim,
517 10,
518 &mut rng,
519 );
520 }
521
522 fn all_metrics() -> [Metric; 4] {
523 [
524 Metric::L2,
525 Metric::InnerProduct,
526 Metric::Cosine,
527 Metric::CosineNormalized,
528 ]
529 }
530
531 const MAX_DIM: usize = 256;
533
534 #[test]
535 fn test_unaligned_f32() {
536 let dist = rand_distr::Normal::new(0.0, 1.0).unwrap();
537 for metric in all_metrics() {
538 for dim in 0..MAX_DIM {
539 println!("Metric = {:?}, dim = {}", metric, dim);
540 let unaligned = <f32 as DistanceProvider<f32>>::distance_comparer(metric, None);
541 let simple = <f32 as ReferenceProvider<f32>>::reference_implementation(metric);
542 let bounds = get_float_bounds(metric);
543 do_test(unaligned, simple, bounds, dim, dist);
544 }
545 }
546 }
547
548 #[test]
549 fn test_unaligned_f16() {
550 let dist = rand_distr::Normal::new(0.0, 1.0).unwrap();
551 for metric in all_metrics() {
552 for dim in 0..MAX_DIM {
553 println!("Metric = {:?}, dim = {}", metric, dim);
554 let unaligned = <f16 as DistanceProvider<f16>>::distance_comparer(metric, None);
555 let simple = <f16 as ReferenceProvider<f16>>::reference_implementation(metric);
556 let bounds = get_float_bounds(metric);
557 do_test(unaligned, simple, bounds, dim, dist);
558 }
559 }
560 }
561
562 #[test]
563 fn test_unaligned_u8() {
564 let dist = rand::distr::StandardUniform {};
565 for metric in all_metrics() {
566 for dim in 0..MAX_DIM {
567 println!("Metric = {:?}, dim = {}", metric, dim);
568 let unaligned = <u8 as DistanceProvider<u8>>::distance_comparer(metric, None);
569 let simple = <u8 as ReferenceProvider<u8>>::reference_implementation(metric);
570 let bounds = get_int_bounds(metric);
571 do_test(unaligned, simple, bounds, dim, dist);
572 }
573 }
574 }
575
576 #[test]
577 fn test_unaligned_i8() {
578 let dist = rand::distr::StandardUniform {};
579 for metric in all_metrics() {
580 for dim in 0..MAX_DIM {
581 println!("Metric = {:?}, dim = {}", metric, dim);
582 let unaligned = <i8 as DistanceProvider<i8>>::distance_comparer(metric, None);
583 let simple = <i8 as ReferenceProvider<i8>>::reference_implementation(metric);
584
585 let bounds = get_int_bounds(metric);
586 do_test(unaligned, simple, bounds, dim, dist);
587 }
588 }
589 }
590}
591
592#[cfg(test)]
593mod distance_provider_f32_tests {
594 use approx::assert_abs_diff_eq;
595 use rand::{rngs::StdRng, Rng, SeedableRng};
596
597 use super::*;
598 use crate::{distance::reference, test_util::*};
599
600 #[repr(C, align(32))]
601 pub struct F32Slice112([f32; 112]);
602 #[repr(C, align(32))]
603 pub struct F32Slice104([f32; 104]);
604 #[repr(C, align(32))]
605 pub struct F32Slice128([f32; 128]);
606 #[repr(C, align(32))]
607 pub struct F32Slice256([f32; 256]);
608 #[repr(C, align(32))]
609 pub struct F32Slice4096([f32; 4096]);
610
611 pub fn get_turing_test_data_f32_dim(dim: usize) -> (Vec<f32>, Vec<f32>) {
612 let mut a_slice = vec![0.0f32; dim];
613 let mut b_slice = vec![0.0f32; dim];
614
615 let mut rng = StdRng::seed_from_u64(42);
616 for i in 0..dim {
617 a_slice[i] = rng.random_range(-1.0..1.0);
618 b_slice[i] = rng.random_range(-1.0..1.0);
619 }
620
621 ((a_slice), (b_slice))
622 }
623
624 #[test]
625 fn test_dist_l2_float_turing_104() {
626 let (a_data, b_data) = get_turing_test_data_f32_dim(104);
627 let (a_slice, b_slice) = (
628 F32Slice104(a_data.try_into().unwrap()),
629 F32Slice104(b_data.try_into().unwrap()),
630 );
631
632 let distance: f32 = compare_two_vec::<f32>(104, Metric::L2, &a_slice.0, &b_slice.0);
633
634 assert_abs_diff_eq!(
635 distance as f64,
636 no_vector_compare_f32_as_f64(&a_slice.0, &b_slice.0),
637 epsilon = 1e-4f64
638 );
639 }
640
641 #[test]
642 fn test_dist_l2_float_turing_112() {
643 let (a_data, b_data) = get_turing_test_data_f32_dim(112);
644 let (a_slice, b_slice) = (
645 F32Slice112(a_data.try_into().unwrap()),
646 F32Slice112(b_data.try_into().unwrap()),
647 );
648
649 let distance: f32 = compare_two_vec::<f32>(112, Metric::L2, &a_slice.0, &b_slice.0);
650
651 assert_abs_diff_eq!(
652 distance as f64,
653 no_vector_compare_f32_as_f64(&a_slice.0, &b_slice.0),
654 epsilon = 1e-4f64
655 );
656 }
657
658 #[test]
659 fn test_dist_l2_float_turing_128() {
660 let (a_data, b_data) = get_turing_test_data_f32_dim(128);
661 let (a_slice, b_slice) = (
662 F32Slice128(a_data.try_into().unwrap()),
663 F32Slice128(b_data.try_into().unwrap()),
664 );
665
666 let distance: f32 = compare_two_vec::<f32>(128, Metric::L2, &a_slice.0, &b_slice.0);
667
668 assert_abs_diff_eq!(
669 distance as f64,
670 no_vector_compare_f32_as_f64(&a_slice.0, &b_slice.0),
671 epsilon = 1e-4f64
672 );
673 }
674
675 #[test]
676 fn test_dist_l2_float_turing_256() {
677 let (a_data, b_data) = get_turing_test_data_f32_dim(256);
678 let (a_slice, b_slice) = (
679 F32Slice256(a_data.try_into().unwrap()),
680 F32Slice256(b_data.try_into().unwrap()),
681 );
682
683 let distance: f32 = compare_two_vec::<f32>(256, Metric::L2, &a_slice.0, &b_slice.0);
684
685 assert_abs_diff_eq!(
686 distance as f64,
687 no_vector_compare_f32_as_f64(&a_slice.0, &b_slice.0),
688 epsilon = 1e-3f64
689 );
690 }
691
692 #[test]
693 fn test_dist_l2_float_turing_4096() {
694 let (a_data, b_data) = get_turing_test_data_f32_dim(4096);
695 let (a_slice, b_slice) = (
696 F32Slice4096(a_data.try_into().unwrap()),
697 F32Slice4096(b_data.try_into().unwrap()),
698 );
699
700 let distance: f32 = compare_two_vec::<f32>(4096, Metric::L2, &a_slice.0, &b_slice.0);
701
702 assert_abs_diff_eq!(
703 distance as f64,
704 no_vector_compare_f32_as_f64(&a_slice.0, &b_slice.0),
705 epsilon = 1e-2f64
706 );
707 }
708
709 #[test]
710 fn test_dist_ip_float_turing_112() {
711 let (a_data, b_data) = get_turing_test_data_f32_dim(112);
712 let (a_slice, b_slice) = (
713 F32Slice112(a_data.try_into().unwrap()),
714 F32Slice112(b_data.try_into().unwrap()),
715 );
716
717 let distance: f32 =
718 compare_two_vec::<f32>(112, Metric::InnerProduct, &a_slice.0, &b_slice.0);
719
720 assert_abs_diff_eq!(
721 distance,
722 reference::reference_innerproduct_f32_similarity(&a_slice.0, &b_slice.0).into_inner(),
723 epsilon = 1e-4f32
724 );
725 }
726
727 #[test]
728 fn distance_test() {
729 #[repr(C, align(32))]
730 struct Vector32ByteAligned {
731 v: [f32; 512],
732 }
733
734 let two_vec = Box::new(Vector32ByteAligned {
736 v: [
737 69.02492, 78.84786, 63.125072, 90.90581, 79.2592, 70.81731, 3.0829668, 33.33287,
738 20.777142, 30.147898, 23.681915, 42.553043, 12.602162, 7.3808074, 19.157589,
739 65.6791, 76.44677, 76.89124, 86.40756, 84.70118, 87.86142, 16.126896, 5.1277637,
740 95.11038, 83.946945, 22.735607, 11.548555, 59.51482, 24.84603, 15.573776, 78.27185,
741 71.13179, 38.574017, 80.0228, 13.175261, 62.887978, 15.205181, 18.89392, 96.13162,
742 87.55455, 34.179806, 62.920044, 4.9305916, 54.349373, 21.731495, 14.982187,
743 40.262867, 20.15214, 36.61963, 72.450806, 55.565, 95.5375, 93.73356, 95.36308,
744 66.30762, 58.0397, 18.951357, 67.11702, 43.043316, 30.65622, 99.85361, 2.5889993,
745 27.844774, 39.72441, 46.463238, 71.303764, 90.45308, 36.390602, 63.344395,
746 26.427078, 35.99528, 82.35505, 32.529175, 23.165905, 74.73179, 9.856939, 59.38126,
747 35.714924, 79.81213, 46.704124, 24.47884, 36.01743, 0.46678782, 29.528152,
748 1.8980742, 24.68853, 75.58984, 98.72279, 68.62601, 11.890173, 49.49361, 55.45572,
749 72.71067, 34.107483, 51.357758, 76.400635, 81.32725, 66.45081, 17.848074,
750 62.398876, 94.20444, 2.10886, 17.416393, 64.88253, 29.000723, 62.434315, 53.907238,
751 70.51412, 78.70744, 55.181683, 64.45116, 23.419212, 53.68544, 43.506958, 46.89598,
752 35.905994, 64.51397, 91.95555, 20.322979, 74.80128, 97.548744, 58.312725, 78.81985,
753 31.911612, 14.445949, 49.85094, 70.87396, 40.06766, 7.129991, 78.48008, 75.21636,
754 93.623604, 95.95479, 29.571129, 22.721554, 26.73875, 52.075504, 56.783104,
755 94.65493, 61.778534, 85.72401, 85.369514, 29.922367, 41.410553, 94.12884,
756 80.276855, 55.604828, 54.70947, 74.07216, 44.61955, 31.38113, 68.48596, 34.56782,
757 14.424729, 48.204506, 9.675444, 32.01946, 92.32695, 36.292683, 78.31955, 98.05327,
758 14.343918, 46.017002, 95.90888, 82.63626, 16.873539, 3.698051, 7.8042626,
759 64.194405, 96.71023, 67.93692, 21.618402, 51.92182, 22.834194, 61.56986, 19.749891,
760 55.31206, 38.29552, 67.57593, 67.145836, 38.92673, 94.95708, 72.38746, 90.70901,
761 69.43995, 9.394085, 31.646872, 88.20112, 9.134722, 99.98214, 5.423498, 41.51995,
762 76.94409, 77.373276, 3.2966614, 9.611201, 57.231106, 30.747868, 76.10228, 91.98308,
763 70.893585, 0.9067178, 43.96515, 16.321218, 27.734184, 83.271835, 88.23312,
764 87.16445, 5.556643, 15.627432, 58.547127, 93.6459, 40.539192, 49.124157, 91.13276,
765 57.485855, 8.827019, 4.9690843, 46.511234, 53.91469, 97.71925, 20.135271,
766 23.353004, 70.92099, 93.38748, 87.520134, 51.684677, 29.89813, 9.110392, 65.809204,
767 34.16554, 93.398605, 84.58669, 96.409645, 9.876037, 94.767784, 99.21523, 1.9330144,
768 94.92429, 75.12728, 17.218828, 97.89164, 35.476578, 77.629456, 69.573746,
769 40.200542, 42.117836, 5.861628, 75.45282, 82.73633, 0.98086596, 77.24894,
770 11.248695, 61.070026, 52.692616, 80.5449, 80.76036, 29.270136, 67.60252, 48.782394,
771 95.18851, 83.47162, 52.068756, 46.66002, 90.12216, 15.515327, 33.694042, 96.963036,
772 73.49627, 62.805485, 44.715607, 59.98627, 3.8921833, 37.565327, 29.69184,
773 39.429665, 83.46899, 44.286453, 21.54851, 56.096413, 18.169249, 5.214751,
774 14.691341, 99.779335, 26.32643, 67.69903, 36.41243, 67.27333, 12.157213, 96.18984,
775 2.438283, 78.14289, 0.14715195, 98.769, 53.649532, 21.615898, 39.657497, 95.45616,
776 18.578386, 71.47976, 22.348118, 17.85519, 6.3717127, 62.176777, 22.033644,
777 23.178005, 79.44858, 89.70233, 37.21273, 71.86182, 21.284317, 52.908623, 30.095518,
778 63.64478, 77.55823, 80.04871, 15.133011, 30.439043, 70.16561, 4.4014096, 89.28944,
779 26.29093, 46.827854, 11.764729, 61.887516, 47.774887, 57.19503, 59.444664,
780 28.592825, 98.70386, 1.2497544, 82.28431, 46.76423, 83.746124, 53.032673, 86.53457,
781 99.42168, 90.184, 92.27852, 9.059965, 71.75723, 70.45299, 10.924053, 68.329704,
782 77.27232, 6.677854, 75.63629, 57.370533, 17.09031, 10.554659, 99.56178, 37.53221,
783 72.311104, 75.7565, 65.2042, 36.096478, 64.69502, 38.88497, 64.33723, 84.87812,
784 66.84958, 8.508932, 79.134, 83.431015, 66.72124, 61.801838, 64.30524, 37.194263,
785 77.94725, 89.705185, 23.643505, 19.505919, 48.40264, 43.01083, 21.171177,
786 18.717121, 10.805857, 69.66983, 77.85261, 57.323063, 3.28964, 38.758026, 5.349946,
787 7.46572, 57.485138, 30.822384, 33.9411, 95.53746, 65.57723, 42.1077, 28.591347,
788 11.917269, 5.031073, 31.835615, 19.34116, 85.71027, 87.4516, 1.3798475, 70.70583,
789 51.988052, 45.217144, 14.308596, 54.557167, 86.18323, 79.13666, 76.866745,
790 46.010685, 79.739235, 44.667603, 39.36416, 72.605896, 73.83187, 13.137412,
791 6.7911267, 63.952374, 10.082436, 86.00318, 99.760376, 92.84948, 63.786434,
792 3.4429908, 18.244314, 75.65299, 14.964747, 70.126366, 80.89449, 91.266655,
793 96.58798, 46.439327, 38.253975, 87.31036, 21.093178, 37.19671, 58.28973, 9.75231,
794 12.350321, 25.75115, 87.65073, 53.610504, 36.850048, 18.66356, 94.48941, 83.71898,
795 44.49315, 44.186737, 19.360733, 84.365974, 46.76272, 44.924366, 50.279808,
796 54.868866, 91.33004, 18.683397, 75.13282, 15.070831, 47.04839, 53.780903,
797 26.911152, 74.65651, 57.659935, 25.604189, 37.235474, 65.39667, 53.952206,
798 40.37131, 59.173275, 96.00756, 54.591274, 10.787476, 69.51549, 31.970142,
799 25.408005, 55.972492, 85.01888, 97.48981, 91.006134, 28.98619, 97.151276,
800 34.388496, 47.498177, 11.985874, 64.73775, 33.877014, 13.370312, 34.79146,
801 86.19321, 15.019405, 94.07832, 93.50433, 60.168625, 50.95409, 38.27827, 47.458614,
802 32.83715, 69.54998, 69.0361, 84.1418, 34.270298, 74.23852, 70.707466, 78.59845,
803 9.651399, 24.186779, 58.255756, 53.72362, 92.46477, 97.75528, 20.257462, 30.122698,
804 50.41517, 28.156603, 42.644154,
805 ],
806 });
807
808 let distance: f32 = compare::<f32>(256, Metric::L2, &two_vec.v);
809
810 assert_eq!(distance, 429141.2);
811 }
812
813 fn compare<T>(dim: usize, metric: Metric, v: &[T]) -> f32
814 where
815 T: DistanceProvider<T>,
816 {
817 let distance_comparer = T::distance_comparer(metric, Some(dim));
818 distance_comparer.call(&v[..dim], &v[dim..])
819 }
820
821 pub fn compare_two_vec<T>(dim: usize, metric: Metric, v1: &[T], v2: &[T]) -> f32
822 where
823 T: DistanceProvider<T>,
824 {
825 let distance_comparer = T::distance_comparer(metric, Some(dim));
826 distance_comparer.call(&v1[..dim], &v2[..dim])
827 }
828}
829
830#[cfg(test)]
831mod distance_provider_f16_tests {
832 use approx::assert_abs_diff_eq;
833
834 use super::{distance_provider_f32_tests::get_turing_test_data_f32_dim, *};
835 use crate::{
836 distance::distance_provider::distance_provider_f32_tests::compare_two_vec,
837 test_util::no_vector_compare_f16_as_f64,
838 };
839
840 #[repr(C, align(32))]
841 pub struct F16Slice112([f16; 112]);
842 #[repr(C, align(32))]
843 pub struct F16Slice104([f16; 104]);
844 #[repr(C, align(32))]
845 pub struct F16Slice128([f16; 128]);
846 #[repr(C, align(32))]
847 pub struct F16Slice256([f16; 256]);
848 #[repr(C, align(32))]
849 pub struct F16Slice4096([f16; 4096]);
850
851 fn get_turing_test_data_f16_dim(dim: usize) -> (Vec<f16>, Vec<f16>) {
852 let (a_slice, b_slice) = get_turing_test_data_f32_dim(dim);
853 let a_data = a_slice.iter().map(|x| f16::from_f32(*x)).collect();
854 let b_data = b_slice.iter().map(|x| f16::from_f32(*x)).collect();
855 (a_data, b_data)
856 }
857
858 #[test]
859 fn test_dist_l2_f16_turing_112() {
860 let (a_data, b_data) = get_turing_test_data_f16_dim(112);
862 let (a_slice, b_slice) = (
863 F16Slice112(a_data.try_into().unwrap()),
864 F16Slice112(b_data.try_into().unwrap()),
865 );
866
867 let distance: f32 = compare_two_vec::<f16>(112, Metric::L2, &a_slice.0, &b_slice.0);
868
869 assert_abs_diff_eq!(
871 distance as f64,
872 no_vector_compare_f16_as_f64(&a_slice.0, &b_slice.0),
873 epsilon = 1e-3f64
874 );
875 }
876
877 #[test]
878 fn test_dist_l2_f16_turing_104() {
879 let (a_data, b_data) = get_turing_test_data_f16_dim(104);
881 let (a_slice, b_slice) = (
882 F16Slice104(a_data.try_into().unwrap()),
883 F16Slice104(b_data.try_into().unwrap()),
884 );
885
886 let distance: f32 = compare_two_vec::<f16>(104, Metric::L2, &a_slice.0, &b_slice.0);
887
888 assert_abs_diff_eq!(
890 distance as f64,
891 no_vector_compare_f16_as_f64(&a_slice.0, &b_slice.0),
892 epsilon = 1e-3f64
893 );
894 }
895
896 #[test]
897 fn test_dist_l2_f16_turing_256() {
898 let (a_data, b_data) = get_turing_test_data_f16_dim(256);
900 let (a_slice, b_slice) = (
901 F16Slice256(a_data.try_into().unwrap()),
902 F16Slice256(b_data.try_into().unwrap()),
903 );
904
905 let distance: f32 = compare_two_vec::<f16>(256, Metric::L2, &a_slice.0, &b_slice.0);
906
907 assert_abs_diff_eq!(
909 distance as f64,
910 no_vector_compare_f16_as_f64(&a_slice.0, &b_slice.0),
911 epsilon = 1e-3f64
912 );
913 }
914
915 #[test]
916 fn test_dist_l2_f16_turing_128() {
917 let (a_data, b_data) = get_turing_test_data_f16_dim(128);
919 let (a_slice, b_slice) = (
920 F16Slice128(a_data.try_into().unwrap()),
921 F16Slice128(b_data.try_into().unwrap()),
922 );
923
924 let distance: f32 = compare_two_vec::<f16>(128, Metric::L2, &a_slice.0, &b_slice.0);
925
926 assert_abs_diff_eq!(
928 distance as f64,
929 no_vector_compare_f16_as_f64(&a_slice.0, &b_slice.0),
930 epsilon = 1e-3f64
931 );
932 }
933
934 #[test]
935 fn test_dist_l2_f16_turing_4096() {
936 let (a_data, b_data) = get_turing_test_data_f16_dim(4096);
938 let (a_slice, b_slice) = (
939 F16Slice4096(a_data.try_into().unwrap()),
940 F16Slice4096(b_data.try_into().unwrap()),
941 );
942
943 let distance: f32 = compare_two_vec::<f16>(4096, Metric::L2, &a_slice.0, &b_slice.0);
944
945 assert_abs_diff_eq!(
947 distance as f64,
948 no_vector_compare_f16_as_f64(&a_slice.0, &b_slice.0),
949 epsilon = 1e-2f64
950 );
951 }
952
953 #[test]
954 fn test_dist_l2_f16_produces_nan_distance_for_infinity_vectors() {
955 let a_data = vec![f16::INFINITY; 384];
956 let b_data = vec![f16::INFINITY; 384];
957
958 let distance: f32 = compare_two_vec::<f16>(384, Metric::L2, &a_data, &b_data);
959 assert!(distance.is_nan());
960 }
961}