usearch 2.1.2 → 2.2.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.
- package/.github/workflows/prerelease.yml +18 -3
- package/CMakeLists.txt +15 -0
- package/Cargo.toml +1 -1
- package/README.md +2 -2
- package/conanfile.py +1 -1
- package/include/usearch/index_plugins.hpp +50 -6
- package/package.json +1 -1
- package/python/lib.cpp +11 -0
- package/python/usearch/index.py +17 -4
- package/setup.py +3 -4
- package/simsimd/.github/workflows/prerelease.yml +42 -9
- package/simsimd/.github/workflows/release.yml +15 -11
- package/simsimd/.vscode/settings.json +5 -1
- package/simsimd/CMakeLists.txt +5 -2
- package/simsimd/README.md +69 -48
- package/simsimd/bench.cxx +5 -6
- package/simsimd/include/simsimd/simsimd.h +300 -140
- package/simsimd/include/simsimd/simsimd_bio.h +54 -0
- package/simsimd/include/simsimd/simsimd_chem.h +65 -24
- package/simsimd/include/simsimd/simsimd_text.h +92 -0
- package/simsimd/package.json +1 -1
- package/simsimd/pyproject.toml +2 -1
- package/simsimd/python/{python.c → lib.c} +44 -15
- package/simsimd/python/test.py +35 -20
- package/simsimd/setup.py +2 -6
- package/wasmer.toml +1 -1
- /package/{cluster.ipynb → python/scripts/cluster.ipynb} +0 -0
package/simsimd/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# SimSIMD
|
|
1
|
+
# SimSIMD 📏
|
|
2
2
|
|
|
3
|
-
SIMD-accelerated similarity measures, metrics, distance functions for x86 and Arm.
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
SIMD-accelerated similarity measures, metrics, and distance functions for x86 and Arm.
|
|
4
|
+
They are tuned for Machine Learning applications and mid-size vectors with 100-1024 dimensions.
|
|
5
|
+
One can expect the following performance for Cosine (Angular) distance, the most common metric in AI.
|
|
6
6
|
|
|
7
7
|
| Method | Vectors | Any Length | Speed on 256b | Speed on 1024b |
|
|
8
8
|
| :----- | :------ | :--------- | ------------: | -------------: |
|
|
@@ -12,7 +12,7 @@ For Cosine (Angular) distance, the most common metric in AI, one can expect foll
|
|
|
12
12
|
| NEON | `f16` | ❌ | 16 GB/s | 18 GB/s |
|
|
13
13
|
|
|
14
14
|
> The benchmarks were done on Arm-based "Graviton 3" CPUs powering AWS `c7g.metal` instances.
|
|
15
|
-
> We only use Arm NEON implementation with
|
|
15
|
+
> We only use Arm NEON implementation with vector lengths multiples of 128 bits, avoiding additional head or tail `for` loops for misaligned data.
|
|
16
16
|
> By default, we use GCC12, `-O3`, `-march=native` for benchmarks.
|
|
17
17
|
> Serial versions imply auto-vectorization pragmas.
|
|
18
18
|
|
|
@@ -28,7 +28,7 @@ FetchContent_MakeAvailable(simsimd)
|
|
|
28
28
|
include_directories(${simsimd_SOURCE_DIR}/include)
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
Want to use in Python with [USearch](https://github.com/unum-cloud/usearch)?
|
|
31
|
+
Want to use it in Python with [USearch](https://github.com/unum-cloud/usearch)?
|
|
32
32
|
|
|
33
33
|
```py
|
|
34
34
|
from usearch import Index, CompiledMetric, MetricKind, MetricSignature
|
|
@@ -45,60 +45,81 @@ index = Index(256, metric=metric)
|
|
|
45
45
|
|
|
46
46
|
## Available Metrics
|
|
47
47
|
|
|
48
|
-
In the C99 interface all
|
|
49
|
-
|
|
48
|
+
In the C99 interface, all functions are prepended with the `simsimd_` namespace prefix.
|
|
49
|
+
The signature defines the number of arguments:
|
|
50
50
|
|
|
51
51
|
- two pointers, and length,
|
|
52
52
|
- two pointers.
|
|
53
53
|
|
|
54
|
-
The latter is
|
|
55
|
-
Constraints define the limitations on the number of dimensions
|
|
56
|
-
|
|
57
|
-
| Name | Signature | ISA
|
|
58
|
-
| :---------------------- | :-------: |
|
|
59
|
-
| `dot_f32_sve` | ✳️✳️📏 |
|
|
60
|
-
| `dot_f32x4_neon` | ✳️✳️📏 | Arm NEON
|
|
61
|
-
| `cos_f32_sve` | ✳️✳️📏 |
|
|
62
|
-
| `cos_f16_sve` | ✳️✳️📏 |
|
|
63
|
-
| `cos_f16x4_neon` | ✳️✳️📏 | Arm NEON
|
|
64
|
-
| `cos_i8x16_neon` | ✳️✳️📏 | Arm NEON
|
|
65
|
-
| `cos_f32x4_neon` | ✳️✳️📏 | Arm NEON
|
|
66
|
-
| `cos_f16x16_avx512` | ✳️✳️📏 |
|
|
67
|
-
| `cos_f32x4_avx2` | ✳️✳️📏 | x86 AVX2
|
|
68
|
-
| `l2sq_f32_sve` | ✳️✳️📏 |
|
|
69
|
-
| `l2sq_f16_sve` | ✳️✳️📏 |
|
|
70
|
-
| `hamming_b1x8_sve` | ✳️✳️📏 |
|
|
71
|
-
| `hamming_b1x128_sve` | ✳️✳️📏 |
|
|
72
|
-
| `hamming_b1x128_avx512` | ✳️✳️📏 |
|
|
73
|
-
| `tanimoto_b1x8_naive` | ✳️✳️📏 |
|
|
74
|
-
| `tanimoto_maccs_naive` | ✳️✳️ |
|
|
75
|
-
| `tanimoto_maccs_neon` | ✳️✳️ | Arm NEON
|
|
76
|
-
| `tanimoto_maccs_sve` | ✳️✳️ |
|
|
77
|
-
| `tanimoto_maccs_avx512` | ✳️✳️ |
|
|
54
|
+
The latter is intended for cases where the number of dimensions is hard-coded.
|
|
55
|
+
Constraints define the limitations on the number of dimensions an argument vector can have.
|
|
56
|
+
|
|
57
|
+
| Name | Signature | ISA Extension | 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` |
|
|
78
78
|
|
|
79
79
|
## Benchmarks
|
|
80
80
|
|
|
81
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
|
|
82
|
+
Light-weight distance functions would be memory bound, implying that multi-core performance may be lower if the bus bandwidth cannot saturate all the cores.
|
|
83
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 |
|
|
87
|
-
| :--------------------- | ------: |
|
|
88
|
-
| `
|
|
89
|
-
| `
|
|
90
|
-
| `cos_f32_naive` | 1 | 15.3
|
|
91
|
-
| `cos_f32_naive` | 32 |
|
|
92
|
-
| `
|
|
93
|
-
| `
|
|
94
|
-
| `
|
|
95
|
-
| `
|
|
96
|
-
|
|
97
|
-
|
|
84
|
+
This is well illustrated by the single-core performance of the Intel `i9-13950HX`, equipped with DDR5 memory.
|
|
85
|
+
|
|
86
|
+
| Method | Threads | Vector Size | Speed |
|
|
87
|
+
| :--------------------- | ------: | ----------: | --------: |
|
|
88
|
+
| `dot_f32x4_avx2` | 1 | 1024 b | 96.2 GB/s |
|
|
89
|
+
| `dot_f32x4_avx2` | 32 | 1024 b | 23.6 GB/s |
|
|
90
|
+
| `cos_f32_naive` | 1 | 1024 b | 15.3 GB/s |
|
|
91
|
+
| `cos_f32_naive` | 32 | 1024 b | 4.5 GB/s |
|
|
92
|
+
| `cos_f32x4_avx2` | 1 | 1024 b | 56.3 GB/s |
|
|
93
|
+
| `cos_f32x4_avx2` | 32 | 1024 b | 13.9 GB/s |
|
|
94
|
+
| `tanimoto_maccs_naive` | 1 | 21 b | 2.8 GB/s |
|
|
95
|
+
| `tanimoto_maccs_naive` | 32 | 21 b | 1.2 GB/s |
|
|
96
|
+
|
|
97
|
+
Switching to the Intel Sapphire Rapids server platform, we can also evaluate some of the AVX-512 extensions, including `VPOPCNTDQ` and `F16`.
|
|
98
|
+
|
|
99
|
+
| Method | Threads | Vector Size | Speed |
|
|
100
|
+
| :---------------------- | ------: | ----------: | ---------: |
|
|
101
|
+
| `dot_f32x4_avx2` | 1 | 1024 b | 57.8 GB/s |
|
|
102
|
+
| `dot_f32x4_avx2` | 224 | 1024 b | 16.1 GB/s |
|
|
103
|
+
| `cos_f32_naive` | 1 | 1024 b | 10.7 GB/s |
|
|
104
|
+
| `cos_f32_naive` | 224 | 1024 b | 3.0 GB/s |
|
|
105
|
+
| `cos_f32x4_avx2` | 1 | 1024 b | 39.5 GB/s |
|
|
106
|
+
| `cos_f32x4_avx2` | 224 | 1024 b | 15.1 GB/s |
|
|
107
|
+
| `cos_f16x16_avx512` | 1 | 1024 b | 50.6 GB/s |
|
|
108
|
+
| `cos_f16x16_avx512` | 224 | 1024 b | 15.9 GB/s |
|
|
109
|
+
| `hamming_b1x128_avx512` | 1 | 1024 b | 790.3 GB/s |
|
|
110
|
+
| `hamming_b1x128_avx512` | 224 | 1024 b | 259.3 GB/s |
|
|
111
|
+
| `tanimoto_maccs_naive` | 1 | 21 b | 3.0 GB/s |
|
|
112
|
+
| `tanimoto_maccs_naive` | 224 | 21 b | 1.3 GB/s |
|
|
113
|
+
| `tanimoto_maccs_avx512` | 1 | 21 b | 13.1 GB/s |
|
|
114
|
+
| `tanimoto_maccs_avx512` | 224 | 21 b | 3.7 GB/s |
|
|
115
|
+
|
|
116
|
+
To replicate this on your hardware, please run the following on Linux:
|
|
98
117
|
|
|
99
118
|
```sh
|
|
100
119
|
git clone https://github.com/ashvardanian/SimSIMD.git && cd SimSIMD
|
|
101
|
-
cmake -DCMAKE_BUILD_TYPE=Release -DSIMSIMD_BUILD_BENCHMARKS=1
|
|
120
|
+
cmake -DCMAKE_BUILD_TYPE=Release -DSIMSIMD_BUILD_BENCHMARKS=1 \
|
|
121
|
+
-DCMAKE_CXX_COMPILER="g++-12" -DCMAKE_C_COMPILER="gcc-12" \
|
|
122
|
+
-B ./build && make -C ./build && ./build/simsimd_bench
|
|
102
123
|
```
|
|
103
124
|
|
|
104
125
|
MacOS:
|
package/simsimd/bench.cxx
CHANGED
|
@@ -100,7 +100,7 @@ int main(int argc, char** argv) {
|
|
|
100
100
|
register_<std::uint8_t, 21>("tanimoto_maccs_naive", simsimd_tanimoto_maccs_naive);
|
|
101
101
|
register_<simsimd_f32_t>("cos_f32_naive", cos_f32_naive);
|
|
102
102
|
|
|
103
|
-
#if
|
|
103
|
+
#if SIMSIMD_TARGET_ARM_SVE
|
|
104
104
|
register_<simsimd_f32_t>("dot_f32_sve", simsimd_dot_f32_sve);
|
|
105
105
|
register_<simsimd_f32_t>("cos_f32_sve", simsimd_cos_f32_sve);
|
|
106
106
|
register_<std::int16_t>("cos_f16_sve", simsimd_cos_f16_sve);
|
|
@@ -111,27 +111,26 @@ int main(int argc, char** argv) {
|
|
|
111
111
|
register_<std::uint8_t, 21>("tanimoto_maccs_sve", simsimd_tanimoto_maccs_sve);
|
|
112
112
|
#endif
|
|
113
113
|
|
|
114
|
-
#if
|
|
114
|
+
#if SIMSIMD_TARGET_ARM_NEON
|
|
115
115
|
register_<simsimd_f32_t>("dot_f32x4_neon", simsimd_dot_f32x4_neon);
|
|
116
116
|
register_<std::int16_t>("cos_f16x4_neon", simsimd_cos_f16x4_neon);
|
|
117
117
|
register_<std::int8_t>("cos_i8x16_neon", simsimd_cos_i8x16_neon);
|
|
118
|
+
register_<std::int8_t>("l2sq_i8x16_neon", simsimd_l2sq_i8x16_neon);
|
|
118
119
|
register_<simsimd_f32_t>("cos_f32x4_neon", simsimd_cos_f32x4_neon);
|
|
119
120
|
register_<std::uint8_t, 21>("tanimoto_maccs_neon", simsimd_tanimoto_maccs_neon);
|
|
120
121
|
#endif
|
|
121
122
|
|
|
122
|
-
#if
|
|
123
|
+
#if SIMSIMD_TARGET_X86_AVX2
|
|
123
124
|
register_<simsimd_f32_t>("dot_f32x4_avx2", simsimd_dot_f32x4_avx2);
|
|
124
125
|
register_<simsimd_f32_t>("cos_f32x4_avx2", simsimd_cos_f32x4_avx2);
|
|
125
126
|
#endif
|
|
126
127
|
|
|
127
|
-
#if
|
|
128
|
+
#if SIMSIMD_TARGET_X86_AVX512
|
|
128
129
|
register_<std::int16_t>("cos_f16x16_avx512", simsimd_cos_f16x16_avx512);
|
|
129
130
|
register_<std::uint8_t>("hamming_b1x128_avx512", simsimd_hamming_b1x128_avx512);
|
|
130
131
|
register_<std::uint8_t, 21>("tanimoto_maccs_avx512", simsimd_tanimoto_maccs_avx512);
|
|
131
132
|
#endif
|
|
132
133
|
|
|
133
|
-
|
|
134
|
-
|
|
135
134
|
bm::RunSpecifiedBenchmarks();
|
|
136
135
|
bm::Shutdown();
|
|
137
136
|
return 0;
|