usearch 2.8.13 → 2.8.15

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.13
8
+ version: 2.8.15
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.13"
3
+ version = "2.8.15"
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
@@ -433,7 +433,7 @@ doi = {10.5281/zenodo.7949416},
433
433
  author = {Vardanian, Ash},
434
434
  title = {{USearch by Unum Cloud}},
435
435
  url = {https://github.com/unum-cloud/usearch},
436
- version = {2.8.13},
436
+ version = {2.8.15},
437
437
  year = {2023},
438
438
  month = oct,
439
439
  }
package/VERSION CHANGED
@@ -1 +1 @@
1
- 2.8.13
1
+ 2.8.15
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.13'
10
+ version = '2.8.15'
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 13
14
+ #define USEARCH_VERSION_PATCH 15
15
15
 
16
16
  // Inferring C++ version
17
17
  // https://stackoverflow.com/a/61552074
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "usearch",
3
- "version": "2.8.13",
3
+ "version": "2.8.15",
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.13"
3
+ version="2.8.15"
4
4
  description="Smaller & Faster Single-File Vector Search Engine from Unum"
5
5
  license="Apache-2.0"
6
6
  readme="README.md"