usearch 2.8.14 → 2.8.16
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 +4 -4
- package/.github/workflows/release.yml +5 -2
- package/CITATION.cff +1 -1
- package/Cargo.toml +1 -1
- package/README.md +2 -2
- package/VERSION +1 -1
- package/conanfile.py +1 -1
- package/include/usearch/index.hpp +1 -1
- package/include/usearch/index_plugins.hpp +2 -1
- package/package.json +1 -1
- package/simsimd/README.md +55 -25
- package/simsimd/bench.js +51 -0
- package/simsimd/binding.gyp +18 -0
- package/simsimd/include/simsimd/probability.h +5 -5
- package/simsimd/include/simsimd/simsimd.h +6 -2
- package/simsimd/include/simsimd/spatial.h +19 -20
- 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/wasmer.toml +1 -1
- package/simsimd/javascript/simsimd.js +0 -45
- package/simsimd/javascript/test/simsimd.test.js +0 -47
|
@@ -59,7 +59,7 @@ jobs:
|
|
|
59
59
|
- name: Set up Node.js
|
|
60
60
|
uses: actions/setup-node@v3
|
|
61
61
|
with:
|
|
62
|
-
node-version:
|
|
62
|
+
node-version: 20
|
|
63
63
|
- name: Build JavaScript
|
|
64
64
|
run: npm install
|
|
65
65
|
- name: Test JavaScript
|
|
@@ -151,7 +151,7 @@ jobs:
|
|
|
151
151
|
- name: Set up Node.js
|
|
152
152
|
uses: actions/setup-node@v3
|
|
153
153
|
with:
|
|
154
|
-
node-version:
|
|
154
|
+
node-version: 20
|
|
155
155
|
- name: Build and test JavaScript
|
|
156
156
|
run: |
|
|
157
157
|
npm install
|
|
@@ -210,7 +210,7 @@ jobs:
|
|
|
210
210
|
- name: Set up Node.js
|
|
211
211
|
uses: actions/setup-node@v3
|
|
212
212
|
with:
|
|
213
|
-
node-version:
|
|
213
|
+
node-version: 20
|
|
214
214
|
- name: Build JavaScript
|
|
215
215
|
run: npm install
|
|
216
216
|
- name: Test JavaScript
|
|
@@ -272,7 +272,7 @@ jobs:
|
|
|
272
272
|
- name: Set up Node.js
|
|
273
273
|
uses: actions/setup-node@v3
|
|
274
274
|
with:
|
|
275
|
-
node-version:
|
|
275
|
+
node-version: 20
|
|
276
276
|
- name: Build JavaScript
|
|
277
277
|
run: npm install
|
|
278
278
|
- name: Test JavaScript
|
|
@@ -24,7 +24,10 @@ jobs:
|
|
|
24
24
|
- uses: actions/checkout@v3
|
|
25
25
|
with:
|
|
26
26
|
persist-credentials: false
|
|
27
|
-
-
|
|
27
|
+
- name: Set up Node.js
|
|
28
|
+
uses: actions/setup-node@v3
|
|
29
|
+
with:
|
|
30
|
+
node-version: 20
|
|
28
31
|
- run: npm install --save-dev --prefix ./package-ci @semantic-release/exec @semantic-release/git conventional-changelog-eslint semantic-release && npx --prefix ./package-ci semantic-release
|
|
29
32
|
|
|
30
33
|
rebase:
|
|
@@ -425,7 +428,7 @@ jobs:
|
|
|
425
428
|
- name: Set up Node.js
|
|
426
429
|
uses: actions/setup-node@v3
|
|
427
430
|
with:
|
|
428
|
-
node-version:
|
|
431
|
+
node-version: 20
|
|
429
432
|
|
|
430
433
|
- name: Build and Test
|
|
431
434
|
run: |
|
package/CITATION.cff
CHANGED
package/Cargo.toml
CHANGED
package/README.md
CHANGED
|
@@ -36,7 +36,7 @@ Linux • MacOS • Windows • iOS • WebAssembly
|
|
|
36
36
|
</p>
|
|
37
37
|
|
|
38
38
|
<div align="center">
|
|
39
|
-
<a href="https://pepy.tech/project/usearch"> <img alt="PyPI" src="https://static.pepy.tech/personalized-badge/usearch?period=
|
|
39
|
+
<a href="https://pepy.tech/project/usearch"> <img alt="PyPI" src="https://static.pepy.tech/personalized-badge/usearch?period=total&units=abbreviation&left_color=black&right_color=blue&left_text=USearch%20Python%20installs"> </a>
|
|
40
40
|
<a href="https://www.npmjs.com/package/usearch"> <img alt="NPM" src="https://img.shields.io/npm/dy/usearch?label=NPM%20installs"> </a>
|
|
41
41
|
<a href="https://crates.io/crates/usearch"> <img alt="Crate" src="https://img.shields.io/crates/d/usearch?label=Crate%20installs"> </a>
|
|
42
42
|
<a href="https://www.nuget.org/packages/Cloud.Unum.USearch"> <img alt="NuGet" src="https://img.shields.io/nuget/dt/Cloud.Unum.USearch?label=NuGet%20installs"> </a>
|
|
@@ -433,7 +433,7 @@ doi = {10.5281/zenodo.7949416},
|
|
|
433
433
|
author = {Vardanian, Ash},
|
|
434
434
|
title = {{USearch by Unum Cloud}},
|
|
435
435
|
url = {https://github.com/unum-cloud/usearch},
|
|
436
|
-
version = {2.8.
|
|
436
|
+
version = {2.8.16},
|
|
437
437
|
year = {2023},
|
|
438
438
|
month = oct,
|
|
439
439
|
}
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.8.
|
|
1
|
+
2.8.16
|
package/conanfile.py
CHANGED
|
@@ -7,7 +7,7 @@ required_conan_version = ">=1.53.0"
|
|
|
7
7
|
class USearchConan(ConanFile):
|
|
8
8
|
|
|
9
9
|
name = "usearch"
|
|
10
|
-
version = '2.8.
|
|
10
|
+
version = '2.8.16'
|
|
11
11
|
license = "Apache-2.0"
|
|
12
12
|
description = "Smaller & Faster Single-File Vector Search Engine from Unum"
|
|
13
13
|
homepage = "https://github.com/unum-cloud/usearch"
|
|
@@ -1345,8 +1345,9 @@ class metric_punned_t {
|
|
|
1345
1345
|
#if USEARCH_USE_SIMSIMD
|
|
1346
1346
|
if (!configure_with_simsimd())
|
|
1347
1347
|
configure_with_auto_vectorized();
|
|
1348
|
-
#
|
|
1348
|
+
#else
|
|
1349
1349
|
configure_with_auto_vectorized();
|
|
1350
|
+
#endif
|
|
1350
1351
|
|
|
1351
1352
|
if (scalar_kind == scalar_kind_t::b1x8_k)
|
|
1352
1353
|
raw_arg3_ = raw_arg4_ = divide_round_up<CHAR_BIT>(dimensions_);
|
package/package.json
CHANGED
package/simsimd/README.md
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
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
6
|
<img alt="GitHub code size in bytes" src="https://img.shields.io/github/languages/code-size/ashvardanian/simsimd">
|
|
7
7
|
</div>
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## Hardware-Accelerated Similarity Metrics and Distance Functions
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
- Zero-dependency [header-only C 99](#using-simsimd-in-c) library with bindings for [Python](#using-simsimd-in-python) and [JavaScript](#using-simsimd-in-javascript).
|
|
12
|
+
- Targets ARM NEON, SVE, x86 AVX2, AVX-512 (VNNI, FP16) hardware backends.
|
|
13
|
+
- Zero-copy compatible with NumPy, PyTorch, TensorFlow, and other tensors.
|
|
14
|
+
- Handles `f64` double-, `f32` single-, and `f16` half-precision, `i8` integral, and binary vectors.
|
|
15
|
+
- __Up to 200x faster__ than [`scipy.spatial.distance`][scipy] and [`numpy.inner`][numpy].
|
|
16
|
+
- Used in [USearch](https://github.com/unum-cloud/usearch) and several DBMS products.
|
|
12
17
|
|
|
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).
|
|
18
|
+
__Implemented distance functions__ include:
|
|
19
|
+
|
|
20
|
+
- Euclidean (L2), Inner Distance, and Cosine (Angular) spatial distances.
|
|
21
|
+
- Hamming (~ Manhattan) and Jaccard (~ Tanimoto) binary distances.
|
|
22
|
+
- Kullback-Leibler and Jensen–Shannon divergences for probability distributions.
|
|
23
23
|
|
|
24
24
|
[scipy]: https://docs.scipy.org/doc/scipy/reference/spatial.distance.html#module-scipy.spatial.distance
|
|
25
25
|
[numpy]: https://numpy.org/doc/stable/reference/generated/numpy.inner.html
|
|
@@ -43,18 +43,18 @@ Given 1000 embeddings from OpenAI Ada API with 1536 dimensions, running on the A
|
|
|
43
43
|
| :------------- | ----------------: | ----------------: | ---------------: | :------------------------------------- | :-------------- |
|
|
44
44
|
| Cosine | __32 x__ | __79 x__ | __133 x__ | `scipy.spatial.distance.cosine` | `cosine` |
|
|
45
45
|
| Euclidean ² | __5 x__ | __26 x__ | __17 x__ | `scipy.spatial.distance.sqeuclidean` | `sqeuclidean` |
|
|
46
|
-
| Inner
|
|
46
|
+
| Inner Distance | __2 x__ | __9 x__ | __18 x__ | `numpy.inner` | `inner` |
|
|
47
47
|
| Jensen Shannon | __31 x__ | __53 x__ | | `scipy.spatial.distance.jensenshannon` | `jensenshannon` |
|
|
48
48
|
|
|
49
49
|
### Intel Sapphire Rapids
|
|
50
50
|
|
|
51
|
-
On the Intel Sapphire Rapids platform, SimSIMD was benchmarked against auto-vectorized code using GCC 12. GCC handles single-precision `float
|
|
51
|
+
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
52
|
|
|
53
53
|
| Kind | GCC 12 `f32` | GCC 12 `f16` | SimSIMD `f16` | `f16` improvement |
|
|
54
54
|
| :------------- | -----------: | -----------: | ------------: | ----------------: |
|
|
55
55
|
| Cosine | 3.28 M/s | _336.29 k/s_ | _6.88 M/s_ | __20 x__ |
|
|
56
56
|
| Euclidean ² | 4.62 M/s | _147.25 k/s_ | _5.32 M/s_ | __36 x__ |
|
|
57
|
-
| Inner
|
|
57
|
+
| Inner Distance | 3.81 M/s | _192.02 k/s_ | _5.99 M/s_ | __31 x__ |
|
|
58
58
|
| Jensen Shannon | 1.18 M/s | _18.13 k/s_ | _2.14 M/s_ | __118 x__ |
|
|
59
59
|
|
|
60
60
|
__Broader Benchmarking Results__:
|
|
@@ -63,7 +63,7 @@ __Broader Benchmarking Results__:
|
|
|
63
63
|
- [4th Gen Intel Xeon Platinum](https://ashvardanian.com/posts/simsimd-faster-scipy/#appendix-2-performance-on-4th-gen-intel-xeon-platinum-8480).
|
|
64
64
|
- [AWS Graviton 3](https://ashvardanian.com/posts/simsimd-faster-scipy/#appendix-3-performance-on-aws-graviton-3).
|
|
65
65
|
|
|
66
|
-
## Using in Python
|
|
66
|
+
## Using SimSIMD in Python
|
|
67
67
|
|
|
68
68
|
### Installation
|
|
69
69
|
|
|
@@ -92,7 +92,7 @@ batch2 = np.random.randn(100, 1536).astype(np.float32)
|
|
|
92
92
|
dist = simsimd.cosine(batch1, batch2)
|
|
93
93
|
```
|
|
94
94
|
|
|
95
|
-
If either batch has more than one vector, the other batch must have one or same number of vectors.
|
|
95
|
+
If either batch has more than one vector, the other batch must have one or the same number of vectors.
|
|
96
96
|
If it contains just one, the value is broadcasted.
|
|
97
97
|
|
|
98
98
|
### All Pairwise Distances
|
|
@@ -124,7 +124,7 @@ print(simsimd.get_capabilities())
|
|
|
124
124
|
### Using Python API with USearch
|
|
125
125
|
|
|
126
126
|
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
|
|
127
|
+
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
128
|
|
|
129
129
|
```py
|
|
130
130
|
from usearch.index import Index, CompiledMetric, MetricKind, MetricSignature
|
|
@@ -141,7 +141,18 @@ index = Index(256, metric=metric)
|
|
|
141
141
|
|
|
142
142
|
## Using SimSIMD in JavaScript
|
|
143
143
|
|
|
144
|
-
|
|
144
|
+
To install, choose one of the following options depending on your environment:
|
|
145
|
+
|
|
146
|
+
- `npm install --save simsimd`
|
|
147
|
+
- `yarn add simsimd`
|
|
148
|
+
- `pnpm add simsimd`
|
|
149
|
+
- `bun install simsimd`
|
|
150
|
+
|
|
151
|
+
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).
|
|
152
|
+
|
|
153
|
+
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.
|
|
154
|
+
|
|
155
|
+
After you install it, you will be able to call the SimSIMD functions on various `TypedArray` variants:
|
|
145
156
|
|
|
146
157
|
```js
|
|
147
158
|
const { sqeuclidean, cosine, inner, hamming, jaccard } = require('simsimd');
|
|
@@ -155,8 +166,6 @@ console.log('Squared Euclidean Distance:', distance);
|
|
|
155
166
|
|
|
156
167
|
## Using SimSIMD in C
|
|
157
168
|
|
|
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
169
|
For integration within a CMake-based project, add the following segment to your `CMakeLists.txt`:
|
|
161
170
|
|
|
162
171
|
```cmake
|
|
@@ -166,12 +175,30 @@ FetchContent_Declare(
|
|
|
166
175
|
GIT_SHALLOW TRUE
|
|
167
176
|
)
|
|
168
177
|
FetchContent_MakeAvailable(simsimd)
|
|
169
|
-
include_directories(${simsimd_SOURCE_DIR}/include)
|
|
170
178
|
```
|
|
171
179
|
|
|
172
|
-
|
|
180
|
+
If you're aiming to utilize the `_Float16` functionality with SimSIMD, ensure your development environment is compatible with C 11.
|
|
181
|
+
For other functionalities of SimSIMD, C 99 compatibility will suffice.
|
|
182
|
+
A minimal usage example would be:
|
|
173
183
|
|
|
174
|
-
|
|
184
|
+
```c
|
|
185
|
+
#include <simsimd/simsimd.h>
|
|
186
|
+
|
|
187
|
+
int main() {
|
|
188
|
+
simsimd_f32_t vector_a[1536];
|
|
189
|
+
simsimd_f32_t vector_b[1536];
|
|
190
|
+
simsimd_f32_t distance = simsimd_avx512_f32_cos(vector_a, vector_b, 1536);
|
|
191
|
+
return 0;
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
All of the functions names follow the same pattern: `simsimd_{backend}_{type}_{metric}`.
|
|
196
|
+
|
|
197
|
+
- The backend can be `avx512`, `avx2`, `neon`, or `sve`.
|
|
198
|
+
- The type can be `f64`, `f32`, `f16`, `i8`, or `b8`.
|
|
199
|
+
- The metric can be `cos`, `ip`, `l2sq`, `hamming`, `jaccard`, `kl`, or `js`.
|
|
200
|
+
|
|
201
|
+
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
202
|
|
|
176
203
|
## Benchmarking and Contributing
|
|
177
204
|
|
|
@@ -189,6 +216,9 @@ __To test and benchmark with Python bindings__:
|
|
|
189
216
|
```sh
|
|
190
217
|
pip install -e .
|
|
191
218
|
pytest python/test.py -s -x
|
|
219
|
+
|
|
220
|
+
pip install numpy scipy scikit-learn # for comparison baselines
|
|
221
|
+
python python/bench.py # to run default benchmarks
|
|
192
222
|
python python/bench.py --n 1000 --ndim 1000000 # batch size and dimensions
|
|
193
223
|
```
|
|
194
224
|
|
package/simsimd/bench.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
const benchmark = require('benchmark');
|
|
2
|
+
|
|
3
|
+
// Assuming the vectors are of the same length
|
|
4
|
+
function cosineDistance(a, b) {
|
|
5
|
+
let dotProduct = 0;
|
|
6
|
+
let magA = 0;
|
|
7
|
+
let magB = 0;
|
|
8
|
+
for (let i = 0; i < a.length; i++) {
|
|
9
|
+
dotProduct += a[i] * b[i];
|
|
10
|
+
magA += a[i] * a[i];
|
|
11
|
+
magB += b[i] * b[i];
|
|
12
|
+
}
|
|
13
|
+
return 1 - (dotProduct / (Math.sqrt(magA) * Math.sqrt(magB)));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
// Generate random data for testing
|
|
18
|
+
const dimensions = 1536; // Adjust dimensions as needed
|
|
19
|
+
const array1 = Array.from({ length: dimensions }, () => Math.random() * 100);
|
|
20
|
+
const array2 = Array.from({ length: dimensions }, () => Math.random() * 100);
|
|
21
|
+
const floatArray1 = new Float32Array(array1);
|
|
22
|
+
const floatArray2 = new Float32Array(array2);
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
// Create benchmark suite
|
|
26
|
+
const singleSuite = new benchmark.Suite('Single Vector Processing');
|
|
27
|
+
|
|
28
|
+
// Single-vector processing benchmarks
|
|
29
|
+
singleSuite
|
|
30
|
+
|
|
31
|
+
// Pure JavaScript
|
|
32
|
+
.add('Array of Numbers', () => {
|
|
33
|
+
cosineDistance(array1, array2);
|
|
34
|
+
})
|
|
35
|
+
.add('TypedArray of Float32', () => {
|
|
36
|
+
cosineDistance(floatArray1, floatArray2);
|
|
37
|
+
})
|
|
38
|
+
.on('cycle', (event) => {
|
|
39
|
+
if (event.target.error) {
|
|
40
|
+
console.error(String(event.target.error));
|
|
41
|
+
} else {
|
|
42
|
+
console.log(String(event.target));
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
.on('complete', () => {
|
|
46
|
+
console.log('Fastest Single-Vector Processing is ' + singleSuite.filter('fastest').map('name'));
|
|
47
|
+
})
|
|
48
|
+
.run({
|
|
49
|
+
noCache: true,
|
|
50
|
+
async: false,
|
|
51
|
+
});
|
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
|
}
|
|
@@ -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 6
|
|
19
|
+
#define SIMSIMD_VERSION_PATCH 0
|
|
16
20
|
|
|
17
21
|
#include "binary.h" // Hamming, Jaccard
|
|
18
22
|
#include "probability.h" // Kullback-Leibler, Jensen–Shannon
|
|
@@ -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:
|
|
@@ -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
|
+
|