usearch 2.11.0 → 2.13.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 (50) hide show
  1. package/README.md +126 -37
  2. package/binding.gyp +11 -12
  3. package/c/README.md +9 -3
  4. package/c/lib.cpp +50 -13
  5. package/c/test.c +60 -55
  6. package/c/usearch.h +16 -0
  7. package/cpp/CMakeLists.txt +6 -0
  8. package/cpp/README.md +46 -14
  9. package/cpp/bench.cpp +99 -47
  10. package/cpp/test.cpp +948 -132
  11. package/include/usearch/index.hpp +894 -272
  12. package/include/usearch/index_dense.hpp +419 -152
  13. package/include/usearch/index_plugins.hpp +99 -49
  14. package/javascript/dist/cjs/usearch.d.ts +39 -1
  15. package/javascript/dist/cjs/usearch.js +11 -1
  16. package/javascript/dist/esm/usearch.d.ts +39 -1
  17. package/javascript/dist/esm/usearch.js +11 -1
  18. package/javascript/tsconfig-esm.json +3 -2
  19. package/javascript/usearch.ts +18 -7
  20. package/package.json +2 -2
  21. package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
  22. package/prebuilds/linux-arm64/usearch.node +0 -0
  23. package/prebuilds/linux-x64/usearch.node +0 -0
  24. package/simsimd/.cmake-format.py +19 -0
  25. package/simsimd/CONTRIBUTING.md +49 -8
  26. package/simsimd/Cargo.lock +1 -1
  27. package/simsimd/Cargo.toml +10 -5
  28. package/simsimd/Package.swift +16 -0
  29. package/simsimd/README.md +69 -15
  30. package/simsimd/binding.gyp +14 -19
  31. package/simsimd/build.rs +2 -0
  32. package/simsimd/c/lib.c +18 -0
  33. package/simsimd/include/module.modulemap +4 -0
  34. package/simsimd/include/simsimd/binary.h +2 -0
  35. package/simsimd/include/simsimd/dot.h +466 -32
  36. package/simsimd/include/simsimd/probability.h +20 -10
  37. package/simsimd/include/simsimd/simsimd.h +444 -98
  38. package/simsimd/include/simsimd/spatial.h +480 -44
  39. package/simsimd/include/simsimd/types.h +161 -39
  40. package/simsimd/javascript/simsimd.ts +26 -2
  41. package/simsimd/package.json +1 -1
  42. package/simsimd/rust/benches/cosine.rs +8 -2
  43. package/simsimd/rust/benches/native.rs +240 -2
  44. package/simsimd/rust/benches/sqeuclidean.rs +8 -2
  45. package/simsimd/rust/lib.rs +50 -13
  46. package/simsimd/swift/source/SimSIMD.swift +123 -0
  47. package/simsimd/swift/tests/SimSIMDTests.swift +92 -0
  48. package/prebuilds/win32-ia32/usearch.node +0 -0
  49. package/prebuilds/win32-x64/usearch.node +0 -0
  50. package/simsimd/.releaserc +0 -87
@@ -5,13 +5,34 @@
5
5
  To rerun experiments utilize the following command:
6
6
 
7
7
  ```sh
8
- sudo apt install libopenblas-dev # BLAS installation is optional
9
- cmake -DCMAKE_BUILD_TYPE=Release -DSIMSIMD_BUILD_BENCHMARKS=1 -DSIMSIMD_BUILD_TESTS=1 -B ./build_release
8
+ sudo apt install libopenblas-dev # BLAS installation is optional, but recommended for benchmarks
9
+ cmake -DCMAKE_BUILD_TYPE=Release -DSIMSIMD_BUILD_TESTS=1 -DSIMSIMD_BUILD_BENCHMARKS=1 -DSIMSIMD_BUILD_BENCHMARKS_WITH_CBLAS=1 -B build_release
10
10
  cmake --build build_release --config Release
11
11
  build_release/simsimd_bench
12
12
  build_release/simsimd_bench --benchmark_filter=js
13
13
  build_release/simsimd_test_run_time
14
- build_release/simsimd_test_compile_time
14
+ build_release/simsimd_test_compile_time # no need to run this one, it's just a compile-time test
15
+ ```
16
+
17
+ To utilize newest instructions, use GCC 12 or newer, or Clang 16 or newer.
18
+ To install them on Ubuntu 22.04, use:
19
+
20
+ ```sh
21
+ sudo apt install gcc-12 g++-12
22
+ sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-12 100
23
+ sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-12 100
24
+ ```
25
+
26
+ On MacOS it's recommended to use Homebrew and install Clang, as opposed to "Apple Clang".
27
+ Replacing the default compiler is not recommended, as it may break the system, but you can pass it as an environment variable:
28
+
29
+ ```sh
30
+ brew install llvm
31
+ cmake -DCMAKE_BUILD_TYPE=Release -DSIMSIMD_BUILD_TESTS=1 \
32
+ -DCMAKE_C_COMPILER="$(brew --prefix llvm)/bin/clang" \
33
+ -DCMAKE_CXX_COMPILER="$(brew --prefix llvm)/bin/clang++" \
34
+ -B build_release
35
+ cmake --build build_release --config Release
15
36
  ```
16
37
 
17
38
  ## Python
@@ -31,11 +52,31 @@ The `-Wd` will silence overflows and runtime warnings.
31
52
  Benchmarking:
32
53
 
33
54
  ```sh
34
- pip install numpy scipy scikit-learn # for comparison baselines
35
- python python/bench.py # to run default benchmarks
36
- python python/bench.py --n 1000 --ndim 1000000 # batch size and dimensions
55
+ pip install numpy scipy scikit-learn # for comparison baselines
56
+ python python/bench.py # to run default benchmarks
57
+ python python/bench.py --n 1000 --ndim 1536 # batch size and dimensions
37
58
  ```
38
59
 
60
+ You can also benchmark against other libraries:
61
+
62
+ ```sh
63
+ $ python python/bench.py --help
64
+ > usage: bench.py [-h] [--n N] [--ndim NDIM] [--scipy] [--scikit] [--torch] [--tf] [--jax]
65
+ >
66
+ > Benchmark SimSIMD vs. other libraries
67
+ >
68
+ > options:
69
+ > -h, --help show this help message and exit
70
+ > --n N Number of vectors (default: 1000)
71
+ > --ndim NDIM Number of dimensions (default: 1536)
72
+ > --scipy Profile SciPy
73
+ > --scikit Profile scikit-learn
74
+ > --torch Profile PyTorch
75
+ > --tf Profile TensorFlow
76
+ > --jax Profile JAX
77
+ ```
78
+
79
+
39
80
  Before merging your changes you may want to test your changes against the entire matrix of Python versions USearch supports.
40
81
  For that you need the `cibuildwheel`, which is tricky to use on MacOS and Windows, as it would target just the local environment.
41
82
  Still, if you have Docker running on any desktop OS, you can use it to build and test the Python bindings for all Python versions for Linux:
@@ -52,7 +93,7 @@ cibuildwheel --platform macos # works only on MacOS
52
93
  cibuildwheel --platform windows # works only on Windows
53
94
  ```
54
95
 
55
- You may need root previligies for multi-architecture builds:
96
+ You may need root privileges for multi-architecture builds:
56
97
 
57
98
  ```sh
58
99
  sudo $(which cibuildwheel) --platform linux
@@ -70,7 +111,7 @@ python -m cibuildwheel --platform windows
70
111
  cargo test -p simsimd
71
112
  cargo test -p simsimd -- --nocapture # To see the output
72
113
  cargo bench
73
- open ./target/criterion/report/index.html
114
+ open target/criterion/report/index.html
74
115
  ```
75
116
 
76
117
  ## JavaScript
@@ -496,7 +496,7 @@ dependencies = [
496
496
 
497
497
  [[package]]
498
498
  name = "simsimd"
499
- version = "4.2.1"
499
+ version = "5.0.0"
500
500
  dependencies = [
501
501
  "cc",
502
502
  "criterion",
@@ -1,13 +1,10 @@
1
1
  [package]
2
2
  name = "simsimd"
3
3
  description = "Fastest SIMD-Accelerated Vector Similarity Functions for x86 and Arm"
4
- version = "4.2.2"
4
+ version = "5.0.0"
5
5
  edition = "2021"
6
6
  license = "Apache-2.0"
7
- authors = [
8
- "Ash Vardanian <1983160+ashvardanian@users.noreply.github.com>",
9
- "Pedro Planel <pplanel@gmail.com>",
10
- ]
7
+ authors = ["Ash Vardanian <1983160+ashvardanian@users.noreply.github.com>"]
11
8
  repository = "https://github.com/ashvardanian/SimSIMD"
12
9
  documentation = "https://docs.rs/simsimd"
13
10
  homepage = "https://ashvardanian.com/posts/simsimd-faster-scipy"
@@ -19,6 +16,8 @@ categories = [
19
16
  "wasm",
20
17
  "external-ffi-bindings",
21
18
  ]
19
+ include = ["/rust/**", "/c/**", "/include/**", "/build.rs"]
20
+
22
21
 
23
22
  [lib]
24
23
  name = "simsimd"
@@ -38,6 +37,12 @@ name = "sqeuclidean"
38
37
  harness = false
39
38
  path = "rust/benches/sqeuclidean.rs"
40
39
 
40
+ [profile.bench]
41
+ opt-level = 3 # Corresponds to -O3
42
+ lto = true # Enables Link Time Optimization for further optimizations
43
+ codegen-units = 1 # May increase compilation time but optimizes further
44
+ rpath = false # On some systems, setting this to false can help with optimizations
45
+
41
46
  [dev-dependencies]
42
47
  criterion = { version = "0.5.1" }
43
48
  rand = { version = "0.8.5" }
@@ -0,0 +1,16 @@
1
+ // swift-tools-version:5.0
2
+ // The swift-tools-version declares the minimum version of Swift required to build this package.
3
+
4
+ import PackageDescription
5
+
6
+ let package = Package(
7
+ name: "SimSIMD",
8
+ products: [
9
+ .library(name: "SimSIMD", targets: ["SimSIMD"]),
10
+ ],
11
+ targets: [
12
+ .testTarget(name: "SimSIMDTests", dependencies: ["SimSIMD"], path: "swift/tests"),
13
+ .target(name: "SimSIMD", dependencies: ["CSimSIMD"], path: "swift/source"),
14
+ .systemLibrary(name: "CSimSIMD", path: "include")
15
+ ]
16
+ )
package/simsimd/README.md CHANGED
@@ -1,12 +1,14 @@
1
1
  # SimSIMD 📏
2
2
 
3
- _Computing dot-products, similarity measures, and distances between low- and high-dimensional vectors is ubiquitous in Machine Learning, Scientific Computing, Geo-Spatial Analysis, and Information Retrieval.
3
+ ![SimSIMD banner](https://github.com/ashvardanian/ashvardanian/blob/master/repositories/SimSIMD.png?raw=true)
4
+
5
+ Computing dot-products, similarity measures, and distances between low- and high-dimensional vectors is ubiquitous in Machine Learning, Scientific Computing, Geo-Spatial Analysis, and Information Retrieval.
4
6
  These algorithms generally have linear complexity in time, constant complexity in space, and are data-parallel.
5
7
  In other words, it is easily parallelizable and vectorizable and often available in packages like BLAS and LAPACK, as well as higher-level `numpy` and `scipy` Python libraries.
6
8
  Ironically, even with decades of evolution in compilers and numerical computing, [most libraries can be 3-200x slower than hardware potential][benchmarks] even on the most popular hardware, like 64-bit x86 and Arm CPUs.
7
9
  SimSIMD attempts to fill that gap.
8
10
  1️⃣ SimSIMD functions are practically as fast as `memcpy`.
9
- 2️⃣ SimSIMD [compiles to more platforms than NumPy (105 vs 35)][compatibility] and has more backends than most BLAS implementations._
11
+ 2️⃣ SimSIMD [compiles to more platforms than NumPy (105 vs 35)][compatibility] and has more backends than most BLAS implementations.
10
12
 
11
13
  [benchmarks]: https://ashvardanian.com/posts/simsimd-faster-scipy
12
14
  [compatibility]: https://pypi.org/project/simsimd/#files
@@ -64,8 +66,8 @@ Moreover, SimSIMD...
64
66
 
65
67
  Due to the high-level of fragmentation of SIMD support in different x86 CPUs, SimSIMD uses the names of select Intel CPU generations for its backends.
66
68
  They, however, also work on AMD CPUs.
67
- Inel Haswell is compatible with AMD Zen 1/2/3, while AMD Genoa Zen 4 covers AVX-512 instructions added to Intel Skylake and Ice Lake.
68
- You can learn more about the technical implementation details in the following blogposts:
69
+ Intel Haswell is compatible with AMD Zen 1/2/3, while AMD Genoa Zen 4 covers AVX-512 instructions added to Intel Skylake and Ice Lake.
70
+ You can learn more about the technical implementation details in the following blog-posts:
69
71
 
70
72
  - [Uses Horner's method for polynomial approximations, beating GCC 12 by 119x](https://ashvardanian.com/posts/gcc-12-vs-avx512fp16/).
71
73
  - [Uses Arm SVE and x86 AVX-512's masked loads to eliminate tail `for`-loops](https://ashvardanian.com/posts/simsimd-faster-scipy/#tails-of-the-past-the-significance-of-masked-loads).
@@ -377,18 +379,49 @@ fn main() {
377
379
  }
378
380
  ```
379
381
 
382
+ ### Half-Precision Brain-Float Numbers
383
+
384
+ The "brain-float-16" is a popular machine learning format.
385
+ It's broadly supported in hardware and is very machine-friendly, but software support is still lagging behind.
386
+ [Unlike NumPy](https://github.com/numpy/numpy/issues/19808), you can already use `bf16` datatype in SimSIMD.
387
+ Luckily, to downcast `f32` to `bf16` you only have to drop the last 16 bits:
388
+
389
+ ```py
390
+ import numpy as np
391
+ import simsimd as simd
392
+
393
+ a = np.random.randn(ndim).astype(np.float32)
394
+ b = np.random.randn(ndim).astype(np.float32)
395
+
396
+ # NumPy doesn't natively support brain-float, so we need a trick!
397
+ # Luckily, it's very easy to reduce the representation accuracy
398
+ # by simply masking the low 16-bits of our 32-bit single-precision
399
+ # numbers. We can also add `0x8000` to round the numbers.
400
+ a_f32rounded = ((a.view(np.uint32) + 0x8000) & 0xFFFF0000).view(np.float32)
401
+ b_f32rounded = ((b.view(np.uint32) + 0x8000) & 0xFFFF0000).view(np.float32)
402
+
403
+ # To represent them as brain-floats, we need to drop the second half
404
+ a_bf16 = np.right_shift(a_f32rounded.view(np.uint32), 16).astype(np.uint16)
405
+ b_bf16 = np.right_shift(b_f32rounded.view(np.uint32), 16).astype(np.uint16)
406
+
407
+ # Now we can compare the results
408
+ expected = np.inner(a_f32rounded, b_f32rounded)
409
+ result = simd.inner(a_bf16, b_bf16, "bf16")
410
+ ```
411
+
380
412
  ### Dynamic Dispatch
381
413
 
382
414
  SimSIMD provides a dynamic dispatch mechanism to select the most advanced micro-kernel for the current CPU.
383
415
  You can query supported backends and use the `SimSIMD::capabilities` function to select the best one.
384
416
 
385
417
  ```rust
386
- println!("uses neon: {}", capabilties::uses_neon());
387
- println!("uses sve: {}", capabilties::uses_sve());
388
- println!("uses haswell: {}", capabilties::uses_haswell());
389
- println!("uses skylake: {}", capabilties::uses_skylake());
390
- println!("uses ice: {}", capabilties::uses_ice());
391
- println!("uses sapphire: {}", capabilties::uses_sapphire());
418
+ println!("uses neon: {}", capabilities::uses_neon());
419
+ println!("uses sve: {}", capabilities::uses_sve());
420
+ println!("uses haswell: {}", capabilities::uses_haswell());
421
+ println!("uses skylake: {}", capabilities::uses_skylake());
422
+ println!("uses ice: {}", capabilities::uses_ice());
423
+ println!("uses genoa: {}", capabilities::uses_genoa());
424
+ println!("uses sapphire: {}", capabilities::uses_sapphire());
392
425
  ```
393
426
 
394
427
  ## Using SimSIMD in JavaScript
@@ -400,8 +433,7 @@ To install, choose one of the following options depending on your environment:
400
433
  - `pnpm add simsimd`
401
434
  - `bun install simsimd`
402
435
 
403
- The package is distributed with prebuilt binaries for Node.js v10 and above for Linux (x86_64, arm64), macOS (x86_64, arm64), and Windows (i386, x86_64).
404
- If your platform is not supported, you can build the package from the source via `npm run build`.
436
+ The package is distributed with prebuilt binaries, but if your platform is not supported, you can build the package from the source via `npm run build`.
405
437
  This will automatically happen unless you install the package with the `--ignore-scripts` flag or use Bun.
406
438
  After you install it, you will be able to call the SimSIMD functions on various `TypedArray` variants:
407
439
 
@@ -415,14 +447,34 @@ const distance = sqeuclidean(vectorA, vectorB);
415
447
  console.log('Squared Euclidean Distance:', distance);
416
448
  ```
417
449
 
418
- Other numeric types and precision levels are supported as well:
450
+ Other numeric types and precision levels are supported as well.
451
+ For double-precsion floating-point numbers, use `Float64Array`:
419
452
 
420
453
  ```js
421
454
  const vectorA = new Float64Array([1.0, 2.0, 3.0]);
422
455
  const vectorB = new Float64Array([4.0, 5.0, 6.0]);
423
-
424
456
  const distance = cosine(vectorA, vectorB);
425
- console.log('Cosine Similarity:', distance);
457
+ ```
458
+
459
+ When doing machine learning and vector search with high-dimensional vectors you may want to quantize them to 8-bit integers.
460
+ You may want to project values from the $[-1, 1]$ range to the $[-100, 100]$ range and then cast them to `Uint8Array`:
461
+
462
+ ```js
463
+ const quantizedVectorA = new Uint8Array(vectorA.map(v => (v * 100)));
464
+ const quantizedVectorB = new Uint8Array(vectorB.map(v => (v * 100)));
465
+ const distance = cosine(quantizedVectorA, quantizedVectorB);
466
+ ```
467
+
468
+ A more extreme quantization case would be to use binary vectors.
469
+ You can map all positive values to `1` and all negative values and zero to `0`, packing eight values into a single byte.
470
+ After that, Hamming and Jaccard distances can be computed.
471
+
472
+ ```js
473
+ const { toBinary, hamming } = require('simsimd');
474
+
475
+ const binaryVectorA = toBinary(vectorA);
476
+ const binaryVectorB = toBinary(vectorB);
477
+ const distance = hamming(binaryVectorA, binaryVectorB);
426
478
  ```
427
479
 
428
480
  ## Using SimSIMD in C
@@ -469,6 +521,7 @@ int uses_sve = simsimd_uses_sve();
469
521
  int uses_haswell = simsimd_uses_haswell();
470
522
  int uses_skylake = simsimd_uses_skylake();
471
523
  int uses_ice = simsimd_uses_ice();
524
+ int uses_genoa = simsimd_uses_genoa();
472
525
  int uses_sapphire = simsimd_uses_sapphire();
473
526
 
474
527
  simsimd_capability_t capabilities = simsimd_capabilities();
@@ -590,6 +643,7 @@ To explicitly disable half-precision support, define the following macro before
590
643
 
591
644
  ```c
592
645
  #define SIMSIMD_NATIVE_F16 0 // or 1
646
+ #define SIMSIMD_NATIVE_BF16 0 // or 1
593
647
  #include <simsimd/simsimd.h>
594
648
  ```
595
649
 
@@ -1,13 +1,11 @@
1
1
  {
2
- "variables": {
3
- "openssl_fips": ""
4
- },
2
+ "variables": {"openssl_fips": ""},
5
3
  "targets": [
6
4
  {
7
5
  "target_name": "simsimd",
8
6
  "sources": ["javascript/lib.c"],
9
7
  "include_dirs": ["include"],
10
- "defines": ["SIMSIMD_NATIVE_F16=0"],
8
+ "defines": ["SIMSIMD_NATIVE_F16=0", "SIMSIMD_NATIVE_BF16=0"],
11
9
  "cflags": [
12
10
  "-std=c11",
13
11
  "-ffast-math",
@@ -17,20 +15,17 @@
17
15
  "-Wno-switch",
18
16
  ],
19
17
  "conditions": [
20
- ["OS=='mac'", {
21
- "xcode_settings": {
22
- "MACOSX_DEPLOYMENT_TARGET": "11.0",
23
- "OTHER_CFLAGS": [
24
- "-arch arm64",
25
- "-arch x86_64"
26
- ],
27
- "OTHER_LDFLAGS": [
28
- "-arch arm64",
29
- "-arch x86_64"
30
- ]
31
- }
32
- }]
33
- ]
18
+ [
19
+ "OS=='mac'",
20
+ {
21
+ "xcode_settings": {
22
+ "MACOSX_DEPLOYMENT_TARGET": "11.0",
23
+ "OTHER_CFLAGS": ["-arch arm64", "-arch x86_64"],
24
+ "OTHER_LDFLAGS": ["-arch arm64", "-arch x86_64"],
25
+ }
26
+ },
27
+ ]
28
+ ],
34
29
  }
35
- ]
30
+ ],
36
31
  }
package/simsimd/build.rs CHANGED
@@ -5,6 +5,7 @@ fn main() {
5
5
  .file("c/lib.c")
6
6
  .include("include")
7
7
  .define("SIMSIMD_NATIVE_F16", "0")
8
+ .define("SIMSIMD_NATIVE_BF16", "0")
8
9
  .define("SIMSIMD_DYNAMIC_DISPATCH", "1")
9
10
  .flag("-O3")
10
11
  .flag("-std=c99") // Enforce C99 standard
@@ -19,6 +20,7 @@ fn main() {
19
20
  "arm" | "aarch64" => vec!["SIMSIMD_TARGET_NEON", "SIMSIMD_TARGET_SVE"],
20
21
  _ => vec![
21
22
  "SIMSIMD_TARGET_SAPPHIRE",
23
+ "SIMSIMD_TARGET_GENOA",
22
24
  "SIMSIMD_TARGET_ICE",
23
25
  "SIMSIMD_TARGET_SKYLAKE",
24
26
  "SIMSIMD_TARGET_HASWELL",
package/simsimd/c/lib.c CHANGED
@@ -5,6 +5,7 @@
5
5
  */
6
6
  #define SIMSIMD_DYNAMIC_DISPATCH 1
7
7
  #define SIMSIMD_NATIVE_F16 0
8
+ #define SIMSIMD_NATIVE_BF16 0
8
9
 
9
10
  /* Depending on the Operating System, the following intrinsics are available
10
11
  * on recent compiler toolchains:
@@ -28,6 +29,9 @@
28
29
  #if !defined(SIMSIMD_TARGET_ICE) && (defined(_MSC_VER) || defined(__linux__))
29
30
  #define SIMSIMD_TARGET_ICE 1
30
31
  #endif
32
+ #if !defined(SIMSIMD_TARGET_GENOA) && (defined(__linux__))
33
+ #define SIMSIMD_TARGET_GENOA 1
34
+ #endif
31
35
  #if !defined(SIMSIMD_TARGET_SAPPHIRE) && (defined(__linux__))
32
36
  #define SIMSIMD_TARGET_SAPPHIRE 1
33
37
  #endif
@@ -67,22 +71,27 @@ simsimd_capability_t simsimd_capabilities(void) {
67
71
 
68
72
  // Dot products
69
73
  SIMSIMD_METRIC_DECLARATION(dot, f16, f16)
74
+ SIMSIMD_METRIC_DECLARATION(dot, bf16, bf16)
70
75
  SIMSIMD_METRIC_DECLARATION(dot, f32, f32)
71
76
  SIMSIMD_METRIC_DECLARATION(dot, f64, f64)
72
77
  SIMSIMD_METRIC_DECLARATION(dot, f16c, f16)
78
+ SIMSIMD_METRIC_DECLARATION(dot, bf16c, bf16)
73
79
  SIMSIMD_METRIC_DECLARATION(dot, f32c, f32)
74
80
  SIMSIMD_METRIC_DECLARATION(dot, f64c, f64)
75
81
  SIMSIMD_METRIC_DECLARATION(vdot, f16c, f16)
82
+ SIMSIMD_METRIC_DECLARATION(vdot, bf16c, bf16)
76
83
  SIMSIMD_METRIC_DECLARATION(vdot, f32c, f32)
77
84
  SIMSIMD_METRIC_DECLARATION(vdot, f64c, f64)
78
85
 
79
86
  // Spatial distances
80
87
  SIMSIMD_METRIC_DECLARATION(cos, i8, i8)
81
88
  SIMSIMD_METRIC_DECLARATION(cos, f16, f16)
89
+ SIMSIMD_METRIC_DECLARATION(cos, bf16, bf16)
82
90
  SIMSIMD_METRIC_DECLARATION(cos, f32, f32)
83
91
  SIMSIMD_METRIC_DECLARATION(cos, f64, f64)
84
92
  SIMSIMD_METRIC_DECLARATION(l2sq, i8, i8)
85
93
  SIMSIMD_METRIC_DECLARATION(l2sq, f16, f16)
94
+ SIMSIMD_METRIC_DECLARATION(l2sq, bf16, bf16)
86
95
  SIMSIMD_METRIC_DECLARATION(l2sq, f32, f32)
87
96
  SIMSIMD_METRIC_DECLARATION(l2sq, f64, f64)
88
97
 
@@ -92,17 +101,26 @@ SIMSIMD_METRIC_DECLARATION(jaccard, b8, b8)
92
101
 
93
102
  // Probability distributions
94
103
  SIMSIMD_METRIC_DECLARATION(kl, f16, f16)
104
+ SIMSIMD_METRIC_DECLARATION(kl, bf16, bf16)
95
105
  SIMSIMD_METRIC_DECLARATION(kl, f32, f32)
96
106
  SIMSIMD_METRIC_DECLARATION(kl, f64, f64)
97
107
  SIMSIMD_METRIC_DECLARATION(js, f16, f16)
108
+ SIMSIMD_METRIC_DECLARATION(js, bf16, bf16)
98
109
  SIMSIMD_METRIC_DECLARATION(js, f32, f32)
99
110
  SIMSIMD_METRIC_DECLARATION(js, f64, f64)
100
111
 
101
112
  SIMSIMD_DYNAMIC int simsimd_uses_neon(void) { return (simsimd_capabilities() & simsimd_cap_neon_k) != 0; }
113
+ SIMSIMD_DYNAMIC int simsimd_uses_neon_f16(void) { return (simsimd_capabilities() & simsimd_cap_neon_f16_k) != 0; }
114
+ SIMSIMD_DYNAMIC int simsimd_uses_neon_bf16(void) { return (simsimd_capabilities() & simsimd_cap_neon_bf16_k) != 0; }
115
+ SIMSIMD_DYNAMIC int simsimd_uses_neon_i8(void) { return (simsimd_capabilities() & simsimd_cap_neon_i8_k) != 0; }
102
116
  SIMSIMD_DYNAMIC int simsimd_uses_sve(void) { return (simsimd_capabilities() & simsimd_cap_sve_k) != 0; }
117
+ SIMSIMD_DYNAMIC int simsimd_uses_sve_f16(void) { return (simsimd_capabilities() & simsimd_cap_sve_f16_k) != 0; }
118
+ SIMSIMD_DYNAMIC int simsimd_uses_sve_bf16(void) { return (simsimd_capabilities() & simsimd_cap_sve_bf16_k) != 0; }
119
+ SIMSIMD_DYNAMIC int simsimd_uses_sve_i8(void) { return (simsimd_capabilities() & simsimd_cap_sve_i8_k) != 0; }
103
120
  SIMSIMD_DYNAMIC int simsimd_uses_haswell(void) { return (simsimd_capabilities() & simsimd_cap_haswell_k) != 0; }
104
121
  SIMSIMD_DYNAMIC int simsimd_uses_skylake(void) { return (simsimd_capabilities() & simsimd_cap_skylake_k) != 0; }
105
122
  SIMSIMD_DYNAMIC int simsimd_uses_ice(void) { return (simsimd_capabilities() & simsimd_cap_ice_k) != 0; }
123
+ SIMSIMD_DYNAMIC int simsimd_uses_genoa(void) { return (simsimd_capabilities() & simsimd_cap_genoa_k) != 0; }
106
124
  SIMSIMD_DYNAMIC int simsimd_uses_sapphire(void) { return (simsimd_capabilities() & simsimd_cap_sapphire_k) != 0; }
107
125
 
108
126
  #ifdef __cplusplus
@@ -0,0 +1,4 @@
1
+ module CSimSIMD {
2
+ header "simsimd/simsimd.h"
3
+ export *
4
+ }
@@ -78,6 +78,7 @@ SIMSIMD_PUBLIC void simsimd_jaccard_b8_serial(simsimd_b8_t const* a, simsimd_b8_
78
78
 
79
79
  #if SIMSIMD_TARGET_ARM
80
80
  #if SIMSIMD_TARGET_NEON
81
+ #pragma GCC push_options
81
82
  #pragma GCC target("+simd")
82
83
  #pragma clang attribute push(__attribute__((target("+simd"))), apply_to = function)
83
84
 
@@ -117,6 +118,7 @@ SIMSIMD_PUBLIC void simsimd_jaccard_b8_neon(simsimd_b8_t const* a, simsimd_b8_t
117
118
  #endif // SIMSIMD_TARGET_NEON
118
119
 
119
120
  #if SIMSIMD_TARGET_SVE
121
+ #pragma GCC push_options
120
122
  #pragma GCC target("+sve")
121
123
  #pragma clang attribute push(__attribute__((target("+sve"))), apply_to = function)
122
124