usearch 0.22.3 → 1.1.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 (93) hide show
  1. package/.github/workflows/prerelease.yml +3 -3
  2. package/.releaserc +10 -2
  3. package/.vscode/launch.json +10 -10
  4. package/.vscode/settings.json +9 -1
  5. package/.vscode/tasks.json +4 -4
  6. package/CMakeLists.txt +6 -1
  7. package/Cargo.toml +2 -2
  8. package/README.md +35 -41
  9. package/build.rs +2 -2
  10. package/c/CMakeLists.txt +48 -0
  11. package/c/README.md +34 -0
  12. package/c/lib.cpp +83 -72
  13. package/c/test.c +20 -20
  14. package/c/usearch.h +132 -32
  15. package/conanfile.py +1 -1
  16. package/cpp/CMakeLists.txt +3 -1
  17. package/cpp/README.md +16 -16
  18. package/cpp/bench.cpp +50 -126
  19. package/cpp/test.cpp +164 -80
  20. package/docs/benchmarks.md +26 -5
  21. package/docs/c/reference.rst +3 -3
  22. package/docs/compilation.md +31 -49
  23. package/docs/cpp/index.rst +1 -1
  24. package/docs/cpp/reference.rst +4 -4
  25. package/golang/lib.go +275 -141
  26. package/golang/lib_test.go +105 -0
  27. package/include/usearch/index.hpp +1681 -1656
  28. package/include/usearch/index_dense.hpp +1400 -0
  29. package/include/usearch/index_plugins.hpp +1263 -0
  30. package/java/README.md +1 -1
  31. package/java/cloud/unum/usearch/Index.java +10 -10
  32. package/java/cloud/unum/usearch/cloud_unum_usearch_Index.cpp +34 -37
  33. package/java/test/IndexTest.java +1 -1
  34. package/javascript/README.md +6 -6
  35. package/javascript/lib.cpp +156 -55
  36. package/javascript/test.js +26 -11
  37. package/javascript/usearch.d.ts +102 -0
  38. package/javascript/usearch.js +2 -118
  39. package/objc/USearchObjective.mm +57 -31
  40. package/objc/include/USearchObjective.h +32 -22
  41. package/package.json +5 -3
  42. package/python/README.md +23 -14
  43. package/python/lib.cpp +468 -444
  44. package/python/scripts/bench.ipynb +3 -2
  45. package/python/scripts/bench.py +4 -4
  46. package/python/scripts/index_faiss.py +5 -5
  47. package/python/scripts/join.py +4 -4
  48. package/python/scripts/test.py +152 -61
  49. package/python/scripts/test_jit.py +10 -12
  50. package/python/scripts/test_sparse.py +32 -0
  51. package/python/usearch/client.py +26 -28
  52. package/python/usearch/eval.py +73 -23
  53. package/python/usearch/index.py +520 -228
  54. package/python/usearch/io.py +57 -25
  55. package/python/usearch/numba.py +4 -4
  56. package/python/usearch/server.py +10 -10
  57. package/rust/lib.cpp +34 -30
  58. package/rust/lib.hpp +14 -12
  59. package/rust/lib.rs +8 -7
  60. package/setup.py +5 -2
  61. package/simsimd/.github/workflows/prerelease.yml +73 -0
  62. package/simsimd/.github/workflows/release.yml +110 -0
  63. package/simsimd/.github/workflows/update_version.sh +3 -0
  64. package/simsimd/.releaserc +77 -0
  65. package/simsimd/.vscode/launch.json +27 -1
  66. package/simsimd/.vscode/settings.json +22 -1
  67. package/simsimd/.vscode/tasks.json +6 -0
  68. package/simsimd/CMakeLists.txt +3 -2
  69. package/simsimd/README.md +82 -46
  70. package/simsimd/bench.cxx +63 -24
  71. package/simsimd/include/simsimd/simsimd.h +88 -66
  72. package/simsimd/include/simsimd/simsimd_chem.h +126 -0
  73. package/simsimd/package.json +8 -0
  74. package/simsimd/pyproject.toml +42 -0
  75. package/simsimd/python/python.c +81 -0
  76. package/simsimd/python/run.sh +1 -0
  77. package/simsimd/python/test.c +109 -0
  78. package/simsimd/python/test.py +23 -0
  79. package/simsimd/setup.py +44 -0
  80. package/swift/Index+Sugar.swift +75 -23
  81. package/swift/README.md +26 -2
  82. package/swift/Test.swift +19 -7
  83. package/swift/USearch.swift +2 -2
  84. package/tsconfig.json +8 -0
  85. package/wasm/CMakeLists.txt +1 -0
  86. package/wasmer.toml +1 -1
  87. package/wolfram/CMakeLists.txt +1 -0
  88. package/wolfram/lib.cpp +11 -13
  89. package/golang/usearch.h +0 -9
  90. package/golang/usearch_par_test.go +0 -40
  91. package/golang/usearch_test.go +0 -82
  92. package/include/usearch/index_punned_dense.hpp +0 -1001
  93. package/include/usearch/index_punned_helpers.hpp +0 -676
@@ -0,0 +1,77 @@
1
+ {
2
+ "branches": [
3
+ "main"
4
+ ],
5
+ "debug": true,
6
+ "ci": true,
7
+ "dryRun": false,
8
+ "plugins": [
9
+ [
10
+ "@semantic-release/commit-analyzer",
11
+ {
12
+ "preset": "eslint",
13
+ "releaseRules": [
14
+ {
15
+ "tag": "Add",
16
+ "release": "minor"
17
+ },
18
+ {
19
+ "tag": "Improve",
20
+ "release": "patch"
21
+ },
22
+ {
23
+ "tag": "Make",
24
+ "release": "patch"
25
+ },
26
+ {
27
+ "tag": "Refactor",
28
+ "release": false
29
+ }
30
+ ]
31
+ }
32
+ ],
33
+ [
34
+ "@semantic-release/release-notes-generator",
35
+ {
36
+ "preset": "eslint",
37
+ "releaseRules": [
38
+ {
39
+ "tag": "Add",
40
+ "release": "minor"
41
+ },
42
+ {
43
+ "tag": "Improve",
44
+ "release": "patch"
45
+ },
46
+ {
47
+ "tag": "Make",
48
+ "release": "patch"
49
+ },
50
+ {
51
+ "tag": "Refactor",
52
+ "release": false
53
+ }
54
+ ]
55
+ }
56
+ ],
57
+ "@semantic-release/github",
58
+ [
59
+ "@semantic-release/exec",
60
+ {
61
+ "prepareCmd": "bash .github/workflows/update_version.sh '${nextRelease.version}'"
62
+ }
63
+ ],
64
+ [
65
+ "@semantic-release/git",
66
+ {
67
+ "assets": [
68
+ "VERSION",
69
+ "conanfile.py",
70
+ "package.json",
71
+ "Cargo.toml",
72
+ ],
73
+ "message": "Build: Released ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
74
+ }
75
+ ]
76
+ ]
77
+ }
@@ -18,7 +18,33 @@
18
18
  ],
19
19
  "stopAtEntry": false,
20
20
  "preLaunchTask": "Build Benchmark: Debug",
21
- "MIMode": "gdb"
21
+ "linux": {
22
+ "MIMode": "gdb",
23
+ },
24
+ "osx": {
25
+ "MIMode": "lldb"
26
+ }
27
+ },
28
+ {
29
+ "name": "Debug Test",
30
+ "type": "cppdbg",
31
+ "request": "launch",
32
+ "program": "${workspaceFolder}/build/test",
33
+ "cwd": "${workspaceFolder}",
34
+ "environment": [
35
+ {
36
+ "name": "ASAN_OPTIONS",
37
+ "value": "detect_leaks=0:atexit=1:strict_init_order=1:strict_string_checks=1"
38
+ }
39
+ ],
40
+ "stopAtEntry": false,
41
+ "preLaunchTask": "Build Test: Debug",
42
+ "linux": {
43
+ "MIMode": "gdb"
44
+ },
45
+ "osx": {
46
+ "MIMode": "lldb"
47
+ }
22
48
  }
23
49
  ]
24
50
  }
@@ -64,7 +64,28 @@
64
64
  "thread": "cpp",
65
65
  "typeinfo": "cpp",
66
66
  "complex": "cpp",
67
- "immintrin.h": "c"
67
+ "immintrin.h": "c",
68
+ "__bit_reference": "cpp",
69
+ "__bits": "cpp",
70
+ "__config": "cpp",
71
+ "__debug": "cpp",
72
+ "__errc": "cpp",
73
+ "__hash_table": "cpp",
74
+ "__locale": "cpp",
75
+ "__mutex_base": "cpp",
76
+ "__node_handle": "cpp",
77
+ "__split_buffer": "cpp",
78
+ "__threading_support": "cpp",
79
+ "__tuple": "cpp",
80
+ "__verbose_abort": "cpp",
81
+ "charconv": "cpp",
82
+ "ios": "cpp",
83
+ "locale": "cpp",
84
+ "optional": "cpp",
85
+ "variant": "cpp",
86
+ "__nullptr": "cpp",
87
+ "unordered_set": "cpp",
88
+ "span": "cpp"
68
89
  },
69
90
  "cSpell.words": [
70
91
  "dtype",
@@ -7,6 +7,12 @@
7
7
  "args": [],
8
8
  "type": "shell"
9
9
  },
10
+ {
11
+ "label": "Build Test: Debug",
12
+ "command": "cmake -DCMAKE_BUILD_TYPE=Debug -B ./build && make test py_simsimd -C ./build",
13
+ "args": [],
14
+ "type": "shell"
15
+ },
10
16
  {
11
17
  "label": "Build Benchmark: Release",
12
18
  "command": "cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -B ./build_release && make -j 2 -C ./build_release",
@@ -1,6 +1,6 @@
1
1
  cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
2
- project(simsimd LANGUAGES CXX)
3
- set(CMAKE_CXX_STANDARD 11)
2
+ project(simsimd LANGUAGES CXX C)
3
+ set(CMAKE_CXX_STANDARD 17)
4
4
  set(CMAKE_CXX_STANDARD_REQUIRED YES)
5
5
  set(CMAKE_CXX_EXTENSIONS NO)
6
6
 
@@ -9,6 +9,7 @@ option(SIMSIMD_BUILD_BENCHMARKS "Compile a micro-benchmark for current ISA" OFF)
9
9
 
10
10
  # Get external content: Google Benchmark, Thrust
11
11
  include(FetchContent)
12
+ include_directories(include/)
12
13
 
13
14
  # Fetch GBenchmark and surpress internal tests.
14
15
  # https://github.com/google/benchmark/blob/main/docs/user_guide.md#using-register-benchmark
package/simsimd/README.md CHANGED
@@ -1,18 +1,20 @@
1
1
  # SimSIMD
2
2
 
3
3
  SIMD-accelerated similarity measures, metrics, distance functions for x86 and Arm.
4
- Tuned for Machine Learning applications, mid-size vectors with 100-512 dimensions.
5
-
6
- | Distance | Serial | x86 AVX | Arm NEON | Arm SVE |
7
- | :---------------- | :----: | :-------------: | :------: | :-----: |
8
- | `f32` Dot Product | ✅ | AVX2-FMA | ✅ | ✅ |
9
- | `f32` Cosine | ✅ | AVX2-FMA | ✅ | ✅ |
10
- | `f32` Euclidean | ✅ | ❌ | ❌ | ✅ |
11
- | | | | | |
12
- | `f16` Dot Product | ✅ | ❌ | ❌ | ✅ |
13
- | `f16` Euclidean | ✅ | ❌ | ❌ | ✅ |
14
- | | | | | |
15
- | `u1` Hamming | ✅ | AVX512VPOPCNTDQ | ✅ | ✅ |
4
+ Tuned for Machine Learning applications, mid-size vectors with 100-1024 dimensions.
5
+ For Cosine (Angular) distance, the most common metric in AI, one can expect following performance.
6
+
7
+ | Method | Vectors | Any Length | Speed on 256b | Speed on 1024b |
8
+ | :----- | :------ | :--------- | ------------: | -------------: |
9
+ | Serial | `f32` | ✅ | 5 GB/s | 5 GB/s |
10
+ | SVE | `f32` | ✅ | 34 GB/s | 40 GB/s |
11
+ | SVE | `f16` | ✅ | 28 GB/s | 35 GB/s |
12
+ | NEON | `f16` | ❌ | 16 GB/s | 18 GB/s |
13
+
14
+ > The benchmarks were done on Arm-based "Graviton 3" CPUs powering AWS `c7g.metal` instances.
15
+ > We only use Arm NEON implementation with vectors lengths that are multiples of 128 bits, avoiding any additional head or tail `for` loops for misaligned data.
16
+ > By default, we use GCC12, `-O3`, `-march=native` for benchmarks.
17
+ > Serial versions imply auto-vectorization pragmas.
16
18
 
17
19
  Need something like this in your CMake-based project?
18
20
 
@@ -26,49 +28,76 @@ FetchContent_MakeAvailable(simsimd)
26
28
  include_directories(${simsimd_SOURCE_DIR}/include)
27
29
  ```
28
30
 
29
- ## Benchmarks
30
-
31
- By default, we use GCC12, `-O3`, `-march=native` for benchmarks.
32
- Serial versions imply auto-vectorization pragmas.
31
+ Want to use in Python with [USearch](https://github.com/unum-cloud/usearch)?
33
32
 
34
- ---
33
+ ```py
34
+ from usearch import Index, CompiledMetric, MetricKind, MetricSignature
35
+ from simsimd import to_int, cos_f32x4_neon
35
36
 
36
- Cosine distance performance on a single core of a 64-core Arm-based "Graviton 3" CPUs powering AWS `c7g.metal` instances:
37
-
38
- | Method | Vectors | Any Length | Performance |
39
- | :----- | :--------- | :--------- | ----------: |
40
- | Serial | `f32` x16 | ✅ | 5 GB/s |
41
- | Serial | `f32` x256 | ✅ | 5 GB/s |
42
- | | | | |
43
- | NEON | `f32` x16 | ❌ | 18 GB/s |
44
- | NEON | `f32` x256 | ❌ | 29 GB/s |
45
- | | | | |
46
- | SVE | `f32` x16 | ✅ | 15 GB/s |
47
- | SVE | `f32` x256 | ✅ | 39 GB/s |
48
-
49
- We only use Arm NEON implementation with vectors lengths that are multiples of 128 bits, avoiding any additional head or tail `for` loops for misaligned data.
50
- SVE looses to NEON on very short vectors, but outperforms on longer sequences.
51
-
52
- ---
37
+ metric = CompiledMetric(
38
+ pointer=to_int(cos_f32x4_neon),
39
+ kind=MetricKind.Cos,
40
+ signature=MetricSignature.ArrayArraySize,
41
+ )
53
42
 
54
- On the x86 AMD Zen2 cores making up the 64-core Threadripper PRO 3995WX the numbers are:
43
+ index = Index(256, metric=metric)
44
+ ```
55
45
 
56
- | Method | Vectors | Any Length | Performance |
57
- | :------ | :--------- | :--------- | ----------: |
58
- | Serial | `f32` x16 | ✅ | 9 GB/s |
59
- | Serial | `f32` x256 | ✅ | 10 GB/s |
60
- | | | | |
61
- | AVX-FMA | `f32` x16 | ❌ | 20 GB/s |
62
- | AVX-FMA | `f32` x256 | ❌ | 24 GB/s |
46
+ ## Available Metrics
47
+
48
+ In the C99 interface all function are prepended with `simsimd_` namespace prefix.
49
+ Signature defines the number of arguments:
50
+
51
+ - two pointers, and length,
52
+ - two pointers.
53
+
54
+ The latter is obviously intended for cases, where the number of dimensions is hard-coded.
55
+ Constraints define the limitations on the number of dimensions that an argument vector can have.
56
+
57
+ | Name | Signature | ISA Extesion | Constraints |
58
+ | :---------------------- | :-------: | :----------: | :------------: |
59
+ | `dot_f32_sve` | ✳️✳️📏 | Arm SVE | |
60
+ | `dot_f32x4_neon` | ✳️✳️📏 | Arm NEON | `d % 4 == 0` |
61
+ | `cos_f32_sve` | ✳️✳️📏 | Arm SVE | |
62
+ | `cos_f16_sve` | ✳️✳️📏 | Arm SVE | |
63
+ | `cos_f16x4_neon` | ✳️✳️📏 | Arm NEON | `d % 4 == 0` |
64
+ | `cos_i8x16_neon` | ✳️✳️📏 | Arm NEON | `d % 16 == 0` |
65
+ | `cos_f32x4_neon` | ✳️✳️📏 | Arm NEON | `d % 4 == 0` |
66
+ | `cos_f16x16_avx512` | ✳️✳️📏 | x86 AVX-512 | `d % 16 == 0` |
67
+ | `cos_f32x4_avx2` | ✳️✳️📏 | x86 AVX2 | `d % 4 == 0` |
68
+ | `l2sq_f32_sve` | ✳️✳️📏 | Arm SVE | |
69
+ | `l2sq_f16_sve` | ✳️✳️📏 | Arm SVE | |
70
+ | `hamming_b1x8_sve` | ✳️✳️📏 | Arm SVE | `d % 8 == 0` |
71
+ | `hamming_b1x128_sve` | ✳️✳️📏 | Arm SVE | `d % 128 == 0` |
72
+ | `hamming_b1x128_avx512` | ✳️✳️📏 | x86 AVX-512 | `d % 128 == 0` |
73
+ | `tanimoto_b1x8_naive` | ✳️✳️📏 | | `d % 8 == 0` |
74
+ | `tanimoto_maccs_naive` | ✳️✳️ | | `d == 166` |
75
+ | `tanimoto_maccs_neon` | ✳️✳️ | Arm NEON | `d == 166` |
76
+ | `tanimoto_maccs_sve` | ✳️✳️ | Arm SVE | `d == 166` |
77
+ | `tanimoto_maccs_avx512` | ✳️✳️ | x86 AVX-512 | `d == 166` |
63
78
 
64
- The gap between auto-vectorized code and directly using 128-bit registers is much less pronounced.
65
- With AVX2 and 256-bit registers the results should be better, but would be less broadly applicable.
79
+ ## Benchmarks
66
80
 
67
- ---
81
+ The benchmarks are repeated for every function with a different number of cores involved.
82
+ Light-weight distance functions would be memory bound, implying that multi-core performance may be lower, if the bus bandwidth is not enough to saturate all the cores.
83
+ Similarly, heavy-weight distance functions running on all cores may result in CPU frequency downclocking.
84
+ This is well illustrated by the single-core performance of `i9-13950HX`, equipped with DDR5 memory.
85
+
86
+ | Method | Threads | Speed on 1024b |
87
+ | :--------------------- | ------: | -------------: |
88
+ | `tanimoto_maccs_naive` | 1 | 2.8 Gb/s |
89
+ | `tanimoto_maccs_naive` | 32 | 1.2 Gb/s |
90
+ | `cos_f32_naive` | 1 | 15.3 Gb/s |
91
+ | `cos_f32_naive` | 32 | 4.5 Gb/s |
92
+ | `dot_f32x4_avx2` | 1 | 96.2 Gb/s |
93
+ | `dot_f32x4_avx2` | 32 | 23.6 Gb/s |
94
+ | `cos_f32x4_avx2` | 1 | 56.3 Gb/s |
95
+ | `cos_f32x4_avx2` | 32 | 13.9 Gb/s |
68
96
 
69
97
  To replicate on your hardware, please run following on Linux:
70
98
 
71
99
  ```sh
100
+ git clone https://github.com/ashvardanian/SimSIMD.git && cd SimSIMD
72
101
  cmake -DCMAKE_BUILD_TYPE=Release -DSIMSIMD_BUILD_BENCHMARKS=1 -B ./build && make -C ./build && ./build/simsimd_bench
73
102
  ```
74
103
 
@@ -76,10 +105,17 @@ MacOS:
76
105
 
77
106
  ```sh
78
107
  brew install llvm
108
+ git clone https://github.com/ashvardanian/SimSIMD.git && cd SimSIMD
79
109
  cmake -B ./build \
80
110
  -DCMAKE_C_COMPILER="/opt/homebrew/opt/llvm/bin/clang" \
81
111
  -DCMAKE_CXX_COMPILER="/opt/homebrew/opt/llvm/bin/clang++" \
82
112
  -DSIMSIMD_BUILD_BENCHMARKS=1 \
83
113
  && \
84
114
  make -C ./build -j && ./build/simsimd_bench
85
- ```
115
+ ```
116
+
117
+ Install and test locally:
118
+
119
+ ```sh
120
+ pip install -e . && pytest python/test.py -s -x
121
+ ```
package/simsimd/bench.cxx CHANGED
@@ -3,16 +3,24 @@
3
3
  #include <benchmark/benchmark.h>
4
4
 
5
5
  #include <simsimd/simsimd.h>
6
+ #include <simsimd/simsimd_chem.h>
6
7
 
7
8
  namespace bm = benchmark;
8
9
 
9
10
  static const std::size_t threads_k = std::thread::hardware_concurrency();
10
- static const std::size_t time_k = 10;
11
+ static constexpr std::size_t time_k = 10;
12
+ static constexpr std::size_t bytes_k = 1024;
11
13
 
12
- template <typename scalar_at, typename metric_at, std::size_t bytes_per_vector_ak = 256,
13
- std::size_t dimensions_ak = bytes_per_vector_ak / sizeof(scalar_at)> //
14
+ template <typename return_at, typename... args_at>
15
+ constexpr std::size_t number_of_arguments(return_at (*f)(args_at...)) {
16
+ return sizeof...(args_at);
17
+ }
18
+
19
+ template <typename scalar_at, std::size_t bytes_per_vector_ak = bytes_k,
20
+ typename metric_at = void> //
14
21
  static void measure(bm::State& state, metric_at metric) {
15
22
 
23
+ constexpr ::size_t dimensions_ak = bytes_per_vector_ak / sizeof(scalar_at);
16
24
  alignas(64) scalar_at a[dimensions_ak]{};
17
25
  alignas(64) scalar_at b[dimensions_ak]{};
18
26
  float c{};
@@ -20,15 +28,37 @@ static void measure(bm::State& state, metric_at metric) {
20
28
  std::fill_n(a, dimensions_ak, static_cast<scalar_at>(1));
21
29
  std::fill_n(b, dimensions_ak, static_cast<scalar_at>(2));
22
30
 
31
+ std::size_t iterations = 0;
23
32
  for (auto _ : state)
24
- bm::DoNotOptimize((c = metric(a, b, dimensions_ak)));
33
+ if constexpr (number_of_arguments(metric_at{}) == 3)
34
+ bm::DoNotOptimize((c = metric(a, b, dimensions_ak))), iterations++;
35
+ else
36
+ bm::DoNotOptimize((c = metric(a, b))), iterations++;
37
+
38
+ state.counters["bytes"] = bm::Counter(iterations * bytes_per_vector_ak * 2u, bm::Counter::kIsRate);
39
+ state.counters["pairs"] = bm::Counter(iterations, bm::Counter::kIsRate);
40
+ }
25
41
 
26
- state.SetBytesProcessed(state.iterations() * bytes_per_vector_ak * 2u);
27
- state.SetItemsProcessed(state.iterations());
42
+ template <typename scalar_at, std::size_t bytes_per_vector_ak = bytes_k, typename metric_at = void>
43
+ void register_(char const* name, metric_at distance_func) {
44
+ bm::RegisterBenchmark(name, measure<scalar_at, bytes_per_vector_ak, metric_at>, distance_func)
45
+ ->Threads(1)
46
+ ->MinTime(time_k);
47
+ bm::RegisterBenchmark(name, measure<scalar_at, bytes_per_vector_ak, metric_at>, distance_func)
48
+ ->Threads(threads_k)
49
+ ->MinTime(time_k);
28
50
  }
29
51
 
30
- template <typename scalar_at, typename metric_at> void register_(char const* name, metric_at distance_func) {
31
- bm::RegisterBenchmark(name, measure<scalar_at, metric_at>, distance_func)->Threads(threads_k)->MinTime(time_k);
52
+ simsimd_f32_t cos_f32_naive(simsimd_f32_t* v1, simsimd_f32_t* v2, std::size_t n) {
53
+ simsimd_f32_t inner_product = 0;
54
+ simsimd_f32_t magnitude1 = 0;
55
+ simsimd_f32_t magnitude2 = 0;
56
+ for (std::size_t i = 0; i != n; ++i) {
57
+ inner_product += v1[i] * v2[i];
58
+ magnitude1 += v1[i] * v1[i];
59
+ magnitude2 += v2[i] * v2[i];
60
+ }
61
+ return 1 - inner_product / (std::sqrt(magnitude1) * std::sqrt(magnitude2));
32
62
  }
33
63
 
34
64
  int main(int argc, char** argv) {
@@ -45,7 +75,7 @@ int main(int argc, char** argv) {
45
75
  compiled_with_neon = true;
46
76
  #endif
47
77
  #if defined(__AVX2__)
48
- compiled_withavx2 = true;
78
+ compiled_with_avx2 = true;
49
79
  #endif
50
80
  #if defined(__AVX512VPOPCNTDQ__)
51
81
  compiled_with_avx512popcnt = true;
@@ -59,6 +89,7 @@ int main(int argc, char** argv) {
59
89
  std::printf("- Arm SVE support enabled: %s\n", flags[compiled_with_sve]);
60
90
  std::printf("- x86 AVX2 support enabled: %s\n", flags[compiled_with_avx2]);
61
91
  std::printf("- x86 AVX512VPOPCNTDQ support enabled: %s\n", flags[compiled_with_avx512popcnt]);
92
+ std::printf("Default vector length: %zu bytes\n", bytes_k);
62
93
  std::printf("\n");
63
94
 
64
95
  // Run the benchmarks
@@ -66,33 +97,41 @@ int main(int argc, char** argv) {
66
97
  if (bm::ReportUnrecognizedArguments(argc, argv))
67
98
  return 1;
68
99
 
100
+ register_<std::uint8_t, 21>("tanimoto_maccs_naive", simsimd_tanimoto_maccs_naive);
101
+ register_<simsimd_f32_t>("cos_f32_naive", cos_f32_naive);
102
+
69
103
  #if defined(__ARM_FEATURE_SVE)
70
- register_<simsimd_f32_t>("dot_f32sve", simsimd_dot_f32sve);
71
- register_<simsimd_f32_t>("cos_f32sve", simsimd_cos_f32sve);
72
- register_<simsimd_f32_t>("l2sq_f32sve", simsimd_l2sq_f32sve);
73
- register_<std::int16_t>("l2sq_f16sve", simsimd_l2sq_f16sve);
74
- register_<std::uint8_t>("hamming_b1x8sve", simsimd_hamming_b1x8sve);
75
- register_<std::uint8_t>("hamming_b1x128sve", simsimd_hamming_b1x128sve);
104
+ register_<simsimd_f32_t>("dot_f32_sve", simsimd_dot_f32_sve);
105
+ register_<simsimd_f32_t>("cos_f32_sve", simsimd_cos_f32_sve);
106
+ register_<std::int16_t>("cos_f16_sve", simsimd_cos_f16_sve);
107
+ register_<simsimd_f32_t>("l2sq_f32_sve", simsimd_l2sq_f32_sve);
108
+ register_<std::int16_t>("l2sq_f16_sve", simsimd_l2sq_f16_sve);
109
+ register_<std::uint8_t>("hamming_b1x8_sve", simsimd_hamming_b1x8_sve);
110
+ register_<std::uint8_t>("hamming_b1x128_sve", simsimd_hamming_b1x128_sve);
111
+ register_<std::uint8_t, 21>("tanimoto_maccs_sve", simsimd_tanimoto_maccs_sve);
76
112
  #endif
77
113
 
78
114
  #if defined(__ARM_NEON)
79
- register_<simsimd_f32_t>("dot_f32x4neon", simsimd_dot_f32x4neon);
80
- register_<std::int16_t>("cos_f16x4neon", simsimd_cos_f16x4neon);
81
- register_<std::int8_t>("cos_i8x16neon", simsimd_cos_i8x16neon);
82
- register_<simsimd_f32_t>("cos_f32x4neon", simsimd_cos_f32x4neon);
115
+ register_<simsimd_f32_t>("dot_f32x4_neon", simsimd_dot_f32x4_neon);
116
+ register_<std::int16_t>("cos_f16x4_neon", simsimd_cos_f16x4_neon);
117
+ register_<std::int8_t>("cos_i8x16_neon", simsimd_cos_i8x16_neon);
118
+ register_<simsimd_f32_t>("cos_f32x4_neon", simsimd_cos_f32x4_neon);
119
+ register_<std::uint8_t, 21>("tanimoto_maccs_neon", simsimd_tanimoto_maccs_neon);
83
120
  #endif
84
121
 
85
122
  #if defined(__AVX2__)
86
- register_<simsimd_f32_t>("dot_f32x4avx2", simsimd_dot_f32x4avx2);
87
- register_<std::int8_t>("dot_i8x16avx2", simsimd_dot_i8x16avx2);
88
- register_<simsimd_f32_t>("cos_f32x4avx2", simsimd_cos_f32x4avx2);
123
+ register_<simsimd_f32_t>("dot_f32x4_avx2", simsimd_dot_f32x4_avx2);
124
+ register_<simsimd_f32_t>("cos_f32x4_avx2", simsimd_cos_f32x4_avx2);
89
125
  #endif
90
126
 
91
127
  #if defined(__AVX512F__)
92
- register_<std::int16_t>("cos_f16x16avx512", simsimd_cos_f16x16avx512);
93
- register_<std::uint8_t>("hamming_b1x128avx512", simsimd_hamming_b1x128avx512);
128
+ register_<std::int16_t>("cos_f16x16_avx512", simsimd_cos_f16x16_avx512);
129
+ register_<std::uint8_t>("hamming_b1x128_avx512", simsimd_hamming_b1x128_avx512);
130
+ register_<std::uint8_t, 21>("tanimoto_maccs_avx512", simsimd_tanimoto_maccs_avx512);
94
131
  #endif
95
132
 
133
+
134
+
96
135
  bm::RunSpecifiedBenchmarks();
97
136
  bm::Shutdown();
98
137
  return 0;