usearch 2.7.7 → 2.8.1

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.
Files changed (54) hide show
  1. package/.dockerignore +93 -0
  2. package/.github/workflows/Dockerfile.libs +6 -2
  3. package/.github/workflows/prerelease.yml +242 -245
  4. package/.github/workflows/release.yml +399 -357
  5. package/.gitignore +1 -0
  6. package/.vscode/settings.json +3 -1
  7. package/CITATION.cff +1 -1
  8. package/CMakeLists.txt +35 -5
  9. package/Cargo.toml +1 -1
  10. package/README.md +1 -1
  11. package/build.gradle +6 -0
  12. package/c/README.md +3 -3
  13. package/c/lib.cpp +75 -11
  14. package/c/usearch.h +22 -1
  15. package/conanfile.py +1 -1
  16. package/cpp/README.md +2 -1
  17. package/cpp/bench.cpp +3 -0
  18. package/cpp/test.cpp +12 -12
  19. package/csharp/nuget/nuget-package.props +1 -1
  20. package/docs/compilation.md +5 -13
  21. package/golang/lib.go +4 -1
  22. package/include/usearch/index.hpp +31 -30
  23. package/include/usearch/index_dense.hpp +49 -48
  24. package/include/usearch/index_plugins.hpp +70 -8
  25. package/java/cloud/unum/usearch/Index.java +118 -26
  26. package/java/cloud/unum/usearch/cloud_unum_usearch_Index.cpp +8 -8
  27. package/javascript/usearch.js +1 -0
  28. package/objc/USearchObjective.mm +4 -1
  29. package/objc/include/USearchObjective.h +1 -0
  30. package/package.json +1 -1
  31. package/pyproject.toml +10 -8
  32. package/python/lib.cpp +3 -2
  33. package/python/scripts/bench.ipynb +24 -2
  34. package/python/usearch/index.py +8 -3
  35. package/rust/lib.cpp +14 -12
  36. package/rust/lib.hpp +13 -13
  37. package/rust/lib.rs +47 -0
  38. package/setup.py +15 -3
  39. package/simsimd/.github/workflows/prerelease.yml +7 -8
  40. package/simsimd/.github/workflows/release.yml +18 -20
  41. package/simsimd/README.md +13 -8
  42. package/simsimd/binding.gyp +1 -1
  43. package/simsimd/cpp/bench.cxx +17 -3
  44. package/simsimd/include/simsimd/binary.h +1 -3
  45. package/simsimd/include/simsimd/probability.h +234 -361
  46. package/simsimd/include/simsimd/simsimd.h +95 -65
  47. package/simsimd/include/simsimd/spatial.h +0 -3
  48. package/simsimd/include/simsimd/types.h +12 -7
  49. package/simsimd/javascript/test.js +23 -5
  50. package/simsimd/package.json +2 -2
  51. package/wasmer.toml +1 -1
  52. package/wolfram/lib.cpp +1 -1
  53. package/csharp/eng/build_lib.sh +0 -65
  54. package/csharp/eng/clean.sh +0 -12
@@ -110,7 +110,7 @@ inline static simsimd_capability_t simsimd_capabilities() {
110
110
  #if SIMSIMD_TARGET_X86
111
111
 
112
112
  /// The states of 4 registers populated for a specific "cpuid" assmebly call
113
- union {
113
+ union four_registers_t {
114
114
  int array[4];
115
115
  struct {
116
116
  unsigned eax, ebx, ecx, edx;
@@ -176,6 +176,11 @@ inline static simsimd_capability_t simsimd_capabilities() {
176
176
  return simsimd_cap_serial_k;
177
177
  }
178
178
 
179
+ #pragma GCC diagnostic push
180
+ #pragma GCC diagnostic ignored "-Wcast-function-type"
181
+ #pragma clang diagnostic push
182
+ #pragma clang diagnostic ignored "-Wcast-function-type"
183
+
179
184
  /**
180
185
  * @brief Determines the best suited metric implementation based on the given datatype,
181
186
  * supported and allowed by hardware capabilities.
@@ -213,28 +218,33 @@ inline static void simsimd_find_metric_punned( //
213
218
  #if SIMSIMD_TARGET_ARM_NEON
214
219
  if (viable & simsimd_cap_arm_neon_k)
215
220
  switch (kind) {
216
- case simsimd_metric_ip_k: *m = (simsimd_metric_punned_t)&simsimd_neon_f32_ip, *c = simsimd_cap_arm_neon_k; break;
217
- case simsimd_metric_cos_k: *m = (simsimd_metric_punned_t)&simsimd_neon_f32_cos, *c = simsimd_cap_arm_neon_k; break;
218
- case simsimd_metric_l2sq_k: *m = (simsimd_metric_punned_t)&simsimd_neon_f32_l2sq, *c = simsimd_cap_arm_neon_k; break;
219
- case simsimd_metric_js_k: *m = (simsimd_metric_punned_t)&simsimd_neon_f32_js, *c = simsimd_cap_arm_neon_k; break;
220
- case simsimd_metric_kl_k: *m = (simsimd_metric_punned_t)&simsimd_neon_f32_kl, *c = simsimd_cap_arm_neon_k; break;
221
+ case simsimd_metric_ip_k: *m = (simsimd_metric_punned_t)&simsimd_neon_f32_ip, *c = simsimd_cap_arm_neon_k; return;
222
+ case simsimd_metric_cos_k: *m = (simsimd_metric_punned_t)&simsimd_neon_f32_cos, *c = simsimd_cap_arm_neon_k; return;
223
+ case simsimd_metric_l2sq_k: *m = (simsimd_metric_punned_t)&simsimd_neon_f32_l2sq, *c = simsimd_cap_arm_neon_k; return;
224
+ case simsimd_metric_js_k: *m = (simsimd_metric_punned_t)&simsimd_neon_f32_js, *c = simsimd_cap_arm_neon_k; return;
225
+ case simsimd_metric_kl_k: *m = (simsimd_metric_punned_t)&simsimd_neon_f32_kl, *c = simsimd_cap_arm_neon_k; return;
226
+ default: break;
221
227
  }
222
228
  #endif
223
229
  #if SIMSIMD_TARGET_X86_AVX512
224
230
  if (viable & simsimd_cap_x86_avx512_k)
225
231
  switch (kind) {
226
- case simsimd_metric_ip_k: *m = (simsimd_metric_punned_t)&simsimd_avx512_f32_ip, *c = simsimd_cap_x86_avx512_k; break;
227
- case simsimd_metric_cos_k: *m = (simsimd_metric_punned_t)&simsimd_avx512_f32_cos, *c = simsimd_cap_x86_avx512_k; break;
228
- case simsimd_metric_l2sq_k: *m = (simsimd_metric_punned_t)&simsimd_avx512_f32_l2sq, *c = simsimd_cap_x86_avx512_k; break;
232
+ case simsimd_metric_ip_k: *m = (simsimd_metric_punned_t)&simsimd_avx512_f32_ip, *c = simsimd_cap_x86_avx512_k; return;
233
+ case simsimd_metric_cos_k: *m = (simsimd_metric_punned_t)&simsimd_avx512_f32_cos, *c = simsimd_cap_x86_avx512_k; return;
234
+ case simsimd_metric_l2sq_k: *m = (simsimd_metric_punned_t)&simsimd_avx512_f32_l2sq, *c = simsimd_cap_x86_avx512_k; return;
235
+ case simsimd_metric_js_k: *m = (simsimd_metric_punned_t)&simsimd_avx512_f32_js, *c = simsimd_cap_x86_avx512_k; return;
236
+ case simsimd_metric_kl_k: *m = (simsimd_metric_punned_t)&simsimd_avx512_f32_kl, *c = simsimd_cap_x86_avx512_k; return;
237
+ default: break;
229
238
  }
230
239
  #endif
231
240
  if (viable & simsimd_cap_serial_k)
232
241
  switch (kind) {
233
- case simsimd_metric_ip_k: *m = (simsimd_metric_punned_t)&simsimd_serial_f32_ip, *c = simsimd_cap_serial_k; break;
234
- case simsimd_metric_cos_k: *m = (simsimd_metric_punned_t)&simsimd_serial_f32_cos, *c = simsimd_cap_serial_k; break;
235
- case simsimd_metric_l2sq_k: *m = (simsimd_metric_punned_t)&simsimd_serial_f32_l2sq, *c = simsimd_cap_serial_k; break;
236
- case simsimd_metric_js_k: *m = (simsimd_metric_punned_t)&simsimd_serial_f32_js, *c = simsimd_cap_serial_k; break;
237
- case simsimd_metric_kl_k: *m = (simsimd_metric_punned_t)&simsimd_serial_f32_kl, *c = simsimd_cap_serial_k; break;
242
+ case simsimd_metric_ip_k: *m = (simsimd_metric_punned_t)&simsimd_serial_f32_ip, *c = simsimd_cap_serial_k; return;
243
+ case simsimd_metric_cos_k: *m = (simsimd_metric_punned_t)&simsimd_serial_f32_cos, *c = simsimd_cap_serial_k; return;
244
+ case simsimd_metric_l2sq_k: *m = (simsimd_metric_punned_t)&simsimd_serial_f32_l2sq, *c = simsimd_cap_serial_k; return;
245
+ case simsimd_metric_js_k: *m = (simsimd_metric_punned_t)&simsimd_serial_f32_js, *c = simsimd_cap_serial_k; return;
246
+ case simsimd_metric_kl_k: *m = (simsimd_metric_punned_t)&simsimd_serial_f32_kl, *c = simsimd_cap_serial_k; return;
247
+ default: break;
238
248
  }
239
249
 
240
250
  break;
@@ -242,48 +252,57 @@ inline static void simsimd_find_metric_punned( //
242
252
  // Half-precision floating-point vectors
243
253
  case simsimd_datatype_f16_k:
244
254
 
245
- #if SIMSIMD_TARGET_ARM_NEON
246
- if (viable & simsimd_cap_arm_neon_k)
247
- switch (kind) {
248
- case simsimd_metric_ip_k: *m = (simsimd_metric_punned_t)&simsimd_neon_f16_ip, *c = simsimd_cap_arm_neon_k; break;
249
- case simsimd_metric_cos_k: *m = (simsimd_metric_punned_t)&simsimd_neon_f16_cos, *c = simsimd_cap_arm_neon_k; break;
250
- case simsimd_metric_l2sq_k: *m = (simsimd_metric_punned_t)&simsimd_neon_f16_l2sq, *c = simsimd_cap_arm_neon_k; break;
251
- case simsimd_metric_js_k: *m = (simsimd_metric_punned_t)&simsimd_neon_f16_js, *c = simsimd_cap_arm_neon_k; break;
252
- case simsimd_metric_kl_k: *m = (simsimd_metric_punned_t)&simsimd_neon_f16_kl, *c = simsimd_cap_arm_neon_k; break;
253
- }
254
- #endif
255
255
  #if SIMSIMD_TARGET_ARM_SVE
256
256
  if (viable & simsimd_cap_arm_sve_k)
257
257
  switch (kind) {
258
- case simsimd_metric_ip_k: *m = (simsimd_metric_punned_t)&simsimd_sve_f16_ip, *c = simsimd_cap_arm_sve_k; break;
259
- case simsimd_metric_cos_k: *m = (simsimd_metric_punned_t)&simsimd_sve_f16_cos, *c = simsimd_cap_arm_sve_k; break;
260
- case simsimd_metric_l2sq_k: *m = (simsimd_metric_punned_t)&simsimd_sve_f16_l2sq, *c = simsimd_cap_arm_sve_k; break;
258
+ case simsimd_metric_ip_k: *m = (simsimd_metric_punned_t)&simsimd_sve_f16_ip, *c = simsimd_cap_arm_sve_k; return;
259
+ case simsimd_metric_cos_k: *m = (simsimd_metric_punned_t)&simsimd_sve_f16_cos, *c = simsimd_cap_arm_sve_k; return;
260
+ case simsimd_metric_l2sq_k: *m = (simsimd_metric_punned_t)&simsimd_sve_f16_l2sq, *c = simsimd_cap_arm_sve_k; return;
261
+ default: break;
261
262
  }
262
263
  #endif
263
- #if SIMSIMD_TARGET_X86_AVX2
264
- if (viable & simsimd_cap_x86_avx2_k)
264
+ #if SIMSIMD_TARGET_ARM_NEON
265
+ if (viable & simsimd_cap_arm_neon_k)
265
266
  switch (kind) {
266
- case simsimd_metric_ip_k: *m = (simsimd_metric_punned_t)&simsimd_avx2_f16_ip, *c = simsimd_cap_x86_avx2_k; break;
267
- case simsimd_metric_cos_k: *m = (simsimd_metric_punned_t)&simsimd_avx2_f16_cos, *c = simsimd_cap_x86_avx2_k; break;
268
- case simsimd_metric_l2sq_k: *m = (simsimd_metric_punned_t)&simsimd_avx2_f16_l2sq, *c = simsimd_cap_x86_avx2_k; break;
267
+ case simsimd_metric_ip_k: *m = (simsimd_metric_punned_t)&simsimd_neon_f16_ip, *c = simsimd_cap_arm_neon_k; return;
268
+ case simsimd_metric_cos_k: *m = (simsimd_metric_punned_t)&simsimd_neon_f16_cos, *c = simsimd_cap_arm_neon_k; return;
269
+ case simsimd_metric_l2sq_k: *m = (simsimd_metric_punned_t)&simsimd_neon_f16_l2sq, *c = simsimd_cap_arm_neon_k; return;
270
+ case simsimd_metric_js_k: *m = (simsimd_metric_punned_t)&simsimd_neon_f16_js, *c = simsimd_cap_arm_neon_k; return;
271
+ case simsimd_metric_kl_k: *m = (simsimd_metric_punned_t)&simsimd_neon_f16_kl, *c = simsimd_cap_arm_neon_k; return;
272
+ default: break;
269
273
  }
270
274
  #endif
271
275
  #if SIMSIMD_TARGET_X86_AVX512
272
- if (viable & simsimd_cap_x86_avx512_k)
276
+ if (viable & simsimd_cap_x86_avx512fp16_k)
277
+ switch (kind) {
278
+ case simsimd_metric_ip_k: *m = (simsimd_metric_punned_t)&simsimd_avx512_f16_ip, *c = simsimd_cap_x86_avx512fp16_k; return;
279
+ case simsimd_metric_cos_k: *m = (simsimd_metric_punned_t)&simsimd_avx512_f16_cos, *c = simsimd_cap_x86_avx512fp16_k; return;
280
+ case simsimd_metric_l2sq_k: *m = (simsimd_metric_punned_t)&simsimd_avx512_f16_l2sq, *c = simsimd_cap_x86_avx512fp16_k; return;
281
+ case simsimd_metric_js_k: *m = (simsimd_metric_punned_t)&simsimd_avx512_f16_js, *c = simsimd_cap_x86_avx512fp16_k; return;
282
+ case simsimd_metric_kl_k: *m = (simsimd_metric_punned_t)&simsimd_avx512_f16_kl, *c = simsimd_cap_x86_avx512fp16_k; return;
283
+ default: break;
284
+ }
285
+ #endif
286
+ #if SIMSIMD_TARGET_X86_AVX2
287
+ if (viable & simsimd_cap_x86_avx2fp16_k)
273
288
  switch (kind) {
274
- case simsimd_metric_ip_k: *m = (simsimd_metric_punned_t)&simsimd_avx512_f16_ip, *c = simsimd_cap_x86_avx512_k; break;
275
- case simsimd_metric_cos_k: *m = (simsimd_metric_punned_t)&simsimd_avx512_f16_cos, *c = simsimd_cap_x86_avx512_k; break;
276
- case simsimd_metric_l2sq_k: *m = (simsimd_metric_punned_t)&simsimd_avx512_f16_l2sq, *c = simsimd_cap_x86_avx512_k; break;
289
+ case simsimd_metric_ip_k: *m = (simsimd_metric_punned_t)&simsimd_avx2_f16_ip, *c = simsimd_cap_x86_avx2fp16_k; return;
290
+ case simsimd_metric_cos_k: *m = (simsimd_metric_punned_t)&simsimd_avx2_f16_cos, *c = simsimd_cap_x86_avx2fp16_k; return;
291
+ case simsimd_metric_l2sq_k: *m = (simsimd_metric_punned_t)&simsimd_avx2_f16_l2sq, *c = simsimd_cap_x86_avx2fp16_k; return;
292
+ case simsimd_metric_js_k: *m = (simsimd_metric_punned_t)&simsimd_avx2_f16_js, *c = simsimd_cap_x86_avx2fp16_k; return;
293
+ case simsimd_metric_kl_k: *m = (simsimd_metric_punned_t)&simsimd_avx2_f16_kl, *c = simsimd_cap_x86_avx2fp16_k; return;
294
+ default: break;
277
295
  }
278
296
  #endif
279
297
 
280
298
  if (viable & simsimd_cap_serial_k)
281
299
  switch (kind) {
282
- case simsimd_metric_ip_k: *m = (simsimd_metric_punned_t)&simsimd_serial_f16_ip, *c = simsimd_cap_serial_k; break;
283
- case simsimd_metric_cos_k: *m = (simsimd_metric_punned_t)&simsimd_serial_f16_cos, *c = simsimd_cap_serial_k; break;
284
- case simsimd_metric_l2sq_k: *m = (simsimd_metric_punned_t)&simsimd_serial_f16_l2sq, *c = simsimd_cap_serial_k; break;
285
- case simsimd_metric_js_k: *m = (simsimd_metric_punned_t)&simsimd_serial_f16_js, *c = simsimd_cap_serial_k; break;
286
- case simsimd_metric_kl_k: *m = (simsimd_metric_punned_t)&simsimd_serial_f16_kl, *c = simsimd_cap_serial_k; break;
300
+ case simsimd_metric_ip_k: *m = (simsimd_metric_punned_t)&simsimd_serial_f16_ip, *c = simsimd_cap_serial_k; return;
301
+ case simsimd_metric_cos_k: *m = (simsimd_metric_punned_t)&simsimd_serial_f16_cos, *c = simsimd_cap_serial_k; return;
302
+ case simsimd_metric_l2sq_k: *m = (simsimd_metric_punned_t)&simsimd_serial_f16_l2sq, *c = simsimd_cap_serial_k; return;
303
+ case simsimd_metric_js_k: *m = (simsimd_metric_punned_t)&simsimd_serial_f16_js, *c = simsimd_cap_serial_k; return;
304
+ case simsimd_metric_kl_k: *m = (simsimd_metric_punned_t)&simsimd_serial_f16_kl, *c = simsimd_cap_serial_k; return;
305
+ default: break;
287
306
  }
288
307
 
289
308
  break;
@@ -293,33 +312,37 @@ inline static void simsimd_find_metric_punned( //
293
312
  #if SIMSIMD_TARGET_ARM_NEON
294
313
  if (viable & simsimd_cap_arm_neon_k)
295
314
  switch (kind) {
296
- case simsimd_metric_ip_k: *m = (simsimd_metric_punned_t)&simsimd_neon_i8_ip, *c = simsimd_cap_arm_neon_k; break;
297
- case simsimd_metric_cos_k: *m = (simsimd_metric_punned_t)&simsimd_neon_i8_cos, *c = simsimd_cap_arm_neon_k; break;
298
- case simsimd_metric_l2sq_k: *m = (simsimd_metric_punned_t)&simsimd_neon_i8_l2sq, *c = simsimd_cap_arm_neon_k; break;
315
+ case simsimd_metric_ip_k: *m = (simsimd_metric_punned_t)&simsimd_neon_i8_ip, *c = simsimd_cap_arm_neon_k; return;
316
+ case simsimd_metric_cos_k: *m = (simsimd_metric_punned_t)&simsimd_neon_i8_cos, *c = simsimd_cap_arm_neon_k; return;
317
+ case simsimd_metric_l2sq_k: *m = (simsimd_metric_punned_t)&simsimd_neon_i8_l2sq, *c = simsimd_cap_arm_neon_k; return;
318
+ default: break;
299
319
  }
300
320
  #endif
301
- #if SIMSIMD_TARGET_X86_AVX2
302
- if (viable & simsimd_cap_x86_avx2_k)
321
+ #if SIMSIMD_TARGET_X86_AVX512
322
+ if (viable & simsimd_cap_x86_avx512_k)
303
323
  switch (kind) {
304
- case simsimd_metric_ip_k: *m = (simsimd_metric_punned_t)&simsimd_avx2_i8_ip, *c = simsimd_cap_x86_avx2_k; break;
305
- case simsimd_metric_cos_k: *m = (simsimd_metric_punned_t)&simsimd_avx2_i8_cos, *c = simsimd_cap_x86_avx2_k; break;
306
- case simsimd_metric_l2sq_k: *m = (simsimd_metric_punned_t)&simsimd_avx2_i8_l2sq, *c = simsimd_cap_x86_avx2_k; break;
324
+ case simsimd_metric_ip_k: *m = (simsimd_metric_punned_t)&simsimd_avx512_i8_ip, *c = simsimd_cap_x86_avx512_k; return;
325
+ case simsimd_metric_cos_k: *m = (simsimd_metric_punned_t)&simsimd_avx512_i8_cos, *c = simsimd_cap_x86_avx512_k; return;
326
+ case simsimd_metric_l2sq_k: *m = (simsimd_metric_punned_t)&simsimd_avx512_i8_l2sq, *c = simsimd_cap_x86_avx512_k; return;
327
+ default: break;
307
328
  }
308
329
  #endif
309
- #if SIMSIMD_TARGET_X86_AVX512
310
- if (viable & simsimd_cap_x86_avx512_k)
330
+ #if SIMSIMD_TARGET_X86_AVX2
331
+ if (viable & simsimd_cap_x86_avx2_k)
311
332
  switch (kind) {
312
- case simsimd_metric_ip_k: *m = (simsimd_metric_punned_t)&simsimd_avx512_i8_ip, *c = simsimd_cap_x86_avx512_k; break;
313
- case simsimd_metric_cos_k: *m = (simsimd_metric_punned_t)&simsimd_avx512_i8_cos, *c = simsimd_cap_x86_avx512_k; break;
314
- case simsimd_metric_l2sq_k: *m = (simsimd_metric_punned_t)&simsimd_avx512_i8_l2sq, *c = simsimd_cap_x86_avx512_k; break;
333
+ case simsimd_metric_ip_k: *m = (simsimd_metric_punned_t)&simsimd_avx2_i8_ip, *c = simsimd_cap_x86_avx2_k; return;
334
+ case simsimd_metric_cos_k: *m = (simsimd_metric_punned_t)&simsimd_avx2_i8_cos, *c = simsimd_cap_x86_avx2_k; return;
335
+ case simsimd_metric_l2sq_k: *m = (simsimd_metric_punned_t)&simsimd_avx2_i8_l2sq, *c = simsimd_cap_x86_avx2_k; return;
336
+ default: break;
315
337
  }
316
338
  #endif
317
339
 
318
340
  if (viable & simsimd_cap_serial_k)
319
341
  switch (kind) {
320
- case simsimd_metric_ip_k: *m = (simsimd_metric_punned_t)&simsimd_serial_i8_ip, *c = simsimd_cap_serial_k; break;
321
- case simsimd_metric_cos_k: *m = (simsimd_metric_punned_t)&simsimd_serial_i8_cos, *c = simsimd_cap_serial_k; break;
322
- case simsimd_metric_l2sq_k: *m = (simsimd_metric_punned_t)&simsimd_serial_i8_l2sq, *c = simsimd_cap_serial_k; break;
342
+ case simsimd_metric_ip_k: *m = (simsimd_metric_punned_t)&simsimd_serial_i8_ip, *c = simsimd_cap_serial_k; return;
343
+ case simsimd_metric_cos_k: *m = (simsimd_metric_punned_t)&simsimd_serial_i8_cos, *c = simsimd_cap_serial_k; return;
344
+ case simsimd_metric_l2sq_k: *m = (simsimd_metric_punned_t)&simsimd_serial_i8_l2sq, *c = simsimd_cap_serial_k; return;
345
+ default: break;
323
346
  }
324
347
 
325
348
  break;
@@ -330,29 +353,33 @@ inline static void simsimd_find_metric_punned( //
330
353
  #if SIMSIMD_TARGET_ARM_NEON
331
354
  if (viable & simsimd_cap_arm_neon_k)
332
355
  switch (kind) {
333
- case simsimd_metric_hamming_k: *m = (simsimd_metric_punned_t)&simsimd_neon_b8_hamming, *c = simsimd_cap_arm_neon_k; break;
334
- case simsimd_metric_jaccard_k: *m = (simsimd_metric_punned_t)&simsimd_neon_b8_jaccard, *c = simsimd_cap_arm_neon_k; break;
356
+ case simsimd_metric_hamming_k: *m = (simsimd_metric_punned_t)&simsimd_neon_b8_hamming, *c = simsimd_cap_arm_neon_k; return;
357
+ case simsimd_metric_jaccard_k: *m = (simsimd_metric_punned_t)&simsimd_neon_b8_jaccard, *c = simsimd_cap_arm_neon_k; return;
358
+ default: break;
335
359
  }
336
360
  #endif
337
361
  #if SIMSIMD_TARGET_ARM_SVE
338
362
  if (viable & simsimd_cap_arm_sve_k)
339
363
  switch (kind) {
340
- case simsimd_metric_hamming_k: *m = (simsimd_metric_punned_t)&simsimd_sve_b8_hamming, *c = simsimd_cap_arm_sve_k; break;
341
- case simsimd_metric_jaccard_k: *m = (simsimd_metric_punned_t)&simsimd_sve_b8_jaccard, *c = simsimd_cap_arm_sve_k; break;
364
+ case simsimd_metric_hamming_k: *m = (simsimd_metric_punned_t)&simsimd_sve_b8_hamming, *c = simsimd_cap_arm_sve_k; return;
365
+ case simsimd_metric_jaccard_k: *m = (simsimd_metric_punned_t)&simsimd_sve_b8_jaccard, *c = simsimd_cap_arm_sve_k; return;
366
+ default: break;
342
367
  }
343
368
  #endif
344
369
  #if SIMSIMD_TARGET_X86_AVX512
345
370
  if (viable & simsimd_cap_x86_avx512vpopcntdq_k)
346
371
  switch (kind) {
347
- case simsimd_metric_hamming_k: *m = (simsimd_metric_punned_t)&simsimd_avx512_b8_hamming, *c = simsimd_cap_x86_avx512vpopcntdq_k; break;
348
- case simsimd_metric_jaccard_k: *m = (simsimd_metric_punned_t)&simsimd_avx512_b8_jaccard, *c = simsimd_cap_x86_avx512vpopcntdq_k; break;
372
+ case simsimd_metric_hamming_k: *m = (simsimd_metric_punned_t)&simsimd_avx512_b8_hamming, *c = simsimd_cap_x86_avx512vpopcntdq_k; return;
373
+ case simsimd_metric_jaccard_k: *m = (simsimd_metric_punned_t)&simsimd_avx512_b8_jaccard, *c = simsimd_cap_x86_avx512vpopcntdq_k; return;
374
+ default: break;
349
375
  }
350
376
  #endif
351
377
 
352
378
  if (viable & simsimd_cap_serial_k)
353
379
  switch (kind) {
354
- case simsimd_metric_hamming_k: *m = (simsimd_metric_punned_t)&simsimd_serial_b8_hamming, *c = simsimd_cap_serial_k; break;
355
- case simsimd_metric_jaccard_k: *m = (simsimd_metric_punned_t)&simsimd_serial_b8_jaccard, *c = simsimd_cap_serial_k; break;
380
+ case simsimd_metric_hamming_k: *m = (simsimd_metric_punned_t)&simsimd_serial_b8_hamming, *c = simsimd_cap_serial_k; return;
381
+ case simsimd_metric_jaccard_k: *m = (simsimd_metric_punned_t)&simsimd_serial_b8_jaccard, *c = simsimd_cap_serial_k; return;
382
+ default: break;
356
383
  }
357
384
 
358
385
  break;
@@ -360,6 +387,9 @@ inline static void simsimd_find_metric_punned( //
360
387
  // clang-format on
361
388
  }
362
389
 
390
+ #pragma clang diagnostic pop
391
+ #pragma GCC diagnostic pop
392
+
363
393
  /**
364
394
  * @brief Selects the most suitable metric implementation based on the given metric kind, datatype,
365
395
  * and allowed capabilities. @b Don't call too often and prefer caching the `simsimd_capabilities()`.
@@ -816,8 +816,6 @@ __attribute__((target("avx512fp16,avx512vl,avx512f"))) //
816
816
  inline static simsimd_f32_t
817
817
  simsimd_avx512_f16_ip(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n) {
818
818
  __m512h ab_vec = _mm512_set1_ph(0);
819
- simsimd_size_t i = 0;
820
-
821
819
  for (simsimd_size_t i = 0; i < n; i += 32) {
822
820
  __mmask32 mask = n - i >= 32 ? 0xFFFFFFFF : ((1u << (n - i)) - 1u);
823
821
  __m512i a_vec = _mm512_maskz_loadu_epi16(mask, a + i);
@@ -887,7 +885,6 @@ simsimd_avx512_i8_cos(simsimd_i8_t const* a, simsimd_i8_t const* b, simsimd_size
887
885
  __m512i ab_i32s_vec = _mm512_setzero_si512();
888
886
  __m512i a2_i32s_vec = _mm512_setzero_si512();
889
887
  __m512i b2_i32s_vec = _mm512_setzero_si512();
890
- simsimd_size_t i = 0;
891
888
 
892
889
  for (simsimd_size_t i = 0; i < n; i += 32) {
893
890
  __mmask32 mask = n - i >= 32 ? 0xFFFFFFFF : ((1u << (n - i)) - 1u);
@@ -161,7 +161,7 @@ inline static simsimd_f32_t simsimd_approximate_inverse_square_root(simsimd_f32_
161
161
  /**
162
162
  * @brief Computes `log(x)` using the Mercator series.
163
163
  * The series converges to the natural logarithm for args between -1 and 1.
164
- * Published in 1668 in Logarithmotechnia.
164
+ * Published in 1668 in "Logarithmotechnia".
165
165
  */
166
166
  inline static simsimd_f32_t simsimd_approximate_log(simsimd_f32_t number) {
167
167
  simsimd_f32_t x = number - 1;
@@ -181,14 +181,19 @@ inline static simsimd_f32_t simsimd_approximate_log(simsimd_f32_t number) {
181
181
  * https://github.com/OpenCyphal/libcanard/blob/636795f4bc395f56af8d2c61d3757b5e762bb9e5/canard.c#L811-L834
182
182
  */
183
183
  inline static float simsimd_uncompress_f16(unsigned short x) {
184
+ union float_or_unsigned_int_t {
185
+ float f;
186
+ unsigned int i;
187
+ };
184
188
  unsigned int exponent = (x & 0x7C00) >> 10;
185
189
  unsigned int mantissa = (x & 0x03FF) << 13;
186
- float mantissa_as_float = (float)mantissa;
187
- unsigned int v = (*(unsigned int*)&mantissa_as_float) >> 23;
188
- unsigned int result_as_uint =
189
- (x & 0x8000) << 16 | (exponent != 0) * ((exponent + 112) << 23 | mantissa) |
190
- ((exponent == 0) & (mantissa != 0)) * ((v - 37) << 23 | ((mantissa << (150 - v)) & 0x007FE000));
191
- return *(float*)&result_as_uint;
190
+ union float_or_unsigned_int_t mantissa_union;
191
+ mantissa_union.f = (float)mantissa;
192
+ unsigned int v = (mantissa_union.i) >> 23;
193
+ union float_or_unsigned_int_t result_union;
194
+ result_union.i = (x & 0x8000) << 16 | (exponent != 0) * ((exponent + 112) << 23 | mantissa) |
195
+ ((exponent == 0) & (mantissa != 0)) * ((v - 37) << 23 | ((mantissa << (150 - v)) & 0x007FE000));
196
+ return result_union.f;
192
197
  }
193
198
 
194
199
  #ifdef __cplusplus
@@ -4,8 +4,11 @@ import assert from 'node:assert';
4
4
 
5
5
  const simsimd = bindings('simsimd');
6
6
 
7
- const typedArray1 = new Float32Array([1.0, 2.0, 3.0]);
8
- const typedArray2 = new Float32Array([4.0, 5.0, 6.0]);
7
+ const f32Array1 = new Float32Array([1.0, 2.0, 3.0]);
8
+ const f32Array2 = new Float32Array([4.0, 5.0, 6.0]);
9
+
10
+ const u8Array1 = new Uint8Array([1, 2, 3]);
11
+ const u8Array2 = new Uint8Array([4, 5, 6]);
9
12
 
10
13
  function assertAlmostEqual(actual, expected, tolerance = 1e-6) {
11
14
  const lowerBound = expected - tolerance;
@@ -13,17 +16,32 @@ function assertAlmostEqual(actual, expected, tolerance = 1e-6) {
13
16
  assert(actual >= lowerBound && actual <= upperBound, `Expected ${actual} to be almost equal to ${expected}`);
14
17
  }
15
18
 
19
+ test('Distance from itself', () => {
20
+ assertAlmostEqual(simsimd.sqeuclidean(f32Array1, f32Array1), 0.0, 0.01);
21
+ assertAlmostEqual(simsimd.cosine(f32Array1, f32Array1), 0.0, 0.01);
22
+
23
+ // Inner-product distance on non-nroamalized vectors would yield:
24
+ // 1 - 1 - 4 - 9 = -13
25
+ assertAlmostEqual(simsimd.inner(f32Array1, f32Array1), -13.0, 0.01);
26
+
27
+ assertAlmostEqual(simsimd.kullbackleibler(f32Array1, f32Array1), 0.0, 0.01);
28
+ assertAlmostEqual(simsimd.jensenshannon(f32Array1, f32Array1), 0.0, 0.01);
29
+
30
+ assertAlmostEqual(simsimd.hamming(u8Array1, u8Array1), 0.0, 0.01);
31
+ assertAlmostEqual(simsimd.jaccard(u8Array1, u8Array1), 0.0, 0.01);
32
+ });
33
+
16
34
  test('Squared Euclidean Distance', () => {
17
- const result = simsimd.sqeuclidean(typedArray1, typedArray2);
35
+ const result = simsimd.sqeuclidean(f32Array1, f32Array2);
18
36
  assertAlmostEqual(result, 27.0, 0.01);
19
37
  });
20
38
 
21
39
  test('Inner Product', () => {
22
- const result = simsimd.inner(typedArray1, typedArray2);
40
+ const result = simsimd.inner(f32Array1, f32Array2);
23
41
  assertAlmostEqual(result, -31.0, 0.01);
24
42
  });
25
43
 
26
44
  test('Cosine Similarity', () => {
27
- const result = simsimd.cosine(typedArray1, typedArray2);
45
+ const result = simsimd.cosine(f32Array1, f32Array2);
28
46
  assertAlmostEqual(result, 0.029, 0.01);
29
47
  });
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "simsimd",
3
- "version": "3.1.0",
3
+ "version": "3.2.0",
4
4
  "description": "Vector Similarity Functions 3x-200x Faster than SciPy and NumPy",
5
5
  "author": "Ash Vardanian",
6
6
  "license": "Apache 2.0",
@@ -34,4 +34,4 @@
34
34
  "typescript": "^5.1.6",
35
35
  "usearch": "^2.7.2"
36
36
  }
37
- }
37
+ }
package/wasmer.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name="unum/usearch"
3
- version="2.7.7"
3
+ version="2.8.1"
4
4
  description="Smaller & Faster Single-File Vector Search Engine from Unum"
5
5
  license="Apache-2.0"
6
6
  readme="README.md"
package/wolfram/lib.cpp CHANGED
@@ -9,7 +9,7 @@ using vector_view_t = span_gt<float>;
9
9
 
10
10
  using add_result_t = typename index_t::add_result_t;
11
11
  using search_result_t = typename index_t::search_result_t;
12
- using key_t = typename index_t::key_t;
12
+ using vector_key_t = typename index_t::vector_key_t;
13
13
 
14
14
  EXTERN_C DLLEXPORT int WolframLibrary_initialize(WolframLibraryData libData) { return LIBRARY_NO_ERROR; }
15
15
  EXTERN_C DLLEXPORT void WolframLibrary_uninitialize(WolframLibraryData libData) { return; }
@@ -1,65 +0,0 @@
1
- #!/bin/bash
2
-
3
- # Get absolute path to the usearch dir
4
- # FIX: realpath is not available on OSX, so use pwd
5
- SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
6
- SCRIPT_DIR="${SCRIPT_DIR}/"
7
-
8
- # Define project paths
9
- REPO_ROOT=`cd -P "${SCRIPT_DIR}../.." && pwd`
10
- REPO_ROOT="${REPO_ROOT}/"
11
- C_DIR="${REPO_ROOT}c/"
12
- CSHARP_DIR="${REPO_ROOT}csharp/"
13
- BUILD_ARTIFACTS_DIR="${CSHARP_DIR}lib/"
14
-
15
- LIB_FILE="libusearch_c"
16
-
17
- # Determine the architecture type (only x64 is supported)
18
- ARCH_TYPE="$(uname -m)"
19
- case "$ARCH_TYPE" in
20
- x86_64)
21
- ARCH="x64"
22
- ;;
23
- # i386|i486|i586|i686)
24
- # ARCH="x86"
25
- # ;;
26
- *)
27
- echo "Unsupported architecture"
28
- exit 1
29
- ;;
30
- esac
31
- echo "Detected architecture: $ARCH"
32
-
33
- # Determine the OS type (linux or macos) and set the shared library extension accordingly
34
- case "$(uname -s)" in
35
- Darwin)
36
- BUILD_ARTIFACTS_DIR+="runtimes/osx-${ARCH}/native/"
37
- LIB_FILE+=".dylib"
38
- ;;
39
- Linux)
40
- BUILD_ARTIFACTS_DIR+="runtimes/linux-${ARCH}/native/"
41
- LIB_FILE+=".so"
42
- ;;
43
- *)
44
- echo "Unsupported operating system"
45
- exit 1
46
- ;;
47
- esac
48
-
49
- MAKE_TARGET="${LIB_FILE}"
50
-
51
- # Build the native dynamic lib
52
- cd "$C_DIR" || { echo "C directory not found in $C_DIR"; exit 1; }
53
- if [ ! -f Makefile ]; then
54
- echo "Makefile not found in $C_DIR"
55
- exit 1
56
- fi
57
- make "${MAKE_TARGET}"
58
- if [ $? -ne 0 ]; then
59
- echo "Build failed!"
60
- exit 1
61
- fi
62
-
63
- # Create output dir for shared lib and copy it there
64
- mkdir -p "$BUILD_ARTIFACTS_DIR"
65
- cp "${C_DIR}/${LIB_FILE}" "$BUILD_ARTIFACTS_DIR"
@@ -1,12 +0,0 @@
1
- #!/bin/bash
2
-
3
- # Get absolute path to the usearch csharp dir
4
- SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
5
- SCRIPT_DIR="${SCRIPT_DIR}/"
6
- CSHARP_DIR=`cd -P "${SCRIPT_DIR}.." && pwd`
7
- CSHARP_DIR="${CSHARP_DIR}/"
8
-
9
- rm -rf ${CSHARP_DIR}lib # Local temp path for native libs
10
- rm -rf ${CSHARP_DIR}packages # Local temp path for nuget packages
11
- find ${CSHARP_DIR} -type d -name 'bin' -exec rm -rf {} +
12
- find ${CSHARP_DIR} -type d -name 'obj' -exec rm -rf {} +