usearch 2.15.3 → 2.16.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 (48) hide show
  1. package/README.md +1 -1
  2. package/cpp/test.cpp +16 -0
  3. package/include/usearch/index.hpp +21 -5
  4. package/include/usearch/index_dense.hpp +6 -1
  5. package/include/usearch/index_plugins.hpp +345 -8
  6. package/javascript/lib.cpp +17 -5
  7. package/javascript/usearch.test.js +190 -21
  8. package/package.json +1 -1
  9. package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
  10. package/prebuilds/linux-arm64/usearch.node +0 -0
  11. package/prebuilds/linux-x64/usearch.node +0 -0
  12. package/simsimd/.git-blame-ignore-revs +2 -0
  13. package/simsimd/CONTRIBUTING.md +71 -23
  14. package/simsimd/Cargo.lock +1 -1
  15. package/simsimd/Cargo.toml +4 -4
  16. package/simsimd/MANIFEST.in +2 -1
  17. package/simsimd/Package.swift +15 -3
  18. package/simsimd/README.md +104 -35
  19. package/simsimd/binding.gyp +6 -2
  20. package/simsimd/build.rs +2 -0
  21. package/simsimd/c/lib.c +180 -99
  22. package/simsimd/include/simsimd/binary.h +311 -102
  23. package/simsimd/include/simsimd/curved.h +134 -135
  24. package/simsimd/include/simsimd/dot.h +448 -274
  25. package/simsimd/include/simsimd/elementwise.h +1437 -0
  26. package/simsimd/include/simsimd/geospatial.h +2 -2
  27. package/simsimd/include/simsimd/mesh.h +2 -2
  28. package/simsimd/include/simsimd/probability.h +88 -88
  29. package/simsimd/include/simsimd/simsimd.h +1157 -772
  30. package/simsimd/include/simsimd/sparse.h +768 -147
  31. package/simsimd/include/simsimd/spatial.h +955 -376
  32. package/simsimd/include/simsimd/types.h +145 -71
  33. package/simsimd/javascript/lib.c +1 -2
  34. package/simsimd/package.json +4 -4
  35. package/simsimd/rust/lib.rs +14 -1
  36. package/simsimd/scripts/bench.cxx +1070 -0
  37. package/simsimd/scripts/bench.ipynb +187 -0
  38. package/simsimd/{javascript → scripts}/bench.js +1 -1
  39. package/simsimd/{rust/benches/sqeuclidean.rs → scripts/bench_sqeuclidean.rs} +6 -6
  40. package/simsimd/scripts/bench_vectors.py +700 -0
  41. package/simsimd/scripts/bench_vectors_live.py +213 -0
  42. package/simsimd/scripts/test.c +155 -0
  43. package/simsimd/{javascript → scripts}/test.mjs +2 -2
  44. package/simsimd/scripts/test.py +1410 -0
  45. package/simsimd/swift/{source/SimSIMD.swift → SimSIMD.swift} +6 -2
  46. package/simsimd/swift/{tests/SimSIMDTests.swift → Test.swift} +1 -1
  47. /package/simsimd/{rust/benches/cosine.rs → scripts/bench_cosine.rs} +0 -0
  48. /package/simsimd/{rust/benches/native.rs → scripts/bench_native.rs} +0 -0
@@ -23,6 +23,7 @@
23
23
  * F, CD, VL, DQ, BW, VNNI, VPOPCNTDQ, IFMA, VBMI, VAES, GFNI, VBMI2, BITALG, VPCLMULQDQ, BF16
24
24
  * > In other words, it extends Sunny Cove with BF16 support
25
25
  * - Intel Golden Cove (Sapphire Rapids): extends Zen4 and Sunny Cove with FP16 support
26
+ * - AMD Zen5 (Turin): makes VP2INTERSECT cool again
26
27
  *
27
28
  * Intel Palm Cove was an irrelevant intermediate release extending Skylake with IFMA and VBMI.
28
29
  * Intel Willow Cove was an irrelevant intermediate release extending Sunny Cove with VP2INTERSECT,
@@ -35,6 +36,7 @@
35
36
  * 2. Intel Ice Lake (2019-2021): advanced integer algorithms.
36
37
  * 3. AMD Genoa (2023+): brain-floating point support.
37
38
  * 4. Intel Sapphire Rapids (2023+): advanced mixed-precision float processing.
39
+ * 5. AMD Turin (2024+): advanced sparse algorithms.
38
40
  *
39
41
  * To list all available macros for x86, take a recent compiler, like GCC 12 and run:
40
42
  * gcc-12 -march=sapphirerapids -dM -E - < /dev/null | egrep "SSE|AVX" | sort
@@ -87,8 +89,8 @@
87
89
  #define SIMSIMD_H
88
90
 
89
91
  #define SIMSIMD_VERSION_MAJOR 5
90
- #define SIMSIMD_VERSION_MINOR 6
91
- #define SIMSIMD_VERSION_PATCH 4
92
+ #define SIMSIMD_VERSION_MINOR 9
93
+ #define SIMSIMD_VERSION_PATCH 6
92
94
 
93
95
  /**
94
96
  * @brief Removes compile-time dispatching, and replaces it with runtime dispatching.
@@ -103,13 +105,14 @@
103
105
  #include "binary.h" // Hamming, Jaccard
104
106
  #include "curved.h" // Mahalanobis, Bilinear Forms
105
107
  #include "dot.h" // Inner (dot) product, and its conjugate
108
+ #include "elementwise.h" // Weighted Sum, Fused-Multiply-Add
106
109
  #include "geospatial.h" // Haversine and Vincenty
107
110
  #include "probability.h" // Kullback-Leibler, Jensen–Shannon
108
111
  #include "sparse.h" // Intersect
109
112
  #include "spatial.h" // L2, Cosine
110
113
 
111
114
  // On Apple Silicon, `mrs` is not allowed in user-space, so we need to use the `sysctl` API.
112
- #if defined(SIMSIMD_DEFINED_APPLE)
115
+ #if defined(_SIMSIMD_DEFINED_APPLE)
113
116
  #include <sys/sysctl.h>
114
117
  #endif
115
118
 
@@ -147,7 +150,9 @@ typedef enum {
147
150
  simsimd_metric_tanimoto_k = 'j', ///< Tanimoto coefficient is same as Jaccard
148
151
 
149
152
  // Sets:
150
- simsimd_metric_intersect_k = 'x', ///< Equivalent to unnormalized Jaccard
153
+ simsimd_metric_intersect_k = 'x', ///< Equivalent to unnormalized Jaccard
154
+ simsimd_metric_spdot_counts_k = 'y', ///< Sparse sets with integer weights
155
+ simsimd_metric_spdot_weights_k = 'z', ///< Sparse sets with brain floating-point weights
151
156
 
152
157
  // Curved Spaces:
153
158
  simsimd_metric_bilinear_k = 'b', ///< Bilinear form
@@ -160,6 +165,10 @@ typedef enum {
160
165
  simsimd_metric_js_k = 's', ///< Jensen-Shannon divergence
161
166
  simsimd_metric_jensen_shannon_k = 's', ///< Jensen-Shannon divergence alias
162
167
 
168
+ // BLAS-like operations:
169
+ simsimd_metric_fma_k = 'f', ///< Fused Multiply-Add
170
+ simsimd_metric_wsum_k = 'w', ///< Weighted Sum
171
+
163
172
  } simsimd_metric_kind_t;
164
173
 
165
174
  /**
@@ -174,6 +183,8 @@ typedef enum {
174
183
  simsimd_cap_ice_k = 1 << 12, ///< x86 AVX512 capability with advanced integer algos
175
184
  simsimd_cap_genoa_k = 1 << 13, ///< x86 AVX512 capability with `bf16` support
176
185
  simsimd_cap_sapphire_k = 1 << 14, ///< x86 AVX512 capability with `f16` support
186
+ simsimd_cap_turin_k = 1 << 15, ///< x86 AVX512 capability with conflict detection
187
+ simsimd_cap_sierra_k = 1 << 16, ///< x86 AVX2+VNNI capability with `i8` dot-products
177
188
 
178
189
  simsimd_cap_neon_k = 1 << 20, ///< ARM NEON baseline capability
179
190
  simsimd_cap_neon_f16_k = 1 << 21, ///< ARM NEON `f16` capability
@@ -196,8 +207,10 @@ typedef enum {
196
207
  * interfaces.
197
208
  */
198
209
  typedef enum {
199
- simsimd_datatype_unknown_k = 0, ///< Unknown data type
200
- simsimd_datatype_b8_k = 1 << 1, ///< Single-bit values packed into 8-bit words
210
+ simsimd_datatype_unknown_k = 0, ///< Unknown data type
211
+ simsimd_datatype_b8_k = 1 << 1, ///< Single-bit values packed into 8-bit words
212
+ simsimd_datatype_b1x8_k = simsimd_datatype_b8_k, ///< Single-bit values packed into 8-bit words
213
+ simsimd_datatype_i4x2_k = 1 << 19, ///< 4-bit signed integers packed into 8-bit words
201
214
 
202
215
  simsimd_datatype_i8_k = 1 << 2, ///< 8-bit signed integer
203
216
  simsimd_datatype_i16_k = 1 << 3, ///< 16-bit signed integer
@@ -226,11 +239,12 @@ typedef enum {
226
239
  * @param[in] a Pointer to the first data array.
227
240
  * @param[in] b Pointer to the second data array.
228
241
  * @param[in] n Number of scalar words in the input arrays.
229
- * When dealing with sub-byte data types, the number of scalar words is the number of bytes.
242
+ * When dealing with sub-byte types, the number of scalar words is the number of bytes.
243
+ * When dealing with complex types, the number of scalar words is the sum of real and imaginary parts.
230
244
  * @param[out] d Output value as a double-precision float.
231
245
  * In complex dot-products @b two scalars are exported for the real and imaginary parts.
232
246
  */
233
- typedef void (*simsimd_metric_dense_punned_t)(void const* a, void const* b, simsimd_size_t n, simsimd_distance_t* d);
247
+ typedef void (*simsimd_metric_dense_punned_t)(void const *a, void const *b, simsimd_size_t n, simsimd_distance_t *d);
234
248
 
235
249
  /**
236
250
  * @brief Type-punned function pointer for sparse vector representations and similarity measures.
@@ -241,9 +255,9 @@ typedef void (*simsimd_metric_dense_punned_t)(void const* a, void const* b, sims
241
255
  * @param[in] b_length Number of scalar words in the second input array.
242
256
  * @param[out] d Output value as a double-precision float, generally without decimals.
243
257
  */
244
- typedef void (*simsimd_metric_sparse_punned_t)(void const* a, void const* b, //
258
+ typedef void (*simsimd_metric_sparse_punned_t)(void const *a, void const *b, //
245
259
  simsimd_size_t a_length, simsimd_size_t b_length, //
246
- simsimd_distance_t* d);
260
+ simsimd_distance_t *d);
247
261
 
248
262
  /**
249
263
  * @brief Type-punned function pointer for curved vector spaces and similarity measures.
@@ -254,8 +268,39 @@ typedef void (*simsimd_metric_sparse_punned_t)(void const* a, void const* b,
254
268
  * @param[in] n Number of scalar words in the input arrays.
255
269
  * @param[out] d Output value as a double-precision float.
256
270
  */
257
- typedef void (*simsimd_metric_curved_punned_t)(void const* a, void const* b, void const* c, //
258
- simsimd_size_t n, simsimd_distance_t* d);
271
+ typedef void (*simsimd_metric_curved_punned_t)(void const *a, void const *b, void const *c, //
272
+ simsimd_size_t n, simsimd_distance_t *d);
273
+
274
+ /**
275
+ * @brief Type-punned function pointer for FMA operations on dense vector representations.
276
+ * Implements the `y = alpha * a * b + beta * c` operation.
277
+ *
278
+ * @param[in] a Pointer to the first data array.
279
+ * @param[in] b Pointer to the second data array.
280
+ * @param[in] c Pointer to the third data array.
281
+ * @param[in] n Number of scalar words in the input arrays.
282
+ * @param[in] alpha Scaling factor for the first two arrays.
283
+ * @param[in] beta Scaling factor for the third array.
284
+ * @param[out] y Output value in the same precision as the input arrays.
285
+ */
286
+ typedef void (*simsimd_kernel_fma_punned_t)(void const *a, void const *b, void const *c, //
287
+ simsimd_size_t n, simsimd_distance_t alpha, simsimd_distance_t beta,
288
+ void *y);
289
+
290
+ /**
291
+ * @brief Type-punned function pointer for Weighted Sum operations on dense vector representations.
292
+ * Implements the `y = alpha * a + beta * b` operation.
293
+ *
294
+ * @param[in] a Pointer to the first data array.
295
+ * @param[in] b Pointer to the second data array.
296
+ * @param[in] n Number of scalar words in the input arrays.
297
+ * @param[in] alpha Scaling factor for the first array.
298
+ * @param[in] beta Scaling factor for the second array.
299
+ * @param[out] y Output value in the same precision as the input arrays.
300
+ */
301
+ typedef void (*simsimd_kernel_wsum_punned_t)(void const *a, void const *b, //
302
+ simsimd_size_t n, simsimd_distance_t alpha, simsimd_distance_t beta,
303
+ void *y);
259
304
 
260
305
  /**
261
306
  * @brief Type-punned function pointer for a SimSIMD public interface.
@@ -271,8 +316,8 @@ SIMSIMD_DYNAMIC void simsimd_find_metric_punned( //
271
316
  simsimd_datatype_t datatype, //
272
317
  simsimd_capability_t supported, //
273
318
  simsimd_capability_t allowed, //
274
- simsimd_metric_punned_t* metric_output, //
275
- simsimd_capability_t* capability_output);
319
+ simsimd_metric_punned_t *metric_output, //
320
+ simsimd_capability_t *capability_output);
276
321
  #else
277
322
  SIMSIMD_PUBLIC simsimd_capability_t simsimd_capabilities(void);
278
323
  SIMSIMD_PUBLIC void simsimd_find_metric_punned( //
@@ -280,11 +325,11 @@ SIMSIMD_PUBLIC void simsimd_find_metric_punned( //
280
325
  simsimd_datatype_t datatype, //
281
326
  simsimd_capability_t supported, //
282
327
  simsimd_capability_t allowed, //
283
- simsimd_metric_punned_t* metric_output, //
284
- simsimd_capability_t* capability_output);
328
+ simsimd_metric_punned_t *metric_output, //
329
+ simsimd_capability_t *capability_output);
285
330
  #endif
286
331
 
287
- #if SIMSIMD_TARGET_X86
332
+ #if _SIMSIMD_TARGET_X86
288
333
 
289
334
  /**
290
335
  * @brief Function to determine the SIMD capabilities of the current 64-bit x86 machine at @b runtime.
@@ -343,6 +388,9 @@ SIMSIMD_PUBLIC simsimd_capability_t _simsimd_capabilities_x86(void) {
343
388
  // Check for AVX512BF16 (Function ID 7, Sub-leaf 1, EAX register)
344
389
  // https://github.com/llvm/llvm-project/blob/50598f0ff44f3a4e75706f8c53f3380fe7faa896/clang/lib/Headers/cpuid.h#L205
345
390
  unsigned supports_avx512bf16 = (info7sub1.named.eax & 0x00000020) != 0;
391
+ // Clang doesn't show the VP2INTERSECT flag, but we can get it from QEMU
392
+ // https://stackoverflow.com/a/68289220/2766161
393
+ unsigned supports_avx512vp2intersect = (info7.named.edx & 0x00000100) != 0;
346
394
 
347
395
  // Convert specific features into CPU generations
348
396
  unsigned supports_haswell = supports_avx2 && supports_f16c && supports_fma;
@@ -351,6 +399,9 @@ SIMSIMD_PUBLIC simsimd_capability_t _simsimd_capabilities_x86(void) {
351
399
  supports_avx512vbmi2 && supports_avx512vpopcntdq;
352
400
  unsigned supports_genoa = supports_avx512bf16;
353
401
  unsigned supports_sapphire = supports_avx512fp16;
402
+ // We don't want to accidently enable AVX512VP2INTERSECT on Intel Tiger Lake CPUs
403
+ unsigned supports_turin = supports_avx512vp2intersect && supports_avx512bf16;
404
+ unsigned supports_sierra = 0;
354
405
 
355
406
  return (simsimd_capability_t)( //
356
407
  (simsimd_cap_haswell_k * supports_haswell) | //
@@ -358,12 +409,14 @@ SIMSIMD_PUBLIC simsimd_capability_t _simsimd_capabilities_x86(void) {
358
409
  (simsimd_cap_ice_k * supports_ice) | //
359
410
  (simsimd_cap_genoa_k * supports_genoa) | //
360
411
  (simsimd_cap_sapphire_k * supports_sapphire) | //
412
+ (simsimd_cap_turin_k * supports_turin) | //
413
+ (simsimd_cap_sierra_k * supports_sierra) | //
361
414
  (simsimd_cap_serial_k));
362
415
  }
363
416
 
364
- #endif // SIMSIMD_TARGET_X86
417
+ #endif // _SIMSIMD_TARGET_X86
365
418
 
366
- #if SIMSIMD_TARGET_ARM
419
+ #if _SIMSIMD_TARGET_ARM
367
420
 
368
421
  /* Compiling the next section one may get: selected processor does not support system register name 'id_aa64zfr0_el1'.
369
422
  * Suppressing assembler errors is very complicated, so when dealing with older ARM CPUs it's simpler to compile this
@@ -378,18 +431,14 @@ SIMSIMD_PUBLIC simsimd_capability_t _simsimd_capabilities_x86(void) {
378
431
  * @return A bitmask of the SIMD capabilities represented as a `simsimd_capability_t` enum value.
379
432
  */
380
433
  SIMSIMD_PUBLIC simsimd_capability_t _simsimd_capabilities_arm(void) {
381
- #if defined(SIMSIMD_DEFINED_APPLE)
434
+ #if defined(_SIMSIMD_DEFINED_APPLE)
382
435
  // On Apple Silicon, `mrs` is not allowed in user-space, so we need to use the `sysctl` API.
383
436
  uint32_t supports_neon = 0, supports_fp16 = 0, supports_bf16 = 0, supports_i8mm = 0;
384
437
  size_t size = sizeof(supports_neon);
385
- if (sysctlbyname("hw.optional.neon", &supports_neon, &size, NULL, 0) != 0)
386
- supports_neon = 0;
387
- if (sysctlbyname("hw.optional.arm.FEAT_FP16", &supports_fp16, &size, NULL, 0) != 0)
388
- supports_fp16 = 0;
389
- if (sysctlbyname("hw.optional.arm.FEAT_BF16", &supports_bf16, &size, NULL, 0) != 0)
390
- supports_bf16 = 0;
391
- if (sysctlbyname("hw.optional.arm.FEAT_I8MM", &supports_i8mm, &size, NULL, 0) != 0)
392
- supports_i8mm = 0;
438
+ if (sysctlbyname("hw.optional.neon", &supports_neon, &size, NULL, 0) != 0) supports_neon = 0;
439
+ if (sysctlbyname("hw.optional.arm.FEAT_FP16", &supports_fp16, &size, NULL, 0) != 0) supports_fp16 = 0;
440
+ if (sysctlbyname("hw.optional.arm.FEAT_BF16", &supports_bf16, &size, NULL, 0) != 0) supports_bf16 = 0;
441
+ if (sysctlbyname("hw.optional.arm.FEAT_I8MM", &supports_i8mm, &size, NULL, 0) != 0) supports_i8mm = 0;
393
442
 
394
443
  return (simsimd_capability_t)( //
395
444
  (simsimd_cap_neon_k * (supports_neon)) | //
@@ -398,23 +447,7 @@ SIMSIMD_PUBLIC simsimd_capability_t _simsimd_capabilities_arm(void) {
398
447
  (simsimd_cap_neon_i8_k * (supports_neon && supports_i8mm)) | //
399
448
  (simsimd_cap_serial_k));
400
449
 
401
- #elif defined(SIMSIMD_DEFINED_LINUX)
402
- // This is how the `arm-cpusysregs` library does it:
403
- //
404
- // int ID_AA64ISAR1_EL1_BF16() const { return (int)(_aa64isar1 >> 44) & 0x0F; }
405
- // int ID_AA64ZFR0_EL1_BF16() const { return (int)(_aa64zfr0 >> 20) & 0x0F; }
406
- // int ID_AA64PFR0_EL1_FP() const { return (int)(_aa64pfr0 >> 16) & 0x0F; }
407
- // int ID_AA64ISAR0_EL1_DP() const { return (int)(_aa64isar0 >> 44) & 0x0F; }
408
- // int ID_AA64PFR0_EL1_SVE() const { return (int)(_aa64pfr0 >> 32) & 0x0F; }
409
- // int ID_AA64ZFR0_EL1_SVEver() const { return (int)(_aa64zfr0) & 0x0F; }
410
- // bool FEAT_BF16() const { return ID_AA64ISAR1_EL1_BF16() >= 1 || ID_AA64ZFR0_EL1_BF16() >= 1; }
411
- // bool FEAT_FP16() const { return ID_AA64PFR0_EL1_FP() >= 1 && ID_AA64PFR0_EL1_FP() < 15; }
412
- // bool FEAT_DotProd() const { return ID_AA64ISAR0_EL1_DP() >= 1; }
413
- // bool FEAT_SVE() const { return ID_AA64PFR0_EL1_SVE() >= 1; }
414
- // bool FEAT_SVE2() const { return ID_AA64ZFR0_EL1_SVEver() >= 1; }
415
- // bool FEAT_I8MM() const { return ID_AA64ZFR0_EL1_I8MM() >= 1; }
416
- //
417
- // https://github.com/lelegard/arm-cpusysregs/tree/4837c62e619a5e5f12bf41b16a1ee1e71d62c76d
450
+ #elif defined(_SIMSIMD_DEFINED_LINUX)
418
451
 
419
452
  // Read CPUID registers directly
420
453
  unsigned long id_aa64isar0_el1 = 0, id_aa64isar1_el1 = 0, id_aa64pfr0_el1 = 0, id_aa64zfr0_el1 = 0;
@@ -444,8 +477,7 @@ SIMSIMD_PUBLIC simsimd_capability_t _simsimd_capabilities_arm(void) {
444
477
 
445
478
  // Now let's unpack the status flags from ID_AA64ZFR0_EL1
446
479
  // https://developer.arm.com/documentation/ddi0601/2024-03/AArch64-Registers/ID-AA64ZFR0-EL1--SVE-Feature-ID-Register-0?lang=en
447
- if (supports_sve)
448
- __asm__ __volatile__("mrs %0, ID_AA64ZFR0_EL1" : "=r"(id_aa64zfr0_el1));
480
+ if (supports_sve) __asm__ __volatile__("mrs %0, ID_AA64ZFR0_EL1" : "=r"(id_aa64zfr0_el1));
449
481
  // I8MM, bits [47:44] of ID_AA64ZFR0_EL1
450
482
  unsigned supports_sve_i8mm = ((id_aa64zfr0_el1 >> 44) & 0xF) >= 1;
451
483
  // BF16, bits [23:20] of ID_AA64ZFR0_EL1
@@ -471,7 +503,7 @@ SIMSIMD_PUBLIC simsimd_capability_t _simsimd_capabilities_arm(void) {
471
503
  (simsimd_cap_sve2_k * (supports_sve2)) | //
472
504
  (simsimd_cap_sve2p1_k * (supports_sve2p1)) | //
473
505
  (simsimd_cap_serial_k));
474
- #else // SIMSIMD_DEFINED_LINUX
506
+ #else // if !_SIMSIMD_DEFINED_LINUX
475
507
  return simsimd_cap_serial_k;
476
508
  #endif
477
509
  }
@@ -486,12 +518,12 @@ SIMSIMD_PUBLIC simsimd_capability_t _simsimd_capabilities_arm(void) {
486
518
  * @return A bitmask of the SIMD capabilities represented as a `simsimd_capability_t` enum value.
487
519
  */
488
520
  SIMSIMD_PUBLIC simsimd_capability_t _simsimd_capabilities_implementation(void) {
489
- #if SIMSIMD_TARGET_X86
521
+ #if _SIMSIMD_TARGET_X86
490
522
  return _simsimd_capabilities_x86();
491
- #endif // SIMSIMD_TARGET_X86
492
- #if SIMSIMD_TARGET_ARM
523
+ #endif // _SIMSIMD_TARGET_X86
524
+ #if _SIMSIMD_TARGET_ARM
493
525
  return _simsimd_capabilities_arm();
494
- #endif // SIMSIMD_TARGET_ARM
526
+ #endif // _SIMSIMD_TARGET_ARM
495
527
  return simsimd_cap_serial_k;
496
528
  }
497
529
 
@@ -505,623 +537,689 @@ SIMSIMD_PUBLIC simsimd_capability_t _simsimd_capabilities_implementation(void) {
505
537
  #pragma clang diagnostic ignored "-Wvolatile"
506
538
  #endif
507
539
 
508
- /**
509
- * @brief Determines the best suited metric implementation based on the given datatype,
510
- * supported and allowed by hardware capabilities.
511
- *
512
- * @param kind The kind of metric to be evaluated.
513
- * @param datatype The data type for which the metric needs to be evaluated.
514
- * @param supported The hardware capabilities supported by the CPU.
515
- * @param allowed The hardware capabilities allowed for use.
516
- * @param metric_output Output variable for the selected similarity function.
517
- * @param capability_output Output variable for the utilized hardware capabilities.
518
- */
519
- SIMSIMD_INTERNAL void _simsimd_find_metric_punned_implementation( //
520
- simsimd_metric_kind_t kind, //
521
- simsimd_datatype_t datatype, //
522
- simsimd_capability_t supported, //
523
- simsimd_capability_t allowed, //
524
- simsimd_metric_punned_t* metric_output, //
525
- simsimd_capability_t* capability_output) {
526
-
527
- // Modern compilers abso-freaking-lutely love optimizing-out my logic!
528
- // Just marking the variables as `volatile` is not enough, so we have
529
- // to add inline assembly to further discourage them!
530
- #if defined(_MSC_VER)
531
- _ReadWriteBarrier();
532
- #else
533
- __asm__ __volatile__("" ::: "memory");
534
- #endif
535
-
536
- volatile simsimd_metric_punned_t* m = metric_output;
537
- volatile simsimd_capability_t* c = capability_output;
538
- volatile simsimd_capability_t viable = (simsimd_capability_t)(supported & allowed);
539
- *m = (simsimd_metric_punned_t)0;
540
- *c = (simsimd_capability_t)0;
541
-
540
+ SIMSIMD_INTERNAL void _simsimd_find_metric_punned_f64(simsimd_capability_t v, simsimd_metric_kind_t k,
541
+ simsimd_metric_punned_t *m, simsimd_capability_t *c) {
542
542
  typedef simsimd_metric_punned_t m_t;
543
- switch (datatype) {
544
-
545
- case simsimd_datatype_unknown_k: break;
546
-
547
- // These data-types are not supported yet
548
- case simsimd_datatype_i16_k: break;
549
- case simsimd_datatype_i32_k: break;
550
- case simsimd_datatype_i64_k: break;
551
- case simsimd_datatype_u8_k: break;
552
- case simsimd_datatype_u64_k: break;
553
-
554
- // Double-precision floating-point vectors
555
- case simsimd_datatype_f64_k: {
556
543
  #if SIMSIMD_TARGET_SVE
557
- if (viable & simsimd_cap_sve_k)
558
- switch (kind) {
559
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f64_sve, *c = simsimd_cap_sve_k; return;
560
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f64_sve, *c = simsimd_cap_sve_k; return;
561
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f64_sve, *c = simsimd_cap_sve_k; return;
562
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f64_sve, *c = simsimd_cap_sve_k; return;
563
- default: break;
564
- }
544
+ if (v & simsimd_cap_sve_k) switch (k) {
545
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f64_sve, *c = simsimd_cap_sve_k; return;
546
+ case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f64_sve, *c = simsimd_cap_sve_k; return;
547
+ case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f64_sve, *c = simsimd_cap_sve_k; return;
548
+ case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f64_sve, *c = simsimd_cap_sve_k; return;
549
+ default: break;
550
+ }
565
551
  #endif
566
552
  #if SIMSIMD_TARGET_NEON
567
- if (viable & simsimd_cap_neon_k)
568
- switch (kind) {
569
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f64_neon, *c = simsimd_cap_neon_k; return;
570
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f64_neon, *c = simsimd_cap_neon_k; return;
571
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f64_neon, *c = simsimd_cap_neon_k; return;
572
- default: break;
573
- }
553
+ if (v & simsimd_cap_neon_k) switch (k) {
554
+ case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f64_neon, *c = simsimd_cap_neon_k; return;
555
+ case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f64_neon, *c = simsimd_cap_neon_k; return;
556
+ case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f64_neon, *c = simsimd_cap_neon_k; return;
557
+ default: break;
558
+ }
574
559
  #endif
575
560
  #if SIMSIMD_TARGET_SKYLAKE
576
- if (viable & simsimd_cap_skylake_k)
577
- switch (kind) {
578
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f64_skylake, *c = simsimd_cap_skylake_k; return;
579
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f64_skylake, *c = simsimd_cap_skylake_k; return;
580
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f64_skylake, *c = simsimd_cap_skylake_k; return;
581
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f64_skylake, *c = simsimd_cap_skylake_k; return;
582
- default: break;
583
- }
584
- #endif
585
- if (viable & simsimd_cap_serial_k)
586
- switch (kind) {
587
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f64_serial, *c = simsimd_cap_serial_k; return;
588
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f64_serial, *c = simsimd_cap_serial_k; return;
589
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f64_serial, *c = simsimd_cap_serial_k; return;
590
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f64_serial, *c = simsimd_cap_serial_k; return;
591
- case simsimd_metric_js_k: *m = (m_t)&simsimd_js_f64_serial, *c = simsimd_cap_serial_k; return;
592
- case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_f64_serial, *c = simsimd_cap_serial_k; return;
593
- case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f64_serial, *c = simsimd_cap_serial_k; return;
594
- case simsimd_metric_mahalanobis_k:
595
- *m = (m_t)&simsimd_mahalanobis_f64_serial, *c = simsimd_cap_serial_k;
596
- return;
597
- default: break;
598
- }
599
-
600
- break;
601
- }
602
-
603
- // Single-precision floating-point vectors
604
- case simsimd_datatype_f32_k: {
561
+ if (v & simsimd_cap_skylake_k) switch (k) {
562
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f64_skylake, *c = simsimd_cap_skylake_k; return;
563
+ case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f64_skylake, *c = simsimd_cap_skylake_k; return;
564
+ case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f64_skylake, *c = simsimd_cap_skylake_k; return;
565
+ case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f64_skylake, *c = simsimd_cap_skylake_k; return;
566
+ case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_f64_skylake, *c = simsimd_cap_skylake_k; return;
567
+ case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_f64_skylake, *c = simsimd_cap_skylake_k; return;
568
+ default: break;
569
+ }
570
+ #endif
571
+ #if SIMSIMD_TARGET_HASWELL
572
+ if (v & simsimd_cap_haswell_k) switch (k) {
573
+ case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f64_haswell, *c = simsimd_cap_haswell_k; return;
574
+ case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f64_haswell, *c = simsimd_cap_haswell_k; return;
575
+ case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f64_haswell, *c = simsimd_cap_haswell_k; return;
576
+ case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_f64_haswell, *c = simsimd_cap_haswell_k; return;
577
+ case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_f64_haswell, *c = simsimd_cap_haswell_k; return;
578
+ default: break;
579
+ }
580
+ #endif
581
+ if (v & simsimd_cap_serial_k) switch (k) {
582
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f64_serial, *c = simsimd_cap_serial_k; return;
583
+ case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f64_serial, *c = simsimd_cap_serial_k; return;
584
+ case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f64_serial, *c = simsimd_cap_serial_k; return;
585
+ case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f64_serial, *c = simsimd_cap_serial_k; return;
586
+ case simsimd_metric_js_k: *m = (m_t)&simsimd_js_f64_serial, *c = simsimd_cap_serial_k; return;
587
+ case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_f64_serial, *c = simsimd_cap_serial_k; return;
588
+ case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f64_serial, *c = simsimd_cap_serial_k; return;
589
+ case simsimd_metric_mahalanobis_k: *m = (m_t)&simsimd_mahalanobis_f64_serial, *c = simsimd_cap_serial_k; return;
590
+ case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_f64_serial, *c = simsimd_cap_serial_k; return;
591
+ case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_f64_serial, *c = simsimd_cap_serial_k; return;
592
+ default: break;
593
+ }
594
+ }
605
595
 
596
+ SIMSIMD_INTERNAL void _simsimd_find_metric_punned_f32(simsimd_capability_t v, simsimd_metric_kind_t k,
597
+ simsimd_metric_punned_t *m, simsimd_capability_t *c) {
598
+ typedef simsimd_metric_punned_t m_t;
606
599
  #if SIMSIMD_TARGET_SVE
607
- if (viable & simsimd_cap_sve_k)
608
- switch (kind) {
609
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32_sve, *c = simsimd_cap_sve_k; return;
610
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f32_sve, *c = simsimd_cap_sve_k; return;
611
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f32_sve, *c = simsimd_cap_sve_k; return;
612
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f32_sve, *c = simsimd_cap_sve_k; return;
613
- default: break;
614
- }
600
+ if (v & simsimd_cap_sve_k) switch (k) {
601
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32_sve, *c = simsimd_cap_sve_k; return;
602
+ case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f32_sve, *c = simsimd_cap_sve_k; return;
603
+ case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f32_sve, *c = simsimd_cap_sve_k; return;
604
+ case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f32_sve, *c = simsimd_cap_sve_k; return;
605
+ default: break;
606
+ }
615
607
  #endif
616
608
  #if SIMSIMD_TARGET_NEON
617
- if (viable & simsimd_cap_neon_k)
618
- switch (kind) {
619
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32_neon, *c = simsimd_cap_neon_k; return;
620
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f32_neon, *c = simsimd_cap_neon_k; return;
621
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f32_neon, *c = simsimd_cap_neon_k; return;
622
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f32_neon, *c = simsimd_cap_neon_k; return;
623
- case simsimd_metric_js_k: *m = (m_t)&simsimd_js_f32_neon, *c = simsimd_cap_neon_k; return;
624
- case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_f32_neon, *c = simsimd_cap_neon_k; return;
625
- default: break;
626
- }
609
+ if (v & simsimd_cap_neon_k) switch (k) {
610
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32_neon, *c = simsimd_cap_neon_k; return;
611
+ case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f32_neon, *c = simsimd_cap_neon_k; return;
612
+ case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f32_neon, *c = simsimd_cap_neon_k; return;
613
+ case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f32_neon, *c = simsimd_cap_neon_k; return;
614
+ case simsimd_metric_js_k: *m = (m_t)&simsimd_js_f32_neon, *c = simsimd_cap_neon_k; return;
615
+ case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_f32_neon, *c = simsimd_cap_neon_k; return;
616
+ case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_f32_neon, *c = simsimd_cap_neon_k; return;
617
+ case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_f32_neon, *c = simsimd_cap_neon_k; return;
618
+ default: break;
619
+ }
627
620
  #endif
628
621
  #if SIMSIMD_TARGET_SKYLAKE
629
- if (viable & simsimd_cap_skylake_k)
630
- switch (kind) {
631
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32_skylake, *c = simsimd_cap_skylake_k; return;
632
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f32_skylake, *c = simsimd_cap_skylake_k; return;
633
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f32_skylake, *c = simsimd_cap_skylake_k; return;
634
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f32_skylake, *c = simsimd_cap_skylake_k; return;
635
- case simsimd_metric_js_k: *m = (m_t)&simsimd_js_f32_skylake, *c = simsimd_cap_skylake_k; return;
636
- case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_f32_skylake, *c = simsimd_cap_skylake_k; return;
637
- case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f32_skylake, *c = simsimd_cap_skylake_k; return;
638
- case simsimd_metric_mahalanobis_k:
639
- *m = (m_t)&simsimd_mahalanobis_f32_skylake, *c = simsimd_cap_skylake_k;
640
- return;
641
- default: break;
642
- }
622
+ if (v & simsimd_cap_skylake_k) switch (k) {
623
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32_skylake, *c = simsimd_cap_skylake_k; return;
624
+ case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f32_skylake, *c = simsimd_cap_skylake_k; return;
625
+ case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f32_skylake, *c = simsimd_cap_skylake_k; return;
626
+ case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f32_skylake, *c = simsimd_cap_skylake_k; return;
627
+ case simsimd_metric_js_k: *m = (m_t)&simsimd_js_f32_skylake, *c = simsimd_cap_skylake_k; return;
628
+ case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_f32_skylake, *c = simsimd_cap_skylake_k; return;
629
+ case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f32_skylake, *c = simsimd_cap_skylake_k; return;
630
+ case simsimd_metric_mahalanobis_k:
631
+ *m = (m_t)&simsimd_mahalanobis_f32_skylake, *c = simsimd_cap_skylake_k;
632
+ return;
633
+ case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_f32_skylake, *c = simsimd_cap_skylake_k; return;
634
+ case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_f32_skylake, *c = simsimd_cap_skylake_k; return;
635
+ default: break;
636
+ }
643
637
  #endif
644
638
  #if SIMSIMD_TARGET_HASWELL
645
- if (viable & simsimd_cap_haswell_k)
646
- switch (kind) {
647
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32_haswell, *c = simsimd_cap_haswell_k; return;
648
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f32_haswell, *c = simsimd_cap_haswell_k; return;
649
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f32_haswell, *c = simsimd_cap_haswell_k; return;
650
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f32_haswell, *c = simsimd_cap_haswell_k; return;
651
- default: break;
652
- }
653
- #endif
654
-
655
- if (viable & simsimd_cap_serial_k)
656
- switch (kind) {
657
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32_serial, *c = simsimd_cap_serial_k; return;
658
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f32_serial, *c = simsimd_cap_serial_k; return;
659
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f32_serial, *c = simsimd_cap_serial_k; return;
660
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f32_serial, *c = simsimd_cap_serial_k; return;
661
- case simsimd_metric_js_k: *m = (m_t)&simsimd_js_f32_serial, *c = simsimd_cap_serial_k; return;
662
- case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_f32_serial, *c = simsimd_cap_serial_k; return;
663
- case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f32_serial, *c = simsimd_cap_serial_k; return;
664
- case simsimd_metric_mahalanobis_k:
665
- *m = (m_t)&simsimd_mahalanobis_f32_serial, *c = simsimd_cap_serial_k;
666
- return;
667
- default: break;
668
- }
669
-
670
- break;
671
- }
672
- // Half-precision floating-point vectors
673
- case simsimd_datatype_f16_k: {
639
+ if (v & simsimd_cap_haswell_k) switch (k) {
640
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32_haswell, *c = simsimd_cap_haswell_k; return;
641
+ case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f32_haswell, *c = simsimd_cap_haswell_k; return;
642
+ case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f32_haswell, *c = simsimd_cap_haswell_k; return;
643
+ case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f32_haswell, *c = simsimd_cap_haswell_k; return;
644
+ case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_f32_haswell, *c = simsimd_cap_haswell_k; return;
645
+ case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_f32_haswell, *c = simsimd_cap_haswell_k; return;
646
+ default: break;
647
+ }
648
+ #endif
649
+ if (v & simsimd_cap_serial_k) switch (k) {
650
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32_serial, *c = simsimd_cap_serial_k; return;
651
+ case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f32_serial, *c = simsimd_cap_serial_k; return;
652
+ case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f32_serial, *c = simsimd_cap_serial_k; return;
653
+ case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f32_serial, *c = simsimd_cap_serial_k; return;
654
+ case simsimd_metric_js_k: *m = (m_t)&simsimd_js_f32_serial, *c = simsimd_cap_serial_k; return;
655
+ case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_f32_serial, *c = simsimd_cap_serial_k; return;
656
+ case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f32_serial, *c = simsimd_cap_serial_k; return;
657
+ case simsimd_metric_mahalanobis_k: *m = (m_t)&simsimd_mahalanobis_f32_serial, *c = simsimd_cap_serial_k; return;
658
+ case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_f32_serial, *c = simsimd_cap_serial_k; return;
659
+ case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_f32_serial, *c = simsimd_cap_serial_k; return;
660
+ default: break;
661
+ }
662
+ }
674
663
 
664
+ SIMSIMD_INTERNAL void _simsimd_find_metric_punned_f16(simsimd_capability_t v, simsimd_metric_kind_t k,
665
+ simsimd_metric_punned_t *m, simsimd_capability_t *c) {
666
+ typedef simsimd_metric_punned_t m_t;
675
667
  #if SIMSIMD_TARGET_SVE_F16
676
- if (viable & simsimd_cap_sve_k)
677
- switch (kind) {
678
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16_sve, *c = simsimd_cap_sve_f16_k; return;
679
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f16_sve, *c = simsimd_cap_sve_f16_k; return;
680
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f16_sve, *c = simsimd_cap_sve_f16_k; return;
681
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f16_sve, *c = simsimd_cap_sve_f16_k; return;
682
- default: break;
683
- }
668
+ if (v & simsimd_cap_sve_k) switch (k) {
669
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16_sve, *c = simsimd_cap_sve_f16_k; return;
670
+ case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f16_sve, *c = simsimd_cap_sve_f16_k; return;
671
+ case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f16_sve, *c = simsimd_cap_sve_f16_k; return;
672
+ case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f16_sve, *c = simsimd_cap_sve_f16_k; return;
673
+ default: break;
674
+ }
684
675
  #endif
685
676
  #if SIMSIMD_TARGET_NEON_F16
686
- if (viable & simsimd_cap_neon_f16_k)
687
- switch (kind) {
688
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16_neon, *c = simsimd_cap_neon_f16_k; return;
689
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f16_neon, *c = simsimd_cap_neon_f16_k; return;
690
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f16_neon, *c = simsimd_cap_neon_f16_k; return;
691
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f16_neon, *c = simsimd_cap_neon_f16_k; return;
692
- case simsimd_metric_js_k: *m = (m_t)&simsimd_js_f16_neon, *c = simsimd_cap_neon_f16_k; return;
693
- case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_f16_neon, *c = simsimd_cap_neon_f16_k; return;
694
- case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f16_neon, *c = simsimd_cap_neon_f16_k; return;
695
- case simsimd_metric_mahalanobis_k:
696
- *m = (m_t)&simsimd_mahalanobis_f16_neon, *c = simsimd_cap_neon_f16_k;
697
- return;
698
- default: break;
699
- }
677
+ if (v & simsimd_cap_neon_f16_k) switch (k) {
678
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16_neon, *c = simsimd_cap_neon_f16_k; return;
679
+ case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f16_neon, *c = simsimd_cap_neon_f16_k; return;
680
+ case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f16_neon, *c = simsimd_cap_neon_f16_k; return;
681
+ case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f16_neon, *c = simsimd_cap_neon_f16_k; return;
682
+ case simsimd_metric_js_k: *m = (m_t)&simsimd_js_f16_neon, *c = simsimd_cap_neon_f16_k; return;
683
+ case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_f16_neon, *c = simsimd_cap_neon_f16_k; return;
684
+ case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f16_neon, *c = simsimd_cap_neon_f16_k; return;
685
+ case simsimd_metric_mahalanobis_k: *m = (m_t)&simsimd_mahalanobis_f16_neon, *c = simsimd_cap_neon_f16_k; return;
686
+ case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_f16_neon, *c = simsimd_cap_neon_f16_k; return;
687
+ case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_f16_neon, *c = simsimd_cap_neon_f16_k; return;
688
+ default: break;
689
+ }
700
690
  #endif
701
691
  #if SIMSIMD_TARGET_SAPPHIRE
702
- if (viable & simsimd_cap_sapphire_k)
703
- switch (kind) {
704
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16_sapphire, *c = simsimd_cap_sapphire_k; return;
705
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f16_sapphire, *c = simsimd_cap_sapphire_k; return;
706
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f16_sapphire, *c = simsimd_cap_sapphire_k; return;
707
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f16_sapphire, *c = simsimd_cap_sapphire_k; return;
708
- case simsimd_metric_js_k: *m = (m_t)&simsimd_js_f16_sapphire, *c = simsimd_cap_sapphire_k; return;
709
- case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_f16_sapphire, *c = simsimd_cap_sapphire_k; return;
710
- case simsimd_metric_bilinear_k:
711
- *m = (m_t)&simsimd_bilinear_f16_sapphire, *c = simsimd_cap_sapphire_k;
712
- return;
713
- case simsimd_metric_mahalanobis_k:
714
- *m = (m_t)&simsimd_mahalanobis_f16_sapphire, *c = simsimd_cap_sapphire_k;
715
- return;
716
- default: break;
717
- }
692
+ if (v & simsimd_cap_sapphire_k) switch (k) {
693
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16_sapphire, *c = simsimd_cap_sapphire_k; return;
694
+ case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f16_sapphire, *c = simsimd_cap_sapphire_k; return;
695
+ case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f16_sapphire, *c = simsimd_cap_sapphire_k; return;
696
+ case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f16_sapphire, *c = simsimd_cap_sapphire_k; return;
697
+ case simsimd_metric_js_k: *m = (m_t)&simsimd_js_f16_sapphire, *c = simsimd_cap_sapphire_k; return;
698
+ case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_f16_sapphire, *c = simsimd_cap_sapphire_k; return;
699
+ case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f16_sapphire, *c = simsimd_cap_sapphire_k; return;
700
+ case simsimd_metric_mahalanobis_k:
701
+ *m = (m_t)&simsimd_mahalanobis_f16_sapphire, *c = simsimd_cap_sapphire_k;
702
+ return;
703
+ case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_f16_sapphire, *c = simsimd_cap_sapphire_k; return;
704
+ case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_f16_sapphire, *c = simsimd_cap_sapphire_k; return;
705
+ default: break;
706
+ }
718
707
  #endif
719
708
  #if SIMSIMD_TARGET_HASWELL
720
- if (viable & simsimd_cap_haswell_k)
721
- switch (kind) {
722
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16_haswell, *c = simsimd_cap_haswell_k; return;
723
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f16_haswell, *c = simsimd_cap_haswell_k; return;
724
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f16_haswell, *c = simsimd_cap_haswell_k; return;
725
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f16_haswell, *c = simsimd_cap_haswell_k; return;
726
- case simsimd_metric_js_k: *m = (m_t)&simsimd_js_f16_haswell, *c = simsimd_cap_haswell_k; return;
727
- case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_f16_haswell, *c = simsimd_cap_haswell_k; return;
728
- case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f16_haswell, *c = simsimd_cap_haswell_k; return;
729
- case simsimd_metric_mahalanobis_k:
730
- *m = (m_t)&simsimd_mahalanobis_f16_haswell, *c = simsimd_cap_haswell_k;
731
- return;
732
- default: break;
733
- }
734
- #endif
735
-
736
- if (viable & simsimd_cap_serial_k)
737
- switch (kind) {
738
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16_serial, *c = simsimd_cap_serial_k; return;
739
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f16_serial, *c = simsimd_cap_serial_k; return;
740
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f16_serial, *c = simsimd_cap_serial_k; return;
741
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f16_serial, *c = simsimd_cap_serial_k; return;
742
- case simsimd_metric_js_k: *m = (m_t)&simsimd_js_f16_serial, *c = simsimd_cap_serial_k; return;
743
- case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_f16_serial, *c = simsimd_cap_serial_k; return;
744
- case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f16_serial, *c = simsimd_cap_serial_k; return;
745
- case simsimd_metric_mahalanobis_k:
746
- *m = (m_t)&simsimd_mahalanobis_f16_serial, *c = simsimd_cap_serial_k;
747
- return;
748
- default: break;
749
- }
750
-
751
- break;
752
- }
753
- // Brain floating-point vectors
754
- case simsimd_datatype_bf16_k: {
709
+ if (v & simsimd_cap_haswell_k) switch (k) {
710
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16_haswell, *c = simsimd_cap_haswell_k; return;
711
+ case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f16_haswell, *c = simsimd_cap_haswell_k; return;
712
+ case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f16_haswell, *c = simsimd_cap_haswell_k; return;
713
+ case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f16_haswell, *c = simsimd_cap_haswell_k; return;
714
+ case simsimd_metric_js_k: *m = (m_t)&simsimd_js_f16_haswell, *c = simsimd_cap_haswell_k; return;
715
+ case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_f16_haswell, *c = simsimd_cap_haswell_k; return;
716
+ case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f16_haswell, *c = simsimd_cap_haswell_k; return;
717
+ case simsimd_metric_mahalanobis_k:
718
+ *m = (m_t)&simsimd_mahalanobis_f16_haswell, *c = simsimd_cap_haswell_k;
719
+ return;
720
+ case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_f16_haswell, *c = simsimd_cap_haswell_k; return;
721
+ case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_f16_haswell, *c = simsimd_cap_haswell_k; return;
722
+ default: break;
723
+ }
724
+ #endif
725
+ if (v & simsimd_cap_serial_k) switch (k) {
726
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16_serial, *c = simsimd_cap_serial_k; return;
727
+ case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f16_serial, *c = simsimd_cap_serial_k; return;
728
+ case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f16_serial, *c = simsimd_cap_serial_k; return;
729
+ case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f16_serial, *c = simsimd_cap_serial_k; return;
730
+ case simsimd_metric_js_k: *m = (m_t)&simsimd_js_f16_serial, *c = simsimd_cap_serial_k; return;
731
+ case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_f16_serial, *c = simsimd_cap_serial_k; return;
732
+ case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f16_serial, *c = simsimd_cap_serial_k; return;
733
+ case simsimd_metric_mahalanobis_k: *m = (m_t)&simsimd_mahalanobis_f16_serial, *c = simsimd_cap_serial_k; return;
734
+ case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_f16_serial, *c = simsimd_cap_serial_k; return;
735
+ case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_f16_serial, *c = simsimd_cap_serial_k; return;
736
+ default: break;
737
+ }
738
+ }
739
+
740
+ SIMSIMD_INTERNAL void _simsimd_find_metric_punned_bf16(simsimd_capability_t v, simsimd_metric_kind_t k,
741
+ simsimd_metric_punned_t *m, simsimd_capability_t *c) {
742
+ typedef simsimd_metric_punned_t m_t;
755
743
  #if SIMSIMD_TARGET_SVE_BF16
756
- if (viable & simsimd_cap_sve_bf16_k)
757
- switch (kind) {
758
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_bf16_sve, *c = simsimd_cap_sve_bf16_k; return;
759
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_bf16_sve, *c = simsimd_cap_sve_bf16_k; return;
760
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_bf16_sve, *c = simsimd_cap_sve_bf16_k; return;
761
- default: break;
762
- }
744
+ if (v & simsimd_cap_sve_bf16_k) switch (k) {
745
+ case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_bf16_sve, *c = simsimd_cap_sve_bf16_k; return;
746
+ case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_bf16_sve, *c = simsimd_cap_sve_bf16_k; return;
747
+ case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_bf16_sve, *c = simsimd_cap_sve_bf16_k; return;
748
+ default: break;
749
+ }
763
750
  #endif
764
751
  #if SIMSIMD_TARGET_NEON_BF16
765
- if (viable & simsimd_cap_neon_bf16_k)
766
- switch (kind) {
767
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_bf16_neon, *c = simsimd_cap_neon_bf16_k; return;
768
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_bf16_neon, *c = simsimd_cap_neon_bf16_k; return;
769
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_bf16_neon, *c = simsimd_cap_neon_bf16_k; return;
770
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_bf16_neon, *c = simsimd_cap_neon_bf16_k; return;
771
- default: break;
772
- }
752
+ if (v & simsimd_cap_neon_bf16_k) switch (k) {
753
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_bf16_neon, *c = simsimd_cap_neon_bf16_k; return;
754
+ case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_bf16_neon, *c = simsimd_cap_neon_bf16_k; return;
755
+ case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_bf16_neon, *c = simsimd_cap_neon_bf16_k; return;
756
+ case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_bf16_neon, *c = simsimd_cap_neon_bf16_k; return;
757
+ case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_bf16_neon, *c = simsimd_cap_neon_bf16_k; return;
758
+ case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_bf16_neon, *c = simsimd_cap_neon_bf16_k; return;
759
+ default: break;
760
+ }
773
761
  #endif
774
762
  #if SIMSIMD_TARGET_GENOA
775
- if (viable & simsimd_cap_genoa_k)
776
- switch (kind) {
777
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_bf16_genoa, *c = simsimd_cap_genoa_k; return;
778
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_bf16_genoa, *c = simsimd_cap_genoa_k; return;
779
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_bf16_genoa, *c = simsimd_cap_genoa_k; return;
780
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_bf16_genoa, *c = simsimd_cap_genoa_k; return;
781
- case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_bf16_genoa, *c = simsimd_cap_genoa_k; return;
782
- case simsimd_metric_mahalanobis_k:
783
- *m = (m_t)&simsimd_mahalanobis_bf16_genoa, *c = simsimd_cap_genoa_k;
784
- return;
785
- default: break;
786
- }
763
+ if (v & simsimd_cap_genoa_k) switch (k) {
764
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_bf16_genoa, *c = simsimd_cap_genoa_k; return;
765
+ case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_bf16_genoa, *c = simsimd_cap_genoa_k; return;
766
+ case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_bf16_genoa, *c = simsimd_cap_genoa_k; return;
767
+ case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_bf16_genoa, *c = simsimd_cap_genoa_k; return;
768
+ case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_bf16_genoa, *c = simsimd_cap_genoa_k; return;
769
+ case simsimd_metric_mahalanobis_k: *m = (m_t)&simsimd_mahalanobis_bf16_genoa, *c = simsimd_cap_genoa_k; return;
770
+ default: break;
771
+ }
772
+ #endif
773
+ #if SIMSIMD_TARGET_SKYLAKE
774
+ if (v & simsimd_cap_skylake_k) switch (k) {
775
+ case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_bf16_skylake, *c = simsimd_cap_skylake_k; return;
776
+ case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_bf16_skylake, *c = simsimd_cap_skylake_k; return;
777
+ default: break;
778
+ }
787
779
  #endif
788
780
  #if SIMSIMD_TARGET_HASWELL
789
- if (viable & simsimd_cap_haswell_k)
790
- switch (kind) {
791
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_bf16_haswell, *c = simsimd_cap_haswell_k; return;
792
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_bf16_haswell, *c = simsimd_cap_haswell_k; return;
793
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_bf16_haswell, *c = simsimd_cap_haswell_k; return;
794
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_bf16_haswell, *c = simsimd_cap_haswell_k; return;
795
- case simsimd_metric_bilinear_k:
796
- *m = (m_t)&simsimd_bilinear_bf16_haswell, *c = simsimd_cap_haswell_k;
797
- return;
798
- case simsimd_metric_mahalanobis_k:
799
- *m = (m_t)&simsimd_mahalanobis_bf16_haswell, *c = simsimd_cap_haswell_k;
800
- return;
801
- default: break;
802
- }
803
- #endif
804
- if (viable & simsimd_cap_serial_k)
805
- switch (kind) {
806
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_bf16_serial, *c = simsimd_cap_serial_k; return;
807
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_bf16_serial, *c = simsimd_cap_serial_k; return;
808
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_bf16_serial, *c = simsimd_cap_serial_k; return;
809
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_bf16_serial, *c = simsimd_cap_serial_k; return;
810
- case simsimd_metric_js_k: *m = (m_t)&simsimd_js_bf16_serial, *c = simsimd_cap_serial_k; return;
811
- case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_bf16_serial, *c = simsimd_cap_serial_k; return;
812
- case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_bf16_serial, *c = simsimd_cap_serial_k; return;
813
- case simsimd_metric_mahalanobis_k:
814
- *m = (m_t)&simsimd_mahalanobis_bf16_serial, *c = simsimd_cap_serial_k;
815
- return;
816
- default: break;
817
- }
818
-
819
- break;
820
- }
821
- // Single-byte integer vectors
822
- case simsimd_datatype_i8_k: {
781
+ if (v & simsimd_cap_haswell_k) switch (k) {
782
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_bf16_haswell, *c = simsimd_cap_haswell_k; return;
783
+ case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_bf16_haswell, *c = simsimd_cap_haswell_k; return;
784
+ case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_bf16_haswell, *c = simsimd_cap_haswell_k; return;
785
+ case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_bf16_haswell, *c = simsimd_cap_haswell_k; return;
786
+ case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_bf16_haswell, *c = simsimd_cap_haswell_k; return;
787
+ case simsimd_metric_mahalanobis_k:
788
+ *m = (m_t)&simsimd_mahalanobis_bf16_haswell, *c = simsimd_cap_haswell_k;
789
+ return;
790
+ case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_bf16_haswell, *c = simsimd_cap_haswell_k; return;
791
+ case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_bf16_haswell, *c = simsimd_cap_haswell_k; return;
792
+ default: break;
793
+ }
794
+ #endif
795
+ if (v & simsimd_cap_serial_k) switch (k) {
796
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_bf16_serial, *c = simsimd_cap_serial_k; return;
797
+ case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_bf16_serial, *c = simsimd_cap_serial_k; return;
798
+ case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_bf16_serial, *c = simsimd_cap_serial_k; return;
799
+ case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_bf16_serial, *c = simsimd_cap_serial_k; return;
800
+ case simsimd_metric_js_k: *m = (m_t)&simsimd_js_bf16_serial, *c = simsimd_cap_serial_k; return;
801
+ case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_bf16_serial, *c = simsimd_cap_serial_k; return;
802
+ case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_bf16_serial, *c = simsimd_cap_serial_k; return;
803
+ case simsimd_metric_mahalanobis_k:
804
+ *m = (m_t)&simsimd_mahalanobis_bf16_serial, *c = simsimd_cap_serial_k;
805
+ return;
806
+ case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_bf16_serial, *c = simsimd_cap_serial_k; return;
807
+ case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_bf16_serial, *c = simsimd_cap_serial_k; return;
808
+ default: break;
809
+ }
810
+ }
811
+
812
+ SIMSIMD_INTERNAL void _simsimd_find_metric_punned_i8(simsimd_capability_t v, simsimd_metric_kind_t k,
813
+ simsimd_metric_punned_t *m, simsimd_capability_t *c) {
814
+ typedef simsimd_metric_punned_t m_t;
823
815
  #if SIMSIMD_TARGET_NEON_I8
824
- if (viable & simsimd_cap_neon_i8_k)
825
- switch (kind) {
826
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_i8_neon, *c = simsimd_cap_neon_i8_k; return;
827
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_i8_neon, *c = simsimd_cap_neon_i8_k; return;
828
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_i8_neon, *c = simsimd_cap_neon_i8_k; return;
829
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_i8_neon, *c = simsimd_cap_neon_i8_k; return;
830
- default: break;
831
- }
816
+ if (v & simsimd_cap_neon_i8_k) switch (k) {
817
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_i8_neon, *c = simsimd_cap_neon_i8_k; return;
818
+ case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_i8_neon, *c = simsimd_cap_neon_i8_k; return;
819
+ case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_i8_neon, *c = simsimd_cap_neon_i8_k; return;
820
+ case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_i8_neon, *c = simsimd_cap_neon_i8_k; return;
821
+ default: break;
822
+ }
823
+ #endif
824
+ #if SIMSIMD_TARGET_NEON_F16 //! Scaling of 8-bit integers is performed using 16-bit floats.
825
+ if (v & simsimd_cap_neon_f16_k) switch (k) {
826
+ case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_i8_neon, *c = simsimd_cap_neon_f16_k; return;
827
+ case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_i8_neon, *c = simsimd_cap_neon_f16_k; return;
828
+ default: break;
829
+ }
830
+ #endif
831
+ #if SIMSIMD_TARGET_SAPPHIRE //! Scaling of 8-bit integers is performed using 16-bit floats.
832
+ if (v & simsimd_cap_sapphire_k) switch (k) {
833
+ case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_i8_sapphire, *c = simsimd_cap_sapphire_k; return;
834
+ case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_i8_sapphire, *c = simsimd_cap_sapphire_k; return;
835
+ default: break;
836
+ }
832
837
  #endif
833
838
  #if SIMSIMD_TARGET_ICE
834
- if (viable & simsimd_cap_ice_k)
835
- switch (kind) {
836
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_i8_ice, *c = simsimd_cap_ice_k; return;
837
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_i8_ice, *c = simsimd_cap_ice_k; return;
838
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_i8_ice, *c = simsimd_cap_ice_k; return;
839
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_i8_ice, *c = simsimd_cap_ice_k; return;
840
- default: break;
841
- }
839
+ if (v & simsimd_cap_ice_k) switch (k) {
840
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_i8_ice, *c = simsimd_cap_ice_k; return;
841
+ case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_i8_ice, *c = simsimd_cap_ice_k; return;
842
+ case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_i8_ice, *c = simsimd_cap_ice_k; return;
843
+ case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_i8_ice, *c = simsimd_cap_ice_k; return;
844
+ default: break;
845
+ }
842
846
  #endif
843
847
  #if SIMSIMD_TARGET_HASWELL
844
- if (viable & simsimd_cap_haswell_k)
845
- switch (kind) {
846
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_i8_haswell, *c = simsimd_cap_haswell_k; return;
847
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_i8_haswell, *c = simsimd_cap_haswell_k; return;
848
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_i8_haswell, *c = simsimd_cap_haswell_k; return;
849
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_i8_haswell, *c = simsimd_cap_haswell_k; return;
850
- default: break;
851
- }
852
- #endif
853
-
854
- if (viable & simsimd_cap_serial_k)
855
- switch (kind) {
856
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_i8_serial, *c = simsimd_cap_serial_k; return;
857
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_i8_serial, *c = simsimd_cap_serial_k; return;
858
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_i8_serial, *c = simsimd_cap_serial_k; return;
859
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_i8_serial, *c = simsimd_cap_serial_k; return;
860
- default: break;
861
- }
862
-
863
- break;
864
- }
865
- // Binary vectors
866
- case simsimd_datatype_b8_k: {
848
+ if (v & simsimd_cap_haswell_k) switch (k) {
849
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_i8_haswell, *c = simsimd_cap_haswell_k; return;
850
+ case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_i8_haswell, *c = simsimd_cap_haswell_k; return;
851
+ case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_i8_haswell, *c = simsimd_cap_haswell_k; return;
852
+ case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_i8_haswell, *c = simsimd_cap_haswell_k; return;
853
+ case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_i8_haswell, *c = simsimd_cap_haswell_k; return;
854
+ case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_i8_haswell, *c = simsimd_cap_haswell_k; return;
855
+ default: break;
856
+ }
857
+ #endif
858
+ if (v & simsimd_cap_serial_k) switch (k) {
859
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_i8_serial, *c = simsimd_cap_serial_k; return;
860
+ case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_i8_serial, *c = simsimd_cap_serial_k; return;
861
+ case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_i8_serial, *c = simsimd_cap_serial_k; return;
862
+ case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_i8_serial, *c = simsimd_cap_serial_k; return;
863
+ case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_i8_serial, *c = simsimd_cap_serial_k; return;
864
+ case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_i8_serial, *c = simsimd_cap_serial_k; return;
865
+ default: break;
866
+ }
867
+ }
868
+ SIMSIMD_INTERNAL void _simsimd_find_metric_punned_u8(simsimd_capability_t v, simsimd_metric_kind_t k,
869
+ simsimd_metric_punned_t *m, simsimd_capability_t *c) {
870
+ typedef simsimd_metric_punned_t m_t;
871
+ #if SIMSIMD_TARGET_NEON_I8
872
+ if (v & simsimd_cap_neon_i8_k) switch (k) {
873
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_u8_neon, *c = simsimd_cap_neon_i8_k; return;
874
+ case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_u8_neon, *c = simsimd_cap_neon_i8_k; return;
875
+ case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_u8_neon, *c = simsimd_cap_neon_i8_k; return;
876
+ case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_u8_neon, *c = simsimd_cap_neon_i8_k; return;
877
+ default: break;
878
+ }
879
+ #endif
880
+ #if SIMSIMD_TARGET_NEON_F16 //! Scaling of 8-bit integers is performed using 16-bit floats.
881
+ if (v & simsimd_cap_neon_f16_k) switch (k) {
882
+ case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_u8_neon, *c = simsimd_cap_neon_f16_k; return;
883
+ case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_u8_neon, *c = simsimd_cap_neon_f16_k; return;
884
+ default: break;
885
+ }
886
+ #endif
887
+ #if SIMSIMD_TARGET_SAPPHIRE //! Scaling of 8-bit integers is performed using 16-bit floats.
888
+ if (v & simsimd_cap_sapphire_k) switch (k) {
889
+ case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_u8_sapphire, *c = simsimd_cap_sapphire_k; return;
890
+ case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_u8_sapphire, *c = simsimd_cap_sapphire_k; return;
891
+ default: break;
892
+ }
893
+ #endif
894
+ #if SIMSIMD_TARGET_ICE
895
+ if (v & simsimd_cap_ice_k) switch (k) {
896
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_u8_ice, *c = simsimd_cap_ice_k; return;
897
+ case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_u8_ice, *c = simsimd_cap_ice_k; return;
898
+ case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_u8_ice, *c = simsimd_cap_ice_k; return;
899
+ case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_u8_ice, *c = simsimd_cap_ice_k; return;
900
+ default: break;
901
+ }
902
+ #endif
903
+ #if SIMSIMD_TARGET_HASWELL
904
+ if (v & simsimd_cap_haswell_k) switch (k) {
905
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_u8_haswell, *c = simsimd_cap_haswell_k; return;
906
+ case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_u8_haswell, *c = simsimd_cap_haswell_k; return;
907
+ case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_u8_haswell, *c = simsimd_cap_haswell_k; return;
908
+ case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_u8_haswell, *c = simsimd_cap_haswell_k; return;
909
+ case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_u8_haswell, *c = simsimd_cap_haswell_k; return;
910
+ case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_u8_haswell, *c = simsimd_cap_haswell_k; return;
911
+ default: break;
912
+ }
913
+ #endif
914
+ if (v & simsimd_cap_serial_k) switch (k) {
915
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_u8_serial, *c = simsimd_cap_serial_k; return;
916
+ case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_u8_serial, *c = simsimd_cap_serial_k; return;
917
+ case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_u8_serial, *c = simsimd_cap_serial_k; return;
918
+ case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_u8_serial, *c = simsimd_cap_serial_k; return;
919
+ case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_u8_serial, *c = simsimd_cap_serial_k; return;
920
+ case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_u8_serial, *c = simsimd_cap_serial_k; return;
921
+ default: break;
922
+ }
923
+ }
867
924
 
925
+ SIMSIMD_INTERNAL void _simsimd_find_metric_punned_b8(simsimd_capability_t v, simsimd_metric_kind_t k,
926
+ simsimd_metric_punned_t *m, simsimd_capability_t *c) {
927
+ typedef simsimd_metric_punned_t m_t;
868
928
  #if SIMSIMD_TARGET_SVE
869
- if (viable & simsimd_cap_sve_k)
870
- switch (kind) {
871
- case simsimd_metric_hamming_k: *m = (m_t)&simsimd_hamming_b8_sve, *c = simsimd_cap_sve_k; return;
872
- case simsimd_metric_jaccard_k: *m = (m_t)&simsimd_jaccard_b8_sve, *c = simsimd_cap_sve_k; return;
873
- default: break;
874
- }
929
+ if (v & simsimd_cap_sve_k) switch (k) {
930
+ case simsimd_metric_hamming_k: *m = (m_t)&simsimd_hamming_b8_sve, *c = simsimd_cap_sve_k; return;
931
+ case simsimd_metric_jaccard_k: *m = (m_t)&simsimd_jaccard_b8_sve, *c = simsimd_cap_sve_k; return;
932
+ default: break;
933
+ }
875
934
  #endif
876
935
  #if SIMSIMD_TARGET_NEON
877
- if (viable & simsimd_cap_neon_k)
878
- switch (kind) {
879
- case simsimd_metric_hamming_k: *m = (m_t)&simsimd_hamming_b8_neon, *c = simsimd_cap_neon_k; return;
880
- case simsimd_metric_jaccard_k: *m = (m_t)&simsimd_jaccard_b8_neon, *c = simsimd_cap_neon_k; return;
881
- default: break;
882
- }
936
+ if (v & simsimd_cap_neon_k) switch (k) {
937
+ case simsimd_metric_hamming_k: *m = (m_t)&simsimd_hamming_b8_neon, *c = simsimd_cap_neon_k; return;
938
+ case simsimd_metric_jaccard_k: *m = (m_t)&simsimd_jaccard_b8_neon, *c = simsimd_cap_neon_k; return;
939
+ default: break;
940
+ }
883
941
  #endif
884
942
  #if SIMSIMD_TARGET_ICE
885
- if (viable & simsimd_cap_ice_k)
886
- switch (kind) {
887
- case simsimd_metric_hamming_k: *m = (m_t)&simsimd_hamming_b8_ice, *c = simsimd_cap_ice_k; return;
888
- case simsimd_metric_jaccard_k: *m = (m_t)&simsimd_jaccard_b8_ice, *c = simsimd_cap_ice_k; return;
889
- default: break;
890
- }
943
+ if (v & simsimd_cap_ice_k) switch (k) {
944
+ case simsimd_metric_hamming_k: *m = (m_t)&simsimd_hamming_b8_ice, *c = simsimd_cap_ice_k; return;
945
+ case simsimd_metric_jaccard_k: *m = (m_t)&simsimd_jaccard_b8_ice, *c = simsimd_cap_ice_k; return;
946
+ default: break;
947
+ }
891
948
  #endif
892
949
  #if SIMSIMD_TARGET_HASWELL
893
- if (viable & simsimd_cap_haswell_k)
894
- switch (kind) {
895
- case simsimd_metric_hamming_k: *m = (m_t)&simsimd_hamming_b8_haswell, *c = simsimd_cap_haswell_k; return;
896
- case simsimd_metric_jaccard_k: *m = (m_t)&simsimd_jaccard_b8_haswell, *c = simsimd_cap_haswell_k; return;
897
- default: break;
898
- }
899
- #endif
900
-
901
- if (viable & simsimd_cap_serial_k)
902
- switch (kind) {
903
- case simsimd_metric_hamming_k: *m = (m_t)&simsimd_hamming_b8_serial, *c = simsimd_cap_serial_k; return;
904
- case simsimd_metric_jaccard_k: *m = (m_t)&simsimd_jaccard_b8_serial, *c = simsimd_cap_serial_k; return;
905
- default: break;
906
- }
907
-
908
- break;
909
- }
910
- // Complex floating-point vectors
911
- case simsimd_datatype_f32c_k: {
950
+ if (v & simsimd_cap_haswell_k) switch (k) {
951
+ case simsimd_metric_hamming_k: *m = (m_t)&simsimd_hamming_b8_haswell, *c = simsimd_cap_haswell_k; return;
952
+ case simsimd_metric_jaccard_k: *m = (m_t)&simsimd_jaccard_b8_haswell, *c = simsimd_cap_haswell_k; return;
953
+ default: break;
954
+ }
955
+ #endif
956
+ if (v & simsimd_cap_serial_k) switch (k) {
957
+ case simsimd_metric_hamming_k: *m = (m_t)&simsimd_hamming_b8_serial, *c = simsimd_cap_serial_k; return;
958
+ case simsimd_metric_jaccard_k: *m = (m_t)&simsimd_jaccard_b8_serial, *c = simsimd_cap_serial_k; return;
959
+ default: break;
960
+ }
961
+ }
912
962
 
963
+ SIMSIMD_INTERNAL void _simsimd_find_metric_punned_f64c(simsimd_capability_t v, simsimd_metric_kind_t k,
964
+ simsimd_metric_punned_t *m, simsimd_capability_t *c) {
965
+ typedef simsimd_metric_punned_t m_t;
913
966
  #if SIMSIMD_TARGET_SVE
914
- if (viable & simsimd_cap_sve_k)
915
- switch (kind) {
916
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32c_sve, *c = simsimd_cap_sve_k; return;
917
- case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f32c_sve, *c = simsimd_cap_sve_k; return;
918
- default: break;
919
- }
920
- #endif
921
- #if SIMSIMD_TARGET_NEON
922
- if (viable & simsimd_cap_neon_k)
923
- switch (kind) {
924
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32c_neon, *c = simsimd_cap_neon_k; return;
925
- case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f32c_neon, *c = simsimd_cap_neon_k; return;
926
- default: break;
927
- }
967
+ if (v & simsimd_cap_sve_k) switch (k) {
968
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f64c_sve, *c = simsimd_cap_sve_k; return;
969
+ case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f64c_sve, *c = simsimd_cap_sve_k; return;
970
+ default: break;
971
+ }
928
972
  #endif
929
973
  #if SIMSIMD_TARGET_SKYLAKE
930
- if (viable & simsimd_cap_skylake_k)
931
- switch (kind) {
932
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32c_skylake, *c = simsimd_cap_skylake_k; return;
933
- case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f32c_skylake, *c = simsimd_cap_skylake_k; return;
934
- default: break;
935
- }
936
- #endif
937
- #if SIMSIMD_TARGET_HASWELL
938
- if (viable & simsimd_cap_haswell_k)
939
- switch (kind) {
940
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32c_haswell, *c = simsimd_cap_haswell_k; return;
941
- case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f32c_haswell, *c = simsimd_cap_haswell_k; return;
942
- default: break;
943
- }
944
- #endif
945
-
946
- if (viable & simsimd_cap_serial_k)
947
- switch (kind) {
948
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32c_serial, *c = simsimd_cap_serial_k; return;
949
- case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f32c_serial, *c = simsimd_cap_serial_k; return;
950
- default: break;
951
- }
952
-
953
- break;
954
- }
955
- // Complex double-precision floating-point vectors
956
- case simsimd_datatype_f64c_k: {
974
+ if (v & simsimd_cap_skylake_k) switch (k) {
975
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f64c_skylake, *c = simsimd_cap_skylake_k; return;
976
+ case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f64c_skylake, *c = simsimd_cap_skylake_k; return;
977
+ default: break;
978
+ }
979
+ #endif
980
+ if (v & simsimd_cap_serial_k) switch (k) {
981
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f64c_serial, *c = simsimd_cap_serial_k; return;
982
+ case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f64c_serial, *c = simsimd_cap_serial_k; return;
983
+ default: break;
984
+ }
985
+ }
957
986
 
987
+ SIMSIMD_INTERNAL void _simsimd_find_metric_punned_f32c(simsimd_capability_t v, simsimd_metric_kind_t k,
988
+ simsimd_metric_punned_t *m, simsimd_capability_t *c) {
989
+ typedef simsimd_metric_punned_t m_t;
958
990
  #if SIMSIMD_TARGET_SVE
959
- if (viable & simsimd_cap_sve_k)
960
- switch (kind) {
961
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f64c_sve, *c = simsimd_cap_sve_k; return;
962
- case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f64c_sve, *c = simsimd_cap_sve_k; return;
963
- default: break;
964
- }
991
+ if (v & simsimd_cap_sve_k) switch (k) {
992
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32c_sve, *c = simsimd_cap_sve_k; return;
993
+ case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f32c_sve, *c = simsimd_cap_sve_k; return;
994
+ default: break;
995
+ }
996
+ #endif
997
+ #if SIMSIMD_TARGET_NEON
998
+ if (v & simsimd_cap_neon_k) switch (k) {
999
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32c_neon, *c = simsimd_cap_neon_k; return;
1000
+ case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f32c_neon, *c = simsimd_cap_neon_k; return;
1001
+ default: break;
1002
+ }
965
1003
  #endif
966
1004
  #if SIMSIMD_TARGET_SKYLAKE
967
- if (viable & simsimd_cap_skylake_k)
968
- switch (kind) {
969
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f64c_skylake, *c = simsimd_cap_skylake_k; return;
970
- case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f64c_skylake, *c = simsimd_cap_skylake_k; return;
971
- default: break;
972
- }
973
- #endif
974
-
975
- if (viable & simsimd_cap_serial_k)
976
- switch (kind) {
977
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f64c_serial, *c = simsimd_cap_serial_k; return;
978
- case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f64c_serial, *c = simsimd_cap_serial_k; return;
979
- default: break;
980
- }
981
-
982
- break;
983
- }
984
- // Complex half-precision floating-point vectors
985
- case simsimd_datatype_f16c_k: {
1005
+ if (v & simsimd_cap_skylake_k) switch (k) {
1006
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32c_skylake, *c = simsimd_cap_skylake_k; return;
1007
+ case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f32c_skylake, *c = simsimd_cap_skylake_k; return;
1008
+ default: break;
1009
+ }
1010
+ #endif
1011
+ #if SIMSIMD_TARGET_HASWELL
1012
+ if (v & simsimd_cap_haswell_k) switch (k) {
1013
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32c_haswell, *c = simsimd_cap_haswell_k; return;
1014
+ case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f32c_haswell, *c = simsimd_cap_haswell_k; return;
1015
+ default: break;
1016
+ }
1017
+ #endif
1018
+ if (v & simsimd_cap_serial_k) switch (k) {
1019
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32c_serial, *c = simsimd_cap_serial_k; return;
1020
+ case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f32c_serial, *c = simsimd_cap_serial_k; return;
1021
+ default: break;
1022
+ }
1023
+ }
986
1024
 
1025
+ SIMSIMD_INTERNAL void _simsimd_find_metric_punned_f16c(simsimd_capability_t v, simsimd_metric_kind_t k,
1026
+ simsimd_metric_punned_t *m, simsimd_capability_t *c) {
1027
+ typedef simsimd_metric_punned_t m_t;
987
1028
  #if SIMSIMD_TARGET_SVE_F16
988
- if (viable & simsimd_cap_sve_k)
989
- switch (kind) {
990
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16c_sve, *c = simsimd_cap_sve_f16_k; return;
991
- case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f16c_sve, *c = simsimd_cap_sve_f16_k; return;
992
- default: break;
993
- }
1029
+ if (v & simsimd_cap_sve_k) switch (k) {
1030
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16c_sve, *c = simsimd_cap_sve_f16_k; return;
1031
+ case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f16c_sve, *c = simsimd_cap_sve_f16_k; return;
1032
+ default: break;
1033
+ }
994
1034
  #endif
995
1035
  #if SIMSIMD_TARGET_NEON_F16
996
- if (viable & simsimd_cap_neon_f16_k)
997
- switch (kind) {
998
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16c_neon, *c = simsimd_cap_neon_f16_k; return;
999
- case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f16c_neon, *c = simsimd_cap_neon_f16_k; return;
1000
- default: break;
1001
- }
1036
+ if (v & simsimd_cap_neon_f16_k) switch (k) {
1037
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16c_neon, *c = simsimd_cap_neon_f16_k; return;
1038
+ case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f16c_neon, *c = simsimd_cap_neon_f16_k; return;
1039
+ default: break;
1040
+ }
1002
1041
  #endif
1003
1042
  #if SIMSIMD_TARGET_SAPPHIRE
1004
- if (viable & simsimd_cap_sapphire_k)
1005
- switch (kind) {
1006
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16c_sapphire, *c = simsimd_cap_sapphire_k; return;
1007
- case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f16c_sapphire, *c = simsimd_cap_sapphire_k; return;
1008
- default: break;
1009
- }
1043
+ if (v & simsimd_cap_sapphire_k) switch (k) {
1044
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16c_sapphire, *c = simsimd_cap_sapphire_k; return;
1045
+ case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f16c_sapphire, *c = simsimd_cap_sapphire_k; return;
1046
+ default: break;
1047
+ }
1010
1048
  #endif
1011
1049
  #if SIMSIMD_TARGET_HASWELL
1012
- if (viable & simsimd_cap_haswell_k)
1013
- switch (kind) {
1014
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16c_haswell, *c = simsimd_cap_haswell_k; return;
1015
- case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f16c_haswell, *c = simsimd_cap_haswell_k; return;
1016
- default: break;
1017
- }
1018
- #endif
1019
-
1020
- if (viable & simsimd_cap_serial_k)
1021
- switch (kind) {
1022
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16c_serial, *c = simsimd_cap_serial_k; return;
1023
- case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f16c_serial, *c = simsimd_cap_serial_k; return;
1024
- default: break;
1025
- }
1026
-
1027
- break;
1028
- }
1029
- // Complex Brain floating-point vectors
1030
- case simsimd_datatype_bf16c_k: {
1050
+ if (v & simsimd_cap_haswell_k) switch (k) {
1051
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16c_haswell, *c = simsimd_cap_haswell_k; return;
1052
+ case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f16c_haswell, *c = simsimd_cap_haswell_k; return;
1053
+ default: break;
1054
+ }
1055
+ #endif
1056
+ if (v & simsimd_cap_serial_k) switch (k) {
1057
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16c_serial, *c = simsimd_cap_serial_k; return;
1058
+ case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f16c_serial, *c = simsimd_cap_serial_k; return;
1059
+ default: break;
1060
+ }
1061
+ }
1031
1062
 
1063
+ SIMSIMD_INTERNAL void _simsimd_find_metric_punned_bf16c(simsimd_capability_t v, simsimd_metric_kind_t k,
1064
+ simsimd_metric_punned_t *m, simsimd_capability_t *c) {
1065
+ typedef simsimd_metric_punned_t m_t;
1032
1066
  #if SIMSIMD_TARGET_NEON_BF16
1033
- if (viable & simsimd_cap_neon_bf16_k)
1034
- switch (kind) {
1035
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_bf16c_neon, *c = simsimd_cap_neon_bf16_k; return;
1036
- case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_bf16c_neon, *c = simsimd_cap_neon_bf16_k; return;
1037
- default: break;
1038
- }
1067
+ if (v & simsimd_cap_neon_bf16_k) switch (k) {
1068
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_bf16c_neon, *c = simsimd_cap_neon_bf16_k; return;
1069
+ case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_bf16c_neon, *c = simsimd_cap_neon_bf16_k; return;
1070
+ default: break;
1071
+ }
1039
1072
  #endif
1040
1073
  #if SIMSIMD_TARGET_GENOA
1041
- if (viable & simsimd_cap_genoa_k)
1042
- switch (kind) {
1043
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_bf16c_genoa, *c = simsimd_cap_genoa_k; return;
1044
- case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_bf16c_genoa, *c = simsimd_cap_genoa_k; return;
1045
- default: break;
1046
- }
1047
- #endif
1048
-
1049
- if (viable & simsimd_cap_serial_k)
1050
- switch (kind) {
1051
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_bf16c_serial, *c = simsimd_cap_serial_k; return;
1052
- case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_bf16c_serial, *c = simsimd_cap_serial_k; return;
1053
- default: break;
1054
- }
1055
-
1056
- break;
1057
- }
1058
-
1059
- // Unsigned 16-bit integer vectors
1060
- case simsimd_datatype_u16_k: {
1074
+ if (v & simsimd_cap_genoa_k) switch (k) {
1075
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_bf16c_genoa, *c = simsimd_cap_genoa_k; return;
1076
+ case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_bf16c_genoa, *c = simsimd_cap_genoa_k; return;
1077
+ default: break;
1078
+ }
1079
+ #endif
1080
+ if (v & simsimd_cap_serial_k) switch (k) {
1081
+ case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_bf16c_serial, *c = simsimd_cap_serial_k; return;
1082
+ case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_bf16c_serial, *c = simsimd_cap_serial_k; return;
1083
+ default: break;
1084
+ }
1085
+ }
1061
1086
 
1087
+ SIMSIMD_INTERNAL void _simsimd_find_metric_punned_u16(simsimd_capability_t v, simsimd_metric_kind_t k,
1088
+ simsimd_metric_punned_t *m, simsimd_capability_t *c) {
1089
+ typedef simsimd_metric_punned_t m_t;
1062
1090
  #if SIMSIMD_TARGET_SVE2
1063
- if (viable & simsimd_cap_sve_k)
1064
- switch (kind) {
1065
- case simsimd_metric_intersect_k: *m = (m_t)&simsimd_intersect_u16_sve2, *c = simsimd_cap_sve_k; return;
1066
- default: break;
1067
- }
1091
+ if (v & simsimd_cap_sve2_k) switch (k) {
1092
+ case simsimd_metric_intersect_k: *m = (m_t)&simsimd_intersect_u16_sve2, *c = simsimd_cap_sve2_k; return;
1093
+ case simsimd_metric_spdot_counts_k: *m = (m_t)&simsimd_spdot_counts_u16_sve2, *c = simsimd_cap_sve2_k; return;
1094
+ #if SIMSIMD_TARGET_SVE_BF16 //! We also need `bf16` support for weights
1095
+ case simsimd_metric_spdot_weights_k: *m = (m_t)&simsimd_spdot_weights_u16_sve2, *c = simsimd_cap_sve2_k; return;
1096
+ #endif
1097
+ default: break;
1098
+ }
1068
1099
  #endif
1069
1100
  #if SIMSIMD_TARGET_NEON
1070
- if (viable & simsimd_cap_neon_k)
1071
- switch (kind) {
1072
- case simsimd_metric_intersect_k: *m = (m_t)&simsimd_intersect_u16_neon, *c = simsimd_cap_neon_k; return;
1073
- default: break;
1074
- }
1101
+ if (v & simsimd_cap_neon_k) switch (k) {
1102
+ case simsimd_metric_intersect_k: *m = (m_t)&simsimd_intersect_u16_neon, *c = simsimd_cap_neon_k; return;
1103
+ default: break;
1104
+ }
1105
+ #endif
1106
+ #if SIMSIMD_TARGET_TURIN
1107
+ if (v & simsimd_cap_turin_k) switch (k) {
1108
+ case simsimd_metric_intersect_k: *m = (m_t)&simsimd_intersect_u16_turin, *c = simsimd_cap_turin_k; return;
1109
+ case simsimd_metric_spdot_counts_k: *m = (m_t)&simsimd_spdot_counts_u16_turin, *c = simsimd_cap_turin_k; return;
1110
+ case simsimd_metric_spdot_weights_k:
1111
+ *m = (m_t)&simsimd_spdot_weights_u16_turin, *c = simsimd_cap_turin_k;
1112
+ return;
1113
+ default: break;
1114
+ }
1075
1115
  #endif
1076
1116
  #if SIMSIMD_TARGET_ICE
1077
- if (viable & simsimd_cap_ice_k)
1078
- switch (kind) {
1079
- case simsimd_metric_intersect_k: *m = (m_t)&simsimd_intersect_u16_ice, *c = simsimd_cap_skylake_k; return;
1080
- default: break;
1081
- }
1082
- #endif
1083
- if (viable & simsimd_cap_serial_k)
1084
- switch (kind) {
1085
- case simsimd_metric_intersect_k: *m = (m_t)&simsimd_intersect_u16_serial, *c = simsimd_cap_serial_k; return;
1086
- default: break;
1087
- }
1088
-
1089
- break;
1090
- }
1091
- // Unsigned 32-bit integer vectors
1092
- case simsimd_datatype_u32_k: {
1117
+ if (v & simsimd_cap_ice_k) switch (k) {
1118
+ case simsimd_metric_intersect_k: *m = (m_t)&simsimd_intersect_u16_ice, *c = simsimd_cap_skylake_k; return;
1119
+ default: break;
1120
+ }
1121
+ #endif
1122
+ if (v & simsimd_cap_serial_k) switch (k) {
1123
+ case simsimd_metric_intersect_k: *m = (m_t)&simsimd_intersect_u16_serial, *c = simsimd_cap_serial_k; return;
1124
+ default: break;
1125
+ }
1126
+ }
1093
1127
 
1128
+ SIMSIMD_INTERNAL void _simsimd_find_metric_punned_u32(simsimd_capability_t v, simsimd_metric_kind_t k,
1129
+ simsimd_metric_punned_t *m, simsimd_capability_t *c) {
1130
+ typedef simsimd_metric_punned_t m_t;
1094
1131
  #if SIMSIMD_TARGET_SVE2
1095
- if (viable & simsimd_cap_sve_k)
1096
- switch (kind) {
1097
- case simsimd_metric_intersect_k: *m = (m_t)&simsimd_intersect_u32_sve2, *c = simsimd_cap_sve_k; return;
1098
- default: break;
1099
- }
1132
+ if (v & simsimd_cap_sve2_k) switch (k) {
1133
+ case simsimd_metric_intersect_k: *m = (m_t)&simsimd_intersect_u32_sve2, *c = simsimd_cap_sve2_k; return;
1134
+ default: break;
1135
+ }
1100
1136
  #endif
1101
1137
  #if SIMSIMD_TARGET_NEON
1102
- if (viable & simsimd_cap_neon_k)
1103
- switch (kind) {
1104
- case simsimd_metric_intersect_k: *m = (m_t)&simsimd_intersect_u32_neon, *c = simsimd_cap_neon_k; return;
1105
- default: break;
1106
- }
1138
+ if (v & simsimd_cap_neon_k) switch (k) {
1139
+ case simsimd_metric_intersect_k: *m = (m_t)&simsimd_intersect_u32_neon, *c = simsimd_cap_neon_k; return;
1140
+ default: break;
1141
+ }
1142
+ #endif
1143
+ #if SIMSIMD_TARGET_TURIN
1144
+ if (v & simsimd_cap_turin_k) switch (k) {
1145
+ case simsimd_metric_intersect_k: *m = (m_t)&simsimd_intersect_u32_turin, *c = simsimd_cap_skylake_k; return;
1146
+ default: break;
1147
+ }
1107
1148
  #endif
1108
1149
  #if SIMSIMD_TARGET_ICE
1109
- if (viable & simsimd_cap_ice_k)
1110
- switch (kind) {
1111
- case simsimd_metric_intersect_k: *m = (m_t)&simsimd_intersect_u32_ice, *c = simsimd_cap_skylake_k; return;
1112
- default: break;
1113
- }
1114
- #endif
1115
- if (viable & simsimd_cap_serial_k)
1116
- switch (kind) {
1117
- case simsimd_metric_intersect_k: *m = (m_t)&simsimd_intersect_u32_serial, *c = simsimd_cap_serial_k; return;
1118
- default: break;
1119
- }
1120
-
1121
- break;
1122
- }
1150
+ if (v & simsimd_cap_ice_k) switch (k) {
1151
+ case simsimd_metric_intersect_k: *m = (m_t)&simsimd_intersect_u32_ice, *c = simsimd_cap_skylake_k; return;
1152
+ default: break;
1153
+ }
1154
+ #endif
1155
+ if (v & simsimd_cap_serial_k) switch (k) {
1156
+ case simsimd_metric_intersect_k: *m = (m_t)&simsimd_intersect_u32_serial, *c = simsimd_cap_serial_k; return;
1157
+ default: break;
1158
+ }
1159
+ }
1160
+
1161
+ /**
1162
+ * @brief Determines the best suited metric implementation based on the given datatype,
1163
+ * supported and allowed by hardware capabilities.
1164
+ *
1165
+ * @param kind The kind of metric to be evaluated.
1166
+ * @param datatype The data type for which the metric needs to be evaluated.
1167
+ * @param supported The hardware capabilities supported by the CPU.
1168
+ * @param allowed The hardware capabilities allowed for use.
1169
+ * @param metric_output Output variable for the selected similarity function.
1170
+ * @param capability_output Output variable for the utilized hardware capabilities.
1171
+ */
1172
+ SIMSIMD_INTERNAL void _simsimd_find_metric_punned_implementation( //
1173
+ simsimd_metric_kind_t kind, //
1174
+ simsimd_datatype_t datatype, //
1175
+ simsimd_capability_t supported, //
1176
+ simsimd_capability_t allowed, //
1177
+ simsimd_metric_punned_t *metric_output, //
1178
+ simsimd_capability_t *capability_output) {
1179
+
1180
+ // Modern compilers abso-freaking-lutely love optimizing-out my logic!
1181
+ // Just marking the variables as `volatile` is not enough, so we have
1182
+ // to add inline assembly to further discourage them!
1183
+ #if defined(_MSC_VER)
1184
+ _ReadWriteBarrier();
1185
+ #else
1186
+ __asm__ __volatile__("" ::: "memory");
1187
+ #endif
1188
+
1189
+ simsimd_metric_punned_t *m = metric_output;
1190
+ simsimd_capability_t *c = capability_output;
1191
+ simsimd_capability_t viable = (simsimd_capability_t)(supported & allowed);
1192
+
1193
+ switch (datatype) {
1194
+
1195
+ case simsimd_datatype_f64_k: _simsimd_find_metric_punned_f64(viable, kind, m, c); return;
1196
+ case simsimd_datatype_f32_k: _simsimd_find_metric_punned_f32(viable, kind, m, c); return;
1197
+ case simsimd_datatype_f16_k: _simsimd_find_metric_punned_f16(viable, kind, m, c); return;
1198
+ case simsimd_datatype_bf16_k: _simsimd_find_metric_punned_bf16(viable, kind, m, c); return;
1199
+ case simsimd_datatype_i8_k: _simsimd_find_metric_punned_i8(viable, kind, m, c); return;
1200
+ case simsimd_datatype_u8_k: _simsimd_find_metric_punned_u8(viable, kind, m, c); return;
1201
+ case simsimd_datatype_b8_k: _simsimd_find_metric_punned_b8(viable, kind, m, c); return;
1202
+ case simsimd_datatype_f32c_k: _simsimd_find_metric_punned_f32c(viable, kind, m, c); return;
1203
+ case simsimd_datatype_f64c_k: _simsimd_find_metric_punned_f64c(viable, kind, m, c); return;
1204
+ case simsimd_datatype_f16c_k: _simsimd_find_metric_punned_f16c(viable, kind, m, c); return;
1205
+ case simsimd_datatype_bf16c_k: _simsimd_find_metric_punned_bf16c(viable, kind, m, c); return;
1206
+ case simsimd_datatype_u16_k: _simsimd_find_metric_punned_u16(viable, kind, m, c); return;
1207
+ case simsimd_datatype_u32_k: _simsimd_find_metric_punned_u32(viable, kind, m, c); return;
1208
+
1209
+ // These data-types are not supported yet
1210
+ case simsimd_datatype_i4x2_k: break;
1211
+ case simsimd_datatype_i16_k: break;
1212
+ case simsimd_datatype_i32_k: break;
1213
+ case simsimd_datatype_i64_k: break;
1214
+ case simsimd_datatype_u64_k: break;
1215
+ case simsimd_datatype_unknown_k: break;
1216
+ default: break;
1123
1217
  }
1124
1218
 
1219
+ // Replace with zeros if no suitable implementation was found
1220
+ *m = (simsimd_metric_punned_t)0;
1221
+ *c = (simsimd_capability_t)0;
1222
+
1125
1223
  // Modern compilers abso-freaking-lutely love optimizing-out my logic!
1126
1224
  // Just marking the variables as `volatile` is not enough, so we have
1127
1225
  // to add inline assembly to further discourage them!
@@ -1164,10 +1262,14 @@ SIMSIMD_PUBLIC simsimd_metric_punned_t simsimd_metric_punned( //
1164
1262
  * - Check if the CPU supports AVX512F and AVX512BW extensions on Skylake x86 CPUs and newer
1165
1263
  * - Check if the CPU supports AVX512VNNI, AVX512IFMA, AVX512BITALG, AVX512VBMI2, and AVX512VPOPCNTDQ
1166
1264
  * extensions on Ice Lake x86 CPUs and newer
1265
+ * - Check if the CPU supports AVX512BF16 extensions on Genoa x86 CPUs and newer
1167
1266
  * - Check if the CPU supports AVX512FP16 extensions on Sapphire Rapids x86 CPUs and newer
1267
+ * - Check if the CPU supports AVX2VP2INTERSECT extensions on Turin x86 CPUs and newer
1168
1268
  *
1169
1269
  * @return 1 if the CPU supports the SIMD instruction set, 0 otherwise.
1170
1270
  */
1271
+ SIMSIMD_DYNAMIC simsimd_capability_t simsimd_capabilities(void);
1272
+ SIMSIMD_DYNAMIC int simsimd_uses_dynamic_dispatch(void);
1171
1273
  SIMSIMD_DYNAMIC int simsimd_uses_neon(void);
1172
1274
  SIMSIMD_DYNAMIC int simsimd_uses_neon_f16(void);
1173
1275
  SIMSIMD_DYNAMIC int simsimd_uses_neon_bf16(void);
@@ -1180,9 +1282,10 @@ SIMSIMD_DYNAMIC int simsimd_uses_sve2(void);
1180
1282
  SIMSIMD_DYNAMIC int simsimd_uses_haswell(void);
1181
1283
  SIMSIMD_DYNAMIC int simsimd_uses_skylake(void);
1182
1284
  SIMSIMD_DYNAMIC int simsimd_uses_ice(void);
1183
- SIMSIMD_DYNAMIC int simsimd_uses_sapphire(void);
1184
1285
  SIMSIMD_DYNAMIC int simsimd_uses_genoa(void);
1185
- SIMSIMD_DYNAMIC int simsimd_uses_dynamic_dispatch(void);
1286
+ SIMSIMD_DYNAMIC int simsimd_uses_sapphire(void);
1287
+ SIMSIMD_DYNAMIC int simsimd_uses_turin(void);
1288
+ SIMSIMD_DYNAMIC int simsimd_uses_sierra(void);
1186
1289
 
1187
1290
  /* Inner products
1188
1291
  * - Dot product: the sum of the products of the corresponding elements of two vectors.
@@ -1198,30 +1301,30 @@ SIMSIMD_DYNAMIC int simsimd_uses_dynamic_dispatch(void);
1198
1301
  * @note The dot product is zero if and only if the two vectors are orthogonal.
1199
1302
  * @note Defined only for floating-point and integer data types.
1200
1303
  */
1201
- SIMSIMD_DYNAMIC void simsimd_dot_f16(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
1202
- simsimd_distance_t* d);
1203
- SIMSIMD_DYNAMIC void simsimd_dot_bf16(simsimd_bf16_t const* a, simsimd_bf16_t const* b, simsimd_size_t n,
1204
- simsimd_distance_t* d);
1205
- SIMSIMD_DYNAMIC void simsimd_dot_f32(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
1206
- simsimd_distance_t* d);
1207
- SIMSIMD_DYNAMIC void simsimd_dot_f64(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
1208
- simsimd_distance_t* d);
1209
- SIMSIMD_DYNAMIC void simsimd_dot_f16c(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
1210
- simsimd_distance_t* d);
1211
- SIMSIMD_DYNAMIC void simsimd_dot_bf16c(simsimd_bf16_t const* a, simsimd_bf16_t const* b, simsimd_size_t n,
1212
- simsimd_distance_t* d);
1213
- SIMSIMD_DYNAMIC void simsimd_dot_f32c(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
1214
- simsimd_distance_t* d);
1215
- SIMSIMD_DYNAMIC void simsimd_dot_f64c(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
1216
- simsimd_distance_t* d);
1217
- SIMSIMD_DYNAMIC void simsimd_vdot_f16c(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
1218
- simsimd_distance_t* d);
1219
- SIMSIMD_DYNAMIC void simsimd_vdot_bf16c(simsimd_bf16_t const* a, simsimd_bf16_t const* b, simsimd_size_t n,
1220
- simsimd_distance_t* d);
1221
- SIMSIMD_DYNAMIC void simsimd_vdot_f32c(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
1222
- simsimd_distance_t* d);
1223
- SIMSIMD_DYNAMIC void simsimd_vdot_f64c(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
1224
- simsimd_distance_t* d);
1304
+ SIMSIMD_DYNAMIC void simsimd_dot_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_size_t n,
1305
+ simsimd_distance_t *d);
1306
+ SIMSIMD_DYNAMIC void simsimd_dot_bf16(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_size_t n,
1307
+ simsimd_distance_t *d);
1308
+ SIMSIMD_DYNAMIC void simsimd_dot_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_size_t n,
1309
+ simsimd_distance_t *d);
1310
+ SIMSIMD_DYNAMIC void simsimd_dot_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_size_t n,
1311
+ simsimd_distance_t *d);
1312
+ SIMSIMD_DYNAMIC void simsimd_dot_f16c(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_size_t n,
1313
+ simsimd_distance_t *d);
1314
+ SIMSIMD_DYNAMIC void simsimd_dot_bf16c(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_size_t n,
1315
+ simsimd_distance_t *d);
1316
+ SIMSIMD_DYNAMIC void simsimd_dot_f32c(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_size_t n,
1317
+ simsimd_distance_t *d);
1318
+ SIMSIMD_DYNAMIC void simsimd_dot_f64c(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_size_t n,
1319
+ simsimd_distance_t *d);
1320
+ SIMSIMD_DYNAMIC void simsimd_vdot_f16c(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_size_t n,
1321
+ simsimd_distance_t *d);
1322
+ SIMSIMD_DYNAMIC void simsimd_vdot_bf16c(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_size_t n,
1323
+ simsimd_distance_t *d);
1324
+ SIMSIMD_DYNAMIC void simsimd_vdot_f32c(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_size_t n,
1325
+ simsimd_distance_t *d);
1326
+ SIMSIMD_DYNAMIC void simsimd_vdot_f64c(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_size_t n,
1327
+ simsimd_distance_t *d);
1225
1328
 
1226
1329
  /* Spatial distances
1227
1330
  * - Cosine distance: the cosine of the angle between two vectors.
@@ -1236,26 +1339,42 @@ SIMSIMD_DYNAMIC void simsimd_vdot_f64c(simsimd_f64_t const* a, simsimd_f64_t con
1236
1339
  * @note The output distance value is zero if and only if the two vectors are identical.
1237
1340
  * @note Defined only for floating-point and integer data types.
1238
1341
  */
1239
- SIMSIMD_DYNAMIC void simsimd_cos_i8(simsimd_i8_t const* a, simsimd_i8_t const* b, simsimd_size_t n,
1240
- simsimd_distance_t* d);
1241
- SIMSIMD_DYNAMIC void simsimd_cos_f16(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
1242
- simsimd_distance_t* d);
1243
- SIMSIMD_DYNAMIC void simsimd_cos_bf16(simsimd_bf16_t const* a, simsimd_bf16_t const* b, simsimd_size_t n,
1244
- simsimd_distance_t* d);
1245
- SIMSIMD_DYNAMIC void simsimd_cos_f32(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
1246
- simsimd_distance_t* d);
1247
- SIMSIMD_DYNAMIC void simsimd_cos_f64(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
1248
- simsimd_distance_t* d);
1249
- SIMSIMD_DYNAMIC void simsimd_l2sq_i8(simsimd_i8_t const* a, simsimd_i8_t const* b, simsimd_size_t n,
1250
- simsimd_distance_t* d);
1251
- SIMSIMD_DYNAMIC void simsimd_l2sq_f16(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
1252
- simsimd_distance_t* d);
1253
- SIMSIMD_DYNAMIC void simsimd_l2sq_bf16(simsimd_bf16_t const* a, simsimd_bf16_t const* b, simsimd_size_t n,
1254
- simsimd_distance_t* d);
1255
- SIMSIMD_DYNAMIC void simsimd_l2sq_f32(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
1256
- simsimd_distance_t* d);
1257
- SIMSIMD_DYNAMIC void simsimd_l2sq_f64(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
1258
- simsimd_distance_t* d);
1342
+ SIMSIMD_DYNAMIC void simsimd_cos_i8(simsimd_i8_t const *a, simsimd_i8_t const *b, simsimd_size_t n,
1343
+ simsimd_distance_t *d);
1344
+ SIMSIMD_DYNAMIC void simsimd_cos_u8(simsimd_u8_t const *a, simsimd_u8_t const *b, simsimd_size_t n,
1345
+ simsimd_distance_t *d);
1346
+ SIMSIMD_DYNAMIC void simsimd_cos_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_size_t n,
1347
+ simsimd_distance_t *d);
1348
+ SIMSIMD_DYNAMIC void simsimd_cos_bf16(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_size_t n,
1349
+ simsimd_distance_t *d);
1350
+ SIMSIMD_DYNAMIC void simsimd_cos_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_size_t n,
1351
+ simsimd_distance_t *d);
1352
+ SIMSIMD_DYNAMIC void simsimd_cos_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_size_t n,
1353
+ simsimd_distance_t *d);
1354
+ SIMSIMD_DYNAMIC void simsimd_l2sq_i8(simsimd_i8_t const *a, simsimd_i8_t const *b, simsimd_size_t n,
1355
+ simsimd_distance_t *d);
1356
+ SIMSIMD_DYNAMIC void simsimd_l2sq_u8(simsimd_u8_t const *a, simsimd_u8_t const *b, simsimd_size_t n,
1357
+ simsimd_distance_t *d);
1358
+ SIMSIMD_DYNAMIC void simsimd_l2sq_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_size_t n,
1359
+ simsimd_distance_t *d);
1360
+ SIMSIMD_DYNAMIC void simsimd_l2sq_bf16(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_size_t n,
1361
+ simsimd_distance_t *d);
1362
+ SIMSIMD_DYNAMIC void simsimd_l2sq_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_size_t n,
1363
+ simsimd_distance_t *d);
1364
+ SIMSIMD_DYNAMIC void simsimd_l2sq_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_size_t n,
1365
+ simsimd_distance_t *d);
1366
+ SIMSIMD_DYNAMIC void simsimd_l2_i8(simsimd_i8_t const *a, simsimd_i8_t const *b, simsimd_size_t n,
1367
+ simsimd_distance_t *d);
1368
+ SIMSIMD_DYNAMIC void simsimd_l2_u8(simsimd_u8_t const *a, simsimd_u8_t const *b, simsimd_size_t n,
1369
+ simsimd_distance_t *d);
1370
+ SIMSIMD_DYNAMIC void simsimd_l2_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_size_t n,
1371
+ simsimd_distance_t *d);
1372
+ SIMSIMD_DYNAMIC void simsimd_l2_bf16(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_size_t n,
1373
+ simsimd_distance_t *d);
1374
+ SIMSIMD_DYNAMIC void simsimd_l2_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_size_t n,
1375
+ simsimd_distance_t *d);
1376
+ SIMSIMD_DYNAMIC void simsimd_l2_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_size_t n,
1377
+ simsimd_distance_t *d);
1259
1378
 
1260
1379
  /* Binary distances
1261
1380
  * - Hamming distance: the number of positions at which the corresponding bits are different.
@@ -1270,10 +1389,10 @@ SIMSIMD_DYNAMIC void simsimd_l2sq_f64(simsimd_f64_t const* a, simsimd_f64_t cons
1270
1389
  * @note The output distance value is zero if and only if the two vectors are identical.
1271
1390
  * @note Defined only for binary data.
1272
1391
  */
1273
- SIMSIMD_DYNAMIC void simsimd_hamming_b8(simsimd_b8_t const* a, simsimd_b8_t const* b, simsimd_size_t n,
1274
- simsimd_distance_t* d);
1275
- SIMSIMD_DYNAMIC void simsimd_jaccard_b8(simsimd_b8_t const* a, simsimd_b8_t const* b, simsimd_size_t n,
1276
- simsimd_distance_t* d);
1392
+ SIMSIMD_DYNAMIC void simsimd_hamming_b8(simsimd_b8_t const *a, simsimd_b8_t const *b, simsimd_size_t n,
1393
+ simsimd_distance_t *d);
1394
+ SIMSIMD_DYNAMIC void simsimd_jaccard_b8(simsimd_b8_t const *a, simsimd_b8_t const *b, simsimd_size_t n,
1395
+ simsimd_distance_t *d);
1277
1396
 
1278
1397
  /* Probability distributions
1279
1398
  * - Jensen-Shannon divergence: a measure of similarity between two probability distributions.
@@ -1289,22 +1408,22 @@ SIMSIMD_DYNAMIC void simsimd_jaccard_b8(simsimd_b8_t const* a, simsimd_b8_t cons
1289
1408
  * @note The output divergence value is zero if and only if the two distributions are identical.
1290
1409
  * @note Defined only for floating-point data types.
1291
1410
  */
1292
- SIMSIMD_DYNAMIC void simsimd_kl_f16(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
1293
- simsimd_distance_t* d);
1294
- SIMSIMD_DYNAMIC void simsimd_kl_bf16(simsimd_bf16_t const* a, simsimd_bf16_t const* b, simsimd_size_t n,
1295
- simsimd_distance_t* d);
1296
- SIMSIMD_DYNAMIC void simsimd_kl_f32(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
1297
- simsimd_distance_t* d);
1298
- SIMSIMD_DYNAMIC void simsimd_kl_f64(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
1299
- simsimd_distance_t* d);
1300
- SIMSIMD_DYNAMIC void simsimd_js_f16(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
1301
- simsimd_distance_t* d);
1302
- SIMSIMD_DYNAMIC void simsimd_js_bf16(simsimd_bf16_t const* a, simsimd_bf16_t const* b, simsimd_size_t n,
1303
- simsimd_distance_t* d);
1304
- SIMSIMD_DYNAMIC void simsimd_js_f32(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
1305
- simsimd_distance_t* d);
1306
- SIMSIMD_DYNAMIC void simsimd_js_f64(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
1307
- simsimd_distance_t* d);
1411
+ SIMSIMD_DYNAMIC void simsimd_kl_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_size_t n,
1412
+ simsimd_distance_t *d);
1413
+ SIMSIMD_DYNAMIC void simsimd_kl_bf16(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_size_t n,
1414
+ simsimd_distance_t *d);
1415
+ SIMSIMD_DYNAMIC void simsimd_kl_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_size_t n,
1416
+ simsimd_distance_t *d);
1417
+ SIMSIMD_DYNAMIC void simsimd_kl_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_size_t n,
1418
+ simsimd_distance_t *d);
1419
+ SIMSIMD_DYNAMIC void simsimd_js_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_size_t n,
1420
+ simsimd_distance_t *d);
1421
+ SIMSIMD_DYNAMIC void simsimd_js_bf16(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_size_t n,
1422
+ simsimd_distance_t *d);
1423
+ SIMSIMD_DYNAMIC void simsimd_js_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_size_t n,
1424
+ simsimd_distance_t *d);
1425
+ SIMSIMD_DYNAMIC void simsimd_js_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_size_t n,
1426
+ simsimd_distance_t *d);
1308
1427
 
1309
1428
  #else
1310
1429
 
@@ -1321,22 +1440,24 @@ SIMSIMD_DYNAMIC void simsimd_js_f64(simsimd_f64_t const* a, simsimd_f64_t const*
1321
1440
  */
1322
1441
 
1323
1442
  // clang-format off
1324
- SIMSIMD_PUBLIC simsimd_capability_t simsimd_capabilities(void) { return _simsimd_capabilities_implementation(); }
1443
+ SIMSIMD_PUBLIC int simsimd_uses_neon(void) { return _SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_NEON; }
1444
+ SIMSIMD_PUBLIC int simsimd_uses_neon_f16(void) { return _SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_NEON_F16 ; }
1445
+ SIMSIMD_PUBLIC int simsimd_uses_neon_bf16(void) { return _SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_NEON_BF16; }
1446
+ SIMSIMD_PUBLIC int simsimd_uses_neon_i8(void) { return _SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_NEON_I8; }
1447
+ SIMSIMD_PUBLIC int simsimd_uses_sve(void) { return _SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_SVE; }
1448
+ SIMSIMD_PUBLIC int simsimd_uses_sve_f16(void) { return _SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_SVE_F16; }
1449
+ SIMSIMD_PUBLIC int simsimd_uses_sve_bf16(void) { return _SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_SVE_BF16; }
1450
+ SIMSIMD_PUBLIC int simsimd_uses_sve_i8(void) { return _SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_SVE_I8; }
1451
+ SIMSIMD_PUBLIC int simsimd_uses_sve2(void) { return _SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_SVE2; }
1452
+ SIMSIMD_PUBLIC int simsimd_uses_haswell(void) { return _SIMSIMD_TARGET_X86 && SIMSIMD_TARGET_HASWELL; }
1453
+ SIMSIMD_PUBLIC int simsimd_uses_skylake(void) { return _SIMSIMD_TARGET_X86 && SIMSIMD_TARGET_SKYLAKE; }
1454
+ SIMSIMD_PUBLIC int simsimd_uses_ice(void) { return _SIMSIMD_TARGET_X86 && SIMSIMD_TARGET_ICE; }
1455
+ SIMSIMD_PUBLIC int simsimd_uses_genoa(void) { return _SIMSIMD_TARGET_X86 && SIMSIMD_TARGET_GENOA; }
1456
+ SIMSIMD_PUBLIC int simsimd_uses_sapphire(void) { return _SIMSIMD_TARGET_X86 && SIMSIMD_TARGET_SAPPHIRE; }
1457
+ SIMSIMD_PUBLIC int simsimd_uses_turin(void) { return _SIMSIMD_TARGET_X86 && SIMSIMD_TARGET_TURIN; }
1458
+ SIMSIMD_PUBLIC int simsimd_uses_sierra(void) { return _SIMSIMD_TARGET_X86 && SIMSIMD_TARGET_SIERRA; }
1325
1459
  SIMSIMD_PUBLIC int simsimd_uses_dynamic_dispatch(void) { return 0; }
1326
- SIMSIMD_PUBLIC int simsimd_uses_neon(void) { return SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_NEON; }
1327
- SIMSIMD_PUBLIC int simsimd_uses_neon_f16(void) { return SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_NEON_F16 ; }
1328
- SIMSIMD_PUBLIC int simsimd_uses_neon_bf16(void) { return SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_NEON_BF16; }
1329
- SIMSIMD_PUBLIC int simsimd_uses_neon_i8(void) { return SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_NEON_I8; }
1330
- SIMSIMD_PUBLIC int simsimd_uses_sve(void) { return SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_SVE; }
1331
- SIMSIMD_PUBLIC int simsimd_uses_sve_f16(void) { return SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_SVE_F16; }
1332
- SIMSIMD_PUBLIC int simsimd_uses_sve_bf16(void) { return SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_SVE_BF16; }
1333
- SIMSIMD_PUBLIC int simsimd_uses_sve_i8(void) { return SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_SVE_I8; }
1334
- SIMSIMD_PUBLIC int simsimd_uses_sve2(void) { return SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_SVE2; }
1335
- SIMSIMD_PUBLIC int simsimd_uses_haswell(void) { return SIMSIMD_TARGET_X86 && SIMSIMD_TARGET_HASWELL; }
1336
- SIMSIMD_PUBLIC int simsimd_uses_skylake(void) { return SIMSIMD_TARGET_X86 && SIMSIMD_TARGET_SKYLAKE; }
1337
- SIMSIMD_PUBLIC int simsimd_uses_ice(void) { return SIMSIMD_TARGET_X86 && SIMSIMD_TARGET_ICE; }
1338
- SIMSIMD_PUBLIC int simsimd_uses_sapphire(void) { return SIMSIMD_TARGET_X86 && SIMSIMD_TARGET_SAPPHIRE; }
1339
- SIMSIMD_PUBLIC int simsimd_uses_genoa(void) { return SIMSIMD_TARGET_X86 && SIMSIMD_TARGET_GENOA; }
1460
+ SIMSIMD_PUBLIC simsimd_capability_t simsimd_capabilities(void) { return _simsimd_capabilities_implementation(); }
1340
1461
  SIMSIMD_PUBLIC void simsimd_find_metric_punned( //
1341
1462
  simsimd_metric_kind_t kind, //
1342
1463
  simsimd_datatype_t datatype, //
@@ -1362,8 +1483,32 @@ SIMSIMD_PUBLIC void simsimd_find_metric_punned( //
1362
1483
  * @note The dot product is zero if and only if the two vectors are orthogonal.
1363
1484
  * @note Defined only for floating-point and integer data types.
1364
1485
  */
1365
- SIMSIMD_PUBLIC void simsimd_dot_f16(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
1366
- simsimd_distance_t* d) {
1486
+ SIMSIMD_PUBLIC void simsimd_dot_i8(simsimd_i8_t const *a, simsimd_i8_t const *b, simsimd_size_t n,
1487
+ simsimd_distance_t *d) {
1488
+ #if SIMSIMD_TARGET_NEON_F16
1489
+ simsimd_dot_i8_neon(a, b, n, d);
1490
+ #elif SIMSIMD_TARGET_ICE
1491
+ simsimd_dot_i8_ice(a, b, n, d);
1492
+ #elif SIMSIMD_TARGET_HASWELL
1493
+ simsimd_dot_i8_haswell(a, b, n, d);
1494
+ #else
1495
+ simsimd_dot_i8_serial(a, b, n, d);
1496
+ #endif
1497
+ }
1498
+ SIMSIMD_PUBLIC void simsimd_dot_u8(simsimd_u8_t const *a, simsimd_u8_t const *b, simsimd_size_t n,
1499
+ simsimd_distance_t *d) {
1500
+ #if SIMSIMD_TARGET_NEON_F16
1501
+ simsimd_dot_u8_neon(a, b, n, d);
1502
+ #elif SIMSIMD_TARGET_ICE
1503
+ simsimd_dot_u8_ice(a, b, n, d);
1504
+ #elif SIMSIMD_TARGET_HASWELL
1505
+ simsimd_dot_u8_haswell(a, b, n, d);
1506
+ #else
1507
+ simsimd_dot_u8_serial(a, b, n, d);
1508
+ #endif
1509
+ }
1510
+ SIMSIMD_PUBLIC void simsimd_dot_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_size_t n,
1511
+ simsimd_distance_t *d) {
1367
1512
  #if SIMSIMD_TARGET_SVE_F16
1368
1513
  simsimd_dot_f16_sve(a, b, n, d);
1369
1514
  #elif SIMSIMD_TARGET_NEON_F16
@@ -1376,9 +1521,8 @@ SIMSIMD_PUBLIC void simsimd_dot_f16(simsimd_f16_t const* a, simsimd_f16_t const*
1376
1521
  simsimd_dot_f16_serial(a, b, n, d);
1377
1522
  #endif
1378
1523
  }
1379
-
1380
- SIMSIMD_PUBLIC void simsimd_dot_bf16(simsimd_bf16_t const* a, simsimd_bf16_t const* b, simsimd_size_t n,
1381
- simsimd_distance_t* d) {
1524
+ SIMSIMD_PUBLIC void simsimd_dot_bf16(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_size_t n,
1525
+ simsimd_distance_t *d) {
1382
1526
  #if SIMSIMD_TARGET_GENOA
1383
1527
  simsimd_dot_bf16_genoa(a, b, n, d);
1384
1528
  #elif SIMSIMD_TARGET_HASWELL
@@ -1389,9 +1533,8 @@ SIMSIMD_PUBLIC void simsimd_dot_bf16(simsimd_bf16_t const* a, simsimd_bf16_t con
1389
1533
  simsimd_dot_bf16_serial(a, b, n, d);
1390
1534
  #endif
1391
1535
  }
1392
-
1393
- SIMSIMD_PUBLIC void simsimd_dot_f32(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
1394
- simsimd_distance_t* d) {
1536
+ SIMSIMD_PUBLIC void simsimd_dot_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_size_t n,
1537
+ simsimd_distance_t *d) {
1395
1538
  #if SIMSIMD_TARGET_SVE
1396
1539
  simsimd_dot_f32_sve(a, b, n, d);
1397
1540
  #elif SIMSIMD_TARGET_NEON
@@ -1404,8 +1547,8 @@ SIMSIMD_PUBLIC void simsimd_dot_f32(simsimd_f32_t const* a, simsimd_f32_t const*
1404
1547
  simsimd_dot_f32_serial(a, b, n, d);
1405
1548
  #endif
1406
1549
  }
1407
- SIMSIMD_PUBLIC void simsimd_dot_f64(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
1408
- simsimd_distance_t* d) {
1550
+ SIMSIMD_PUBLIC void simsimd_dot_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_size_t n,
1551
+ simsimd_distance_t *d) {
1409
1552
  #if SIMSIMD_TARGET_SVE
1410
1553
  simsimd_dot_f64_sve(a, b, n, d);
1411
1554
  #elif SIMSIMD_TARGET_SKYLAKE
@@ -1414,8 +1557,8 @@ SIMSIMD_PUBLIC void simsimd_dot_f64(simsimd_f64_t const* a, simsimd_f64_t const*
1414
1557
  simsimd_dot_f64_serial(a, b, n, d);
1415
1558
  #endif
1416
1559
  }
1417
- SIMSIMD_PUBLIC void simsimd_dot_f16c(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
1418
- simsimd_distance_t* d) {
1560
+ SIMSIMD_PUBLIC void simsimd_dot_f16c(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_size_t n,
1561
+ simsimd_distance_t *d) {
1419
1562
  #if SIMSIMD_TARGET_SVE_F16
1420
1563
  simsimd_dot_f16c_sve(a, b, n, d);
1421
1564
  #elif SIMSIMD_TARGET_NEON_F16
@@ -1428,8 +1571,8 @@ SIMSIMD_PUBLIC void simsimd_dot_f16c(simsimd_f16_t const* a, simsimd_f16_t const
1428
1571
  simsimd_dot_f16c_serial(a, b, n, d);
1429
1572
  #endif
1430
1573
  }
1431
- SIMSIMD_PUBLIC void simsimd_dot_bf16c(simsimd_bf16_t const* a, simsimd_bf16_t const* b, simsimd_size_t n,
1432
- simsimd_distance_t* d) {
1574
+ SIMSIMD_PUBLIC void simsimd_dot_bf16c(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_size_t n,
1575
+ simsimd_distance_t *d) {
1433
1576
  #if SIMSIMD_TARGET_GENOA
1434
1577
  simsimd_dot_bf16c_genoa(a, b, n, d);
1435
1578
  #elif SIMSIMD_TARGET_NEON_BF16
@@ -1438,8 +1581,8 @@ SIMSIMD_PUBLIC void simsimd_dot_bf16c(simsimd_bf16_t const* a, simsimd_bf16_t co
1438
1581
  simsimd_dot_bf16c_serial(a, b, n, d);
1439
1582
  #endif
1440
1583
  }
1441
- SIMSIMD_PUBLIC void simsimd_dot_f32c(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
1442
- simsimd_distance_t* d) {
1584
+ SIMSIMD_PUBLIC void simsimd_dot_f32c(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_size_t n,
1585
+ simsimd_distance_t *d) {
1443
1586
  #if SIMSIMD_TARGET_SVE
1444
1587
  simsimd_dot_f32c_sve(a, b, n, d);
1445
1588
  #elif SIMSIMD_TARGET_NEON
@@ -1452,8 +1595,8 @@ SIMSIMD_PUBLIC void simsimd_dot_f32c(simsimd_f32_t const* a, simsimd_f32_t const
1452
1595
  simsimd_dot_f32c_serial(a, b, n, d);
1453
1596
  #endif
1454
1597
  }
1455
- SIMSIMD_PUBLIC void simsimd_dot_f64c(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
1456
- simsimd_distance_t* d) {
1598
+ SIMSIMD_PUBLIC void simsimd_dot_f64c(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_size_t n,
1599
+ simsimd_distance_t *d) {
1457
1600
  #if SIMSIMD_TARGET_SVE
1458
1601
  simsimd_dot_f64c_sve(a, b, n, d);
1459
1602
  #elif SIMSIMD_TARGET_SKYLAKE
@@ -1462,8 +1605,8 @@ SIMSIMD_PUBLIC void simsimd_dot_f64c(simsimd_f64_t const* a, simsimd_f64_t const
1462
1605
  simsimd_dot_f64c_serial(a, b, n, d);
1463
1606
  #endif
1464
1607
  }
1465
- SIMSIMD_PUBLIC void simsimd_vdot_f16c(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
1466
- simsimd_distance_t* d) {
1608
+ SIMSIMD_PUBLIC void simsimd_vdot_f16c(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_size_t n,
1609
+ simsimd_distance_t *d) {
1467
1610
  #if SIMSIMD_TARGET_SVE
1468
1611
  simsimd_vdot_f16c_sve(a, b, n, d);
1469
1612
  #elif SIMSIMD_TARGET_NEON
@@ -1476,8 +1619,8 @@ SIMSIMD_PUBLIC void simsimd_vdot_f16c(simsimd_f16_t const* a, simsimd_f16_t cons
1476
1619
  simsimd_vdot_f16c_serial(a, b, n, d);
1477
1620
  #endif
1478
1621
  }
1479
- SIMSIMD_PUBLIC void simsimd_vdot_bf16c(simsimd_bf16_t const* a, simsimd_bf16_t const* b, simsimd_size_t n,
1480
- simsimd_distance_t* d) {
1622
+ SIMSIMD_PUBLIC void simsimd_vdot_bf16c(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_size_t n,
1623
+ simsimd_distance_t *d) {
1481
1624
  #if SIMSIMD_TARGET_GENOA
1482
1625
  simsimd_vdot_bf16c_genoa(a, b, n, d);
1483
1626
  #elif SIMSIMD_TARGET_NEON_BF16
@@ -1486,8 +1629,8 @@ SIMSIMD_PUBLIC void simsimd_vdot_bf16c(simsimd_bf16_t const* a, simsimd_bf16_t c
1486
1629
  simsimd_vdot_bf16c_serial(a, b, n, d);
1487
1630
  #endif
1488
1631
  }
1489
- SIMSIMD_PUBLIC void simsimd_vdot_f32c(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
1490
- simsimd_distance_t* d) {
1632
+ SIMSIMD_PUBLIC void simsimd_vdot_f32c(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_size_t n,
1633
+ simsimd_distance_t *d) {
1491
1634
  #if SIMSIMD_TARGET_SVE
1492
1635
  simsimd_vdot_f32c_sve(a, b, n, d);
1493
1636
  #elif SIMSIMD_TARGET_NEON
@@ -1500,8 +1643,8 @@ SIMSIMD_PUBLIC void simsimd_vdot_f32c(simsimd_f32_t const* a, simsimd_f32_t cons
1500
1643
  simsimd_vdot_f32c_serial(a, b, n, d);
1501
1644
  #endif
1502
1645
  }
1503
- SIMSIMD_PUBLIC void simsimd_vdot_f64c(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
1504
- simsimd_distance_t* d) {
1646
+ SIMSIMD_PUBLIC void simsimd_vdot_f64c(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_size_t n,
1647
+ simsimd_distance_t *d) {
1505
1648
  #if SIMSIMD_TARGET_SVE
1506
1649
  simsimd_vdot_f64c_sve(a, b, n, d);
1507
1650
  #elif SIMSIMD_TARGET_SKYLAKE
@@ -1524,8 +1667,8 @@ SIMSIMD_PUBLIC void simsimd_vdot_f64c(simsimd_f64_t const* a, simsimd_f64_t cons
1524
1667
  * @note The output distance value is zero if and only if the two vectors are identical.
1525
1668
  * @note Defined only for floating-point and integer data types.
1526
1669
  */
1527
- SIMSIMD_PUBLIC void simsimd_cos_i8(simsimd_i8_t const* a, simsimd_i8_t const* b, simsimd_size_t n,
1528
- simsimd_distance_t* d) {
1670
+ SIMSIMD_PUBLIC void simsimd_cos_i8(simsimd_i8_t const *a, simsimd_i8_t const *b, simsimd_size_t n,
1671
+ simsimd_distance_t *d) {
1529
1672
  #if SIMSIMD_TARGET_NEON
1530
1673
  simsimd_cos_i8_neon(a, b, n, d);
1531
1674
  #elif SIMSIMD_TARGET_ICE
@@ -1536,8 +1679,20 @@ SIMSIMD_PUBLIC void simsimd_cos_i8(simsimd_i8_t const* a, simsimd_i8_t const* b,
1536
1679
  simsimd_cos_i8_serial(a, b, n, d);
1537
1680
  #endif
1538
1681
  }
1539
- SIMSIMD_PUBLIC void simsimd_cos_f16(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
1540
- simsimd_distance_t* d) {
1682
+ SIMSIMD_PUBLIC void simsimd_cos_u8(simsimd_u8_t const *a, simsimd_u8_t const *b, simsimd_size_t n,
1683
+ simsimd_distance_t *d) {
1684
+ #if SIMSIMD_TARGET_NEON
1685
+ simsimd_cos_u8_neon(a, b, n, d);
1686
+ #elif SIMSIMD_TARGET_ICE
1687
+ simsimd_cos_u8_ice(a, b, n, d);
1688
+ #elif SIMSIMD_TARGET_HASWELL
1689
+ simsimd_cos_u8_haswell(a, b, n, d);
1690
+ #else
1691
+ simsimd_cos_u8_serial(a, b, n, d);
1692
+ #endif
1693
+ }
1694
+ SIMSIMD_PUBLIC void simsimd_cos_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_size_t n,
1695
+ simsimd_distance_t *d) {
1541
1696
  #if SIMSIMD_TARGET_SVE_F16
1542
1697
  simsimd_cos_f16_sve(a, b, n, d);
1543
1698
  #elif SIMSIMD_TARGET_NEON_F16
@@ -1550,8 +1705,8 @@ SIMSIMD_PUBLIC void simsimd_cos_f16(simsimd_f16_t const* a, simsimd_f16_t const*
1550
1705
  simsimd_cos_f16_serial(a, b, n, d);
1551
1706
  #endif
1552
1707
  }
1553
- SIMSIMD_PUBLIC void simsimd_cos_bf16(simsimd_bf16_t const* a, simsimd_bf16_t const* b, simsimd_size_t n,
1554
- simsimd_distance_t* d) {
1708
+ SIMSIMD_PUBLIC void simsimd_cos_bf16(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_size_t n,
1709
+ simsimd_distance_t *d) {
1555
1710
  #if SIMSIMD_TARGET_GENOA
1556
1711
  simsimd_cos_bf16_genoa(a, b, n, d);
1557
1712
  #elif SIMSIMD_TARGET_HASWELL
@@ -1564,8 +1719,8 @@ SIMSIMD_PUBLIC void simsimd_cos_bf16(simsimd_bf16_t const* a, simsimd_bf16_t con
1564
1719
  simsimd_cos_bf16_serial(a, b, n, d);
1565
1720
  #endif
1566
1721
  }
1567
- SIMSIMD_PUBLIC void simsimd_cos_f32(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
1568
- simsimd_distance_t* d) {
1722
+ SIMSIMD_PUBLIC void simsimd_cos_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_size_t n,
1723
+ simsimd_distance_t *d) {
1569
1724
  #if SIMSIMD_TARGET_SVE
1570
1725
  simsimd_cos_f32_sve(a, b, n, d);
1571
1726
  #elif SIMSIMD_TARGET_NEON
@@ -1578,8 +1733,8 @@ SIMSIMD_PUBLIC void simsimd_cos_f32(simsimd_f32_t const* a, simsimd_f32_t const*
1578
1733
  simsimd_cos_f32_serial(a, b, n, d);
1579
1734
  #endif
1580
1735
  }
1581
- SIMSIMD_PUBLIC void simsimd_cos_f64(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
1582
- simsimd_distance_t* d) {
1736
+ SIMSIMD_PUBLIC void simsimd_cos_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_size_t n,
1737
+ simsimd_distance_t *d) {
1583
1738
  #if SIMSIMD_TARGET_SVE
1584
1739
  simsimd_cos_f64_sve(a, b, n, d);
1585
1740
  #elif SIMSIMD_TARGET_NEON
@@ -1590,8 +1745,8 @@ SIMSIMD_PUBLIC void simsimd_cos_f64(simsimd_f64_t const* a, simsimd_f64_t const*
1590
1745
  simsimd_cos_f64_serial(a, b, n, d);
1591
1746
  #endif
1592
1747
  }
1593
- SIMSIMD_PUBLIC void simsimd_l2sq_i8(simsimd_i8_t const* a, simsimd_i8_t const* b, simsimd_size_t n,
1594
- simsimd_distance_t* d) {
1748
+ SIMSIMD_PUBLIC void simsimd_l2sq_i8(simsimd_i8_t const *a, simsimd_i8_t const *b, simsimd_size_t n,
1749
+ simsimd_distance_t *d) {
1595
1750
  #if SIMSIMD_TARGET_NEON
1596
1751
  simsimd_l2sq_i8_neon(a, b, n, d);
1597
1752
  #elif SIMSIMD_TARGET_ICE
@@ -1602,8 +1757,20 @@ SIMSIMD_PUBLIC void simsimd_l2sq_i8(simsimd_i8_t const* a, simsimd_i8_t const* b
1602
1757
  simsimd_l2sq_i8_serial(a, b, n, d);
1603
1758
  #endif
1604
1759
  }
1605
- SIMSIMD_PUBLIC void simsimd_l2sq_f16(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
1606
- simsimd_distance_t* d) {
1760
+ SIMSIMD_PUBLIC void simsimd_l2sq_u8(simsimd_u8_t const *a, simsimd_u8_t const *b, simsimd_size_t n,
1761
+ simsimd_distance_t *d) {
1762
+ #if SIMSIMD_TARGET_NEON
1763
+ simsimd_l2sq_u8_neon(a, b, n, d);
1764
+ #elif SIMSIMD_TARGET_ICE
1765
+ simsimd_l2sq_u8_ice(a, b, n, d);
1766
+ #elif SIMSIMD_TARGET_HASWELL
1767
+ simsimd_l2sq_u8_haswell(a, b, n, d);
1768
+ #else
1769
+ simsimd_l2sq_u8_serial(a, b, n, d);
1770
+ #endif
1771
+ }
1772
+ SIMSIMD_PUBLIC void simsimd_l2sq_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_size_t n,
1773
+ simsimd_distance_t *d) {
1607
1774
  #if SIMSIMD_TARGET_SVE_F16
1608
1775
  simsimd_l2sq_f16_sve(a, b, n, d);
1609
1776
  #elif SIMSIMD_TARGET_NEON_F16
@@ -1616,8 +1783,8 @@ SIMSIMD_PUBLIC void simsimd_l2sq_f16(simsimd_f16_t const* a, simsimd_f16_t const
1616
1783
  simsimd_l2sq_f16_serial(a, b, n, d);
1617
1784
  #endif
1618
1785
  }
1619
- SIMSIMD_PUBLIC void simsimd_l2sq_bf16(simsimd_bf16_t const* a, simsimd_bf16_t const* b, simsimd_size_t n,
1620
- simsimd_distance_t* d) {
1786
+ SIMSIMD_PUBLIC void simsimd_l2sq_bf16(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_size_t n,
1787
+ simsimd_distance_t *d) {
1621
1788
  #if SIMSIMD_TARGET_GENOA
1622
1789
  simsimd_l2sq_bf16_genoa(a, b, n, d);
1623
1790
  #elif SIMSIMD_TARGET_HASWELL
@@ -1630,8 +1797,8 @@ SIMSIMD_PUBLIC void simsimd_l2sq_bf16(simsimd_bf16_t const* a, simsimd_bf16_t co
1630
1797
  simsimd_l2sq_bf16_serial(a, b, n, d);
1631
1798
  #endif
1632
1799
  }
1633
- SIMSIMD_PUBLIC void simsimd_l2sq_f32(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
1634
- simsimd_distance_t* d) {
1800
+ SIMSIMD_PUBLIC void simsimd_l2sq_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_size_t n,
1801
+ simsimd_distance_t *d) {
1635
1802
  #if SIMSIMD_TARGET_SVE
1636
1803
  simsimd_l2sq_f32_sve(a, b, n, d);
1637
1804
  #elif SIMSIMD_TARGET_NEON
@@ -1644,8 +1811,8 @@ SIMSIMD_PUBLIC void simsimd_l2sq_f32(simsimd_f32_t const* a, simsimd_f32_t const
1644
1811
  simsimd_l2sq_f32_serial(a, b, n, d);
1645
1812
  #endif
1646
1813
  }
1647
- SIMSIMD_PUBLIC void simsimd_l2sq_f64(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
1648
- simsimd_distance_t* d) {
1814
+ SIMSIMD_PUBLIC void simsimd_l2sq_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_size_t n,
1815
+ simsimd_distance_t *d) {
1649
1816
  #if SIMSIMD_TARGET_SVE
1650
1817
  simsimd_l2sq_f64_sve(a, b, n, d);
1651
1818
  #elif SIMSIMD_TARGET_NEON
@@ -1656,8 +1823,8 @@ SIMSIMD_PUBLIC void simsimd_l2sq_f64(simsimd_f64_t const* a, simsimd_f64_t const
1656
1823
  simsimd_l2sq_f64_serial(a, b, n, d);
1657
1824
  #endif
1658
1825
  }
1659
- SIMSIMD_PUBLIC void simsimd_l2_i8(simsimd_i8_t const* a, simsimd_i8_t const* b, simsimd_size_t n,
1660
- simsimd_distance_t* d) {
1826
+ SIMSIMD_PUBLIC void simsimd_l2_i8(simsimd_i8_t const *a, simsimd_i8_t const *b, simsimd_size_t n,
1827
+ simsimd_distance_t *d) {
1661
1828
  #if SIMSIMD_TARGET_NEON
1662
1829
  simsimd_l2_i8_neon(a, b, n, d);
1663
1830
  #elif SIMSIMD_TARGET_ICE
@@ -1668,8 +1835,20 @@ SIMSIMD_PUBLIC void simsimd_l2_i8(simsimd_i8_t const* a, simsimd_i8_t const* b,
1668
1835
  simsimd_l2_i8_serial(a, b, n, d);
1669
1836
  #endif
1670
1837
  }
1671
- SIMSIMD_PUBLIC void simsimd_l2_f16(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
1672
- simsimd_distance_t* d) {
1838
+ SIMSIMD_PUBLIC void simsimd_l2_u8(simsimd_u8_t const *a, simsimd_u8_t const *b, simsimd_size_t n,
1839
+ simsimd_distance_t *d) {
1840
+ #if SIMSIMD_TARGET_NEON
1841
+ simsimd_l2_u8_neon(a, b, n, d);
1842
+ #elif SIMSIMD_TARGET_ICE
1843
+ simsimd_l2_u8_ice(a, b, n, d);
1844
+ #elif SIMSIMD_TARGET_HASWELL
1845
+ simsimd_l2_u8_haswell(a, b, n, d);
1846
+ #else
1847
+ simsimd_l2_u8_serial(a, b, n, d);
1848
+ #endif
1849
+ }
1850
+ SIMSIMD_PUBLIC void simsimd_l2_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_size_t n,
1851
+ simsimd_distance_t *d) {
1673
1852
  #if SIMSIMD_TARGET_SVE_F16
1674
1853
  simsimd_l2_f16_sve(a, b, n, d);
1675
1854
  #elif SIMSIMD_TARGET_NEON_F16
@@ -1682,8 +1861,8 @@ SIMSIMD_PUBLIC void simsimd_l2_f16(simsimd_f16_t const* a, simsimd_f16_t const*
1682
1861
  simsimd_l2_f16_serial(a, b, n, d);
1683
1862
  #endif
1684
1863
  }
1685
- SIMSIMD_PUBLIC void simsimd_l2_bf16(simsimd_bf16_t const* a, simsimd_bf16_t const* b, simsimd_size_t n,
1686
- simsimd_distance_t* d) {
1864
+ SIMSIMD_PUBLIC void simsimd_l2_bf16(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_size_t n,
1865
+ simsimd_distance_t *d) {
1687
1866
  #if SIMSIMD_TARGET_GENOA
1688
1867
  simsimd_l2_bf16_genoa(a, b, n, d);
1689
1868
  #elif SIMSIMD_TARGET_HASWELL
@@ -1696,8 +1875,8 @@ SIMSIMD_PUBLIC void simsimd_l2_bf16(simsimd_bf16_t const* a, simsimd_bf16_t cons
1696
1875
  simsimd_l2_bf16_serial(a, b, n, d);
1697
1876
  #endif
1698
1877
  }
1699
- SIMSIMD_PUBLIC void simsimd_l2_f32(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
1700
- simsimd_distance_t* d) {
1878
+ SIMSIMD_PUBLIC void simsimd_l2_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_size_t n,
1879
+ simsimd_distance_t *d) {
1701
1880
  #if SIMSIMD_TARGET_SVE
1702
1881
  simsimd_l2_f32_sve(a, b, n, d);
1703
1882
  #elif SIMSIMD_TARGET_NEON
@@ -1710,8 +1889,8 @@ SIMSIMD_PUBLIC void simsimd_l2_f32(simsimd_f32_t const* a, simsimd_f32_t const*
1710
1889
  simsimd_l2_f32_serial(a, b, n, d);
1711
1890
  #endif
1712
1891
  }
1713
- SIMSIMD_PUBLIC void simsimd_l2_f64(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
1714
- simsimd_distance_t* d) {
1892
+ SIMSIMD_PUBLIC void simsimd_l2_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_size_t n,
1893
+ simsimd_distance_t *d) {
1715
1894
  #if SIMSIMD_TARGET_SVE
1716
1895
  simsimd_l2_f64_sve(a, b, n, d);
1717
1896
  #elif SIMSIMD_TARGET_NEON
@@ -1736,8 +1915,8 @@ SIMSIMD_PUBLIC void simsimd_l2_f64(simsimd_f64_t const* a, simsimd_f64_t const*
1736
1915
  * @note The output distance value is zero if and only if the two vectors are identical.
1737
1916
  * @note Defined only for binary data.
1738
1917
  */
1739
- SIMSIMD_PUBLIC void simsimd_hamming_b8(simsimd_b8_t const* a, simsimd_b8_t const* b, simsimd_size_t n,
1740
- simsimd_distance_t* d) {
1918
+ SIMSIMD_PUBLIC void simsimd_hamming_b8(simsimd_b8_t const *a, simsimd_b8_t const *b, simsimd_size_t n,
1919
+ simsimd_distance_t *d) {
1741
1920
  #if SIMSIMD_TARGET_SVE
1742
1921
  simsimd_hamming_b8_sve(a, b, n, d);
1743
1922
  #elif SIMSIMD_TARGET_NEON
@@ -1750,8 +1929,8 @@ SIMSIMD_PUBLIC void simsimd_hamming_b8(simsimd_b8_t const* a, simsimd_b8_t const
1750
1929
  simsimd_hamming_b8_serial(a, b, n, d);
1751
1930
  #endif
1752
1931
  }
1753
- SIMSIMD_PUBLIC void simsimd_jaccard_b8(simsimd_b8_t const* a, simsimd_b8_t const* b, simsimd_size_t n,
1754
- simsimd_distance_t* d) {
1932
+ SIMSIMD_PUBLIC void simsimd_jaccard_b8(simsimd_b8_t const *a, simsimd_b8_t const *b, simsimd_size_t n,
1933
+ simsimd_distance_t *d) {
1755
1934
  #if SIMSIMD_TARGET_SVE
1756
1935
  simsimd_jaccard_b8_sve(a, b, n, d);
1757
1936
  #elif SIMSIMD_TARGET_NEON
@@ -1779,8 +1958,8 @@ SIMSIMD_PUBLIC void simsimd_jaccard_b8(simsimd_b8_t const* a, simsimd_b8_t const
1779
1958
  * @note The output divergence value is zero if and only if the two distributions are identical.
1780
1959
  * @note Defined only for floating-point data types.
1781
1960
  */
1782
- SIMSIMD_PUBLIC void simsimd_kl_f16(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
1783
- simsimd_distance_t* d) {
1961
+ SIMSIMD_PUBLIC void simsimd_kl_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_size_t n,
1962
+ simsimd_distance_t *d) {
1784
1963
  #if SIMSIMD_TARGET_NEON
1785
1964
  simsimd_kl_f16_neon(a, b, n, d);
1786
1965
  #elif SIMSIMD_TARGET_HASWELL
@@ -1789,12 +1968,12 @@ SIMSIMD_PUBLIC void simsimd_kl_f16(simsimd_f16_t const* a, simsimd_f16_t const*
1789
1968
  simsimd_kl_f16_serial(a, b, n, d);
1790
1969
  #endif
1791
1970
  }
1792
- SIMSIMD_PUBLIC void simsimd_kl_bf16(simsimd_bf16_t const* a, simsimd_bf16_t const* b, simsimd_size_t n,
1793
- simsimd_distance_t* d) {
1971
+ SIMSIMD_PUBLIC void simsimd_kl_bf16(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_size_t n,
1972
+ simsimd_distance_t *d) {
1794
1973
  simsimd_kl_bf16_serial(a, b, n, d);
1795
1974
  }
1796
- SIMSIMD_PUBLIC void simsimd_kl_f32(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
1797
- simsimd_distance_t* d) {
1975
+ SIMSIMD_PUBLIC void simsimd_kl_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_size_t n,
1976
+ simsimd_distance_t *d) {
1798
1977
  #if SIMSIMD_TARGET_NEON
1799
1978
  simsimd_kl_f32_neon(a, b, n, d);
1800
1979
  #elif SIMSIMD_TARGET_SKYLAKE
@@ -1803,12 +1982,12 @@ SIMSIMD_PUBLIC void simsimd_kl_f32(simsimd_f32_t const* a, simsimd_f32_t const*
1803
1982
  simsimd_kl_f32_serial(a, b, n, d);
1804
1983
  #endif
1805
1984
  }
1806
- SIMSIMD_PUBLIC void simsimd_kl_f64(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
1807
- simsimd_distance_t* d) {
1985
+ SIMSIMD_PUBLIC void simsimd_kl_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_size_t n,
1986
+ simsimd_distance_t *d) {
1808
1987
  simsimd_kl_f64_serial(a, b, n, d);
1809
1988
  }
1810
- SIMSIMD_PUBLIC void simsimd_js_f16(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
1811
- simsimd_distance_t* d) {
1989
+ SIMSIMD_PUBLIC void simsimd_js_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_size_t n,
1990
+ simsimd_distance_t *d) {
1812
1991
  #if SIMSIMD_TARGET_NEON
1813
1992
  simsimd_js_f16_neon(a, b, n, d);
1814
1993
  #elif SIMSIMD_TARGET_HASWELL
@@ -1817,12 +1996,12 @@ SIMSIMD_PUBLIC void simsimd_js_f16(simsimd_f16_t const* a, simsimd_f16_t const*
1817
1996
  simsimd_js_f16_serial(a, b, n, d);
1818
1997
  #endif
1819
1998
  }
1820
- SIMSIMD_PUBLIC void simsimd_js_bf16(simsimd_bf16_t const* a, simsimd_bf16_t const* b, simsimd_size_t n,
1821
- simsimd_distance_t* d) {
1999
+ SIMSIMD_PUBLIC void simsimd_js_bf16(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_size_t n,
2000
+ simsimd_distance_t *d) {
1822
2001
  simsimd_js_bf16_serial(a, b, n, d);
1823
2002
  }
1824
- SIMSIMD_PUBLIC void simsimd_js_f32(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
1825
- simsimd_distance_t* d) {
2003
+ SIMSIMD_PUBLIC void simsimd_js_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_size_t n,
2004
+ simsimd_distance_t *d) {
1826
2005
  #if SIMSIMD_TARGET_NEON
1827
2006
  simsimd_js_f32_neon(a, b, n, d);
1828
2007
  #elif SIMSIMD_TARGET_SKYLAKE
@@ -1831,8 +2010,8 @@ SIMSIMD_PUBLIC void simsimd_js_f32(simsimd_f32_t const* a, simsimd_f32_t const*
1831
2010
  simsimd_js_f32_serial(a, b, n, d);
1832
2011
  #endif
1833
2012
  }
1834
- SIMSIMD_PUBLIC void simsimd_js_f64(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
1835
- simsimd_distance_t* d) {
2013
+ SIMSIMD_PUBLIC void simsimd_js_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_size_t n,
2014
+ simsimd_distance_t *d) {
1836
2015
  simsimd_js_f64_serial(a, b, n, d);
1837
2016
  }
1838
2017
 
@@ -1844,32 +2023,70 @@ SIMSIMD_PUBLIC void simsimd_js_f64(simsimd_f64_t const* a, simsimd_f64_t const*
1844
2023
  * @param b_length The number of elements in the second array.
1845
2024
  * @param d The output for the number of elements in the intersection.
1846
2025
  */
1847
- SIMSIMD_PUBLIC void simsimd_intersect_u16(simsimd_u16_t const* a, simsimd_u16_t const* b, simsimd_size_t a_length,
1848
- simsimd_size_t b_length, simsimd_distance_t* d) {
2026
+ SIMSIMD_PUBLIC void simsimd_intersect_u16(simsimd_u16_t const *a, simsimd_u16_t const *b, simsimd_size_t a_length,
2027
+ simsimd_size_t b_length, simsimd_distance_t *d) {
1849
2028
  #if SIMSIMD_TARGET_SVE2
1850
2029
  simsimd_intersect_u16_sve2(a, b, a_length, b_length, d);
1851
2030
  #elif SIMSIMD_TARGET_NEON
1852
2031
  simsimd_intersect_u16_neon(a, b, a_length, b_length, d);
1853
- #elif SIMSIMD_TARGET_SKYLAKE
2032
+ #elif SIMSIMD_TARGET_TURIN
2033
+ simsimd_intersect_u16_turin(a, b, a_length, b_length, d);
2034
+ #elif SIMSIMD_TARGET_ICE
1854
2035
  simsimd_intersect_u16_ice(a, b, a_length, b_length, d);
1855
2036
  #else
1856
2037
  simsimd_intersect_u16_serial(a, b, a_length, b_length, d);
1857
2038
  #endif
1858
2039
  }
1859
2040
 
1860
- SIMSIMD_PUBLIC void simsimd_intersect_u32(simsimd_u32_t const* a, simsimd_u32_t const* b, simsimd_size_t a_length,
1861
- simsimd_size_t b_length, simsimd_distance_t* d) {
2041
+ SIMSIMD_PUBLIC void simsimd_intersect_u32(simsimd_u32_t const *a, simsimd_u32_t const *b, simsimd_size_t a_length,
2042
+ simsimd_size_t b_length, simsimd_distance_t *d) {
1862
2043
  #if SIMSIMD_TARGET_SVE2
1863
2044
  simsimd_intersect_u32_sve2(a, b, a_length, b_length, d);
1864
2045
  #elif SIMSIMD_TARGET_NEON
1865
2046
  simsimd_intersect_u32_neon(a, b, a_length, b_length, d);
1866
- #elif SIMSIMD_TARGET_SKYLAKE
2047
+ #elif SIMSIMD_TARGET_TURIN
2048
+ simsimd_intersect_u32_turin(a, b, a_length, b_length, d);
2049
+ #elif SIMSIMD_TARGET_ICE
1867
2050
  simsimd_intersect_u32_ice(a, b, a_length, b_length, d);
1868
2051
  #else
1869
2052
  simsimd_intersect_u32_serial(a, b, a_length, b_length, d);
1870
2053
  #endif
1871
2054
  }
1872
2055
 
2056
+ /* Weighted set operations
2057
+ *
2058
+ * @param a The first sorted array of integers.
2059
+ * @param b The second sorted array of integers.
2060
+ * @param a_weights The weights for the first array.
2061
+ * @param b_weights The weights for the second array.
2062
+ * @param a_length The number of elements in the first array.
2063
+ * @param b_length The number of elements in the second array.
2064
+ * @param d The output for the number of elements in the intersection.
2065
+ */
2066
+ SIMSIMD_PUBLIC void simsimd_spdot_counts_u16(simsimd_u16_t const *a, simsimd_u16_t const *b,
2067
+ simsimd_i16_t const *a_weights, simsimd_i16_t const *b_weights,
2068
+ simsimd_size_t a_length, simsimd_size_t b_length, simsimd_distance_t *d) {
2069
+ #if SIMSIMD_TARGET_SVE2
2070
+ simsimd_spdot_counts_u16_sve2(a, b, a_weights, b_weights, a_length, b_length, d);
2071
+ #elif SIMSIMD_TARGET_TURIN
2072
+ simsimd_spdot_counts_u16_turin(a, b, a_weights, b_weights, a_length, b_length, d);
2073
+ #else
2074
+ simsimd_spdot_counts_u16_serial(a, b, a_weights, b_weights, a_length, b_length, d);
2075
+ #endif
2076
+ }
2077
+
2078
+ SIMSIMD_PUBLIC void simsimd_spdot_weights_u16(simsimd_u16_t const *a, simsimd_u16_t const *b,
2079
+ simsimd_bf16_t const *a_weights, simsimd_bf16_t const *b_weights,
2080
+ simsimd_size_t a_length, simsimd_size_t b_length, simsimd_distance_t *d) {
2081
+ #if SIMSIMD_TARGET_SVE2
2082
+ simsimd_spdot_weights_u16_sve2(a, b, a_weights, b_weights, a_length, b_length, d);
2083
+ #elif SIMSIMD_TARGET_TURIN
2084
+ simsimd_spdot_weights_u16_turin(a, b, a_weights, b_weights, a_length, b_length, d);
2085
+ #else
2086
+ simsimd_spdot_weights_u16_serial(a, b, a_weights, b_weights, a_length, b_length, d);
2087
+ #endif
2088
+ }
2089
+
1873
2090
  /* Curved space distances
1874
2091
  *
1875
2092
  * @param a The first vector of floating point values.
@@ -1878,17 +2095,17 @@ SIMSIMD_PUBLIC void simsimd_intersect_u32(simsimd_u32_t const* a, simsimd_u32_t
1878
2095
  * @param n The number of dimensions in the vectors.
1879
2096
  * @param d The output for the number of elements in the intersection.
1880
2097
  */
1881
- SIMSIMD_PUBLIC void simsimd_bilinear_f64(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_f64_t const* c,
1882
- simsimd_size_t n, simsimd_distance_t* d) {
2098
+ SIMSIMD_PUBLIC void simsimd_bilinear_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_f64_t const *c,
2099
+ simsimd_size_t n, simsimd_distance_t *d) {
1883
2100
 
1884
2101
  simsimd_bilinear_f64_serial(a, b, c, n, d);
1885
2102
  }
1886
- SIMSIMD_PUBLIC void simsimd_mahalanobis_f64(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_f64_t const* c,
1887
- simsimd_size_t n, simsimd_distance_t* d) {
2103
+ SIMSIMD_PUBLIC void simsimd_mahalanobis_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_f64_t const *c,
2104
+ simsimd_size_t n, simsimd_distance_t *d) {
1888
2105
  simsimd_mahalanobis_f64_serial(a, b, c, n, d);
1889
2106
  }
1890
- SIMSIMD_PUBLIC void simsimd_bilinear_f32(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_f32_t const* c,
1891
- simsimd_size_t n, simsimd_distance_t* d) {
2107
+ SIMSIMD_PUBLIC void simsimd_bilinear_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_f32_t const *c,
2108
+ simsimd_size_t n, simsimd_distance_t *d) {
1892
2109
  #if SIMSIMD_TARGET_SKYLAKE
1893
2110
  simsimd_bilinear_f32_skylake(a, b, c, n, d);
1894
2111
  #elif SIMSIMD_TARGET_NEON
@@ -1897,8 +2114,8 @@ SIMSIMD_PUBLIC void simsimd_bilinear_f32(simsimd_f32_t const* a, simsimd_f32_t c
1897
2114
  simsimd_bilinear_f32_serial(a, b, c, n, d);
1898
2115
  #endif
1899
2116
  }
1900
- SIMSIMD_PUBLIC void simsimd_mahalanobis_f32(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_f32_t const* c,
1901
- simsimd_size_t n, simsimd_distance_t* d) {
2117
+ SIMSIMD_PUBLIC void simsimd_mahalanobis_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_f32_t const *c,
2118
+ simsimd_size_t n, simsimd_distance_t *d) {
1902
2119
  #if SIMSIMD_TARGET_SKYLAKE
1903
2120
  simsimd_mahalanobis_f32_skylake(a, b, c, n, d);
1904
2121
  #elif SIMSIMD_TARGET_NEON
@@ -1907,8 +2124,8 @@ SIMSIMD_PUBLIC void simsimd_mahalanobis_f32(simsimd_f32_t const* a, simsimd_f32_
1907
2124
  simsimd_mahalanobis_f32_serial(a, b, c, n, d);
1908
2125
  #endif
1909
2126
  }
1910
- SIMSIMD_PUBLIC void simsimd_bilinear_f16(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_f16_t const* c,
1911
- simsimd_size_t n, simsimd_distance_t* d) {
2127
+ SIMSIMD_PUBLIC void simsimd_bilinear_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_f16_t const *c,
2128
+ simsimd_size_t n, simsimd_distance_t *d) {
1912
2129
  #if SIMSIMD_TARGET_SAPPHIRE
1913
2130
  simsimd_bilinear_f16_sapphire(a, b, c, n, d);
1914
2131
  #elif SIMSIMD_TARGET_HASWELL
@@ -1919,8 +2136,8 @@ SIMSIMD_PUBLIC void simsimd_bilinear_f16(simsimd_f16_t const* a, simsimd_f16_t c
1919
2136
  simsimd_bilinear_f16_serial(a, b, c, n, d);
1920
2137
  #endif
1921
2138
  }
1922
- SIMSIMD_PUBLIC void simsimd_mahalanobis_f16(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_f16_t const* c,
1923
- simsimd_size_t n, simsimd_distance_t* d) {
2139
+ SIMSIMD_PUBLIC void simsimd_mahalanobis_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_f16_t const *c,
2140
+ simsimd_size_t n, simsimd_distance_t *d) {
1924
2141
  #if SIMSIMD_TARGET_SAPPHIRE
1925
2142
  simsimd_mahalanobis_f16_sapphire(a, b, c, n, d);
1926
2143
  #elif SIMSIMD_TARGET_HASWELL
@@ -1931,8 +2148,8 @@ SIMSIMD_PUBLIC void simsimd_mahalanobis_f16(simsimd_f16_t const* a, simsimd_f16_
1931
2148
  simsimd_mahalanobis_f16_serial(a, b, c, n, d);
1932
2149
  #endif
1933
2150
  }
1934
- SIMSIMD_PUBLIC void simsimd_bilinear_bf16(simsimd_bf16_t const* a, simsimd_bf16_t const* b, simsimd_bf16_t const* c,
1935
- simsimd_size_t n, simsimd_distance_t* d) {
2151
+ SIMSIMD_PUBLIC void simsimd_bilinear_bf16(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_bf16_t const *c,
2152
+ simsimd_size_t n, simsimd_distance_t *d) {
1936
2153
  #if SIMSIMD_TARGET_GENOA
1937
2154
  simsimd_bilinear_bf16_genoa(a, b, c, n, d);
1938
2155
  #elif SIMSIMD_TARGET_HASWELL
@@ -1943,8 +2160,8 @@ SIMSIMD_PUBLIC void simsimd_bilinear_bf16(simsimd_bf16_t const* a, simsimd_bf16_
1943
2160
  simsimd_bilinear_bf16_serial(a, b, c, n, d);
1944
2161
  #endif
1945
2162
  }
1946
- SIMSIMD_PUBLIC void simsimd_mahalanobis_bf16(simsimd_bf16_t const* a, simsimd_bf16_t const* b, simsimd_bf16_t const* c,
1947
- simsimd_size_t n, simsimd_distance_t* d) {
2163
+ SIMSIMD_PUBLIC void simsimd_mahalanobis_bf16(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_bf16_t const *c,
2164
+ simsimd_size_t n, simsimd_distance_t *d) {
1948
2165
  #if SIMSIMD_TARGET_GENOA
1949
2166
  simsimd_mahalanobis_bf16_genoa(a, b, c, n, d);
1950
2167
  #elif SIMSIMD_TARGET_HASWELL
@@ -1956,6 +2173,174 @@ SIMSIMD_PUBLIC void simsimd_mahalanobis_bf16(simsimd_bf16_t const* a, simsimd_bf
1956
2173
  #endif
1957
2174
  }
1958
2175
 
2176
+ /* Elementwise operations
2177
+ *
2178
+ * @param a The first vector of integral or floating point values.
2179
+ * @param b The second vector of integral or floating point values.
2180
+ * @param c The third vector of integral or floating point values.
2181
+ * @param n The number of dimensions in the vectors.
2182
+ * @param alpha The first scaling factor.
2183
+ * @param beta The first scaling factor.
2184
+ * @param r The output vector or integral or floating point values.
2185
+ */
2186
+ SIMSIMD_PUBLIC void simsimd_wsum_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_size_t n,
2187
+ simsimd_distance_t alpha, simsimd_distance_t beta, simsimd_f64_t *r) {
2188
+ #if SIMSIMD_TARGET_SKYLAKE
2189
+ simsimd_wsum_f64_skylake(a, b, n, alpha, beta, r);
2190
+ #elif SIMSIMD_TARGET_HASWELL
2191
+ simsimd_wsum_f64_haswell(a, b, n, alpha, beta, r);
2192
+ #else
2193
+ simsimd_wsum_f64_serial(a, b, n, alpha, beta, r);
2194
+ #endif
2195
+ }
2196
+
2197
+ SIMSIMD_PUBLIC void simsimd_wsum_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_size_t n,
2198
+ simsimd_distance_t alpha, simsimd_distance_t beta, simsimd_f32_t *r) {
2199
+ #if SIMSIMD_TARGET_SKYLAKE
2200
+ simsimd_wsum_f32_skylake(a, b, n, alpha, beta, r);
2201
+ #elif SIMSIMD_TARGET_HASWELL
2202
+ simsimd_wsum_f32_haswell(a, b, n, alpha, beta, r);
2203
+ #elif SIMSIMD_TARGET_NEON
2204
+ simsimd_wsum_f32_neon(a, b, n, alpha, beta, r);
2205
+ #else
2206
+ simsimd_wsum_f32_serial(a, b, n, alpha, beta, r);
2207
+ #endif
2208
+ }
2209
+
2210
+ SIMSIMD_PUBLIC void simsimd_wsum_bf16(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_size_t n,
2211
+ simsimd_distance_t alpha, simsimd_distance_t beta, simsimd_bf16_t *r) {
2212
+ #if SIMSIMD_TARGET_SKYLAKE
2213
+ simsimd_wsum_bf16_skylake(a, b, n, alpha, beta, r);
2214
+ #elif SIMSIMD_TARGET_HASWELL
2215
+ simsimd_wsum_bf16_haswell(a, b, n, alpha, beta, r);
2216
+ #elif SIMSIMD_TARGET_NEON
2217
+ simsimd_wsum_bf16_neon(a, b, n, alpha, beta, r);
2218
+ #else
2219
+ simsimd_wsum_bf16_serial(a, b, n, alpha, beta, r);
2220
+ #endif
2221
+ }
2222
+
2223
+ SIMSIMD_PUBLIC void simsimd_wsum_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_size_t n,
2224
+ simsimd_distance_t alpha, simsimd_distance_t beta, simsimd_f16_t *r) {
2225
+ #if SIMSIMD_TARGET_SAPPHIRE
2226
+ simsimd_wsum_f16_sapphire(a, b, n, alpha, beta, r);
2227
+ #elif SIMSIMD_TARGET_HASWELL
2228
+ simsimd_wsum_f16_haswell(a, b, n, alpha, beta, r);
2229
+ #elif SIMSIMD_TARGET_NEON_F16
2230
+ simsimd_wsum_f16_neon(a, b, n, alpha, beta, r);
2231
+ #else
2232
+ simsimd_wsum_f16_serial(a, b, n, alpha, beta, r);
2233
+ #endif
2234
+ }
2235
+
2236
+ SIMSIMD_PUBLIC void simsimd_wsum_i8(simsimd_i8_t const *a, simsimd_i8_t const *b, simsimd_size_t n,
2237
+ simsimd_distance_t alpha, simsimd_distance_t beta, simsimd_i8_t *r) {
2238
+ #if SIMSIMD_TARGET_SAPPHIRE
2239
+ simsimd_wsum_i8_sapphire(a, b, n, alpha, beta, r);
2240
+ #elif SIMSIMD_TARGET_HASWELL
2241
+ simsimd_wsum_i8_haswell(a, b, n, alpha, beta, r);
2242
+ #elif SIMSIMD_TARGET_NEON_F16
2243
+ simsimd_wsum_i8_neon(a, b, n, alpha, beta, r);
2244
+ #else
2245
+ simsimd_wsum_i8_serial(a, b, n, alpha, beta, r);
2246
+ #endif
2247
+ }
2248
+
2249
+ SIMSIMD_PUBLIC void simsimd_wsum_u8(simsimd_u8_t const *a, simsimd_u8_t const *b, simsimd_size_t n,
2250
+ simsimd_distance_t alpha, simsimd_distance_t beta, simsimd_u8_t *r) {
2251
+ #if SIMSIMD_TARGET_SAPPHIRE
2252
+ simsimd_wsum_u8_sapphire(a, b, n, alpha, beta, r);
2253
+ #elif SIMSIMD_TARGET_HASWELL
2254
+ simsimd_wsum_u8_haswell(a, b, n, alpha, beta, r);
2255
+ #elif SIMSIMD_TARGET_NEON_F16
2256
+ simsimd_wsum_u8_neon(a, b, n, alpha, beta, r);
2257
+ #else
2258
+ simsimd_wsum_u8_serial(a, b, n, alpha, beta, r);
2259
+ #endif
2260
+ }
2261
+
2262
+ SIMSIMD_PUBLIC void simsimd_fma_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_f64_t const *c,
2263
+ simsimd_size_t n, simsimd_distance_t alpha, simsimd_distance_t beta,
2264
+ simsimd_f64_t *r) {
2265
+ #if SIMSIMD_TARGET_SKYLAKE
2266
+ simsimd_fma_f64_skylake(a, b, c, n, alpha, beta, r);
2267
+ #elif SIMSIMD_TARGET_HASWELL
2268
+ simsimd_fma_f64_haswell(a, b, c, n, alpha, beta, r);
2269
+ #else
2270
+ simsimd_fma_f64_serial(a, b, c, n, alpha, beta, r);
2271
+ #endif
2272
+ }
2273
+
2274
+ SIMSIMD_PUBLIC void simsimd_fma_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_f32_t const *c,
2275
+ simsimd_size_t n, simsimd_distance_t alpha, simsimd_distance_t beta,
2276
+ simsimd_f32_t *r) {
2277
+ #if SIMSIMD_TARGET_SKYLAKE
2278
+ simsimd_fma_f32_skylake(a, b, c, n, alpha, beta, r);
2279
+ #elif SIMSIMD_TARGET_HASWELL
2280
+ simsimd_fma_f32_haswell(a, b, c, n, alpha, beta, r);
2281
+ #elif SIMSIMD_TARGET_NEON
2282
+ simsimd_fma_f32_neon(a, b, c, n, alpha, beta, r);
2283
+ #else
2284
+ simsimd_fma_f32_serial(a, b, c, n, alpha, beta, r);
2285
+ #endif
2286
+ }
2287
+
2288
+ SIMSIMD_PUBLIC void simsimd_fma_bf16(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_bf16_t const *c,
2289
+ simsimd_size_t n, simsimd_distance_t alpha, simsimd_distance_t beta,
2290
+ simsimd_bf16_t *r) {
2291
+ #if SIMSIMD_TARGET_SKYLAKE
2292
+ simsimd_fma_bf16_skylake(a, b, c, n, alpha, beta, r);
2293
+ #elif SIMSIMD_TARGET_HASWELL
2294
+ simsimd_fma_bf16_haswell(a, b, c, n, alpha, beta, r);
2295
+ #elif SIMSIMD_TARGET_NEON
2296
+ simsimd_fma_bf16_neon(a, b, c, n, alpha, beta, r);
2297
+ #else
2298
+ simsimd_fma_bf16_serial(a, b, c, n, alpha, beta, r);
2299
+ #endif
2300
+ }
2301
+
2302
+ SIMSIMD_PUBLIC void simsimd_fma_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_f16_t const *c,
2303
+ simsimd_size_t n, simsimd_distance_t alpha, simsimd_distance_t beta,
2304
+ simsimd_f16_t *r) {
2305
+ #if SIMSIMD_TARGET_SAPPHIRE
2306
+ simsimd_fma_f16_sapphire(a, b, c, n, alpha, beta, r);
2307
+ #elif SIMSIMD_TARGET_HASWELL
2308
+ simsimd_fma_f16_haswell(a, b, c, n, alpha, beta, r);
2309
+ #elif SIMSIMD_TARGET_NEON_F16
2310
+ simsimd_fma_f16_neon(a, b, c, n, alpha, beta, r);
2311
+ #else
2312
+ simsimd_fma_f16_serial(a, b, c, n, alpha, beta, r);
2313
+ #endif
2314
+ }
2315
+
2316
+ SIMSIMD_PUBLIC void simsimd_fma_i8(simsimd_i8_t const *a, simsimd_i8_t const *b, simsimd_i8_t const *c,
2317
+ simsimd_size_t n, simsimd_distance_t alpha, simsimd_distance_t beta,
2318
+ simsimd_i8_t *r) {
2319
+ #if SIMSIMD_TARGET_SAPPHIRE
2320
+ simsimd_fma_i8_sapphire(a, b, c, n, alpha, beta, r);
2321
+ #elif SIMSIMD_TARGET_HASWELL
2322
+ simsimd_fma_i8_haswell(a, b, c, n, alpha, beta, r);
2323
+ #elif SIMSIMD_TARGET_NEON_F16
2324
+ simsimd_fma_i8_neon(a, b, c, n, alpha, beta, r);
2325
+ #else
2326
+ simsimd_fma_i8_serial(a, b, c, n, alpha, beta, r);
2327
+ #endif
2328
+ }
2329
+
2330
+ SIMSIMD_PUBLIC void simsimd_fma_u8(simsimd_u8_t const *a, simsimd_u8_t const *b, simsimd_u8_t const *c,
2331
+ simsimd_size_t n, simsimd_distance_t alpha, simsimd_distance_t beta,
2332
+ simsimd_u8_t *r) {
2333
+ #if SIMSIMD_TARGET_SAPPHIRE
2334
+ simsimd_fma_u8_sapphire(a, b, c, n, alpha, beta, r);
2335
+ #elif SIMSIMD_TARGET_HASWELL
2336
+ simsimd_fma_u8_haswell(a, b, c, n, alpha, beta, r);
2337
+ #elif SIMSIMD_TARGET_NEON_F16
2338
+ simsimd_fma_u8_neon(a, b, c, n, alpha, beta, r);
2339
+ #else
2340
+ simsimd_fma_u8_serial(a, b, c, n, alpha, beta, r);
2341
+ #endif
2342
+ }
2343
+
1959
2344
  #endif
1960
2345
 
1961
2346
  #ifdef __cplusplus