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 CHANGED
@@ -5,7 +5,7 @@ authors:
5
5
  given-names: "Ash"
6
6
  orcid: "https://orcid.org/0000-0002-4882-1815"
7
7
  title: "USearch by Unum Cloud"
8
- version: 2.8.12
8
+ version: 2.8.14
9
9
  doi: 10.5281/zenodo.7949416
10
10
  date-released: 2023-10-22
11
11
  url: "https://github.com/unum-cloud/usearch"
package/Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "usearch"
3
- version = "2.8.12"
3
+ version = "2.8.14"
4
4
  authors = ["Ash Vardanian <1983160+ashvardanian@users.noreply.github.com>"]
5
5
  description = "Smaller & Faster Single-File Vector Search Engine from Unum"
6
6
  edition = "2021"
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://pypi.org/project/usearch/"> <img alt="PyPI" src="https://img.shields.io/pypi/dm/usearch?label=PyPi%20pulls"> </a>
40
- <a href="https://www.npmjs.com/package/usearch"> <img alt="NPM" src="https://img.shields.io/npm/dy/usearch?label=NPM%20pulls"> </a>
41
- <a href="https://crates.io/crates/usearch"> <img alt="Crate" src="https://img.shields.io/crates/d/usearch?label=Crate%20pulls"> </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%20pulls"> </a>
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%20pulls"> </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%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
- - ✅ [20x faster than][faster-than-faiss] [FAISS][faiss] implementation of [HNSW algorithm][hnsw-algorithm].
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
- | | FAISS | USearch | Improvement |
90
- | :------------------------------------------- | ----------------------------: | -----------------------------: | ---------------------: |
91
- | Indexing time ⁰ | | | |
92
- | 100 Million 96d `f32`, `f16`, `i8` vectors | 2.6 h, 2.6 h, 2.6 h | 0.3 h, 0.2 h, 0.2 h | __9.6x, 10.4x, 10.7x__ |
93
- | 100 Million 1536d `f32`, `f16`, `i8` vectors | 5.0 h, 4.1 h, 3.8 h | 2.1 h, 1.1 h, 0.8 h | __2.3x 3.6x, 4.4x__ |
94
- | | | | |
95
- | Codebase length ¹ | 84 K [SLOC][sloc] in `faiss/` | 3 K [SLOC][sloc] in `usearch/` | maintainable |
96
- | Supported metrics ² | 9 fixed metrics | any user-defined metrics | 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 |
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=CompiledMetric(...))
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, it can cluster entries much faster than using a separate clustering algorithm implementation.
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.12},
436
+ version = {2.8.14},
428
437
  year = {2023},
429
438
  month = oct,
430
439
  }
package/VERSION CHANGED
@@ -1 +1 @@
1
- 2.8.12
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.12'
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"
@@ -11,7 +11,7 @@
11
11
 
12
12
  #define USEARCH_VERSION_MAJOR 2
13
13
  #define USEARCH_VERSION_MINOR 8
14
- #define USEARCH_VERSION_PATCH 12
14
+ #define USEARCH_VERSION_PATCH 14
15
15
 
16
16
  // Inferring C++ version
17
17
  // https://stackoverflow.com/a/61552074
@@ -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
- return;
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "usearch",
3
- "version": "2.8.12",
3
+ "version": "2.8.14",
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",
package/simsimd/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # SimSIMD 📏
2
2
 
3
3
  <div>
4
- <a href="https://pypi.org/project/simsimd/"> <img alt="PyPI - Downloads" src="https://img.shields.io/pypi/dm/simsimd?label=pypi%20downloads"> </a>
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
- case simsimd_datatype_f64_k: break;
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 `f16` for both storage and `f32` for accumulation.
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 both storage and `f32` for accumulation.
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
 
@@ -1,10 +1,27 @@
1
1
  {
2
2
  "name": "simsimd",
3
- "version": "3.5.5",
4
- "description": "Vector Similarity Functions 3x-200x Faster than SciPy and NumPy",
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
+ }
package/wasmer.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name="unum/usearch"
3
- version="2.8.12"
3
+ version="2.8.14"
4
4
  description="Smaller & Faster Single-File Vector Search Engine from Unum"
5
5
  license="Apache-2.0"
6
6
  readme="README.md"