usearch 2.9.1 → 2.9.2
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/CONTRIBUTING.md +10 -2
- package/Cargo.toml +1 -1
- package/README.md +12 -15
- package/VERSION +1 -1
- package/c/test.c +58 -50
- package/conanfile.py +1 -1
- package/include/usearch/index.hpp +1 -1
- package/include/usearch/index_plugins.hpp +20 -10
- package/javascript/types/usearch.d.ts.map +1 -1
- package/javascript/usearch.js +4 -1
- package/package.json +1 -1
- package/simsimd/CONTRIBUTING.md +88 -0
- package/simsimd/Cargo.lock +4 -3
- package/simsimd/Cargo.toml +10 -2
- package/simsimd/README.md +102 -60
- package/simsimd/include/simsimd/binary.h +44 -0
- package/simsimd/include/simsimd/complex.h +174 -0
- package/simsimd/include/simsimd/simsimd.h +18 -9
- package/simsimd/include/simsimd/spatial.h +128 -36
- package/simsimd/include/simsimd/types.h +3 -2
- package/simsimd/package-lock.json +5 -5
- package/simsimd/package.json +1 -1
- package/simsimd/rust/benches/native.rs +12 -9
- package/simsimd/rust/lib.c +32 -55
- package/simsimd/rust/lib.rs +374 -56
- package/stringzilla/CONTRIBUTING.md +17 -0
- package/stringzilla/Cargo.lock +1 -1
- package/stringzilla/Cargo.toml +1 -1
- package/stringzilla/README.md +175 -34
- package/stringzilla/VERSION +1 -1
- package/stringzilla/build.rs +77 -4
- package/stringzilla/c/lib.c +33 -0
- package/stringzilla/cli/README.md +30 -13
- package/stringzilla/cli/__init__.py +0 -0
- package/stringzilla/cli/split.py +66 -33
- package/stringzilla/cli/wc.py +101 -21
- package/stringzilla/include/stringzilla/experimental.h +122 -1
- package/stringzilla/include/stringzilla/stringzilla.h +262 -132
- package/stringzilla/include/stringzilla/stringzilla.hpp +13 -5
- package/stringzilla/package.json +1 -1
- package/stringzilla/rust/lib.rs +673 -162
- package/wasmer.toml +1 -1
package/CITATION.cff
CHANGED
package/CONTRIBUTING.md
CHANGED
|
@@ -104,6 +104,13 @@ cppcheck --enable=all --force --suppress=cstyleCast --suppress=unusedFunction \
|
|
|
104
104
|
include/index_plugins.hpp
|
|
105
105
|
```
|
|
106
106
|
|
|
107
|
+
I'd recommend putting the following breakpoints when debugging the code in GDB:
|
|
108
|
+
|
|
109
|
+
- `__asan::ReportGenericError` - to detect illegal memory accesses.
|
|
110
|
+
- `__ubsan::ScopedReport::~ScopedReport` - to catch undefined behavior.
|
|
111
|
+
- `__GI_exit` - to stop at exit points - the end of running any executable.
|
|
112
|
+
- `__builtin_unreachable` - to catch all the places where the code is expected to be unreachable.
|
|
113
|
+
|
|
107
114
|
## Python 3
|
|
108
115
|
|
|
109
116
|
Python bindings are built using PyBind11 and are available on [PyPi](https://pypi.org/project/usearch/).
|
|
@@ -215,10 +222,11 @@ USearch provides both Objective-C and Swift bindings through the [Swift Package
|
|
|
215
222
|
The compilation settings are controlled by the `Package.swift` and are independent from CMake used for C/C++ builds.
|
|
216
223
|
|
|
217
224
|
```sh
|
|
218
|
-
swift build
|
|
219
|
-
swift test -v
|
|
225
|
+
swift build && swift test -v
|
|
220
226
|
```
|
|
221
227
|
|
|
228
|
+
Those depend on Apple's `Foundation` library and can only run on Apple devices.
|
|
229
|
+
|
|
222
230
|
## GoLang
|
|
223
231
|
|
|
224
232
|
USearch provides GoLang bindings, that depend on the C library that must be installed beforehand.
|
package/Cargo.toml
CHANGED
package/README.md
CHANGED
|
@@ -30,19 +30,18 @@ Spatial • Binary • Probabilistic • User-Defined Metrics
|
|
|
30
30
|
<a href="https://unum-cloud.github.io/usearch/swift">Swift</a> •
|
|
31
31
|
<a href="https://unum-cloud.github.io/usearch/csharp">C#</a> •
|
|
32
32
|
<a href="https://unum-cloud.github.io/usearch/golang">GoLang</a> •
|
|
33
|
-
<a href="https://unum-cloud.github.io/usearch/wolfram">Wolfram</a>
|
|
34
|
-
<a href="https://unum-cloud.github.io/usearch/sqlite">SQLite3</a>
|
|
33
|
+
<a href="https://unum-cloud.github.io/usearch/wolfram">Wolfram</a>
|
|
35
34
|
<br/>
|
|
36
|
-
Linux • MacOS • Windows • iOS • WebAssembly
|
|
35
|
+
Linux • MacOS • Windows • iOS • WebAssembly •
|
|
36
|
+
<a href="https://unum-cloud.github.io/usearch/sqlite">SQLite3</a>
|
|
37
37
|
</p>
|
|
38
38
|
|
|
39
39
|
<div align="center">
|
|
40
|
-
<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=
|
|
41
|
-
<a href="https://www.npmjs.com/package/usearch"> <img alt="NPM" src="https://img.shields.io/npm/dy/usearch?label=
|
|
42
|
-
<a href="https://crates.io/crates/usearch"> <img alt="Crate" src="https://img.shields.io/crates/d/usearch?label=
|
|
43
|
-
<a href="https://www.nuget.org/packages/Cloud.Unum.USearch"> <img alt="NuGet" src="https://img.shields.io/nuget/dt/Cloud.Unum.USearch?label=
|
|
44
|
-
<a href="https://central.sonatype.com/artifact/cloud.unum/usearch/overview"> <img alt="Maven" src="https://img.shields.io/nexus/r/cloud.unum/usearch?server=https%3A%2F%2Fs01.oss.sonatype.org%2F&label=
|
|
45
|
-
<a href="https://hub.docker.com/r/unum/usearch"> <img alt="Docker" src="https://img.shields.io/docker/pulls/unum/usearch?label=Docker%20installs"> </a>
|
|
40
|
+
<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=Python%20PyPi%20installs"> </a>
|
|
41
|
+
<a href="https://www.npmjs.com/package/usearch"> <img alt="NPM" src="https://img.shields.io/npm/dy/usearch?label=JavaScript%20NPM%20installs"> </a>
|
|
42
|
+
<a href="https://crates.io/crates/usearch"> <img alt="Crate" src="https://img.shields.io/crates/d/usearch?label=Rust%20Crate%20installs"> </a>
|
|
43
|
+
<a href="https://www.nuget.org/packages/Cloud.Unum.USearch"> <img alt="NuGet" src="https://img.shields.io/nuget/dt/Cloud.Unum.USearch?label=CSharp%20NuGet%20installs"> </a>
|
|
44
|
+
<a href="https://central.sonatype.com/artifact/cloud.unum/usearch/overview"> <img alt="Maven" src="https://img.shields.io/nexus/r/cloud.unum/usearch?server=https%3A%2F%2Fs01.oss.sonatype.org%2F&label=Java%20Maven%20version"> </a>
|
|
46
45
|
<img alt="GitHub code size in bytes" src="https://img.shields.io/github/languages/code-size/unum-cloud/usearch?label=Repo%20size">
|
|
47
46
|
</div>
|
|
48
47
|
|
|
@@ -50,18 +49,16 @@ Linux • MacOS • Windows • iOS • WebAssembly
|
|
|
50
49
|
|
|
51
50
|
- ✅ __[10x faster][faster-than-faiss]__ [HNSW][hnsw-algorithm] implementation than [FAISS][faiss].
|
|
52
51
|
- ✅ Simple and extensible [single C++11 header][usearch-header] __library__.
|
|
53
|
-
- ✅ Compatible with a dozen programming languages out of the box.
|
|
54
52
|
- ✅ [Trusted](#integrations) by giants like Google and databases like [ClickHouse][clickhouse-docs].
|
|
55
53
|
- ✅ [SIMD][simd]-optimized and [user-defined metrics](#user-defined-functions) with JIT compilation.
|
|
56
54
|
- ✅ Hardware-agnostic `f16` & `i8` - [half-precision & quarter-precision support](#memory-efficiency-downcasting-and-quantization).
|
|
57
55
|
- ✅ [View large indexes from disk](#serving-index-from-disk) without loading into RAM.
|
|
58
56
|
- ✅ Heterogeneous lookups, renaming/relabeling, and on-the-fly deletions.
|
|
59
|
-
- ✅ Variable dimensionality vectors for unique applications, including search over compressed data.
|
|
60
57
|
- ✅ Binary Tanimoto and Sorensen coefficients for [Genomics and Chemistry applications](#usearch--rdkit--molecular-search).
|
|
61
58
|
- ✅ Space-efficient point-clouds with `uint40_t`, accommodating 4B+ size.
|
|
62
|
-
- ✅ Compatible with OpenMP and custom "executors" for fine-grained
|
|
63
|
-
- ✅ Near-real-time [clustering and sub-clustering](#clustering) for Tens or Millions of clusters.
|
|
59
|
+
- ✅ Compatible with OpenMP and custom "executors" for fine-grained parallelism.
|
|
64
60
|
- ✅ [Semantic Search](#usearch--ai--multi-modal-semantic-search) and [Joins](#joins-one-to-one-one-to-many-and-many-to-many-mappings).
|
|
61
|
+
- 🔄 Near-real-time [clustering and sub-clustering](#clustering) for Tens or Millions of clusters.
|
|
65
62
|
|
|
66
63
|
[faiss]: https://github.com/facebookresearch/faiss
|
|
67
64
|
[usearch-header]: https://github.com/unum-cloud/usearch/blob/main/include/usearch/index.hpp
|
|
@@ -133,7 +130,7 @@ matches = index.search(vector, 10)
|
|
|
133
130
|
|
|
134
131
|
assert matches[0].key == 42
|
|
135
132
|
assert matches[0].distance <= 0.001
|
|
136
|
-
assert np.allclose(index[42], vector)
|
|
133
|
+
assert np.allclose(index[42], vector, atol=0.1) # Ensure high tolerance in mixed-precision comparisons
|
|
137
134
|
```
|
|
138
135
|
|
|
139
136
|
More settings are always available, and the API is designed to be as flexible as possible.
|
|
@@ -434,7 +431,7 @@ doi = {10.5281/zenodo.7949416},
|
|
|
434
431
|
author = {Vardanian, Ash},
|
|
435
432
|
title = {{USearch by Unum Cloud}},
|
|
436
433
|
url = {https://github.com/unum-cloud/usearch},
|
|
437
|
-
version = {2.9.
|
|
434
|
+
version = {2.9.2},
|
|
438
435
|
year = {2023},
|
|
439
436
|
month = oct,
|
|
440
437
|
}
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.9.
|
|
1
|
+
2.9.2
|
package/c/test.c
CHANGED
|
@@ -35,6 +35,7 @@ usearch_init_options_t create_options(size_t const dimensions) {
|
|
|
35
35
|
opts.metric_kind = usearch_metric_ip_k;
|
|
36
36
|
opts.metric = NULL;
|
|
37
37
|
opts.quantization = usearch_scalar_f32_k;
|
|
38
|
+
opts.multi = false;
|
|
38
39
|
return opts;
|
|
39
40
|
}
|
|
40
41
|
|
|
@@ -45,7 +46,7 @@ usearch_init_options_t create_options(size_t const dimensions) {
|
|
|
45
46
|
* dimensions, and connectivity after each operation.
|
|
46
47
|
*/
|
|
47
48
|
void test_init(size_t const collection_size, size_t const dimensions) {
|
|
48
|
-
printf("Test: Index Initialization
|
|
49
|
+
printf("Test: Index Initialization... %zu vectors, %zu dimensions \n", collection_size, dimensions);
|
|
49
50
|
|
|
50
51
|
// Init index
|
|
51
52
|
usearch_error_t error = NULL;
|
|
@@ -84,7 +85,7 @@ void test_init(size_t const collection_size, size_t const dimensions) {
|
|
|
84
85
|
* size, capacity, and presence of each vector in the index.
|
|
85
86
|
*/
|
|
86
87
|
void test_add_vector(size_t const collection_size, size_t const dimensions) {
|
|
87
|
-
printf("Test: Add Vector
|
|
88
|
+
printf("Test: Add Vector... %zu vectors, %zu dimensions \n", collection_size, dimensions);
|
|
88
89
|
|
|
89
90
|
usearch_error_t error = NULL;
|
|
90
91
|
usearch_init_options_t opts = create_options(dimensions);
|
|
@@ -120,7 +121,7 @@ void test_add_vector(size_t const collection_size, size_t const dimensions) {
|
|
|
120
121
|
* found in the index, validating the count of found vectors.
|
|
121
122
|
*/
|
|
122
123
|
void test_find_vector(size_t const collection_size, size_t const dimensions) {
|
|
123
|
-
printf("Test: Find Vector
|
|
124
|
+
printf("Test: Find Vector... %zu vectors, %zu dimensions \n", collection_size, dimensions);
|
|
124
125
|
|
|
125
126
|
usearch_error_t error = NULL;
|
|
126
127
|
usearch_init_options_t opts = create_options(dimensions);
|
|
@@ -161,7 +162,7 @@ void test_find_vector(size_t const collection_size, size_t const dimensions) {
|
|
|
161
162
|
* retrieves vectors associated with the key from the index and checks the count of retrieved vectors.
|
|
162
163
|
*/
|
|
163
164
|
void test_get_vector(size_t const collection_size, size_t const dimensions) {
|
|
164
|
-
printf("Test: Get Vector
|
|
165
|
+
printf("Test: Get Vector... %zu vectors, %zu dimensions \n", collection_size, dimensions);
|
|
165
166
|
|
|
166
167
|
usearch_error_t error = NULL;
|
|
167
168
|
usearch_init_options_t opts = create_options(dimensions);
|
|
@@ -198,7 +199,7 @@ void test_get_vector(size_t const collection_size, size_t const dimensions) {
|
|
|
198
199
|
* the assert in this test expects an error, indicating that the remove functionality is not currently supported.
|
|
199
200
|
*/
|
|
200
201
|
void test_remove_vector(size_t const collection_size, size_t const dimensions) {
|
|
201
|
-
printf("Test: Remove Vector
|
|
202
|
+
printf("Test: Remove Vector... %zu vectors, %zu dimensions \n", collection_size, dimensions);
|
|
202
203
|
|
|
203
204
|
usearch_error_t error = NULL;
|
|
204
205
|
usearch_init_options_t opts = create_options(dimensions);
|
|
@@ -232,7 +233,8 @@ void test_remove_vector(size_t const collection_size, size_t const dimensions) {
|
|
|
232
233
|
* from the saved index.
|
|
233
234
|
*/
|
|
234
235
|
void test_save_load(size_t const collection_size, size_t const dimensions) {
|
|
235
|
-
printf("Test: Save/Load
|
|
236
|
+
printf("Test: Save/Load... %zu vectors, %zu dimensions \n", collection_size, dimensions);
|
|
237
|
+
float* data = create_vectors(collection_size, dimensions);
|
|
236
238
|
|
|
237
239
|
usearch_error_t error = NULL;
|
|
238
240
|
usearch_init_options_t opts = create_options(dimensions);
|
|
@@ -242,23 +244,26 @@ void test_save_load(size_t const collection_size, size_t const dimensions) {
|
|
|
242
244
|
weird_ops.expansion_search = 19;
|
|
243
245
|
weird_ops.metric_kind = usearch_metric_pearson_k;
|
|
244
246
|
weird_ops.quantization = usearch_scalar_f64_k;
|
|
245
|
-
usearch_index_t index = usearch_init(&weird_ops, &error);
|
|
246
|
-
usearch_reserve(index, collection_size, &error);
|
|
247
247
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
248
|
+
{
|
|
249
|
+
|
|
250
|
+
usearch_index_t index = usearch_init(&weird_ops, &error);
|
|
251
|
+
usearch_reserve(index, collection_size, &error);
|
|
252
|
+
|
|
253
|
+
// Add vectors
|
|
254
|
+
for (size_t i = 0; i < collection_size; ++i) {
|
|
255
|
+
usearch_key_t key = i;
|
|
256
|
+
usearch_add(index, key, data + i * dimensions, usearch_scalar_f32_k, &error);
|
|
257
|
+
ASSERT(!error, error);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Save and free the index
|
|
261
|
+
usearch_save(index, "tmp.usearch", &error);
|
|
262
|
+
ASSERT(!error, error);
|
|
263
|
+
usearch_free(index, &error);
|
|
253
264
|
ASSERT(!error, error);
|
|
254
265
|
}
|
|
255
266
|
|
|
256
|
-
// Save and free the index
|
|
257
|
-
usearch_save(index, "tmp.usearch", &error);
|
|
258
|
-
ASSERT(!error, error);
|
|
259
|
-
usearch_free(index, &error);
|
|
260
|
-
ASSERT(!error, error);
|
|
261
|
-
|
|
262
267
|
// Reset the options
|
|
263
268
|
opts.connectivity = 0;
|
|
264
269
|
opts.dimensions = 0;
|
|
@@ -269,45 +274,48 @@ void test_save_load(size_t const collection_size, size_t const dimensions) {
|
|
|
269
274
|
opts.metric_kind = usearch_metric_unknown_k;
|
|
270
275
|
|
|
271
276
|
// Reinit
|
|
272
|
-
|
|
273
|
-
ASSERT(!error, error);
|
|
274
|
-
ASSERT(usearch_size(index, &error) == 0, error);
|
|
277
|
+
{
|
|
275
278
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
ASSERT(usearch_size(index, &error) == collection_size, error);
|
|
280
|
-
ASSERT(usearch_capacity(index, &error) == collection_size, error);
|
|
281
|
-
ASSERT(usearch_dimensions(index, &error) == dimensions, error);
|
|
282
|
-
ASSERT(usearch_connectivity(index, &error) == weird_ops.connectivity, error);
|
|
279
|
+
usearch_index_t index = usearch_init(&opts, &error);
|
|
280
|
+
ASSERT(!error, error);
|
|
281
|
+
ASSERT(usearch_size(index, &error) == 0, error);
|
|
283
282
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
ASSERT(
|
|
288
|
-
|
|
283
|
+
// Load
|
|
284
|
+
usearch_load(index, "tmp.usearch", &error);
|
|
285
|
+
ASSERT(!error, error);
|
|
286
|
+
ASSERT(usearch_size(index, &error) == collection_size, error);
|
|
287
|
+
ASSERT(usearch_capacity(index, &error) == collection_size, error);
|
|
288
|
+
ASSERT(usearch_dimensions(index, &error) == dimensions, error);
|
|
289
|
+
ASSERT(usearch_connectivity(index, &error) == weird_ops.connectivity, error);
|
|
290
|
+
|
|
291
|
+
// Check vectors in the index
|
|
292
|
+
for (size_t i = 0; i < collection_size; ++i) {
|
|
293
|
+
usearch_key_t key = i;
|
|
294
|
+
ASSERT(usearch_contains(index, key, &error), error);
|
|
295
|
+
}
|
|
289
296
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
297
|
+
// Create result buffers
|
|
298
|
+
usearch_key_t* keys = (usearch_key_t*)malloc(collection_size * sizeof(usearch_key_t));
|
|
299
|
+
float* distances = (float*)malloc(collection_size * sizeof(float));
|
|
300
|
+
ASSERT(keys && distances, "Failed to allocate memory");
|
|
301
|
+
|
|
302
|
+
// Find the vectors
|
|
303
|
+
for (size_t i = 0; i < collection_size; i++) {
|
|
304
|
+
size_t found_count = usearch_search(index, data + i * dimensions, usearch_scalar_f32_k, collection_size,
|
|
305
|
+
keys, distances, &error);
|
|
306
|
+
ASSERT(!error, error);
|
|
307
|
+
ASSERT(found_count >= 1 && found_count <= collection_size, "Vector is missing");
|
|
308
|
+
}
|
|
294
309
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
distances, &error);
|
|
299
|
-
ASSERT(!error, error);
|
|
300
|
-
ASSERT(found_count >= 1 && found_count <= collection_size, "Vector is missing");
|
|
310
|
+
free(keys);
|
|
311
|
+
free(distances);
|
|
312
|
+
usearch_free(index, &error);
|
|
301
313
|
}
|
|
302
314
|
|
|
303
315
|
free(data);
|
|
304
|
-
free(keys);
|
|
305
|
-
free(distances);
|
|
306
|
-
usearch_free(index, &error);
|
|
307
316
|
|
|
308
317
|
// Remove the file from disk
|
|
309
318
|
remove("tmp.usearch");
|
|
310
|
-
|
|
311
319
|
printf("Test: Save/Load - PASSED\n");
|
|
312
320
|
}
|
|
313
321
|
|
|
@@ -318,7 +326,7 @@ void test_save_load(size_t const collection_size, size_t const dimensions) {
|
|
|
318
326
|
* not verify the properties or contents of the viewed index.
|
|
319
327
|
*/
|
|
320
328
|
void test_view(size_t const collection_size, size_t const dimensions) {
|
|
321
|
-
printf("Test: View
|
|
329
|
+
printf("Test: View... %zu vectors, %zu dimensions \n", collection_size, dimensions);
|
|
322
330
|
|
|
323
331
|
usearch_error_t error = NULL;
|
|
324
332
|
usearch_init_options_t opts = create_options(dimensions);
|
|
@@ -355,7 +363,7 @@ void test_view(size_t const collection_size, size_t const dimensions) {
|
|
|
355
363
|
int main(int argc, char const* argv[]) {
|
|
356
364
|
|
|
357
365
|
size_t collection_sizes[] = {11, 512};
|
|
358
|
-
size_t dimensions[] = {83,
|
|
366
|
+
size_t dimensions[] = {83, 2}; // Not all distance functions make sense for 1 dimensional data
|
|
359
367
|
for (size_t index = 0; index < sizeof(collection_sizes) / sizeof(collection_sizes[0]); ++index) {
|
|
360
368
|
for (size_t jdx = 0; jdx < sizeof(dimensions) / sizeof(dimensions[0]); ++jdx) {
|
|
361
369
|
test_init(collection_sizes[index], dimensions[jdx]);
|
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.9.
|
|
10
|
+
version = '2.9.2'
|
|
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"
|
|
@@ -926,7 +926,7 @@ class i8_converted_t {
|
|
|
926
926
|
std::int8_t int8_{};
|
|
927
927
|
|
|
928
928
|
public:
|
|
929
|
-
constexpr static
|
|
929
|
+
constexpr static f32_t divisor_k = 100.f;
|
|
930
930
|
constexpr static std::int8_t min_k = -100;
|
|
931
931
|
constexpr static std::int8_t max_k = 100;
|
|
932
932
|
|
|
@@ -938,9 +938,9 @@ class i8_converted_t {
|
|
|
938
938
|
inline i8_converted_t(i8_converted_t const&) = default;
|
|
939
939
|
inline i8_converted_t& operator=(i8_converted_t const&) = default;
|
|
940
940
|
|
|
941
|
-
inline operator
|
|
942
|
-
inline operator
|
|
943
|
-
inline operator
|
|
941
|
+
inline operator f16_t() const noexcept { return static_cast<f16_t>(f32_t(int8_) / divisor_k); }
|
|
942
|
+
inline operator f32_t() const noexcept { return f32_t(int8_) / divisor_k; }
|
|
943
|
+
inline operator f64_t() const noexcept { return f64_t(int8_) / divisor_k; }
|
|
944
944
|
inline explicit operator bool() const noexcept { return int8_ > (max_k / 2); }
|
|
945
945
|
inline explicit operator std::int8_t() const noexcept { return int8_; }
|
|
946
946
|
inline explicit operator std::int16_t() const noexcept { return int8_; }
|
|
@@ -949,9 +949,9 @@ class i8_converted_t {
|
|
|
949
949
|
|
|
950
950
|
inline i8_converted_t(f16_t v)
|
|
951
951
|
: int8_(usearch::clamp<std::int8_t>(static_cast<std::int8_t>(v * divisor_k), min_k, max_k)) {}
|
|
952
|
-
inline i8_converted_t(
|
|
952
|
+
inline i8_converted_t(f32_t v)
|
|
953
953
|
: int8_(usearch::clamp<std::int8_t>(static_cast<std::int8_t>(v * divisor_k), min_k, max_k)) {}
|
|
954
|
-
inline i8_converted_t(
|
|
954
|
+
inline i8_converted_t(f64_t v)
|
|
955
955
|
: int8_(usearch::clamp<std::int8_t>(static_cast<std::int8_t>(v * divisor_k), min_k, max_k)) {}
|
|
956
956
|
};
|
|
957
957
|
|
|
@@ -1165,13 +1165,20 @@ template <typename scalar_at = std::int32_t, typename result_at = float> struct
|
|
|
1165
1165
|
};
|
|
1166
1166
|
|
|
1167
1167
|
/**
|
|
1168
|
-
* @brief Measures Pearson Correlation between two sequences.
|
|
1168
|
+
* @brief Measures Pearson Correlation between two sequences in a single pass.
|
|
1169
1169
|
*/
|
|
1170
1170
|
template <typename scalar_at = float, typename result_at = float> struct metric_pearson_gt {
|
|
1171
1171
|
using scalar_t = scalar_at;
|
|
1172
1172
|
using result_t = result_at;
|
|
1173
1173
|
|
|
1174
1174
|
inline result_t operator()(scalar_t const* a, scalar_t const* b, std::size_t dim) const noexcept {
|
|
1175
|
+
// The correlation coefficient can't be defined for one or zero-dimensional data.
|
|
1176
|
+
if (dim <= 1)
|
|
1177
|
+
return 0;
|
|
1178
|
+
// Conventional Pearson Correlation Coefficient definiton subtracts the mean value of each
|
|
1179
|
+
// sequence from each element, before dividing them. WikiPedia article suggests a convenient
|
|
1180
|
+
// single-pass algorithm for calculating sample correlations, though depending on the numbers
|
|
1181
|
+
// involved, it can sometimes be numerically unstable.
|
|
1175
1182
|
result_t a_sum{}, b_sum{}, ab_sum{};
|
|
1176
1183
|
result_t a_sq_sum{}, b_sq_sum{};
|
|
1177
1184
|
#if USEARCH_USE_OPENMP
|
|
@@ -1190,9 +1197,12 @@ template <typename scalar_at = float, typename result_at = float> struct metric_
|
|
|
1190
1197
|
a_sq_sum += ai * ai;
|
|
1191
1198
|
b_sq_sum += bi * bi;
|
|
1192
1199
|
}
|
|
1193
|
-
result_t denom =
|
|
1194
|
-
|
|
1195
|
-
|
|
1200
|
+
result_t denom = (dim * a_sq_sum - a_sum * a_sum) * (dim * b_sq_sum - b_sum * b_sum);
|
|
1201
|
+
if (denom == 0)
|
|
1202
|
+
return 0;
|
|
1203
|
+
result_t corr = dim * ab_sum - a_sum * b_sum;
|
|
1204
|
+
denom = std::sqrt(denom);
|
|
1205
|
+
return -corr / denom;
|
|
1196
1206
|
}
|
|
1197
1207
|
};
|
|
1198
1208
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usearch.d.ts","sourceRoot":"","sources":["../usearch.js"],"names":[],"mappings":"AAsIA;IAEI;;;;;;;;;;;OAWG;IACH;oBATkC,MAAM;gBAAU,UAAU;sBAAiC,UAAU;sBAAiC,MAAM;uBAAqB,MAAM;0BAAwB,MAAM;eAAa,OAAO;gBAChN,UAAU,iBACV,UAAU,iBACV,MAAM,kBACN,MAAM,qBACN,MAAM,UACN,OAAO,
|
|
1
|
+
{"version":3,"file":"usearch.d.ts","sourceRoot":"","sources":["../usearch.js"],"names":[],"mappings":"AAsIA;IAEI;;;;;;;;;;;OAWG;IACH;oBATkC,MAAM;gBAAU,UAAU;sBAAiC,UAAU;sBAAiC,MAAM;uBAAqB,MAAM;0BAAwB,MAAM;eAAa,OAAO;gBAChN,UAAU,iBACV,UAAU,iBACV,MAAM,kBACN,MAAM,qBACN,MAAM,UACN,OAAO,EAmCjB;IADG,oBAAwI;IAG5I;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,UAPW,MAAM,GAAC,MAAM,EAAE,GAAC,cAAc,WAE9B,YAAY,GAAC,YAAY,GAAC,SAAS,QAoB7C;IAED;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,gBANW,YAAY,GAAC,YAAY,GAAC,SAAS,GAAC,MAAM,MAAM,MAAM,CAAC,CAAC,KACxD,MAAM,GACL,OAAO,GAAC,YAAY,CAqB/B;IAED;;;;;;;;;OASG;IACH,eAJW,MAAM,GAAC,MAAM,EAAE,GAAC,cAAc,GAC7B,OAAO,GAAC,OAAO,EAAE,CAU5B;IAED;;;;;;OAMG;IACH,YAJW,MAAM,GAAC,MAAM,EAAE,GAAC,cAAc,GAC7B,MAAM,GAAC,MAAM,EAAE,CAU1B;IAED;;;;;;;;;OASG;IACH,aAJW,MAAM,GAAC,MAAM,EAAE,GAAC,cAAc,GAC7B,MAAM,GAAC,MAAM,EAAE,CAU1B;IAED;;;OAGG;IACH,cAFY,MAAM,CAEsC;IAExD;;;OAGG;IACH,gBAFY,MAAM,CAE0C;IAE5D;;;OAGG;IACH,QAFY,MAAM,CAE0B;IAE5C;;;OAGG;IACH,YAFY,MAAM,CAEkC;IAEpD;;;;OAIG;IACH,WAHW,MAAM,QAMhB;IAED;;;;OAIG;IACH,WAHW,MAAM,QAMhB;IAED;;;;OAIG;IACH,WAHW,MAAM,QAMhB;CACJ;;;;yBA5WS,MAAM;;;;;;;;;;;;;;;;;yBAmBN,MAAM;;;;;;;;;;AAYhB;;GAEG;AACH;IACI;;;;;OAKG;IACH,kBAHW,cAAc,aACd,YAAY,EAKtB;IAFG,qBAAgB;IAChB,wBAA0B;CAEjC;AAED;;GAEG;AACH;IACI;;;;;;;OAOG;IACH,kBALW,cAAc,aACd,YAAY,UACZ,cAAc,KACd,MAAM,EAOhB;IAJG,qBAAgB;IAChB,wBAA0B;IAC1B,uBAAoB;IACpB,UAAU;IAGd;;;;;OAKG;IACH,OAHW,MAAM,GACJ,OAAO,CAQnB;CACJ;AA+RD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,qCA1BW,YAAY,GAAC,YAAY,GAAC,SAAS,GAAC,MAAM,MAAM,MAAM,CAAC,CAAC,WACxD,YAAY,GAAC,YAAY,GAAC,SAAS,GAAC,MAAM,MAAM,MAAM,CAAC,CAAC,cACxD,MAAM,SACN,MAAM,UACN,UAAU,GACT,OAAO,GAAC,YAAY,CA0D/B"}
|
package/javascript/usearch.js
CHANGED
|
@@ -158,7 +158,10 @@ class Index {
|
|
|
158
158
|
throw new Error("Invalid arguments. Expected either individual arguments or a single object argument.");
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
-
if (
|
|
161
|
+
if ((typeof dimensions !== 'bigint' && (!Number.isInteger(dimensions) || dimensions <= 0)) ||
|
|
162
|
+
(typeof connectivity !== 'bigint' && (!Number.isInteger(connectivity) || connectivity < 0)) ||
|
|
163
|
+
(typeof expansion_add !== 'bigint' && (!Number.isInteger(expansion_add) || expansion_add < 0)) ||
|
|
164
|
+
(typeof expansion_search !== 'bigint' && (!Number.isInteger(expansion_search) || expansion_search < 0))) {
|
|
162
165
|
throw new Error("`dimensions`, `connectivity`, `expansion_add`, and `expansion_search` must be non-negative integers, with `dimensions` being positive.");
|
|
163
166
|
}
|
|
164
167
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
## C and C++
|
|
4
|
+
|
|
5
|
+
To rerun experiments utilize the following command:
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
cmake -DCMAKE_BUILD_TYPE=Release -DSIMSIMD_BUILD_BENCHMARKS=1 -B ./build_release
|
|
9
|
+
cmake --build build_release --config Release
|
|
10
|
+
./build_release/simsimd_bench
|
|
11
|
+
./build_release/simsimd_bench --benchmark_filter=js
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Python
|
|
15
|
+
|
|
16
|
+
Testing:
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
pip install -e . # to install the package in editable mode
|
|
20
|
+
pytest python/test.py -s -x -Wd # to run tests
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Here, `-s` will output the logs.
|
|
24
|
+
The `-x` will stop on the first failure.
|
|
25
|
+
The `-Wd` will silence overflows and runtime warnings.
|
|
26
|
+
|
|
27
|
+
Benchmarking:
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
pip install numpy scipy scikit-learn # for comparison baselines
|
|
31
|
+
python python/bench.py # to run default benchmarks
|
|
32
|
+
python python/bench.py --n 1000 --ndim 1000000 # batch size and dimensions
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Before merging your changes you may want to test your changes against the entire matrix of Python versions USearch supports.
|
|
36
|
+
For that you need the `cibuildwheel`, which is tricky to use on MacOS and Windows, as it would target just the local environment.
|
|
37
|
+
Still, if you have Docker running on any desktop OS, you can use it to build and test the Python bindings for all Python versions for Linux:
|
|
38
|
+
|
|
39
|
+
```sh
|
|
40
|
+
pip install cibuildwheel
|
|
41
|
+
cibuildwheel
|
|
42
|
+
cibuildwheel --platform linux # works on any OS and builds all Linux backends
|
|
43
|
+
cibuildwheel --platform linux --archs x86_64 # 64-bit x86, the most common on desktop and servers
|
|
44
|
+
cibuildwheel --platform linux --archs aarch64 # 64-bit Arm for mobile devices, Apple M-series, and AWS Graviton
|
|
45
|
+
cibuildwheel --platform linux --archs i686 # 32-bit Linux
|
|
46
|
+
cibuildwheel --platform linux --archs s390x # emulating big-endian IBM Z
|
|
47
|
+
cibuildwheel --platform macos # works only on MacOS
|
|
48
|
+
cibuildwheel --platform windows # works only on Windows
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
You may need root previligies for multi-architecture builds:
|
|
52
|
+
|
|
53
|
+
```sh
|
|
54
|
+
sudo $(which cibuildwheel) --platform linux
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
On Windows and MacOS, to avoid frequent path resolution issues, you may want to use:
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
python -m cibuildwheel --platform windows
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Rust
|
|
64
|
+
|
|
65
|
+
```sh
|
|
66
|
+
cargo test
|
|
67
|
+
cargo bench
|
|
68
|
+
open ./target/criterion/report/index.html
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## JavaScript
|
|
72
|
+
|
|
73
|
+
Testing and benchmarking:
|
|
74
|
+
|
|
75
|
+
```sh
|
|
76
|
+
npm install --dev
|
|
77
|
+
npm test
|
|
78
|
+
npm run bench
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## GoLang
|
|
82
|
+
|
|
83
|
+
```sh
|
|
84
|
+
cd golang
|
|
85
|
+
go test # To test
|
|
86
|
+
go test -run=^$ -bench=. -benchmem # To benchmark
|
|
87
|
+
```
|
|
88
|
+
|
package/simsimd/Cargo.lock
CHANGED
|
@@ -210,9 +210,9 @@ dependencies = [
|
|
|
210
210
|
|
|
211
211
|
[[package]]
|
|
212
212
|
name = "half"
|
|
213
|
-
version = "2.
|
|
213
|
+
version = "2.4.0"
|
|
214
214
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
215
|
-
checksum = "
|
|
215
|
+
checksum = "b5eceaaeec696539ddaf7b333340f1af35a5aa87ae3e4f3ead0532f72affab2e"
|
|
216
216
|
dependencies = [
|
|
217
217
|
"cfg-if",
|
|
218
218
|
"crunchy",
|
|
@@ -496,10 +496,11 @@ dependencies = [
|
|
|
496
496
|
|
|
497
497
|
[[package]]
|
|
498
498
|
name = "simsimd"
|
|
499
|
-
version = "3.
|
|
499
|
+
version = "3.8.1"
|
|
500
500
|
dependencies = [
|
|
501
501
|
"cc",
|
|
502
502
|
"criterion",
|
|
503
|
+
"half",
|
|
503
504
|
"rand",
|
|
504
505
|
]
|
|
505
506
|
|
package/simsimd/Cargo.toml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "simsimd"
|
|
3
3
|
description = "Fastest SIMD-Accelerated Vector Similarity Functions for x86 and Arm"
|
|
4
|
-
version = "3.
|
|
4
|
+
version = "3.9.0"
|
|
5
5
|
edition = "2021"
|
|
6
6
|
license = "Apache-2.0"
|
|
7
7
|
authors = [
|
|
@@ -12,7 +12,13 @@ repository = "https://github.com/ashvardanian/SimSIMD"
|
|
|
12
12
|
documentation = "https://docs.rs/simsimd"
|
|
13
13
|
homepage = "https://ashvardanian.com/posts/simsimd-faster-scipy"
|
|
14
14
|
keywords = ["simd", "search", "linear-algebra", "vector"]
|
|
15
|
-
categories = [
|
|
15
|
+
categories = [
|
|
16
|
+
"mathematics",
|
|
17
|
+
"hardware-support",
|
|
18
|
+
"no-std",
|
|
19
|
+
"wasm",
|
|
20
|
+
"external-ffi-bindings",
|
|
21
|
+
]
|
|
16
22
|
|
|
17
23
|
[lib]
|
|
18
24
|
name = "simsimd"
|
|
@@ -21,6 +27,7 @@ path = "rust/lib.rs"
|
|
|
21
27
|
[build-dependencies]
|
|
22
28
|
cc = "1.0.83"
|
|
23
29
|
|
|
30
|
+
|
|
24
31
|
[[bench]]
|
|
25
32
|
name = "cosine"
|
|
26
33
|
harness = false
|
|
@@ -34,3 +41,4 @@ path = "rust/benches/sqeuclidean.rs"
|
|
|
34
41
|
[dev-dependencies]
|
|
35
42
|
criterion = { version = "0.5.1" }
|
|
36
43
|
rand = { version = "0.8.5" }
|
|
44
|
+
half = { version = "2.4.0" }
|