usearch 2.8.15 → 2.9.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/ISSUE_TEMPLATE/bug_report.yml +1 -1
- package/.github/workflows/prerelease.yml +37 -11
- package/.github/workflows/release.yml +30 -28
- package/.gitmodules +4 -1
- package/CITATION.cff +1 -1
- package/CMakeLists.txt +6 -8
- package/CONTRIBUTING.md +20 -1
- package/Cargo.toml +1 -1
- package/README.md +8 -7
- package/VERSION +1 -1
- package/conanfile.py +1 -1
- package/cpp/test.cpp +9 -2
- package/include/usearch/index.hpp +11 -11
- package/include/usearch/index_plugins.hpp +4 -2
- package/javascript/usearch.js +1 -1
- package/package.json +1 -1
- package/pyproject.toml +2 -2
- package/setup.py +10 -4
- package/simsimd/.releaserc +3 -2
- package/simsimd/Cargo.lock +708 -0
- package/simsimd/Cargo.toml +36 -0
- package/simsimd/README.md +91 -25
- package/simsimd/binding.gyp +18 -0
- package/simsimd/build.rs +20 -0
- package/simsimd/include/simsimd/probability.h +5 -5
- package/simsimd/include/simsimd/simsimd.h +9 -5
- package/simsimd/include/simsimd/spatial.h +20 -21
- package/simsimd/include/simsimd/types.h +5 -1
- package/simsimd/javascript/bench.js +20 -10
- package/simsimd/javascript/dist-package-cjs.json +3 -0
- package/simsimd/javascript/dist-package-esm.json +3 -0
- package/simsimd/javascript/fallback.ts +193 -0
- package/simsimd/javascript/node-gyp-build.d.ts +1 -0
- package/simsimd/javascript/simsimd.ts +124 -0
- package/simsimd/javascript/test.mjs +153 -0
- package/simsimd/javascript/tsconfig-base.json +25 -0
- package/simsimd/javascript/tsconfig-cjs.json +8 -0
- package/simsimd/javascript/tsconfig-esm.json +8 -0
- package/simsimd/package-lock.json +1688 -0
- package/simsimd/package.json +26 -11
- package/simsimd/rust/benches/cosine.rs +27 -0
- package/simsimd/rust/benches/native.rs +27 -0
- package/simsimd/rust/benches/sqeuclidean.rs +27 -0
- package/simsimd/rust/lib.c +68 -0
- package/simsimd/rust/lib.rs +232 -0
- package/sqlite/README.md +178 -0
- package/sqlite/lib.cpp +325 -0
- package/stringzilla/CONTRIBUTING.md +429 -0
- package/stringzilla/Cargo.lock +25 -0
- package/stringzilla/Cargo.toml +26 -0
- package/stringzilla/LICENSE +201 -0
- package/stringzilla/README.md +1281 -0
- package/stringzilla/VERSION +1 -0
- package/stringzilla/assets/cover-strinzilla.jpeg +0 -0
- package/stringzilla/assets/meme-stringzilla-v2.jpeg +0 -0
- package/stringzilla/assets/meme-stringzilla-v3.jpeg +0 -0
- package/stringzilla/binding.gyp +16 -0
- package/stringzilla/build.rs +14 -0
- package/stringzilla/c/lib.c +304 -0
- package/stringzilla/cli/README.md +48 -0
- package/stringzilla/cli/split.py +72 -0
- package/stringzilla/cli/wc.py +37 -0
- package/stringzilla/include/stringzilla/experimental.h +724 -0
- package/stringzilla/include/stringzilla/module.modulemap +9 -0
- package/stringzilla/include/stringzilla/stringzilla.h +5240 -0
- package/stringzilla/include/stringzilla/stringzilla.hpp +3830 -0
- package/stringzilla/javascript/lib.c +125 -0
- package/stringzilla/javascript/stringzilla.js +22 -0
- package/stringzilla/package-ci.json +10 -0
- package/stringzilla/package.json +32 -0
- package/stringzilla/rust/lib.rs +362 -0
- package/stringzilla/swift/StringProtocol+StringZilla.swift +280 -0
- package/stringzilla/swift/Test.swift +60 -0
- package/wasmer.toml +1 -1
- package/simsimd/javascript/simsimd.js +0 -45
- package/simsimd/javascript/test/simsimd.test.js +0 -47
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "simsimd"
|
|
3
|
+
description = "Fastest SIMD-Accelerated Vector Similarity Functions for x86 and Arm"
|
|
4
|
+
version = "3.8.0"
|
|
5
|
+
edition = "2021"
|
|
6
|
+
license = "Apache-2.0"
|
|
7
|
+
authors = [
|
|
8
|
+
"Ash Vardanian <1983160+ashvardanian@users.noreply.github.com>",
|
|
9
|
+
"Pedro Planel <pplanel@gmail.com>",
|
|
10
|
+
]
|
|
11
|
+
repository = "https://github.com/ashvardanian/SimSIMD"
|
|
12
|
+
documentation = "https://docs.rs/simsimd"
|
|
13
|
+
homepage = "https://ashvardanian.com/posts/simsimd-faster-scipy"
|
|
14
|
+
keywords = ["simd", "search", "linear-algebra", "vector"]
|
|
15
|
+
categories = ["mathematics", "hardware-support", "no-std", "wasm", "external-ffi-bindings"]
|
|
16
|
+
|
|
17
|
+
[lib]
|
|
18
|
+
name = "simsimd"
|
|
19
|
+
path = "rust/lib.rs"
|
|
20
|
+
|
|
21
|
+
[build-dependencies]
|
|
22
|
+
cc = "1.0.83"
|
|
23
|
+
|
|
24
|
+
[[bench]]
|
|
25
|
+
name = "cosine"
|
|
26
|
+
harness = false
|
|
27
|
+
path = "rust/benches/cosine.rs"
|
|
28
|
+
|
|
29
|
+
[[bench]]
|
|
30
|
+
name = "sqeuclidean"
|
|
31
|
+
harness = false
|
|
32
|
+
path = "rust/benches/sqeuclidean.rs"
|
|
33
|
+
|
|
34
|
+
[dev-dependencies]
|
|
35
|
+
criterion = { version = "0.5.1" }
|
|
36
|
+
rand = { version = "0.8.5" }
|
package/simsimd/README.md
CHANGED
|
@@ -1,25 +1,27 @@
|
|
|
1
1
|
# SimSIMD 📏
|
|
2
2
|
|
|
3
3
|
<div>
|
|
4
|
-
<a href="https://pepy.tech/project/simsimd"> <img alt="PyPI" src="https://static.pepy.tech/personalized-badge/simsimd?period=
|
|
4
|
+
<a href="https://pepy.tech/project/simsimd"> <img alt="PyPI" src="https://static.pepy.tech/personalized-badge/simsimd?period=total&units=abbreviation&left_color=black&right_color=blue&left_text=SimSIMD%20Python%20installs"> </a>
|
|
5
5
|
<a href="https://www.npmjs.com/package/simsimd"> <img alt="npm" src="https://img.shields.io/npm/dy/simsimd?label=npm%20dowloads"> </a>
|
|
6
|
+
<a href="https://crates.io/crates/simsimd"> <img alt="rust" src="https://img.shields.io/crates/d/simsimd?logo=rust" /> </a>
|
|
6
7
|
<img alt="GitHub code size in bytes" src="https://img.shields.io/github/languages/code-size/ashvardanian/simsimd">
|
|
7
8
|
</div>
|
|
8
9
|
|
|
9
|
-
##
|
|
10
|
+
## Hardware-Accelerated Similarity Metrics and Distance Functions
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
- Zero-dependency [header-only C 99](#using-simsimd-in-c) library.
|
|
13
|
+
- Bindings for [Python](#using-simsimd-in-python), [Rust](#using-simsimd-in-rust) and [JavaScript](#using-simsimd-in-javascript).
|
|
14
|
+
- Targets ARM NEON, SVE, x86 AVX2, AVX-512 (VNNI, FP16) hardware backends.
|
|
15
|
+
- Zero-copy compatible with NumPy, PyTorch, TensorFlow, and other tensors.
|
|
16
|
+
- Handles `f64` double-, `f32` single-, and `f16` half-precision, `i8` integral, and binary vectors.
|
|
17
|
+
- __Up to 200x faster__ than [`scipy.spatial.distance`][scipy] and [`numpy.inner`][numpy].
|
|
18
|
+
- Used in [USearch](https://github.com/unum-cloud/usearch) and several DBMS products.
|
|
12
19
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
- ✅ Compatible with GCC and Clang on MacOS and Linux, and MinGW on Windows.
|
|
19
|
-
- ✅ Compatible with NumPy, PyTorch, TensorFlow, and other tensors.
|
|
20
|
-
- ✅ Has __no dependencies__, not even LibC.
|
|
21
|
-
- ✅ [JavaScript API](#using-simsimd-in-javascript).
|
|
22
|
-
- ✅ [C API](#using-simsimd-in-c).
|
|
20
|
+
__Implemented distance functions__ include:
|
|
21
|
+
|
|
22
|
+
- Euclidean (L2), Inner Distance, and Cosine (Angular) spatial distances.
|
|
23
|
+
- Hamming (~ Manhattan) and Jaccard (~ Tanimoto) binary distances.
|
|
24
|
+
- Kullback-Leibler and Jensen–Shannon divergences for probability distributions.
|
|
23
25
|
|
|
24
26
|
[scipy]: https://docs.scipy.org/doc/scipy/reference/spatial.distance.html#module-scipy.spatial.distance
|
|
25
27
|
[numpy]: https://numpy.org/doc/stable/reference/generated/numpy.inner.html
|
|
@@ -43,18 +45,18 @@ Given 1000 embeddings from OpenAI Ada API with 1536 dimensions, running on the A
|
|
|
43
45
|
| :------------- | ----------------: | ----------------: | ---------------: | :------------------------------------- | :-------------- |
|
|
44
46
|
| Cosine | __32 x__ | __79 x__ | __133 x__ | `scipy.spatial.distance.cosine` | `cosine` |
|
|
45
47
|
| Euclidean ² | __5 x__ | __26 x__ | __17 x__ | `scipy.spatial.distance.sqeuclidean` | `sqeuclidean` |
|
|
46
|
-
| Inner
|
|
48
|
+
| Inner Distance | __2 x__ | __9 x__ | __18 x__ | `numpy.inner` | `inner` |
|
|
47
49
|
| Jensen Shannon | __31 x__ | __53 x__ | | `scipy.spatial.distance.jensenshannon` | `jensenshannon` |
|
|
48
50
|
|
|
49
51
|
### Intel Sapphire Rapids
|
|
50
52
|
|
|
51
|
-
On the Intel Sapphire Rapids platform, SimSIMD was benchmarked against auto-vectorized code using GCC 12. GCC handles single-precision `float
|
|
53
|
+
On the Intel Sapphire Rapids platform, SimSIMD was benchmarked against auto-vectorized code using GCC 12. GCC handles single-precision `float` but might not be the best choice for `int8` and `_Float16` arrays, which has been part of the C language since 2011.
|
|
52
54
|
|
|
53
55
|
| Kind | GCC 12 `f32` | GCC 12 `f16` | SimSIMD `f16` | `f16` improvement |
|
|
54
56
|
| :------------- | -----------: | -----------: | ------------: | ----------------: |
|
|
55
57
|
| Cosine | 3.28 M/s | _336.29 k/s_ | _6.88 M/s_ | __20 x__ |
|
|
56
58
|
| Euclidean ² | 4.62 M/s | _147.25 k/s_ | _5.32 M/s_ | __36 x__ |
|
|
57
|
-
| Inner
|
|
59
|
+
| Inner Distance | 3.81 M/s | _192.02 k/s_ | _5.99 M/s_ | __31 x__ |
|
|
58
60
|
| Jensen Shannon | 1.18 M/s | _18.13 k/s_ | _2.14 M/s_ | __118 x__ |
|
|
59
61
|
|
|
60
62
|
__Broader Benchmarking Results__:
|
|
@@ -63,7 +65,7 @@ __Broader Benchmarking Results__:
|
|
|
63
65
|
- [4th Gen Intel Xeon Platinum](https://ashvardanian.com/posts/simsimd-faster-scipy/#appendix-2-performance-on-4th-gen-intel-xeon-platinum-8480).
|
|
64
66
|
- [AWS Graviton 3](https://ashvardanian.com/posts/simsimd-faster-scipy/#appendix-3-performance-on-aws-graviton-3).
|
|
65
67
|
|
|
66
|
-
## Using in Python
|
|
68
|
+
## Using SimSIMD in Python
|
|
67
69
|
|
|
68
70
|
### Installation
|
|
69
71
|
|
|
@@ -92,7 +94,7 @@ batch2 = np.random.randn(100, 1536).astype(np.float32)
|
|
|
92
94
|
dist = simsimd.cosine(batch1, batch2)
|
|
93
95
|
```
|
|
94
96
|
|
|
95
|
-
If either batch has more than one vector, the other batch must have one or same number of vectors.
|
|
97
|
+
If either batch has more than one vector, the other batch must have one or the same number of vectors.
|
|
96
98
|
If it contains just one, the value is broadcasted.
|
|
97
99
|
|
|
98
100
|
### All Pairwise Distances
|
|
@@ -124,7 +126,7 @@ print(simsimd.get_capabilities())
|
|
|
124
126
|
### Using Python API with USearch
|
|
125
127
|
|
|
126
128
|
Want to use it in Python with [USearch](https://github.com/unum-cloud/usearch)?
|
|
127
|
-
You can wrap the raw C function pointers SimSIMD backends into a `CompiledMetric
|
|
129
|
+
You can wrap the raw C function pointers SimSIMD backends into a `CompiledMetric` and pass it to USearch, similar to how it handles Numba's JIT-compiled code.
|
|
128
130
|
|
|
129
131
|
```py
|
|
130
132
|
from usearch.index import Index, CompiledMetric, MetricKind, MetricSignature
|
|
@@ -139,9 +141,46 @@ metric = CompiledMetric(
|
|
|
139
141
|
index = Index(256, metric=metric)
|
|
140
142
|
```
|
|
141
143
|
|
|
144
|
+
## Using SimSIMD in Rust
|
|
145
|
+
|
|
146
|
+
To install, add the following to your `Cargo.toml`:
|
|
147
|
+
|
|
148
|
+
```toml
|
|
149
|
+
[dependencies]
|
|
150
|
+
simsimd = "..."
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
To use it:
|
|
154
|
+
|
|
155
|
+
```rust
|
|
156
|
+
use simsimd::{cosine, sqeuclidean};
|
|
157
|
+
|
|
158
|
+
fn main() {
|
|
159
|
+
let vector_a = vec![1.0, 2.0, 3.0];
|
|
160
|
+
let vector_b = vec![4.0, 5.0, 6.0];
|
|
161
|
+
|
|
162
|
+
let distance = cosine(&vector_a, &vector_b);
|
|
163
|
+
println!("Cosine Distance: {}", distance);
|
|
164
|
+
|
|
165
|
+
let distance = sqeuclidean(&vector_a, &vector_b);
|
|
166
|
+
println!("Squared Euclidean Distance: {}", distance);
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
142
170
|
## Using SimSIMD in JavaScript
|
|
143
171
|
|
|
144
|
-
|
|
172
|
+
To install, choose one of the following options depending on your environment:
|
|
173
|
+
|
|
174
|
+
- `npm install --save simsimd`
|
|
175
|
+
- `yarn add simsimd`
|
|
176
|
+
- `pnpm add simsimd`
|
|
177
|
+
- `bun install simsimd`
|
|
178
|
+
|
|
179
|
+
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).
|
|
180
|
+
|
|
181
|
+
If your platform is not supported, you can build the package from source via `npm run build`. This will automatically happen unless you install the package with `--ignore-scripts` flag or use Bun.
|
|
182
|
+
|
|
183
|
+
After you install it, you will be able to call the SimSIMD functions on various `TypedArray` variants:
|
|
145
184
|
|
|
146
185
|
```js
|
|
147
186
|
const { sqeuclidean, cosine, inner, hamming, jaccard } = require('simsimd');
|
|
@@ -155,8 +194,6 @@ console.log('Squared Euclidean Distance:', distance);
|
|
|
155
194
|
|
|
156
195
|
## Using SimSIMD in C
|
|
157
196
|
|
|
158
|
-
If you're aiming to utilize the `_Float16` functionality with SimSIMD, ensure your development environment is compatible with C 11. For other functionalities of SimSIMD, C 99 compatibility will suffice.
|
|
159
|
-
|
|
160
197
|
For integration within a CMake-based project, add the following segment to your `CMakeLists.txt`:
|
|
161
198
|
|
|
162
199
|
```cmake
|
|
@@ -166,12 +203,30 @@ FetchContent_Declare(
|
|
|
166
203
|
GIT_SHALLOW TRUE
|
|
167
204
|
)
|
|
168
205
|
FetchContent_MakeAvailable(simsimd)
|
|
169
|
-
include_directories(${simsimd_SOURCE_DIR}/include)
|
|
170
206
|
```
|
|
171
207
|
|
|
172
|
-
|
|
208
|
+
If you're aiming to utilize the `_Float16` functionality with SimSIMD, ensure your development environment is compatible with C 11.
|
|
209
|
+
For other functionalities of SimSIMD, C 99 compatibility will suffice.
|
|
210
|
+
A minimal usage example would be:
|
|
211
|
+
|
|
212
|
+
```c
|
|
213
|
+
#include <simsimd/simsimd.h>
|
|
214
|
+
|
|
215
|
+
int main() {
|
|
216
|
+
simsimd_f32_t vector_a[1536];
|
|
217
|
+
simsimd_f32_t vector_b[1536];
|
|
218
|
+
simsimd_f32_t distance = simsimd_avx512_f32_cos(vector_a, vector_b, 1536);
|
|
219
|
+
return 0;
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
All of the functions names follow the same pattern: `simsimd_{backend}_{type}_{metric}`.
|
|
173
224
|
|
|
174
|
-
|
|
225
|
+
- The backend can be `avx512`, `avx2`, `neon`, or `sve`.
|
|
226
|
+
- The type can be `f64`, `f32`, `f16`, `i8`, or `b8`.
|
|
227
|
+
- The metric can be `cos`, `ip`, `l2sq`, `hamming`, `jaccard`, `kl`, or `js`.
|
|
228
|
+
|
|
229
|
+
In case you want to avoid hard-coding the backend, you can use the `simsimd_metric_punned_t` to pun the function pointer, and `simsimd_capabilities` function to get the available backends at runtime.
|
|
175
230
|
|
|
176
231
|
## Benchmarking and Contributing
|
|
177
232
|
|
|
@@ -189,6 +244,9 @@ __To test and benchmark with Python bindings__:
|
|
|
189
244
|
```sh
|
|
190
245
|
pip install -e .
|
|
191
246
|
pytest python/test.py -s -x
|
|
247
|
+
|
|
248
|
+
pip install numpy scipy scikit-learn # for comparison baselines
|
|
249
|
+
python python/bench.py # to run default benchmarks
|
|
192
250
|
python python/bench.py --n 1000 --ndim 1000000 # batch size and dimensions
|
|
193
251
|
```
|
|
194
252
|
|
|
@@ -207,3 +265,11 @@ cd golang
|
|
|
207
265
|
go test # To test
|
|
208
266
|
go test -run=^$ -bench=. -benchmem # To benchmark
|
|
209
267
|
```
|
|
268
|
+
|
|
269
|
+
__To test and benchmark Rust bindings__:
|
|
270
|
+
|
|
271
|
+
```sh
|
|
272
|
+
cargo test
|
|
273
|
+
cargo bench
|
|
274
|
+
open ./target/criterion/report/index.html
|
|
275
|
+
```
|
package/simsimd/binding.gyp
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
+
"variables": {
|
|
3
|
+
"openssl_fips": ""
|
|
4
|
+
},
|
|
2
5
|
"targets": [
|
|
3
6
|
{
|
|
4
7
|
"target_name": "simsimd",
|
|
@@ -13,6 +16,21 @@
|
|
|
13
16
|
"-Wno-cast-function-type",
|
|
14
17
|
"-Wno-switch",
|
|
15
18
|
],
|
|
19
|
+
"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
|
+
]
|
|
16
34
|
}
|
|
17
35
|
]
|
|
18
36
|
}
|
package/simsimd/build.rs
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
fn main() {
|
|
2
|
+
cc::Build::new()
|
|
3
|
+
.file("rust/lib.c")
|
|
4
|
+
.include("include")
|
|
5
|
+
.flag("-O3")
|
|
6
|
+
.flag("-DSIMSIMD_NATIVE_F16=0")
|
|
7
|
+
.flag("-std=c99") // Enforce C99 standard
|
|
8
|
+
.flag("-pedantic") // Ensure strict compliance with the C standard
|
|
9
|
+
.warnings(false)
|
|
10
|
+
.compile("simsimd");
|
|
11
|
+
|
|
12
|
+
println!("cargo:rerun-if-changed=rust/lib.c");
|
|
13
|
+
println!("cargo:rerun-if-changed=rust/lib.rs");
|
|
14
|
+
println!("cargo:rerun-if-changed=include/simsimd/simsimd.h");
|
|
15
|
+
|
|
16
|
+
println!("cargo:rerun-if-changed=include/simsimd/binary.h");
|
|
17
|
+
println!("cargo:rerun-if-changed=include/simsimd/probability.h");
|
|
18
|
+
println!("cargo:rerun-if-changed=include/simsimd/spatial.h");
|
|
19
|
+
println!("cargo:rerun-if-changed=include/simsimd/types.h");
|
|
20
|
+
}
|
|
@@ -271,7 +271,7 @@ simsimd_avx2_f32_log2(__m256 x) {
|
|
|
271
271
|
__attribute__((target("avx2,f16c,fma"))) //
|
|
272
272
|
inline static simsimd_f32_t
|
|
273
273
|
simsimd_avx2_f16_kl(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n) {
|
|
274
|
-
__m256 sum_vec =
|
|
274
|
+
__m256 sum_vec = _mm256_setzero_ps();
|
|
275
275
|
simsimd_f32_t epsilon = SIMSIMD_F32_DIVISION_EPSILON;
|
|
276
276
|
__m256 epsilon_vec = _mm256_set1_ps(epsilon);
|
|
277
277
|
simsimd_size_t i = 0;
|
|
@@ -303,7 +303,7 @@ simsimd_avx2_f16_kl(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size
|
|
|
303
303
|
__attribute__((target("avx2,f16c,fma"))) //
|
|
304
304
|
inline static simsimd_f32_t
|
|
305
305
|
simsimd_avx2_f16_js(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n) {
|
|
306
|
-
__m256 sum_vec =
|
|
306
|
+
__m256 sum_vec = _mm256_setzero_ps();
|
|
307
307
|
simsimd_f32_t epsilon = SIMSIMD_F32_DIVISION_EPSILON;
|
|
308
308
|
__m256 epsilon_vec = _mm256_set1_ps(epsilon);
|
|
309
309
|
simsimd_size_t i = 0;
|
|
@@ -377,7 +377,7 @@ simsimd_avx512_f32_log2(__m512 x) {
|
|
|
377
377
|
__attribute__((target("avx512f,avx512vl,bmi2"))) //
|
|
378
378
|
inline static simsimd_f32_t
|
|
379
379
|
simsimd_avx512_f32_kl(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n) {
|
|
380
|
-
__m512 sum_vec =
|
|
380
|
+
__m512 sum_vec = _mm512_setzero();
|
|
381
381
|
simsimd_f32_t epsilon = SIMSIMD_F32_DIVISION_EPSILON;
|
|
382
382
|
__m512 epsilon_vec = _mm512_set1_ps(epsilon);
|
|
383
383
|
__m512 a_vec, b_vec;
|
|
@@ -407,8 +407,8 @@ simsimd_avx512_f32_kl_cycle:
|
|
|
407
407
|
__attribute__((target("avx512f,avx512vl,bmi2"))) //
|
|
408
408
|
inline static simsimd_f32_t
|
|
409
409
|
simsimd_avx512_f32_js(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n) {
|
|
410
|
-
__m512 sum_a_vec =
|
|
411
|
-
__m512 sum_b_vec =
|
|
410
|
+
__m512 sum_a_vec = _mm512_setzero();
|
|
411
|
+
__m512 sum_b_vec = _mm512_setzero();
|
|
412
412
|
simsimd_f32_t epsilon = SIMSIMD_F32_DIVISION_EPSILON;
|
|
413
413
|
__m512 epsilon_vec = _mm512_set1_ps(epsilon);
|
|
414
414
|
__m512 a_vec, b_vec;
|
|
@@ -11,8 +11,12 @@
|
|
|
11
11
|
* Detecting target CPU features at compile time: https://stackoverflow.com/a/28939692/2766161
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
#ifndef
|
|
15
|
-
#define
|
|
14
|
+
#ifndef SIMSIMD_H
|
|
15
|
+
#define SIMSIMD_H
|
|
16
|
+
|
|
17
|
+
#define SIMSIMD_VERSION_MAJOR 3
|
|
18
|
+
#define SIMSIMD_VERSION_MINOR 8
|
|
19
|
+
#define SIMSIMD_VERSION_PATCH 0
|
|
16
20
|
|
|
17
21
|
#include "binary.h" // Hamming, Jaccard
|
|
18
22
|
#include "probability.h" // Kullback-Leibler, Jensen–Shannon
|
|
@@ -65,7 +69,7 @@ typedef enum {
|
|
|
65
69
|
*/
|
|
66
70
|
typedef enum {
|
|
67
71
|
simsimd_cap_serial_k = 1, ///< Serial (non-SIMD) capability
|
|
68
|
-
simsimd_cap_any_k =
|
|
72
|
+
simsimd_cap_any_k = 0x7FFFFFFF, ///< Mask representing any capability with `INT_MAX`
|
|
69
73
|
|
|
70
74
|
simsimd_cap_arm_neon_k = 1 << 10, ///< ARM NEON capability
|
|
71
75
|
simsimd_cap_arm_sve_k = 1 << 11, ///< ARM SVE capability
|
|
@@ -108,11 +112,11 @@ typedef simsimd_f32_t (*simsimd_metric_punned_t)(void const* a, void const* b, s
|
|
|
108
112
|
* @brief Function to determine the SIMD capabilities of the current machine at @b runtime.
|
|
109
113
|
* @return A bitmask of the SIMD capabilities represented as a `simsimd_capability_t` enum value.
|
|
110
114
|
*/
|
|
111
|
-
inline static simsimd_capability_t simsimd_capabilities() {
|
|
115
|
+
inline static simsimd_capability_t simsimd_capabilities(void) {
|
|
112
116
|
|
|
113
117
|
#if SIMSIMD_TARGET_X86
|
|
114
118
|
|
|
115
|
-
/// The states of 4 registers populated for a specific "cpuid"
|
|
119
|
+
/// The states of 4 registers populated for a specific "cpuid" assembly call
|
|
116
120
|
union four_registers_t {
|
|
117
121
|
int array[4];
|
|
118
122
|
struct separate_t {
|
|
@@ -548,12 +548,11 @@ simsimd_sve_f64_cos(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size
|
|
|
548
548
|
// Avoid `simsimd_approximate_inverse_square_root` on Arm NEON
|
|
549
549
|
simsimd_f64_t a2_b2_arr[2] = {a2, b2};
|
|
550
550
|
float64x2_t a2_b2 = vld1q_f64(a2_b2_arr);
|
|
551
|
-
a2_b2 =
|
|
551
|
+
a2_b2 = vrsqrteq_f64(a2_b2);
|
|
552
552
|
vst1q_f64(a2_b2_arr, a2_b2);
|
|
553
553
|
return ab != 0 ? 1 - ab * a2_b2_arr[0] * a2_b2_arr[1] : 1;
|
|
554
554
|
}
|
|
555
555
|
|
|
556
|
-
|
|
557
556
|
#endif // SIMSIMD_TARGET_ARM_SVE
|
|
558
557
|
#endif // SIMSIMD_TARGET_ARM
|
|
559
558
|
|
|
@@ -574,7 +573,7 @@ simsimd_sve_f64_cos(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size
|
|
|
574
573
|
__attribute__((target("avx2,f16c,fma"))) //
|
|
575
574
|
inline static simsimd_f32_t
|
|
576
575
|
simsimd_avx2_f16_l2sq(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n) {
|
|
577
|
-
__m256 d2_vec =
|
|
576
|
+
__m256 d2_vec = _mm256_setzero_ps();
|
|
578
577
|
simsimd_size_t i = 0;
|
|
579
578
|
for (; i + 8 <= n; i += 8) {
|
|
580
579
|
__m256 a_vec = _mm256_cvtph_ps(_mm_loadu_si128((__m128i const*)(a + i)));
|
|
@@ -601,7 +600,7 @@ simsimd_avx2_f16_l2sq(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_si
|
|
|
601
600
|
__attribute__((target("avx2,f16c,fma"))) //
|
|
602
601
|
inline static simsimd_f32_t
|
|
603
602
|
simsimd_avx2_f16_ip(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n) {
|
|
604
|
-
__m256 ab_vec =
|
|
603
|
+
__m256 ab_vec = _mm256_setzero_ps();
|
|
605
604
|
simsimd_size_t i = 0;
|
|
606
605
|
for (; i + 8 <= n; i += 8) {
|
|
607
606
|
__m256 a_vec = _mm256_cvtph_ps(_mm_loadu_si128((__m128i const*)(a + i)));
|
|
@@ -625,7 +624,7 @@ __attribute__((target("avx2,f16c,fma"))) //
|
|
|
625
624
|
inline static simsimd_f32_t
|
|
626
625
|
simsimd_avx2_f16_cos(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n) {
|
|
627
626
|
|
|
628
|
-
__m256 ab_vec =
|
|
627
|
+
__m256 ab_vec = _mm256_setzero_ps(), a2_vec = _mm256_setzero_ps(), b2_vec = _mm256_setzero_ps();
|
|
629
628
|
simsimd_size_t i = 0;
|
|
630
629
|
for (; i + 8 <= n; i += 8) {
|
|
631
630
|
__m256 a_vec = _mm256_cvtph_ps(_mm_loadu_si128((__m128i const*)(a + i)));
|
|
@@ -814,7 +813,7 @@ simsimd_avx2_i8_ip(simsimd_i8_t const* a, simsimd_i8_t const* b, simsimd_size_t
|
|
|
814
813
|
__attribute__((target("avx512f,avx512vl,bmi2"))) //
|
|
815
814
|
inline static simsimd_f32_t
|
|
816
815
|
simsimd_avx512_f32_l2sq(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n) {
|
|
817
|
-
__m512 d2_vec =
|
|
816
|
+
__m512 d2_vec = _mm512_setzero();
|
|
818
817
|
__m512 a_vec, b_vec;
|
|
819
818
|
|
|
820
819
|
simsimd_avx512_f32_l2sq_cycle:
|
|
@@ -839,7 +838,7 @@ simsimd_avx512_f32_l2sq_cycle:
|
|
|
839
838
|
__attribute__((target("avx512f,avx512vl,bmi2"))) //
|
|
840
839
|
inline static simsimd_f32_t
|
|
841
840
|
simsimd_avx512_f32_ip(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n) {
|
|
842
|
-
__m512 ab_vec =
|
|
841
|
+
__m512 ab_vec = _mm512_setzero();
|
|
843
842
|
__m512 a_vec, b_vec;
|
|
844
843
|
|
|
845
844
|
simsimd_avx512_f32_ip_cycle:
|
|
@@ -863,9 +862,9 @@ simsimd_avx512_f32_ip_cycle:
|
|
|
863
862
|
__attribute__((target("avx512f,avx512vl,bmi2"))) //
|
|
864
863
|
inline static simsimd_f32_t
|
|
865
864
|
simsimd_avx512_f32_cos(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n) {
|
|
866
|
-
__m512 ab_vec =
|
|
867
|
-
__m512 a2_vec =
|
|
868
|
-
__m512 b2_vec =
|
|
865
|
+
__m512 ab_vec = _mm512_setzero();
|
|
866
|
+
__m512 a2_vec = _mm512_setzero();
|
|
867
|
+
__m512 b2_vec = _mm512_setzero();
|
|
869
868
|
__m512 a_vec, b_vec;
|
|
870
869
|
|
|
871
870
|
simsimd_avx512_f32_cos_cycle:
|
|
@@ -910,7 +909,7 @@ simsimd_avx512_f32_cos_cycle:
|
|
|
910
909
|
__attribute__((target("avx512fp16,avx512vl,avx512f,bmi2"))) //
|
|
911
910
|
inline static simsimd_f32_t
|
|
912
911
|
simsimd_avx512_f16_l2sq(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n) {
|
|
913
|
-
__m512h d2_vec =
|
|
912
|
+
__m512h d2_vec = _mm512_setzero_ph();
|
|
914
913
|
__m512i a_i16_vec, b_i16_vec;
|
|
915
914
|
|
|
916
915
|
simsimd_avx512_f16_l2sq_cycle:
|
|
@@ -935,7 +934,7 @@ simsimd_avx512_f16_l2sq_cycle:
|
|
|
935
934
|
__attribute__((target("avx512fp16,avx512vl,avx512f,bmi2"))) //
|
|
936
935
|
inline static simsimd_f32_t
|
|
937
936
|
simsimd_avx512_f16_ip(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n) {
|
|
938
|
-
__m512h ab_vec =
|
|
937
|
+
__m512h ab_vec = _mm512_setzero_ph();
|
|
939
938
|
__m512i a_i16_vec, b_i16_vec;
|
|
940
939
|
|
|
941
940
|
simsimd_avx512_f16_ip_cycle:
|
|
@@ -959,9 +958,9 @@ simsimd_avx512_f16_ip_cycle:
|
|
|
959
958
|
__attribute__((target("avx512fp16,avx512vl,avx512f,bmi2"))) //
|
|
960
959
|
inline static simsimd_f32_t
|
|
961
960
|
simsimd_avx512_f16_cos(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n) {
|
|
962
|
-
__m512h ab_vec =
|
|
963
|
-
__m512h a2_vec =
|
|
964
|
-
__m512h b2_vec =
|
|
961
|
+
__m512h ab_vec = _mm512_setzero_ph();
|
|
962
|
+
__m512h a2_vec = _mm512_setzero_ph();
|
|
963
|
+
__m512h b2_vec = _mm512_setzero_ph();
|
|
965
964
|
__m512i a_i16_vec, b_i16_vec;
|
|
966
965
|
|
|
967
966
|
simsimd_avx512_f16_cos_cycle:
|
|
@@ -1084,7 +1083,7 @@ simsimd_avx512_i8_ip(simsimd_i8_t const* a, simsimd_i8_t const* b, simsimd_size_
|
|
|
1084
1083
|
__attribute__((target("avx512f,avx512vl,bmi2"))) //
|
|
1085
1084
|
inline static simsimd_f32_t
|
|
1086
1085
|
simsimd_avx512_f64_l2sq(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n) {
|
|
1087
|
-
__m512d d2_vec =
|
|
1086
|
+
__m512d d2_vec = _mm512_setzero_pd();
|
|
1088
1087
|
__m512d a_vec, b_vec;
|
|
1089
1088
|
|
|
1090
1089
|
simsimd_avx512_f64_l2sq_cycle:
|
|
@@ -1109,7 +1108,7 @@ simsimd_avx512_f64_l2sq_cycle:
|
|
|
1109
1108
|
__attribute__((target("avx512f,avx512vl,bmi2"))) //
|
|
1110
1109
|
inline static simsimd_f32_t
|
|
1111
1110
|
simsimd_avx512_f64_ip(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n) {
|
|
1112
|
-
__m512d ab_vec =
|
|
1111
|
+
__m512d ab_vec = _mm512_setzero_pd();
|
|
1113
1112
|
__m512d a_vec, b_vec;
|
|
1114
1113
|
|
|
1115
1114
|
simsimd_avx512_f64_ip_cycle:
|
|
@@ -1133,9 +1132,9 @@ simsimd_avx512_f64_ip_cycle:
|
|
|
1133
1132
|
__attribute__((target("avx512f,avx512vl,bmi2"))) //
|
|
1134
1133
|
inline static simsimd_f32_t
|
|
1135
1134
|
simsimd_avx512_f64_cos(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n) {
|
|
1136
|
-
__m512d ab_vec =
|
|
1137
|
-
__m512d a2_vec =
|
|
1138
|
-
__m512d b2_vec =
|
|
1135
|
+
__m512d ab_vec = _mm512_setzero_pd();
|
|
1136
|
+
__m512d a2_vec = _mm512_setzero_pd();
|
|
1137
|
+
__m512d b2_vec = _mm512_setzero_pd();
|
|
1139
1138
|
__m512d a_vec, b_vec;
|
|
1140
1139
|
|
|
1141
1140
|
simsimd_avx512_f64_cos_cycle:
|
|
@@ -1173,4 +1172,4 @@ simsimd_avx512_f64_cos_cycle:
|
|
|
1173
1172
|
}
|
|
1174
1173
|
#endif
|
|
1175
1174
|
|
|
1176
|
-
#endif
|
|
1175
|
+
#endif
|
|
@@ -102,7 +102,7 @@ typedef signed char simsimd_i8_t;
|
|
|
102
102
|
typedef unsigned char simsimd_b8_t;
|
|
103
103
|
typedef unsigned long long simsimd_size_t;
|
|
104
104
|
|
|
105
|
-
#if !defined(SIMSIMD_NATIVE_F16)
|
|
105
|
+
#if !defined(SIMSIMD_NATIVE_F16) || SIMSIMD_NATIVE_F16
|
|
106
106
|
/**
|
|
107
107
|
* @brief Half-precision floating-point type.
|
|
108
108
|
*
|
|
@@ -112,12 +112,16 @@ typedef unsigned long long simsimd_size_t;
|
|
|
112
112
|
*/
|
|
113
113
|
#if (defined(__GNUC__) || defined(__clang__)) && (defined(__ARM_ARCH) || defined(__aarch64__)) && \
|
|
114
114
|
(defined(__ARM_FP16_FORMAT_IEEE))
|
|
115
|
+
#if !defined(SIMSIMD_NATIVE_F16)
|
|
115
116
|
#define SIMSIMD_NATIVE_F16 1
|
|
117
|
+
#endif
|
|
116
118
|
typedef __fp16 simsimd_f16_t;
|
|
117
119
|
#elif ((defined(__GNUC__) || defined(__clang__)) && (defined(__x86_64__) || defined(__i386__)) && \
|
|
118
120
|
(defined(__SSE2__) || defined(__AVX512F__)))
|
|
119
121
|
typedef _Float16 simsimd_f16_t;
|
|
122
|
+
#if !defined(SIMSIMD_NATIVE_F16)
|
|
120
123
|
#define SIMSIMD_NATIVE_F16 1
|
|
124
|
+
#endif
|
|
121
125
|
#else // Unknown compiler or architecture
|
|
122
126
|
#define SIMSIMD_NATIVE_F16 0
|
|
123
127
|
#endif // Unknown compiler or architecture
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const simsimd = bindings('simsimd');
|
|
1
|
+
const benchmark = require('benchmark');
|
|
2
|
+
const math = require('mathjs');
|
|
3
|
+
const usearch = require('usearch');
|
|
4
|
+
const MetricKind = usearch.MetricKind;
|
|
5
|
+
const simsimd = require("./dist/cjs/simsimd.js");
|
|
7
6
|
|
|
8
7
|
// Assuming the vectors are of the same length
|
|
9
8
|
function cosineDistance(a, b) {
|
|
@@ -29,6 +28,8 @@ function cosineDistanceMathJS(a, b) {
|
|
|
29
28
|
const dimensions = 1536; // Adjust dimensions as needed
|
|
30
29
|
const array1 = Array.from({ length: dimensions }, () => Math.random() * 100);
|
|
31
30
|
const array2 = Array.from({ length: dimensions }, () => Math.random() * 100);
|
|
31
|
+
const mathm1 = math.matrix(Array.from({ length: dimensions }, () => Math.random() * 100));
|
|
32
|
+
const mathm2 = math.matrix(Array.from({ length: dimensions }, () => Math.random() * 100));
|
|
32
33
|
const floatArray1 = new Float32Array(array1);
|
|
33
34
|
const floatArray2 = new Float32Array(array2);
|
|
34
35
|
const intArray1 = new Int8Array(array1);
|
|
@@ -65,8 +66,8 @@ singleSuite
|
|
|
65
66
|
.add('Array of Numbers with MathJS', () => {
|
|
66
67
|
cosineDistanceMathJS(array1, array2);
|
|
67
68
|
})
|
|
68
|
-
.add('
|
|
69
|
-
cosineDistanceMathJS(
|
|
69
|
+
.add('MathMatrix with MathJS', () => {
|
|
70
|
+
cosineDistanceMathJS(mathm1, mathm2);
|
|
70
71
|
})
|
|
71
72
|
|
|
72
73
|
// SimSIMD
|
|
@@ -78,7 +79,11 @@ singleSuite
|
|
|
78
79
|
})
|
|
79
80
|
|
|
80
81
|
.on('cycle', (event) => {
|
|
81
|
-
|
|
82
|
+
if (event.target.error) {
|
|
83
|
+
console.error(String(event.target.error));
|
|
84
|
+
} else {
|
|
85
|
+
console.log(String(event.target));
|
|
86
|
+
}
|
|
82
87
|
})
|
|
83
88
|
.on('complete', () => {
|
|
84
89
|
console.log('Fastest Single-Vector Processing is ' + singleSuite.filter('fastest').map('name'));
|
|
@@ -106,7 +111,11 @@ batchSuite
|
|
|
106
111
|
usearch.exactSearch(intMatrix1, intMatrix2, dimensions, 1, MetricKind.Cos);
|
|
107
112
|
})
|
|
108
113
|
.on('cycle', (event) => {
|
|
109
|
-
|
|
114
|
+
if (event.target.error) {
|
|
115
|
+
console.error(String(event.target.error));
|
|
116
|
+
} else {
|
|
117
|
+
console.log(String(event.target));
|
|
118
|
+
}
|
|
110
119
|
})
|
|
111
120
|
.on('complete', () => {
|
|
112
121
|
console.log('Fastest Batch-Vector Processing is ' + batchSuite.filter('fastest').map('name'));
|
|
@@ -115,3 +124,4 @@ batchSuite
|
|
|
115
124
|
noCache: true,
|
|
116
125
|
async: false,
|
|
117
126
|
});
|
|
127
|
+
|