usearch 2.8.7 → 2.8.9
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/CITATION.cff +1 -1
- package/CMakeLists.txt +3 -3
- package/CONTRIBUTING.md +26 -3
- package/Cargo.toml +1 -1
- package/Dockerfile +16 -0
- package/README.md +41 -38
- package/VERSION +1 -0
- package/binding.gyp +57 -8
- package/conanfile.py +1 -1
- package/include/usearch/index.hpp +1 -1
- package/include/usearch/index_plugins.hpp +28 -24
- package/javascript/README.md +64 -12
- package/javascript/lib.cpp +11 -3
- package/javascript/usearch.js +4 -2
- package/javascript/usearch.test.js +15 -0
- package/package.json +1 -2
- package/setup.py +76 -15
- package/simsimd/README.md +14 -13
- package/simsimd/include/simsimd/probability.h +2 -2
- package/simsimd/package.json +1 -1
- package/wasmer.toml +1 -1
- package/. npmignore +0 -14
- package/.gitignore +0 -95
- package/.vscode/launch.json +0 -181
- package/.vscode/settings.json +0 -180
- package/.vscode/tasks.json +0 -71
- package/Package.swift +0 -41
- package/csharp/.editorconfig +0 -361
- package/csharp/Cloud.Unum.USearch.sln +0 -34
- package/csharp/DEV_SETUP.md +0 -51
- package/csharp/Directory.Build.props +0 -29
- package/csharp/README.md +0 -74
- package/csharp/build_and_test.cmd +0 -31
- package/csharp/build_and_test.sh +0 -30
- package/csharp/nuget/nuget-package.props +0 -33
- package/csharp/pack.sh +0 -56
- package/csharp/src/Cloud.Unum.USearch.Tests/Cloud.Unum.USearch.Tests.csproj +0 -39
- package/csharp/src/Cloud.Unum.USearch.Tests/USearchIndexTests.cs +0 -1013
- package/csharp/src/Cloud.Unum.USearch.Tests/Usings.cs +0 -1
- package/docs/_static/custom.css +0 -26
- package/docs/_static/custom.js +0 -7
- package/docs/benchmarks.md +0 -245
- package/docs/benchmarks.rst +0 -5
- package/docs/c/index.rst +0 -11
- package/docs/c/reference.rst +0 -7
- package/docs/conf.dox +0 -2668
- package/docs/conf.py +0 -53
- package/docs/contributing.rst +0 -5
- package/docs/cpp/index.rst +0 -11
- package/docs/cpp/reference.rst +0 -17
- package/docs/csharp/index.rst +0 -6
- package/docs/format.md +0 -86
- package/docs/format.rst +0 -5
- package/docs/golang/index.rst +0 -6
- package/docs/index.rst +0 -33
- package/docs/java/index.rst +0 -11
- package/docs/java/reference.rst +0 -7
- package/docs/javascript/index.rst +0 -11
- package/docs/javascript/reference.rst +0 -12
- package/docs/python/index.rst +0 -11
- package/docs/python/reference.rst +0 -42
- package/docs/rust/index.rst +0 -6
- package/docs/swift/index.rst +0 -6
- package/docs/wolfram/index.rst +0 -6
- package/golang/README.md +0 -95
- package/golang/go.mod +0 -3
- package/golang/lib.go +0 -379
- package/golang/lib_test.go +0 -108
- package/java/README.md +0 -22
- package/java/cloud/unum/usearch/Index.java +0 -337
- package/java/cloud/unum/usearch/cloud_unum_usearch_Index.cpp +0 -197
- package/java/cloud/unum/usearch/cloud_unum_usearch_Index.h +0 -125
- package/java/test/IndexTest.java +0 -30
- package/objc/USearchObjective.mm +0 -299
- package/objc/include/USearchObjective.h +0 -154
- package/python/README.md +0 -292
- package/python/lib.cpp +0 -1216
- package/python/scripts/bench.ipynb +0 -193
- package/python/scripts/bench.py +0 -137
- package/python/scripts/bench_exact.py +0 -44
- package/python/scripts/cluster.ipynb +0 -160
- package/python/scripts/index_faiss.py +0 -100
- package/python/scripts/join.py +0 -155
- package/python/scripts/test_index.py +0 -247
- package/python/scripts/test_jit.py +0 -231
- package/python/scripts/test_sparse.py +0 -32
- package/python/scripts/test_tooling.py +0 -133
- package/python/usearch/__init__.py +0 -0
- package/python/usearch/client.py +0 -124
- package/python/usearch/eval.py +0 -470
- package/python/usearch/index.py +0 -1401
- package/python/usearch/io.py +0 -113
- package/python/usearch/numba.py +0 -121
- package/python/usearch/server.py +0 -137
- package/rust/README.md +0 -66
- package/rust/lib.cpp +0 -136
- package/rust/lib.hpp +0 -69
- package/rust/lib.rs +0 -610
- package/simsimd/CMakeLists.txt +0 -67
- package/simsimd/cpp/bench.cxx +0 -206
- package/simsimd/package-ci.json +0 -10
- package/simsimd/setup.py +0 -86
- package/swift/Index+Sugar.swift +0 -153
- package/swift/README.md +0 -48
- package/swift/Test.swift +0 -37
- package/swift/USearch.swift +0 -8
- package/wasm/CMakeLists.txt +0 -7
- package/wasm/README.md +0 -13
- package/wasm/lib.cpp +0 -5
- package/wolfram/CMakeLists.txt +0 -18
- package/wolfram/README.md +0 -13
- package/wolfram/lib.cpp +0 -160
- package/wolfram/test.wls +0 -27
package/javascript/README.md
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
# USearch for JavaScript
|
|
2
2
|
|
|
3
|
+
USearch is a high-performance library for building and querying vector search indexes, optimized for Node.js and WASM environments.
|
|
4
|
+
|
|
3
5
|
## Installation
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
For the first option, use the conventional `npm install`:
|
|
7
|
+
For Node.js environments, install USearch using `npm`:
|
|
7
8
|
|
|
8
9
|
```sh
|
|
9
10
|
npm install usearch
|
|
10
11
|
```
|
|
11
12
|
|
|
12
|
-
For
|
|
13
|
+
For front-end applications using WASM, use the Wasmer package manager:
|
|
13
14
|
|
|
14
15
|
```sh
|
|
15
16
|
wasmer install unum/usearch
|
|
@@ -17,20 +18,71 @@ wasmer install unum/usearch
|
|
|
17
18
|
|
|
18
19
|
## Quickstart
|
|
19
20
|
|
|
21
|
+
Create an index, add vectors, and perform searches with ease:
|
|
22
|
+
|
|
20
23
|
```js
|
|
21
|
-
|
|
22
|
-
index.
|
|
23
|
-
|
|
24
|
+
const usearch = require('usearch');
|
|
25
|
+
const index = new usearch.Index({ metric: 'cos', connectivity: 16, dimensions: 3 });
|
|
26
|
+
index.add(42n, new Float32Array([0.2, 0.6, 0.4]));
|
|
27
|
+
const results = index.search(new Float32Array([0.2, 0.6, 0.4]), 10);
|
|
28
|
+
|
|
29
|
+
assert(index.size() === 1);
|
|
30
|
+
assert.deepEqual(results.keys, new BigUint64Array([42n]));
|
|
31
|
+
assert.deepEqual(results.distances, new Float32Array([0]));
|
|
24
32
|
|
|
25
|
-
|
|
26
|
-
assert.deepEqual(results.keys, new BigUint64Array([42n]))
|
|
27
|
-
assert.deepEqual(results.distances, new Float32Array([0]))
|
|
33
|
+
index.remove(42n);
|
|
28
34
|
```
|
|
29
35
|
|
|
30
36
|
## Serialization
|
|
31
37
|
|
|
38
|
+
Persist and restore your index with serialization methods:
|
|
39
|
+
|
|
40
|
+
```js
|
|
41
|
+
index.save('index.usearch'); // Save the index to a file
|
|
42
|
+
index.load('index.usearch'); // Load the index from a file
|
|
43
|
+
index.view('index.usearch'); // View the index from a file without loading into memory
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Advanced Index Configuration
|
|
47
|
+
|
|
48
|
+
Customize your index with additional configuration options:
|
|
49
|
+
|
|
50
|
+
```js
|
|
51
|
+
const index = new usearch.Index({
|
|
52
|
+
dimensions: 128,
|
|
53
|
+
metric: 'ip',
|
|
54
|
+
quantization: 'f32',
|
|
55
|
+
connectivity: 10,
|
|
56
|
+
expansion_add: 5,
|
|
57
|
+
expansion_search: 3,
|
|
58
|
+
multi: true
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Batch Operations
|
|
63
|
+
|
|
64
|
+
Process multiple vectors at once for efficiency.
|
|
65
|
+
For performance reasons we prefer a flattened `TypedArray` over an Array of Arrays:
|
|
66
|
+
|
|
67
|
+
```js
|
|
68
|
+
const keys = new BigUint64Array([15n, 16n]);
|
|
69
|
+
const vectors = new Float32Array([10, 20, 10, 25]);
|
|
70
|
+
index.add(keys, vectors);
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Retrieve batch search results:
|
|
74
|
+
|
|
75
|
+
```js
|
|
76
|
+
const batchResults = index.search(vectors, 2);
|
|
77
|
+
const firstMatch = batchResults.get(0);
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Index Introspection
|
|
81
|
+
|
|
82
|
+
Inspect and interact with the index:
|
|
83
|
+
|
|
32
84
|
```js
|
|
33
|
-
index.
|
|
34
|
-
index.
|
|
35
|
-
index.
|
|
85
|
+
const dimensions = index.dimensions(); // Get the number of dimensions
|
|
86
|
+
const containsKey = index.contains(42n); // Check if a key is in the index
|
|
87
|
+
const count = index.count(42n); // Get the count of vectors for a key
|
|
36
88
|
```
|
package/javascript/lib.cpp
CHANGED
|
@@ -181,7 +181,7 @@ Napi::Value CompiledIndex::Search(Napi::CallbackInfo const& ctx) {
|
|
|
181
181
|
std::size_t tasks = queries.ElementLength() / native_->dimensions();
|
|
182
182
|
std::size_t wanted = napi_argument_to_size(ctx[1]);
|
|
183
183
|
|
|
184
|
-
auto run_parallel = [&](auto vectors) {
|
|
184
|
+
auto run_parallel = [&](auto vectors) -> Napi::Value {
|
|
185
185
|
Napi::Array result_js = Napi::Array::New(env, 3);
|
|
186
186
|
Napi::BigUint64Array matches_js = Napi::BigUint64Array::New(env, tasks * wanted);
|
|
187
187
|
Napi::Float32Array distances_js = Napi::Float32Array::New(env, tasks * wanted);
|
|
@@ -192,21 +192,29 @@ Napi::Value CompiledIndex::Search(Napi::CallbackInfo const& ctx) {
|
|
|
192
192
|
auto counts_data = counts_js.Data();
|
|
193
193
|
|
|
194
194
|
try {
|
|
195
|
+
bool failed = false;
|
|
195
196
|
executor_stl_t executor;
|
|
196
197
|
executor.fixed(tasks, [&](std::size_t /*thread_idx*/, std::size_t task_idx) {
|
|
197
198
|
auto result = native_->search(vectors + task_idx * native_->dimensions(), wanted);
|
|
198
199
|
if (!result) {
|
|
199
|
-
|
|
200
|
-
|
|
200
|
+
failed = true;
|
|
201
|
+
Napi::TypeError::New(env, result.error.release()).ThrowAsJavaScriptException();
|
|
201
202
|
} else {
|
|
202
203
|
counts_data[task_idx] = result.dump_to(matches_data + task_idx * native_->dimensions(),
|
|
203
204
|
distances_data + task_idx * native_->dimensions());
|
|
204
205
|
}
|
|
205
206
|
});
|
|
207
|
+
|
|
208
|
+
if (failed)
|
|
209
|
+
return env.Null();
|
|
210
|
+
|
|
206
211
|
} catch (std::bad_alloc const&) {
|
|
207
212
|
Napi::TypeError::New(env, "Out of memory").ThrowAsJavaScriptException();
|
|
213
|
+
return env.Null();
|
|
214
|
+
|
|
208
215
|
} catch (...) {
|
|
209
216
|
Napi::TypeError::New(env, "Search failed").ThrowAsJavaScriptException();
|
|
217
|
+
return env.Null();
|
|
210
218
|
}
|
|
211
219
|
|
|
212
220
|
result_js.Set(0u, matches_js);
|
package/javascript/usearch.js
CHANGED
|
@@ -247,10 +247,12 @@ class Index {
|
|
|
247
247
|
// Call the compiled method and create Matches or BatchMatches object with the result
|
|
248
248
|
const result = this._compiledIndex.search(normalizedVectors, k);
|
|
249
249
|
const countInQueries = normalizedVectors.length / Number(this._compiledIndex.dimensions());
|
|
250
|
+
const batchMatches = new BatchMatches(result[0], result[1], result[2], k);
|
|
251
|
+
|
|
250
252
|
if (countInQueries === 1) {
|
|
251
|
-
return
|
|
253
|
+
return batchMatches.get(0);
|
|
252
254
|
} else {
|
|
253
|
-
return
|
|
255
|
+
return batchMatches;
|
|
254
256
|
}
|
|
255
257
|
}
|
|
256
258
|
|
|
@@ -36,6 +36,21 @@ test('Batch operations', () => {
|
|
|
36
36
|
assert.deepEqual(results.distances, new Float32Array([45, 130]), 'distances should be 45 and 130');
|
|
37
37
|
});
|
|
38
38
|
|
|
39
|
+
test("Expected results", () => {
|
|
40
|
+
var index = new usearch.Index({
|
|
41
|
+
metric: "cos",
|
|
42
|
+
connectivity: 16,
|
|
43
|
+
dimensions: 3,
|
|
44
|
+
});
|
|
45
|
+
index.add(42n, new Float32Array([0.2, 0.6, 0.4]));
|
|
46
|
+
var results = index.search(new Float32Array([0.2, 0.6, 0.4]), 10);
|
|
47
|
+
|
|
48
|
+
assert.equal(index.size(), 1);
|
|
49
|
+
assert.deepEqual(results.keys, new BigUint64Array([42n]));
|
|
50
|
+
assert.deepEqual(results.distances, new Float32Array([0]));
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
|
|
39
54
|
|
|
40
55
|
test('Operations with invalid values', () => {
|
|
41
56
|
const indexBatch = new usearch.Index(2, 'l2sq');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "usearch",
|
|
3
|
-
"version": "2.8.
|
|
3
|
+
"version": "2.8.9",
|
|
4
4
|
"description": "Smaller & Faster Single-File Vector Search Engine from Unum",
|
|
5
5
|
"author": "Ash Vardanian (https://ashvardanian.com/)",
|
|
6
6
|
"license": "Apache 2.0",
|
|
@@ -24,7 +24,6 @@
|
|
|
24
24
|
"node-addon-api": "^3.0.0"
|
|
25
25
|
},
|
|
26
26
|
"scripts": {
|
|
27
|
-
"preinstall": "git submodule update --init --recursive",
|
|
28
27
|
"test": "node --test ./javascript/usearch.test.js",
|
|
29
28
|
"install": "node-gyp rebuild"
|
|
30
29
|
},
|
package/setup.py
CHANGED
|
@@ -5,19 +5,49 @@ from setuptools import setup
|
|
|
5
5
|
|
|
6
6
|
from pybind11.setup_helpers import Pybind11Extension
|
|
7
7
|
|
|
8
|
-
|
|
9
8
|
compile_args = []
|
|
10
9
|
link_args = []
|
|
11
10
|
macros_args = []
|
|
12
11
|
|
|
13
|
-
|
|
12
|
+
|
|
13
|
+
def get_bool_env(name: str, preference: bool) -> bool:
|
|
14
|
+
return os.environ.get(name, "1" if preference else "0") == "1"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_bool_env_w_name(name: str, preference: bool) -> bool:
|
|
18
|
+
return name, get_bool_env(name, preference)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def get_is_gcc():
|
|
14
22
|
try:
|
|
15
|
-
compiler_version = subprocess.check_output(
|
|
23
|
+
compiler_version = subprocess.check_output(
|
|
24
|
+
["c++", "--version"], universal_newlines=True
|
|
25
|
+
)
|
|
16
26
|
return "gcc" in compiler_version.lower()
|
|
17
27
|
except Exception:
|
|
18
28
|
return False
|
|
19
29
|
|
|
20
|
-
|
|
30
|
+
|
|
31
|
+
# Check the environment variables
|
|
32
|
+
is_linux: bool = sys.platform == "linux"
|
|
33
|
+
is_macos: bool = sys.platform == "darwin"
|
|
34
|
+
is_windows: bool = sys.platform == "win32"
|
|
35
|
+
|
|
36
|
+
prefer_simsimd: bool = is_linux or is_macos
|
|
37
|
+
prefer_fp16lib: bool = True
|
|
38
|
+
prefer_openmp: bool = is_linux and get_is_gcc()
|
|
39
|
+
|
|
40
|
+
use_simsimd: bool = get_bool_env("USEARCH_USE_SIMSIMD", prefer_simsimd)
|
|
41
|
+
use_fp16lib: bool = get_bool_env("USEARCH_USE_FP16LIB", prefer_fp16lib)
|
|
42
|
+
use_openmp: bool = get_bool_env("USEARCH_USE_OPENMP", prefer_openmp)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
# Common arguments for all platforms
|
|
46
|
+
macros_args.append(("USEARCH_USE_OPENMP", "1" if use_openmp else "0"))
|
|
47
|
+
macros_args.append(("USEARCH_USE_SIMSIMD", "1" if use_simsimd else "0"))
|
|
48
|
+
macros_args.append(("USEARCH_USE_FP16LIB", "1" if use_fp16lib else "0"))
|
|
49
|
+
|
|
50
|
+
if is_linux:
|
|
21
51
|
compile_args.append("-std=c++17")
|
|
22
52
|
compile_args.append("-O3") # Maximize performance
|
|
23
53
|
compile_args.append("-ffast-math") # Maximize floating-point performance
|
|
@@ -27,17 +57,21 @@ if sys.platform == "linux":
|
|
|
27
57
|
# Simplify debugging, but the normal `-g` may make builds much longer!
|
|
28
58
|
compile_args.append("-g1")
|
|
29
59
|
|
|
30
|
-
|
|
31
|
-
macros_args.append(("USEARCH_USE_SIMSIMD", "1"))
|
|
32
|
-
|
|
33
|
-
if is_gcc():
|
|
34
|
-
macros_args.append(("USEARCH_USE_OPENMP", "1"))
|
|
60
|
+
if use_openmp:
|
|
35
61
|
compile_args.append("-fopenmp")
|
|
36
62
|
link_args.append("-lgomp")
|
|
37
|
-
else:
|
|
38
|
-
macros_args.append(("USEARCH_USE_OPENMP", "0"))
|
|
39
63
|
|
|
40
|
-
if
|
|
64
|
+
if use_simsimd:
|
|
65
|
+
macros_args.extend(
|
|
66
|
+
[
|
|
67
|
+
get_bool_env_w_name("SIMSIMD_TARGET_X86_AVX512", True),
|
|
68
|
+
get_bool_env_w_name("SIMSIMD_TARGET_ARM_SVE", True),
|
|
69
|
+
get_bool_env_w_name("SIMSIMD_TARGET_X86_AVX2", True),
|
|
70
|
+
get_bool_env_w_name("SIMSIMD_TARGET_ARM_NEON", True),
|
|
71
|
+
]
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
if is_macos:
|
|
41
75
|
# MacOS 10.15 or higher is needed for `aligned_alloc` support.
|
|
42
76
|
# https://github.com/unum-cloud/usearch/actions/runs/4975434891/jobs/8902603392
|
|
43
77
|
compile_args.append("-mmacosx-version-min=10.15")
|
|
@@ -61,12 +95,34 @@ if sys.platform == "darwin":
|
|
|
61
95
|
# link_args.append("-lomp")
|
|
62
96
|
# macros_args.append(("USEARCH_USE_OPENMP", "1"))
|
|
63
97
|
|
|
64
|
-
if
|
|
98
|
+
if use_simsimd:
|
|
99
|
+
macros_args.extend(
|
|
100
|
+
[
|
|
101
|
+
get_bool_env_w_name("SIMSIMD_TARGET_X86_AVX512", False),
|
|
102
|
+
get_bool_env_w_name("SIMSIMD_TARGET_ARM_SVE", False),
|
|
103
|
+
get_bool_env_w_name("SIMSIMD_TARGET_X86_AVX2", True),
|
|
104
|
+
get_bool_env_w_name("SIMSIMD_TARGET_ARM_NEON", True),
|
|
105
|
+
]
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
if is_windows:
|
|
65
109
|
compile_args.append("/std:c++17")
|
|
66
110
|
compile_args.append("/O2")
|
|
67
111
|
compile_args.append("/fp:fast") # Enable fast math for MSVC
|
|
68
112
|
compile_args.append("/W1") # Reduce warnings verbosity
|
|
69
113
|
|
|
114
|
+
# We don't actually want to use any SimSIMD stuff,
|
|
115
|
+
# as GCC attributes aren't compatible with MSVC
|
|
116
|
+
if use_simsimd:
|
|
117
|
+
macros_args.extend(
|
|
118
|
+
[
|
|
119
|
+
get_bool_env_w_name("SIMSIMD_TARGET_X86_AVX512", False),
|
|
120
|
+
get_bool_env_w_name("SIMSIMD_TARGET_ARM_SVE", False),
|
|
121
|
+
get_bool_env_w_name("SIMSIMD_TARGET_X86_AVX2", False),
|
|
122
|
+
get_bool_env_w_name("SIMSIMD_TARGET_ARM_NEON", False),
|
|
123
|
+
]
|
|
124
|
+
)
|
|
125
|
+
|
|
70
126
|
ext_modules = [
|
|
71
127
|
Pybind11Extension(
|
|
72
128
|
"usearch.compiled",
|
|
@@ -80,11 +136,16 @@ ext_modules = [
|
|
|
80
136
|
__version__ = open("VERSION", "r").read().strip()
|
|
81
137
|
__lib_name__ = "usearch"
|
|
82
138
|
|
|
83
|
-
|
|
84
139
|
this_directory = os.path.abspath(os.path.dirname(__file__))
|
|
85
140
|
with open(os.path.join(this_directory, "README.md")) as f:
|
|
86
141
|
long_description = f.read()
|
|
87
142
|
|
|
143
|
+
# Depending on the macros, adjust the include directories
|
|
144
|
+
include_dirs = ["include"]
|
|
145
|
+
if use_simsimd:
|
|
146
|
+
include_dirs.append("simsimd/include")
|
|
147
|
+
if use_fp16lib:
|
|
148
|
+
include_dirs.append("fp16/include")
|
|
88
149
|
|
|
89
150
|
setup(
|
|
90
151
|
name=__lib_name__,
|
|
@@ -118,7 +179,7 @@ setup(
|
|
|
118
179
|
"Topic :: Database :: Database Engines/Servers",
|
|
119
180
|
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
120
181
|
],
|
|
121
|
-
include_dirs=
|
|
182
|
+
include_dirs=include_dirs,
|
|
122
183
|
ext_modules=ext_modules,
|
|
123
184
|
install_requires=[
|
|
124
185
|
"numpy",
|
package/simsimd/README.md
CHANGED
|
@@ -30,24 +30,23 @@ SimSIMD leverages SIMD intrinsics, capabilities that only select compilers effec
|
|
|
30
30
|
|
|
31
31
|
Given 1000 embeddings from OpenAI Ada API with 1536 dimensions, running on the Apple M2 Pro Arm CPU with NEON support, here's how SimSIMD performs against conventional methods:
|
|
32
32
|
|
|
33
|
-
|
|
|
34
|
-
|
|
|
35
|
-
|
|
|
36
|
-
|
|
|
37
|
-
|
|
|
38
|
-
| `scipy.spatial.distance.jensenshannon` | `jensenshannon`
|
|
39
|
-
| `scipy.special.kl_div` | `kullbackleibler` | __21 x__ | __18 x__ | |
|
|
33
|
+
| Kind | `f32` improvement | `f16` improvement | `i8` improvement | Conventional method | SimSIMD |
|
|
34
|
+
| :------------- | ----------------: | ----------------: | ---------------: | :------------------------------------- | :-------------- |
|
|
35
|
+
| Cosine | __32 x__ | __79 x__ | __133 x__ | `scipy.spatial.distance.cosine` | `cosine` |
|
|
36
|
+
| Euclidean ² | __5 x__ | __26 x__ | __17 x__ | `scipy.spatial.distance.sqeuclidean` | `sqeuclidean` |
|
|
37
|
+
| Inner Product | __2 x__ | __9 x__ | __18 x__ | `numpy.inner` | `inner` |
|
|
38
|
+
| Jensen Shannon | __31 x__ | __53 x__ | | `scipy.spatial.distance.jensenshannon` | `jensenshannon` |
|
|
40
39
|
|
|
41
40
|
### Intel Sapphire Rapids
|
|
42
41
|
|
|
43
42
|
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.
|
|
44
43
|
|
|
45
|
-
|
|
|
46
|
-
|
|
|
47
|
-
|
|
|
48
|
-
|
|
|
49
|
-
|
|
|
50
|
-
|
|
|
44
|
+
| Kind | GCC 12 `f32` | GCC 12 `f16` | SimSIMD `f16` | `f16` improvement |
|
|
45
|
+
| :------------- | -----------: | -----------: | ------------: | ----------------: |
|
|
46
|
+
| Cosine | 3.28 M/s | _336.29 k/s_ | _6.88 M/s_ | __20 x__ |
|
|
47
|
+
| Euclidean ² | 4.62 M/s | _147.25 k/s_ | _5.32 M/s_ | __36 x__ |
|
|
48
|
+
| Inner Product | 3.81 M/s | _192.02 k/s_ | _5.99 M/s_ | __31 x__ |
|
|
49
|
+
| Jensen Shannon | 1.18 M/s | _18.13 k/s_ | _2.14 M/s_ | __118 x__ |
|
|
51
50
|
|
|
52
51
|
__Technical Insights__:
|
|
53
52
|
|
|
@@ -173,6 +172,8 @@ Stay updated with the latest advancements by always using the most recent compil
|
|
|
173
172
|
|
|
174
173
|
Should you wish to integrate SimSIMD within USearch, simply compile USearch with the flag `USEARCH_USE_SIMSIMD=1`. Notably, this is the default setting on the majority of platforms.
|
|
175
174
|
|
|
175
|
+
## Benchmarking and Contributing
|
|
176
|
+
|
|
176
177
|
__To rerun experiments__ utilize the following command:
|
|
177
178
|
|
|
178
179
|
```sh
|
|
@@ -425,8 +425,8 @@ simsimd_avx512_f32_js_cycle:
|
|
|
425
425
|
__mmask16 nonzero_mask_b = _mm512_cmp_ps_mask(b_vec, epsilon_vec, _CMP_GE_OQ);
|
|
426
426
|
__mmask16 nonzero_mask = nonzero_mask_a & nonzero_mask_b;
|
|
427
427
|
__m512 m_recip_approx = _mm512_rcp14_ps(m_vec);
|
|
428
|
-
__m512 ratio_a_vec =
|
|
429
|
-
__m512 ratio_b_vec =
|
|
428
|
+
__m512 ratio_a_vec = _mm512_mul_ps(a_vec, m_recip_approx);
|
|
429
|
+
__m512 ratio_b_vec = _mm512_mul_ps(b_vec, m_recip_approx);
|
|
430
430
|
__m512 log_ratio_a_vec = simsimd_avx512_f32_log2(ratio_a_vec);
|
|
431
431
|
__m512 log_ratio_b_vec = simsimd_avx512_f32_log2(ratio_b_vec);
|
|
432
432
|
sum_a_vec = _mm512_maskz_fmadd_ps(nonzero_mask, a_vec, log_ratio_a_vec, sum_a_vec);
|
package/simsimd/package.json
CHANGED
package/wasmer.toml
CHANGED
package/. npmignore
DELETED
package/.gitignore
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
# Ignore all files without an extension
|
|
2
|
-
*
|
|
3
|
-
!/**/
|
|
4
|
-
!*.*
|
|
5
|
-
|
|
6
|
-
# Temporary files
|
|
7
|
-
.DS_Store
|
|
8
|
-
*.fbin
|
|
9
|
-
*.ibin
|
|
10
|
-
datasets
|
|
11
|
-
bin
|
|
12
|
-
*.usearch
|
|
13
|
-
.cache
|
|
14
|
-
|
|
15
|
-
# C++ builds
|
|
16
|
-
build
|
|
17
|
-
build_release
|
|
18
|
-
build_debug
|
|
19
|
-
build_artifacts
|
|
20
|
-
_deps
|
|
21
|
-
CMakeCache.txt
|
|
22
|
-
CMakeFiles
|
|
23
|
-
cmake_install.cmake
|
|
24
|
-
|
|
25
|
-
# Profiling with GProf and `perf` on Linux
|
|
26
|
-
gmon.out
|
|
27
|
-
perf.data
|
|
28
|
-
|
|
29
|
-
# Python wrappers
|
|
30
|
-
__pycache__
|
|
31
|
-
*.egg-info
|
|
32
|
-
dist/
|
|
33
|
-
wheelhouse/
|
|
34
|
-
|
|
35
|
-
# Python Environments
|
|
36
|
-
venv/
|
|
37
|
-
|
|
38
|
-
# JS wrappers
|
|
39
|
-
package-lock.json
|
|
40
|
-
node_modules/
|
|
41
|
-
|
|
42
|
-
# Rust builds
|
|
43
|
-
Cargo.lock
|
|
44
|
-
target/
|
|
45
|
-
|
|
46
|
-
# Java bindings
|
|
47
|
-
.gradle
|
|
48
|
-
*.class
|
|
49
|
-
|
|
50
|
-
# ObjC and Swift
|
|
51
|
-
.build
|
|
52
|
-
.swiftpm
|
|
53
|
-
|
|
54
|
-
# C# builds
|
|
55
|
-
csharp/**/[Bb]in/
|
|
56
|
-
csharp/**/[Oo]bj/
|
|
57
|
-
csharp/lib
|
|
58
|
-
csharp/packages
|
|
59
|
-
|
|
60
|
-
# Prerequisites
|
|
61
|
-
*.d
|
|
62
|
-
|
|
63
|
-
# Compiled Object files
|
|
64
|
-
*.slo
|
|
65
|
-
*.lo
|
|
66
|
-
*.o
|
|
67
|
-
*.obj
|
|
68
|
-
|
|
69
|
-
# Precompiled Headers
|
|
70
|
-
*.gch
|
|
71
|
-
*.pch
|
|
72
|
-
|
|
73
|
-
# Compiled Dynamic libraries
|
|
74
|
-
*.so
|
|
75
|
-
*.dylib
|
|
76
|
-
*.dll
|
|
77
|
-
|
|
78
|
-
# Fortran module files
|
|
79
|
-
*.mod
|
|
80
|
-
*.smod
|
|
81
|
-
|
|
82
|
-
# Allow golang go.mod
|
|
83
|
-
!go.mod
|
|
84
|
-
|
|
85
|
-
# Compiled Static libraries
|
|
86
|
-
*.lai
|
|
87
|
-
*.la
|
|
88
|
-
*.a
|
|
89
|
-
*.lib
|
|
90
|
-
|
|
91
|
-
# Executables
|
|
92
|
-
*.exe
|
|
93
|
-
*.out
|
|
94
|
-
*.app
|
|
95
|
-
|