usearch 2.8.12 → 2.8.14
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/Cargo.toml +1 -1
- package/README.md +31 -22
- package/VERSION +1 -1
- package/conanfile.py +1 -1
- package/include/usearch/index.hpp +1 -1
- package/include/usearch/index_dense.hpp +3 -4
- package/package.json +1 -1
- package/simsimd/README.md +1 -1
- package/simsimd/include/simsimd/probability.h +5 -2
- package/simsimd/include/simsimd/simsimd.h +24 -1
- package/simsimd/include/simsimd/spatial.h +172 -2
- package/simsimd/package.json +20 -3
- package/wasmer.toml +1 -1
package/CITATION.cff
CHANGED
package/Cargo.toml
CHANGED
package/README.md
CHANGED
|
@@ -36,18 +36,18 @@ Linux • MacOS • Windows • iOS • WebAssembly
|
|
|
36
36
|
</p>
|
|
37
37
|
|
|
38
38
|
<div align="center">
|
|
39
|
-
<a href="https://
|
|
40
|
-
<a href="https://www.npmjs.com/package/usearch"> <img alt="NPM" src="https://img.shields.io/npm/dy/usearch?label=NPM%
|
|
41
|
-
<a href="https://crates.io/crates/usearch"> <img alt="Crate" src="https://img.shields.io/crates/d/usearch?label=Crate%
|
|
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%
|
|
39
|
+
<a href="https://pepy.tech/project/usearch"> <img alt="PyPI" src="https://static.pepy.tech/personalized-badge/usearch?period=month&units=abbreviation&left_color=black&right_color=blue&left_text=Python%20monthly%20installs"> </a>
|
|
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
|
+
<a href="https://crates.io/crates/usearch"> <img alt="Crate" src="https://img.shields.io/crates/d/usearch?label=Crate%20installs"> </a>
|
|
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>
|
|
43
43
|
<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=Maven%20version"> </a>
|
|
44
|
-
<a href="https://hub.docker.com/r/unum/usearch"> <img alt="Docker" src="https://img.shields.io/docker/pulls/unum/usearch?label=Docker%
|
|
44
|
+
<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>
|
|
45
45
|
<img alt="GitHub code size in bytes" src="https://img.shields.io/github/languages/code-size/unum-cloud/usearch?label=Repo%20size">
|
|
46
46
|
</div>
|
|
47
47
|
|
|
48
48
|
---
|
|
49
49
|
|
|
50
|
-
- ✅ [
|
|
50
|
+
- ✅ [10x faster][faster-than-faiss] [HNSW][hnsw-algorithm] implementation than [FAISS][faiss].
|
|
51
51
|
- ✅ Simple and extensible [single C++11 header][usearch-header] implementation.
|
|
52
52
|
- ✅ Compatible with a dozen programming languages out of the box.
|
|
53
53
|
- ✅ [Trusted](#integrations) by some of the most loved Datalakes and Databases, like [ClickHouse][clickhouse-docs].
|
|
@@ -86,28 +86,32 @@ FAISS is a widely recognized standard for high-performance vector search engines
|
|
|
86
86
|
USearch and FAISS both employ the same HNSW algorithm, but they differ significantly in their design principles.
|
|
87
87
|
USearch is compact and broadly compatible without sacrificing performance, primarily focusing on user-defined metrics and fewer dependencies.
|
|
88
88
|
|
|
89
|
-
| |
|
|
90
|
-
| :------------------------------------------- |
|
|
91
|
-
| Indexing time ⁰ |
|
|
92
|
-
| 100 Million 96d `f32`, `f16`, `i8` vectors |
|
|
93
|
-
| 100 Million 1536d `f32`, `f16`, `i8` vectors |
|
|
94
|
-
| |
|
|
95
|
-
| Codebase length ¹ |
|
|
96
|
-
| Supported metrics ² |
|
|
97
|
-
| Supported languages ³ |
|
|
98
|
-
| Supported ID types ⁴ |
|
|
99
|
-
| Required dependencies ⁵ |
|
|
100
|
-
| Bindings ⁶ |
|
|
89
|
+
| | FAISS | USearch | Improvement |
|
|
90
|
+
| :------------------------------------------- | ----------------------: | -----------------------: | ----------------------: |
|
|
91
|
+
| Indexing time ⁰ | | | |
|
|
92
|
+
| 100 Million 96d `f32`, `f16`, `i8` vectors | 2.6 · 2.6 · 2.6 h | 0.3 · 0.2 · 0.2 h | __9.6 · 10.4 · 10.7 x__ |
|
|
93
|
+
| 100 Million 1536d `f32`, `f16`, `i8` vectors | 5.0 · 4.1 · 3.8 h | 2.1 · 1.1 · 0.8 h | __2.3 · 3.6 · 4.4 x__ |
|
|
94
|
+
| | | | |
|
|
95
|
+
| Codebase length ¹ | 84 K [SLOC][sloc] | 3 K [SLOC][sloc] | maintainable |
|
|
96
|
+
| Supported metrics ² | 9 fixed metrics | any metric | extendible |
|
|
97
|
+
| Supported languages ³ | C++, Python | 10 languages | portable |
|
|
98
|
+
| Supported ID types ⁴ | 32-bit, 64-bit | 32-bit, 40-bit, 64-bit | efficient |
|
|
99
|
+
| Required dependencies ⁵ | BLAS, OpenMP | - | light-weight |
|
|
100
|
+
| Bindings ⁶ | SWIG | Native | low-latency |
|
|
101
|
+
| Python binding size ⁷ | [~ 10 MB][faiss-weight] | [< 1 MB][usearch-weight] | deployable |
|
|
101
102
|
|
|
102
103
|
[sloc]: https://en.wikipedia.org/wiki/Source_lines_of_code
|
|
104
|
+
[faiss-weight]: https://pypi.org/project/faiss-cpu/#files
|
|
105
|
+
[usearch-weight]: https://pypi.org/project/usearch/#files
|
|
103
106
|
|
|
104
107
|
> ⁰ [Tested][intel-benchmarks] on Intel Sapphire Rapids, with the simplest inner-product distance, equivalent recall, and memory consumption while also providing far superior search speed.
|
|
105
|
-
> ¹ A shorter codebase makes the project easier to maintain and audit.
|
|
108
|
+
> ¹ A shorter codebase of `usearch/` over `faiss/` makes the project easier to maintain and audit.
|
|
106
109
|
> ² User-defined metrics allow you to customize your search for various applications, from GIS to creating custom metrics for composite embeddings from multiple AI models or hybrid full-text and semantic search.
|
|
107
110
|
> ³ With USearch, you can reuse the same preconstructed index in various programming languages.
|
|
108
111
|
> ⁴ The 40-bit integer allows you to store 4B+ vectors without allocating 8 bytes for every neighbor reference in the proximity graph.
|
|
109
112
|
> ⁵ Lack of obligatory dependencies makes USearch much more portable.
|
|
110
113
|
> ⁶ Native bindings introduce lower call latencies than more straightforward approaches.
|
|
114
|
+
> ⁷ Lighter bindings make downloads and deployments faster.
|
|
111
115
|
|
|
112
116
|
[intel-benchmarks]: https://www.unum.cloud/blog/2023-11-07-scaling-vector-search-with-intel
|
|
113
117
|
|
|
@@ -141,6 +145,7 @@ index = Index(
|
|
|
141
145
|
connectivity=16, # Optional: Limit number of neighbors per graph node
|
|
142
146
|
expansion_add=128, # Optional: Control the recall of indexing
|
|
143
147
|
expansion_search=64, # Optional: Control the quality of the search
|
|
148
|
+
multi=False, # Optional: Allow multiple vectors per key, default = False
|
|
144
149
|
)
|
|
145
150
|
```
|
|
146
151
|
|
|
@@ -161,7 +166,7 @@ index.save("index.usearch")
|
|
|
161
166
|
loaded_copy = index.load("index.usearch")
|
|
162
167
|
view = Index.restore("index.usearch", view=True)
|
|
163
168
|
|
|
164
|
-
other_view = Index(ndim=..., metric
|
|
169
|
+
other_view = Index(ndim=..., metric=...)
|
|
165
170
|
other_view.view("index.usearch")
|
|
166
171
|
```
|
|
167
172
|
|
|
@@ -208,7 +213,9 @@ multi_index.search(...)
|
|
|
208
213
|
|
|
209
214
|
## Clustering
|
|
210
215
|
|
|
211
|
-
Once the index is constructed,
|
|
216
|
+
Once the index is constructed, USearch can perform K-Nearest Neighbors Clustering much faster than standalone clustering libraries, like SciPy,
|
|
217
|
+
UMap, and tSNE.
|
|
218
|
+
Same for dimensionality reduction with PCA.
|
|
212
219
|
Essentially, the `Index` itself can be seen as a clustering, allowing iterative deepening.
|
|
213
220
|
|
|
214
221
|
```py
|
|
@@ -396,6 +403,8 @@ index.add(keys, fingerprints)
|
|
|
396
403
|
matches = index.search(fingerprints, 10)
|
|
397
404
|
```
|
|
398
405
|
|
|
406
|
+
That method was used to build the ["USearch Molecules"](https://github.com/ashvardanian/usearch-molecules), one of the largest Chem-Informatics datasets, containing 7 billion small molecules and 28 billion fingerprints.
|
|
407
|
+
|
|
399
408
|
[smiles]: https://en.wikipedia.org/wiki/Simplified_molecular-input_line-entry_system
|
|
400
409
|
[rdkit-fingerprints]: https://www.rdkit.org/docs/RDKit_Book.html#additional-information-about-the-fingerprints
|
|
401
410
|
|
|
@@ -424,7 +433,7 @@ doi = {10.5281/zenodo.7949416},
|
|
|
424
433
|
author = {Vardanian, Ash},
|
|
425
434
|
title = {{USearch by Unum Cloud}},
|
|
426
435
|
url = {https://github.com/unum-cloud/usearch},
|
|
427
|
-
version = {2.8.
|
|
436
|
+
version = {2.8.14},
|
|
428
437
|
year = {2023},
|
|
429
438
|
month = oct,
|
|
430
439
|
}
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.8.
|
|
1
|
+
2.8.14
|
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.14'
|
|
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"
|
|
@@ -1309,11 +1309,10 @@ class index_dense_gt {
|
|
|
1309
1309
|
shared_lock_t lock(slot_lookup_mutex_);
|
|
1310
1310
|
offset = (std::min)(offset, slot_lookup_.size());
|
|
1311
1311
|
slot_lookup_.for_each([&](key_and_slot_t const& key_and_slot) {
|
|
1312
|
-
if (offset)
|
|
1312
|
+
if (offset)
|
|
1313
|
+
// Skip the first `offset` entries
|
|
1313
1314
|
--offset;
|
|
1314
|
-
|
|
1315
|
-
}
|
|
1316
|
-
if (limit) {
|
|
1315
|
+
else if (limit) {
|
|
1317
1316
|
*keys = key_and_slot.key;
|
|
1318
1317
|
++keys;
|
|
1319
1318
|
--limit;
|
package/package.json
CHANGED
package/simsimd/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# SimSIMD 📏
|
|
2
2
|
|
|
3
3
|
<div>
|
|
4
|
-
<a href="https://
|
|
4
|
+
<a href="https://pepy.tech/project/simsimd"> <img alt="PyPI" src="https://static.pepy.tech/personalized-badge/simsimd?period=month&units=abbreviation&left_color=black&right_color=blue&left_text=Python%20monthly%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>
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
simsimd_##accumulator_type##_t bi = converter(b[i]); \
|
|
33
33
|
d += ai * SIMSIMD_LOG((ai + epsilon) / (bi + epsilon)); \
|
|
34
34
|
} \
|
|
35
|
-
return d;
|
|
35
|
+
return (simsimd_f32_t)d; \
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
#define SIMSIMD_MAKE_JS(name, input_type, accumulator_type, converter, epsilon) \
|
|
@@ -46,13 +46,16 @@
|
|
|
46
46
|
d += ai * SIMSIMD_LOG((ai + epsilon) / (mi + epsilon)); \
|
|
47
47
|
d += bi * SIMSIMD_LOG((bi + epsilon) / (mi + epsilon)); \
|
|
48
48
|
} \
|
|
49
|
-
return d / 2;
|
|
49
|
+
return (simsimd_f32_t)d / 2; \
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
#ifdef __cplusplus
|
|
53
53
|
extern "C" {
|
|
54
54
|
#endif
|
|
55
55
|
|
|
56
|
+
SIMSIMD_MAKE_KL(serial, f64, f64, SIMSIMD_IDENTIFY, SIMSIMD_F32_DIVISION_EPSILON) // simsimd_serial_f64_kl
|
|
57
|
+
SIMSIMD_MAKE_JS(serial, f64, f64, SIMSIMD_IDENTIFY, SIMSIMD_F32_DIVISION_EPSILON) // simsimd_serial_f64_js
|
|
58
|
+
|
|
56
59
|
SIMSIMD_MAKE_KL(serial, f32, f32, SIMSIMD_IDENTIFY, SIMSIMD_F32_DIVISION_EPSILON) // simsimd_serial_f32_kl
|
|
57
60
|
SIMSIMD_MAKE_JS(serial, f32, f32, SIMSIMD_IDENTIFY, SIMSIMD_F32_DIVISION_EPSILON) // simsimd_serial_f32_js
|
|
58
61
|
|
|
@@ -221,7 +221,30 @@ inline static void simsimd_find_metric_punned( //
|
|
|
221
221
|
switch (datatype) {
|
|
222
222
|
|
|
223
223
|
case simsimd_datatype_unknown_k: break;
|
|
224
|
-
|
|
224
|
+
|
|
225
|
+
// Double-precision floating-point vectors
|
|
226
|
+
case simsimd_datatype_f64_k:
|
|
227
|
+
|
|
228
|
+
#if SIMSIMD_TARGET_X86_AVX512
|
|
229
|
+
if (viable & simsimd_cap_x86_avx512_k)
|
|
230
|
+
switch (kind) {
|
|
231
|
+
case simsimd_metric_ip_k: *m = (simsimd_metric_punned_t)&simsimd_avx512_f64_ip, *c = simsimd_cap_x86_avx512_k; return;
|
|
232
|
+
case simsimd_metric_cos_k: *m = (simsimd_metric_punned_t)&simsimd_avx512_f64_cos, *c = simsimd_cap_x86_avx512_k; return;
|
|
233
|
+
case simsimd_metric_l2sq_k: *m = (simsimd_metric_punned_t)&simsimd_avx512_f64_l2sq, *c = simsimd_cap_x86_avx512_k; return;
|
|
234
|
+
default: break;
|
|
235
|
+
}
|
|
236
|
+
#endif
|
|
237
|
+
if (viable & simsimd_cap_serial_k)
|
|
238
|
+
switch (kind) {
|
|
239
|
+
case simsimd_metric_ip_k: *m = (simsimd_metric_punned_t)&simsimd_serial_f64_ip, *c = simsimd_cap_serial_k; return;
|
|
240
|
+
case simsimd_metric_cos_k: *m = (simsimd_metric_punned_t)&simsimd_serial_f64_cos, *c = simsimd_cap_serial_k; return;
|
|
241
|
+
case simsimd_metric_l2sq_k: *m = (simsimd_metric_punned_t)&simsimd_serial_f64_l2sq, *c = simsimd_cap_serial_k; return;
|
|
242
|
+
case simsimd_metric_js_k: *m = (simsimd_metric_punned_t)&simsimd_serial_f64_js, *c = simsimd_cap_serial_k; return;
|
|
243
|
+
case simsimd_metric_kl_k: *m = (simsimd_metric_punned_t)&simsimd_serial_f64_kl, *c = simsimd_cap_serial_k; return;
|
|
244
|
+
default: break;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
break;
|
|
225
248
|
|
|
226
249
|
// Single-precision floating-point vectors
|
|
227
250
|
case simsimd_datatype_f32_k:
|
|
@@ -67,6 +67,10 @@
|
|
|
67
67
|
extern "C" {
|
|
68
68
|
#endif
|
|
69
69
|
|
|
70
|
+
SIMSIMD_MAKE_L2SQ(serial, f64, f64, SIMSIMD_IDENTIFY) // simsimd_serial_f64_l2sq
|
|
71
|
+
SIMSIMD_MAKE_IP(serial, f64, f64, SIMSIMD_IDENTIFY) // simsimd_serial_f64_ip
|
|
72
|
+
SIMSIMD_MAKE_COS(serial, f64, f64, SIMSIMD_IDENTIFY) // simsimd_serial_f64_cos
|
|
73
|
+
|
|
70
74
|
SIMSIMD_MAKE_L2SQ(serial, f32, f32, SIMSIMD_IDENTIFY) // simsimd_serial_f32_l2sq
|
|
71
75
|
SIMSIMD_MAKE_IP(serial, f32, f32, SIMSIMD_IDENTIFY) // simsimd_serial_f32_ip
|
|
72
76
|
SIMSIMD_MAKE_COS(serial, f32, f32, SIMSIMD_IDENTIFY) // simsimd_serial_f32_cos
|
|
@@ -338,7 +342,7 @@ simsimd_neon_i8_ip(simsimd_i8_t const* a, simsimd_i8_t const* b, simsimd_size_t
|
|
|
338
342
|
* @author Ash Vardanian
|
|
339
343
|
*
|
|
340
344
|
* - Implements: L2 squared, inner product, cosine similarity.
|
|
341
|
-
* - Uses `
|
|
345
|
+
* - Uses `f32` for both storage and accumulation.
|
|
342
346
|
* - Requires compiler capabilities: +sve.
|
|
343
347
|
*/
|
|
344
348
|
|
|
@@ -408,7 +412,7 @@ simsimd_sve_f32_cos(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size
|
|
|
408
412
|
* @author Ash Vardanian
|
|
409
413
|
*
|
|
410
414
|
* - Implements: L2 squared, inner product, cosine similarity.
|
|
411
|
-
* - Uses `f16` for
|
|
415
|
+
* - Uses `f16` for storage and `f32` for accumulation.
|
|
412
416
|
* - Requires compiler capabilities: +sve+fp16.
|
|
413
417
|
*/
|
|
414
418
|
|
|
@@ -479,6 +483,77 @@ simsimd_sve_f16_cos(simsimd_f16_t const* a_enum, simsimd_f16_t const* b_enum, si
|
|
|
479
483
|
return ab != 0 ? 1 - ab * a2_b2_arr[0] * a2_b2_arr[1] : 1;
|
|
480
484
|
}
|
|
481
485
|
|
|
486
|
+
/*
|
|
487
|
+
* @file arm_sve_f64.h
|
|
488
|
+
* @brief Arm SVE implementation of the most common similarity metrics for 64-bit floating point numbers.
|
|
489
|
+
* @author Ash Vardanian
|
|
490
|
+
*
|
|
491
|
+
* - Implements: L2 squared, inner product, cosine similarity.
|
|
492
|
+
* - Uses `f64` for both storage and for accumulation.
|
|
493
|
+
* - Requires compiler capabilities: +sve.
|
|
494
|
+
*/
|
|
495
|
+
|
|
496
|
+
__attribute__((target("+sve"))) //
|
|
497
|
+
inline static simsimd_f32_t
|
|
498
|
+
simsimd_sve_f64_l2sq(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n) {
|
|
499
|
+
simsimd_size_t i = 0;
|
|
500
|
+
svfloat64_t d2_vec = svdupq_n_f64(0.0, 0.0);
|
|
501
|
+
do {
|
|
502
|
+
svbool_t pg_vec = svwhilelt_b64((unsigned int)i, (unsigned int)n);
|
|
503
|
+
svfloat64_t a_vec = svld1_f64(pg_vec, a + i);
|
|
504
|
+
svfloat64_t b_vec = svld1_f64(pg_vec, b + i);
|
|
505
|
+
svfloat64_t a_minus_b_vec = svsub_f64_x(pg_vec, a_vec, b_vec);
|
|
506
|
+
d2_vec = svmla_f64_x(pg_vec, d2_vec, a_minus_b_vec, a_minus_b_vec);
|
|
507
|
+
i += svcntd();
|
|
508
|
+
} while (i < n);
|
|
509
|
+
simsimd_f64_t d2 = svaddv_f64(svptrue_b32(), d2_vec);
|
|
510
|
+
return d2;
|
|
511
|
+
}
|
|
512
|
+
__attribute__((target("+sve"))) //
|
|
513
|
+
inline static simsimd_f32_t
|
|
514
|
+
simsimd_sve_f64_ip(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n) {
|
|
515
|
+
simsimd_size_t i = 0;
|
|
516
|
+
svfloat64_t ab_vec = svdupq_n_f64(0.0, 0.0);
|
|
517
|
+
do {
|
|
518
|
+
svbool_t pg_vec = svwhilelt_b64((unsigned int)i, (unsigned int)n);
|
|
519
|
+
svfloat64_t a_vec = svld1_f64(pg_vec, a + i);
|
|
520
|
+
svfloat64_t b_vec = svld1_f64(pg_vec, b + i);
|
|
521
|
+
ab_vec = svmla_f64_x(pg_vec, ab_vec, a_vec, b_vec);
|
|
522
|
+
i += svcntd();
|
|
523
|
+
} while (i < n);
|
|
524
|
+
return 1 - svaddv_f64(svptrue_b32(), ab_vec);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
__attribute__((target("+sve"))) //
|
|
528
|
+
inline static simsimd_f32_t
|
|
529
|
+
simsimd_sve_f64_cos(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n) {
|
|
530
|
+
simsimd_size_t i = 0;
|
|
531
|
+
svfloat64_t ab_vec = svdupq_n_f64(0.0, 0.0);
|
|
532
|
+
svfloat64_t a2_vec = svdupq_n_f64(0.0, 0.0);
|
|
533
|
+
svfloat64_t b2_vec = svdupq_n_f64(0.0, 0.0);
|
|
534
|
+
do {
|
|
535
|
+
svbool_t pg_vec = svwhilelt_b64((unsigned int)i, (unsigned int)n);
|
|
536
|
+
svfloat64_t a_vec = svld1_f64(pg_vec, a + i);
|
|
537
|
+
svfloat64_t b_vec = svld1_f64(pg_vec, b + i);
|
|
538
|
+
ab_vec = svmla_f64_x(pg_vec, ab_vec, a_vec, b_vec);
|
|
539
|
+
a2_vec = svmla_f64_x(pg_vec, a2_vec, a_vec, a_vec);
|
|
540
|
+
b2_vec = svmla_f64_x(pg_vec, b2_vec, b_vec, b_vec);
|
|
541
|
+
i += svcntd();
|
|
542
|
+
} while (i < n);
|
|
543
|
+
|
|
544
|
+
simsimd_f64_t ab = svaddv_f64(svptrue_b32(), ab_vec);
|
|
545
|
+
simsimd_f64_t a2 = svaddv_f64(svptrue_b32(), a2_vec);
|
|
546
|
+
simsimd_f64_t b2 = svaddv_f64(svptrue_b32(), b2_vec);
|
|
547
|
+
|
|
548
|
+
// Avoid `simsimd_approximate_inverse_square_root` on Arm NEON
|
|
549
|
+
simsimd_f64_t a2_b2_arr[2] = {a2, b2};
|
|
550
|
+
float64x2_t a2_b2 = vld1q_f64(a2_b2_arr);
|
|
551
|
+
a2_b2 = vrsqrteq_f64(a2_b2);
|
|
552
|
+
vst1q_f64(a2_b2_arr, a2_b2);
|
|
553
|
+
return ab != 0 ? 1 - ab * a2_b2_arr[0] * a2_b2_arr[1] : 1;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
|
|
482
557
|
#endif // SIMSIMD_TARGET_ARM_SVE
|
|
483
558
|
#endif // SIMSIMD_TARGET_ARM
|
|
484
559
|
|
|
@@ -996,6 +1071,101 @@ simsimd_avx512_i8_ip(simsimd_i8_t const* a, simsimd_i8_t const* b, simsimd_size_
|
|
|
996
1071
|
return simsimd_avx512_i8_cos(a, b, n);
|
|
997
1072
|
}
|
|
998
1073
|
|
|
1074
|
+
/*
|
|
1075
|
+
* @file x86_avx512_f64.h
|
|
1076
|
+
* @brief x86 AVX-512 implementation of the most common similarity metrics for 64-bit floating point numbers.
|
|
1077
|
+
* @author Ash Vardanian
|
|
1078
|
+
*
|
|
1079
|
+
* - Implements: L2 squared, inner product, cosine similarity.
|
|
1080
|
+
* - Uses `f64` for both storage and accumulation.
|
|
1081
|
+
* - Requires compiler capabilities: avx512f, avx512vl, bmi2.
|
|
1082
|
+
*/
|
|
1083
|
+
|
|
1084
|
+
__attribute__((target("avx512f,avx512vl,bmi2"))) //
|
|
1085
|
+
inline static simsimd_f32_t
|
|
1086
|
+
simsimd_avx512_f64_l2sq(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n) {
|
|
1087
|
+
__m512d d2_vec = _mm512_set1_pd(0);
|
|
1088
|
+
__m512d a_vec, b_vec;
|
|
1089
|
+
|
|
1090
|
+
simsimd_avx512_f64_l2sq_cycle:
|
|
1091
|
+
if (n < 8) {
|
|
1092
|
+
__mmask8 mask = _bzhi_u32(0xFFFFFFFF, n);
|
|
1093
|
+
a_vec = _mm512_maskz_loadu_pd(mask, a);
|
|
1094
|
+
b_vec = _mm512_maskz_loadu_pd(mask, b);
|
|
1095
|
+
n = 0;
|
|
1096
|
+
} else {
|
|
1097
|
+
a_vec = _mm512_loadu_pd(a);
|
|
1098
|
+
b_vec = _mm512_loadu_pd(b);
|
|
1099
|
+
a += 8, b += 8, n -= 8;
|
|
1100
|
+
}
|
|
1101
|
+
__m512d d_vec = _mm512_sub_pd(a_vec, b_vec);
|
|
1102
|
+
d2_vec = _mm512_fmadd_pd(d_vec, d_vec, d2_vec);
|
|
1103
|
+
if (n)
|
|
1104
|
+
goto simsimd_avx512_f64_l2sq_cycle;
|
|
1105
|
+
|
|
1106
|
+
return (simsimd_f32_t)_mm512_reduce_add_pd(d2_vec);
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
__attribute__((target("avx512f,avx512vl,bmi2"))) //
|
|
1110
|
+
inline static simsimd_f32_t
|
|
1111
|
+
simsimd_avx512_f64_ip(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n) {
|
|
1112
|
+
__m512d ab_vec = _mm512_set1_pd(0);
|
|
1113
|
+
__m512d a_vec, b_vec;
|
|
1114
|
+
|
|
1115
|
+
simsimd_avx512_f64_ip_cycle:
|
|
1116
|
+
if (n < 8) {
|
|
1117
|
+
__mmask8 mask = _bzhi_u32(0xFFFFFFFF, n);
|
|
1118
|
+
a_vec = _mm512_maskz_loadu_pd(mask, a);
|
|
1119
|
+
b_vec = _mm512_maskz_loadu_pd(mask, b);
|
|
1120
|
+
n = 0;
|
|
1121
|
+
} else {
|
|
1122
|
+
a_vec = _mm512_loadu_pd(a);
|
|
1123
|
+
b_vec = _mm512_loadu_pd(b);
|
|
1124
|
+
a += 8, b += 8, n -= 8;
|
|
1125
|
+
}
|
|
1126
|
+
ab_vec = _mm512_fmadd_pd(a_vec, b_vec, ab_vec);
|
|
1127
|
+
if (n)
|
|
1128
|
+
goto simsimd_avx512_f64_ip_cycle;
|
|
1129
|
+
|
|
1130
|
+
return 1 - (simsimd_f32_t)_mm512_reduce_add_pd(ab_vec);
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
__attribute__((target("avx512f,avx512vl,bmi2"))) //
|
|
1134
|
+
inline static simsimd_f32_t
|
|
1135
|
+
simsimd_avx512_f64_cos(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n) {
|
|
1136
|
+
__m512d ab_vec = _mm512_set1_pd(0);
|
|
1137
|
+
__m512d a2_vec = _mm512_set1_pd(0);
|
|
1138
|
+
__m512d b2_vec = _mm512_set1_pd(0);
|
|
1139
|
+
__m512d a_vec, b_vec;
|
|
1140
|
+
|
|
1141
|
+
simsimd_avx512_f64_cos_cycle:
|
|
1142
|
+
if (n < 8) {
|
|
1143
|
+
__mmask8 mask = _bzhi_u32(0xFFFFFFFF, n);
|
|
1144
|
+
a_vec = _mm512_maskz_loadu_pd(mask, a);
|
|
1145
|
+
b_vec = _mm512_maskz_loadu_pd(mask, b);
|
|
1146
|
+
n = 0;
|
|
1147
|
+
} else {
|
|
1148
|
+
a_vec = _mm512_loadu_pd(a);
|
|
1149
|
+
b_vec = _mm512_loadu_pd(b);
|
|
1150
|
+
a += 8, b += 8, n -= 8;
|
|
1151
|
+
}
|
|
1152
|
+
ab_vec = _mm512_fmadd_pd(a_vec, b_vec, ab_vec);
|
|
1153
|
+
a2_vec = _mm512_fmadd_pd(a_vec, a_vec, a2_vec);
|
|
1154
|
+
b2_vec = _mm512_fmadd_pd(b_vec, b_vec, b2_vec);
|
|
1155
|
+
if (n)
|
|
1156
|
+
goto simsimd_avx512_f64_cos_cycle;
|
|
1157
|
+
|
|
1158
|
+
simsimd_f32_t ab = (simsimd_f32_t)_mm512_reduce_add_pd(ab_vec);
|
|
1159
|
+
simsimd_f32_t a2 = (simsimd_f32_t)_mm512_reduce_add_pd(a2_vec);
|
|
1160
|
+
simsimd_f32_t b2 = (simsimd_f32_t)_mm512_reduce_add_pd(b2_vec);
|
|
1161
|
+
|
|
1162
|
+
// Compute the reciprocal square roots of a2 and b2
|
|
1163
|
+
__m128 rsqrts = _mm_rsqrt14_ps(_mm_set_ps(0.f, 0.f, a2 + 1.e-9f, b2 + 1.e-9f));
|
|
1164
|
+
simsimd_f32_t rsqrt_a2 = _mm_cvtss_f32(rsqrts);
|
|
1165
|
+
simsimd_f32_t rsqrt_b2 = _mm_cvtss_f32(_mm_shuffle_ps(rsqrts, rsqrts, _MM_SHUFFLE(0, 0, 0, 1)));
|
|
1166
|
+
return 1 - ab * rsqrt_a2 * rsqrt_b2;
|
|
1167
|
+
}
|
|
1168
|
+
|
|
999
1169
|
#endif // SIMSIMD_TARGET_X86_AVX512
|
|
1000
1170
|
#endif // SIMSIMD_TARGET_X86
|
|
1001
1171
|
|
package/simsimd/package.json
CHANGED
|
@@ -1,10 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "simsimd",
|
|
3
|
-
"version": "3.
|
|
4
|
-
"description": "Vector Similarity Functions
|
|
3
|
+
"version": "3.6.0",
|
|
4
|
+
"description": "Fastest SIMD-Accelerated Vector Similarity Functions for x86 and Arm",
|
|
5
|
+
"homepage": "https://github.com/ashvardanian/simsimd",
|
|
5
6
|
"author": "Ash Vardanian",
|
|
6
7
|
"license": "Apache 2.0",
|
|
7
8
|
"main": "javascript/simsimd.js",
|
|
9
|
+
"keywords": [
|
|
10
|
+
"vector",
|
|
11
|
+
"distance",
|
|
12
|
+
"similarity",
|
|
13
|
+
"search",
|
|
14
|
+
"ai",
|
|
15
|
+
"math",
|
|
16
|
+
"avx2",
|
|
17
|
+
"avx512",
|
|
18
|
+
"neon",
|
|
19
|
+
"sve",
|
|
20
|
+
"arm",
|
|
21
|
+
"x86",
|
|
22
|
+
"simd",
|
|
23
|
+
"f16"
|
|
24
|
+
],
|
|
8
25
|
"type": "module",
|
|
9
26
|
"scripts": {
|
|
10
27
|
"test": "node --test ./javascript/test",
|
|
@@ -26,4 +43,4 @@
|
|
|
26
43
|
"typescript": "^5.1.6",
|
|
27
44
|
"usearch": "^2.7.2"
|
|
28
45
|
}
|
|
29
|
-
}
|
|
46
|
+
}
|