usearch 2.15.2 → 2.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +1 -1
  2. package/binding.gyp +1 -1
  3. package/c/CMakeLists.txt +10 -3
  4. package/cpp/README.md +1 -1
  5. package/cpp/bench.cpp +2 -2
  6. package/cpp/test.cpp +16 -0
  7. package/include/usearch/index.hpp +44 -17
  8. package/include/usearch/index_dense.hpp +51 -89
  9. package/include/usearch/index_plugins.hpp +468 -43
  10. package/javascript/lib.cpp +17 -5
  11. package/javascript/usearch.test.js +205 -34
  12. package/package.json +1 -1
  13. package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
  14. package/prebuilds/linux-arm64/usearch.node +0 -0
  15. package/prebuilds/linux-x64/usearch.node +0 -0
  16. package/simsimd/.git-blame-ignore-revs +2 -0
  17. package/simsimd/CODE_OF_CONDUCT.md +128 -0
  18. package/simsimd/CONTRIBUTING.md +84 -26
  19. package/simsimd/Cargo.lock +1 -1
  20. package/simsimd/Cargo.toml +4 -4
  21. package/simsimd/MANIFEST.in +3 -0
  22. package/simsimd/Package.swift +15 -3
  23. package/simsimd/README.md +534 -177
  24. package/simsimd/binding.gyp +6 -2
  25. package/simsimd/build.rs +13 -1
  26. package/simsimd/c/lib.c +266 -53
  27. package/simsimd/include/simsimd/binary.h +321 -112
  28. package/simsimd/include/simsimd/curved.h +803 -0
  29. package/simsimd/include/simsimd/dot.h +694 -521
  30. package/simsimd/include/simsimd/elementwise.h +1437 -0
  31. package/simsimd/include/simsimd/geospatial.h +9 -3
  32. package/simsimd/include/simsimd/mesh.h +69 -0
  33. package/simsimd/include/simsimd/probability.h +234 -206
  34. package/simsimd/include/simsimd/simsimd.h +1476 -617
  35. package/simsimd/include/simsimd/sparse.h +1428 -0
  36. package/simsimd/include/simsimd/spatial.h +1556 -742
  37. package/simsimd/include/simsimd/types.h +276 -132
  38. package/simsimd/javascript/lib.c +1 -2
  39. package/simsimd/javascript/simsimd.ts +4 -4
  40. package/simsimd/package.json +4 -4
  41. package/simsimd/rust/lib.rs +179 -1
  42. package/simsimd/scripts/bench.cxx +1070 -0
  43. package/simsimd/scripts/bench.ipynb +187 -0
  44. package/simsimd/{javascript → scripts}/bench.js +1 -1
  45. package/simsimd/{rust/benches/sqeuclidean.rs → scripts/bench_sqeuclidean.rs} +6 -6
  46. package/simsimd/scripts/bench_vectors.py +700 -0
  47. package/simsimd/scripts/bench_vectors_live.py +213 -0
  48. package/simsimd/scripts/test.c +155 -0
  49. package/simsimd/{javascript → scripts}/test.mjs +2 -2
  50. package/simsimd/scripts/test.py +1410 -0
  51. package/simsimd/swift/{source/SimSIMD.swift → SimSIMD.swift} +6 -2
  52. package/simsimd/swift/{tests/SimSIMDTests.swift → Test.swift} +1 -1
  53. /package/simsimd/{rust/benches/cosine.rs → scripts/bench_cosine.rs} +0 -0
  54. /package/simsimd/{rust/benches/native.rs → scripts/bench_native.rs} +0 -0
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "simsimd",
3
- "version": "5.0.0",
4
- "description": "Fastest SIMD-Accelerated Vector Similarity Functions for x86 and Arm",
3
+ "version": "5.9.6",
4
+ "description": "Portable mixed-precision BLAS-like vector math library for x86 and ARM",
5
5
  "homepage": "https://github.com/ashvardanian/simsimd",
6
6
  "author": "Ash Vardanian",
7
7
  "license": "Apache 2.0",
@@ -27,8 +27,8 @@
27
27
  "prebuild-arm64": "prebuildify --arch arm64 --napi --strip --target=10.4.0",
28
28
  "prebuild-darwin-x64+arm64": "prebuildify --arch arm64+x64 --napi --strip --target=10.4.0",
29
29
  "build-js": "rm -fr javascript/dist/* && tsc -p javascript/tsconfig-esm.json && tsc -p javascript/tsconfig-cjs.json && cp javascript/dist-package-esm.json javascript/dist/esm/package.json && cp javascript/dist-package-cjs.json javascript/dist/cjs/package.json",
30
- "test": "node --test ./javascript/test.mjs",
31
- "bench": "node ./javascript/bench.js"
30
+ "test": "node --test ./scripts/test.mjs",
31
+ "bench": "node ./scripts/bench.js"
32
32
  },
33
33
  "main": "javascript/dist/cjs/simsimd.js",
34
34
  "module": "javascript/dist/esm/simsimd.js",
@@ -54,24 +54,29 @@ type ComplexProduct = (f64, f64);
54
54
  extern "C" {
55
55
 
56
56
  fn simsimd_dot_f16(a: *const u16, b: *const u16, c: usize, d: *mut Distance);
57
+ fn simsimd_dot_bf16(a: *const u16, b: *const u16, c: usize, d: *mut Distance);
57
58
  fn simsimd_dot_f32(a: *const f32, b: *const f32, c: usize, d: *mut Distance);
58
59
  fn simsimd_dot_f64(a: *const f64, b: *const f64, c: usize, d: *mut Distance);
59
60
 
60
61
  fn simsimd_dot_f16c(a: *const u16, b: *const u16, c: usize, d: *mut Distance);
62
+ fn simsimd_dot_bf16c(a: *const u16, b: *const u16, c: usize, d: *mut Distance);
61
63
  fn simsimd_dot_f32c(a: *const f32, b: *const f32, c: usize, d: *mut Distance);
62
64
  fn simsimd_dot_f64c(a: *const f64, b: *const f64, c: usize, d: *mut Distance);
63
65
 
64
66
  fn simsimd_vdot_f16c(a: *const u16, b: *const u16, c: usize, d: *mut Distance);
67
+ fn simsimd_vdot_bf16c(a: *const u16, b: *const u16, c: usize, d: *mut Distance);
65
68
  fn simsimd_vdot_f32c(a: *const f32, b: *const f32, c: usize, d: *mut Distance);
66
69
  fn simsimd_vdot_f64c(a: *const f64, b: *const f64, c: usize, d: *mut Distance);
67
70
 
68
71
  fn simsimd_cos_i8(a: *const i8, b: *const i8, c: usize, d: *mut Distance);
69
72
  fn simsimd_cos_f16(a: *const u16, b: *const u16, c: usize, d: *mut Distance);
73
+ fn simsimd_cos_bf16(a: *const u16, b: *const u16, c: usize, d: *mut Distance);
70
74
  fn simsimd_cos_f32(a: *const f32, b: *const f32, c: usize, d: *mut Distance);
71
75
  fn simsimd_cos_f64(a: *const f64, b: *const f64, c: usize, d: *mut Distance);
72
76
 
73
77
  fn simsimd_l2sq_i8(a: *const i8, b: *const i8, c: usize, d: *mut Distance);
74
78
  fn simsimd_l2sq_f16(a: *const u16, b: *const u16, c: usize, d: *mut Distance);
79
+ fn simsimd_l2sq_bf16(a: *const u16, b: *const u16, c: usize, d: *mut Distance);
75
80
  fn simsimd_l2sq_f32(a: *const f32, b: *const f32, c: usize, d: *mut Distance);
76
81
  fn simsimd_l2sq_f64(a: *const f64, b: *const f64, c: usize, d: *mut Distance);
77
82
 
@@ -79,10 +84,12 @@ extern "C" {
79
84
  fn simsimd_jaccard_b8(a: *const u8, b: *const u8, c: usize, d: *mut Distance);
80
85
 
81
86
  fn simsimd_js_f16(a: *const u16, b: *const u16, c: usize, d: *mut Distance);
87
+ fn simsimd_js_bf16(a: *const u16, b: *const u16, c: usize, d: *mut Distance);
82
88
  fn simsimd_js_f32(a: *const f32, b: *const f32, c: usize, d: *mut Distance);
83
89
  fn simsimd_js_f64(a: *const f64, b: *const f64, c: usize, d: *mut Distance);
84
90
 
85
91
  fn simsimd_kl_f16(a: *const u16, b: *const u16, c: usize, d: *mut Distance);
92
+ fn simsimd_kl_bf16(a: *const u16, b: *const u16, c: usize, d: *mut Distance);
86
93
  fn simsimd_kl_f32(a: *const f32, b: *const f32, c: usize, d: *mut Distance);
87
94
  fn simsimd_kl_f64(a: *const f64, b: *const f64, c: usize, d: *mut Distance);
88
95
 
@@ -99,6 +106,8 @@ extern "C" {
99
106
  fn simsimd_uses_ice() -> i32;
100
107
  fn simsimd_uses_genoa() -> i32;
101
108
  fn simsimd_uses_sapphire() -> i32;
109
+ fn simsimd_uses_turin() -> i32;
110
+ fn simsimd_uses_sierra() -> i32;
102
111
  }
103
112
 
104
113
  /// A half-precision floating point number.
@@ -107,6 +116,12 @@ pub struct f16(u16);
107
116
 
108
117
  impl f16 {}
109
118
 
119
+ /// A half-precision floating point number, called brain float.
120
+ #[repr(transparent)]
121
+ pub struct bf16(u16);
122
+
123
+ impl bf16 {}
124
+
110
125
  /// The `capabilities` module provides functions for detecting the hardware features
111
126
  /// available on the current system.
112
127
  pub mod capabilities {
@@ -162,6 +177,14 @@ pub mod capabilities {
162
177
  pub fn uses_sapphire() -> bool {
163
178
  unsafe { crate::simsimd_uses_sapphire() != 0 }
164
179
  }
180
+
181
+ pub fn uses_turin() -> bool {
182
+ unsafe { crate::simsimd_uses_turin() != 0 }
183
+ }
184
+
185
+ pub fn uses_sierra() -> bool {
186
+ unsafe { crate::simsimd_uses_sierra() != 0 }
187
+ }
165
188
  }
166
189
 
167
190
  /// `SpatialSimilarity` provides a set of trait methods for computing similarity
@@ -370,6 +393,50 @@ impl SpatialSimilarity for f16 {
370
393
  }
371
394
  }
372
395
 
396
+ impl SpatialSimilarity for bf16 {
397
+ fn cos(a: &[Self], b: &[Self]) -> Option<Distance> {
398
+ if a.len() != b.len() {
399
+ return None;
400
+ }
401
+
402
+ // Explicitly cast `*const bf16` to `*const u16`
403
+ let a_ptr = a.as_ptr() as *const u16;
404
+ let b_ptr = b.as_ptr() as *const u16;
405
+ let mut distance_value: Distance = 0.0;
406
+ let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
407
+ unsafe { simsimd_cos_bf16(a_ptr, b_ptr, a.len(), distance_ptr) };
408
+ Some(distance_value)
409
+ }
410
+
411
+ fn dot(a: &[Self], b: &[Self]) -> Option<Distance> {
412
+ if a.len() != b.len() {
413
+ return None;
414
+ }
415
+
416
+ // Explicitly cast `*const bf16` to `*const u16`
417
+ let a_ptr = a.as_ptr() as *const u16;
418
+ let b_ptr = b.as_ptr() as *const u16;
419
+ let mut distance_value: Distance = 0.0;
420
+ let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
421
+ unsafe { simsimd_dot_bf16(a_ptr, b_ptr, a.len(), distance_ptr) };
422
+ Some(distance_value)
423
+ }
424
+
425
+ fn l2sq(a: &[Self], b: &[Self]) -> Option<Distance> {
426
+ if a.len() != b.len() {
427
+ return None;
428
+ }
429
+
430
+ // Explicitly cast `*const bf16` to `*const u16`
431
+ let a_ptr = a.as_ptr() as *const u16;
432
+ let b_ptr = b.as_ptr() as *const u16;
433
+ let mut distance_value: Distance = 0.0;
434
+ let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
435
+ unsafe { simsimd_l2sq_bf16(a_ptr, b_ptr, a.len(), distance_ptr) };
436
+ Some(distance_value)
437
+ }
438
+ }
439
+
373
440
  impl SpatialSimilarity for f32 {
374
441
  fn cos(a: &[Self], b: &[Self]) -> Option<Distance> {
375
442
  if a.len() != b.len() {
@@ -464,6 +531,36 @@ impl ProbabilitySimilarity for f16 {
464
531
  }
465
532
  }
466
533
 
534
+ impl ProbabilitySimilarity for bf16 {
535
+ fn jensenshannon(a: &[Self], b: &[Self]) -> Option<Distance> {
536
+ if a.len() != b.len() {
537
+ return None;
538
+ }
539
+
540
+ // Explicitly cast `*const bf16` to `*const u16`
541
+ let a_ptr = a.as_ptr() as *const u16;
542
+ let b_ptr = b.as_ptr() as *const u16;
543
+ let mut distance_value: Distance = 0.0;
544
+ let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
545
+ unsafe { simsimd_js_bf16(a_ptr, b_ptr, a.len(), distance_ptr) };
546
+ Some(distance_value)
547
+ }
548
+
549
+ fn kullbackleibler(a: &[Self], b: &[Self]) -> Option<Distance> {
550
+ if a.len() != b.len() {
551
+ return None;
552
+ }
553
+
554
+ // Explicitly cast `*const bf16` to `*const u16`
555
+ let a_ptr = a.as_ptr() as *const u16;
556
+ let b_ptr = b.as_ptr() as *const u16;
557
+ let mut distance_value: Distance = 0.0;
558
+ let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
559
+ unsafe { simsimd_kl_bf16(a_ptr, b_ptr, a.len(), distance_ptr) };
560
+ Some(distance_value)
561
+ }
562
+ }
563
+
467
564
  impl ProbabilitySimilarity for f32 {
468
565
  fn jensenshannon(a: &[Self], b: &[Self]) -> Option<Distance> {
469
566
  if a.len() != b.len() {
@@ -536,6 +633,36 @@ impl ComplexProducts for f16 {
536
633
  }
537
634
  }
538
635
 
636
+ impl ComplexProducts for bf16 {
637
+ fn dot(a: &[Self], b: &[Self]) -> Option<ComplexProduct> {
638
+ if a.len() != b.len() {
639
+ return None;
640
+ }
641
+ // Prepare the output array where the real and imaginary parts will be stored
642
+ let mut product: [Distance; 2] = [0.0, 0.0];
643
+ let product_ptr: *mut Distance = &mut product[0] as *mut _;
644
+ // Explicitly cast `*const bf16` to `*const u16`
645
+ let a_ptr = a.as_ptr() as *const u16;
646
+ let b_ptr = b.as_ptr() as *const u16;
647
+ unsafe { simsimd_dot_bf16c(a_ptr, b_ptr, a.len(), product_ptr) };
648
+ Some((product[0], product[1]))
649
+ }
650
+
651
+ fn vdot(a: &[Self], b: &[Self]) -> Option<ComplexProduct> {
652
+ if a.len() != b.len() {
653
+ return None;
654
+ }
655
+ // Prepare the output array where the real and imaginary parts will be stored
656
+ let mut product: [Distance; 2] = [0.0, 0.0];
657
+ let product_ptr: *mut Distance = &mut product[0] as *mut _;
658
+ // Explicitly cast `*const bf16` to `*const u16`
659
+ let a_ptr = a.as_ptr() as *const u16;
660
+ let b_ptr = b.as_ptr() as *const u16;
661
+ unsafe { simsimd_vdot_bf16c(a_ptr, b_ptr, a.len(), product_ptr) };
662
+ Some((product[0], product[1]))
663
+ }
664
+ }
665
+
539
666
  impl ComplexProducts for f32 {
540
667
  fn dot(a: &[Self], b: &[Self]) -> Option<ComplexProduct> {
541
668
  if a.len() != b.len() {
@@ -583,6 +710,7 @@ impl ComplexProducts for f64 {
583
710
  #[cfg(test)]
584
711
  mod tests {
585
712
  use super::*;
713
+ use half::bf16 as HalfBF16;
586
714
  use half::f16 as HalfF16;
587
715
 
588
716
  #[test]
@@ -592,7 +720,8 @@ mod tests {
592
720
  || capabilities::uses_skylake()
593
721
  || capabilities::uses_ice()
594
722
  || capabilities::uses_genoa()
595
- || capabilities::uses_sapphire();
723
+ || capabilities::uses_sapphire()
724
+ || capabilities::uses_turin();
596
725
 
597
726
  // The CPU can't simultaneously support ARM and x86 SIMD extensions
598
727
  if uses_arm {
@@ -609,6 +738,8 @@ mod tests {
609
738
  println!("- uses_ice: {}", capabilities::uses_ice());
610
739
  println!("- uses_genoa: {}", capabilities::uses_genoa());
611
740
  println!("- uses_sapphire: {}", capabilities::uses_sapphire());
741
+ println!("- uses_turin: {}", capabilities::uses_turin());
742
+ println!("- uses_sierra: {}", capabilities::uses_sierra());
612
743
  }
613
744
 
614
745
  //
@@ -786,6 +917,26 @@ mod tests {
786
917
  }
787
918
  }
788
919
 
920
+ #[test]
921
+ fn test_cos_bf16_same() {
922
+ // Assuming these u16 values represent bf16 bit patterns, and they are identical
923
+ let a_u16: &[u16] = &[15360, 16384, 17408]; // Corresponding to some bf16 values
924
+ let b_u16: &[u16] = &[15360, 16384, 17408]; // Same as above for simplicity
925
+
926
+ // Reinterpret cast from &[u16] to &[bf16]
927
+ // SAFETY: This is safe as long as the representations are guaranteed to be identical,
928
+ // which they are for transparent structs wrapping the same type.
929
+ let a_bf16: &[bf16] =
930
+ unsafe { std::slice::from_raw_parts(a_u16.as_ptr() as *const bf16, a_u16.len()) };
931
+ let b_bf16: &[bf16] =
932
+ unsafe { std::slice::from_raw_parts(b_u16.as_ptr() as *const bf16, b_u16.len()) };
933
+
934
+ if let Some(result) = SpatialSimilarity::cosine(a_bf16, b_bf16) {
935
+ println!("The result of cos_bf16 is {:.8}", result);
936
+ assert_almost_equal(0.0, result, 0.01); // Example value, adjust according to actual expected value
937
+ }
938
+ }
939
+
789
940
  #[test]
790
941
  fn test_cos_f16_interop() {
791
942
  let a_half: Vec<HalfF16> = vec![1.0, 2.0, 3.0]
@@ -812,4 +963,31 @@ mod tests {
812
963
  assert_almost_equal(0.025, result, 0.01);
813
964
  }
814
965
  }
966
+
967
+ #[test]
968
+ fn test_cos_bf16_interop() {
969
+ let a_half: Vec<HalfBF16> = vec![1.0, 2.0, 3.0]
970
+ .iter()
971
+ .map(|&x| HalfBF16::from_f32(x))
972
+ .collect();
973
+ let b_half: Vec<HalfBF16> = vec![4.0, 5.0, 6.0]
974
+ .iter()
975
+ .map(|&x| HalfBF16::from_f32(x))
976
+ .collect();
977
+
978
+ // SAFETY: This is safe as long as the memory representations are guaranteed to be identical,
979
+ // which they are due to both being #[repr(transparent)] wrappers around u16.
980
+ let a_simsimd: &[bf16] =
981
+ unsafe { std::slice::from_raw_parts(a_half.as_ptr() as *const bf16, a_half.len()) };
982
+ let b_simsimd: &[bf16] =
983
+ unsafe { std::slice::from_raw_parts(b_half.as_ptr() as *const bf16, b_half.len()) };
984
+
985
+ // Use the reinterpret-casted slices with your SpatialSimilarity implementation
986
+ if let Some(result) = SpatialSimilarity::cosine(a_simsimd, b_simsimd) {
987
+ // Expected value might need adjustment depending on actual cosine functionality
988
+ // Assuming identical vectors yield cosine similarity of 1.0
989
+ println!("The result of cos_bf16 (interop) is {:.8}", result);
990
+ assert_almost_equal(0.025, result, 0.01);
991
+ }
992
+ }
815
993
  }