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