usearch 2.16.3 → 2.16.4

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.
@@ -88,9 +88,9 @@
88
88
  #ifndef SIMSIMD_H
89
89
  #define SIMSIMD_H
90
90
 
91
- #define SIMSIMD_VERSION_MAJOR 5
92
- #define SIMSIMD_VERSION_MINOR 9
93
- #define SIMSIMD_VERSION_PATCH 6
91
+ #define SIMSIMD_VERSION_MAJOR 6
92
+ #define SIMSIMD_VERSION_MINOR 0
93
+ #define SIMSIMD_VERSION_PATCH 5
94
94
 
95
95
  /**
96
96
  * @brief Removes compile-time dispatching, and replaces it with runtime dispatching.
@@ -304,28 +304,29 @@ typedef void (*simsimd_kernel_wsum_punned_t)(void const *a, void const *b, //
304
304
 
305
305
  /**
306
306
  * @brief Type-punned function pointer for a SimSIMD public interface.
307
- * Can be a `simsimd_metric_dense_punned_t`, `simsimd_metric_sparse_punned_t`,
308
- * or `simsimd_metric_curved_punned_t`.
307
+ *
308
+ * Can be a `simsimd_metric_dense_punned_t`, `simsimd_metric_sparse_punned_t`, `simsimd_metric_curved_punned_t`,
309
+ * `simsimd_kernel_fma_punned_t`, or `simsimd_kernel_wsum_punned_t`.
309
310
  */
310
- typedef simsimd_metric_dense_punned_t simsimd_metric_punned_t;
311
+ typedef void (*simsimd_kernel_punned_t)(void *);
311
312
 
312
313
  #if SIMSIMD_DYNAMIC_DISPATCH
313
314
  SIMSIMD_DYNAMIC simsimd_capability_t simsimd_capabilities(void);
314
- SIMSIMD_DYNAMIC void simsimd_find_metric_punned( //
315
+ SIMSIMD_DYNAMIC void simsimd_find_kernel_punned( //
315
316
  simsimd_metric_kind_t kind, //
316
317
  simsimd_datatype_t datatype, //
317
318
  simsimd_capability_t supported, //
318
319
  simsimd_capability_t allowed, //
319
- simsimd_metric_punned_t *metric_output, //
320
+ simsimd_kernel_punned_t *kernel_output, //
320
321
  simsimd_capability_t *capability_output);
321
322
  #else
322
323
  SIMSIMD_PUBLIC simsimd_capability_t simsimd_capabilities(void);
323
- SIMSIMD_PUBLIC void simsimd_find_metric_punned( //
324
+ SIMSIMD_PUBLIC void simsimd_find_kernel_punned( //
324
325
  simsimd_metric_kind_t kind, //
325
326
  simsimd_datatype_t datatype, //
326
327
  simsimd_capability_t supported, //
327
328
  simsimd_capability_t allowed, //
328
- simsimd_metric_punned_t *metric_output, //
329
+ simsimd_kernel_punned_t *kernel_output, //
329
330
  simsimd_capability_t *capability_output);
330
331
  #endif
331
332
 
@@ -537,9 +538,9 @@ SIMSIMD_PUBLIC simsimd_capability_t _simsimd_capabilities_implementation(void) {
537
538
  #pragma clang diagnostic ignored "-Wvolatile"
538
539
  #endif
539
540
 
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
- typedef simsimd_metric_punned_t m_t;
541
+ SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_f64(simsimd_capability_t v, simsimd_metric_kind_t k,
542
+ simsimd_kernel_punned_t *m, simsimd_capability_t *c) {
543
+ typedef simsimd_kernel_punned_t m_t;
543
544
  #if SIMSIMD_TARGET_SVE
544
545
  if (v & simsimd_cap_sve_k) switch (k) {
545
546
  case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f64_sve, *c = simsimd_cap_sve_k; return;
@@ -593,9 +594,9 @@ SIMSIMD_INTERNAL void _simsimd_find_metric_punned_f64(simsimd_capability_t v, si
593
594
  }
594
595
  }
595
596
 
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;
597
+ SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_f32(simsimd_capability_t v, simsimd_metric_kind_t k,
598
+ simsimd_kernel_punned_t *m, simsimd_capability_t *c) {
599
+ typedef simsimd_kernel_punned_t m_t;
599
600
  #if SIMSIMD_TARGET_SVE
600
601
  if (v & simsimd_cap_sve_k) switch (k) {
601
602
  case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32_sve, *c = simsimd_cap_sve_k; return;
@@ -661,9 +662,9 @@ SIMSIMD_INTERNAL void _simsimd_find_metric_punned_f32(simsimd_capability_t v, si
661
662
  }
662
663
  }
663
664
 
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;
665
+ SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_f16(simsimd_capability_t v, simsimd_metric_kind_t k,
666
+ simsimd_kernel_punned_t *m, simsimd_capability_t *c) {
667
+ typedef simsimd_kernel_punned_t m_t;
667
668
  #if SIMSIMD_TARGET_SVE_F16
668
669
  if (v & simsimd_cap_sve_k) switch (k) {
669
670
  case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16_sve, *c = simsimd_cap_sve_f16_k; return;
@@ -737,9 +738,9 @@ SIMSIMD_INTERNAL void _simsimd_find_metric_punned_f16(simsimd_capability_t v, si
737
738
  }
738
739
  }
739
740
 
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;
741
+ SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_bf16(simsimd_capability_t v, simsimd_metric_kind_t k,
742
+ simsimd_kernel_punned_t *m, simsimd_capability_t *c) {
743
+ typedef simsimd_kernel_punned_t m_t;
743
744
  #if SIMSIMD_TARGET_SVE_BF16
744
745
  if (v & simsimd_cap_sve_bf16_k) switch (k) {
745
746
  case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_bf16_sve, *c = simsimd_cap_sve_bf16_k; return;
@@ -809,9 +810,9 @@ SIMSIMD_INTERNAL void _simsimd_find_metric_punned_bf16(simsimd_capability_t v, s
809
810
  }
810
811
  }
811
812
 
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;
813
+ SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_i8(simsimd_capability_t v, simsimd_metric_kind_t k,
814
+ simsimd_kernel_punned_t *m, simsimd_capability_t *c) {
815
+ typedef simsimd_kernel_punned_t m_t;
815
816
  #if SIMSIMD_TARGET_NEON_I8
816
817
  if (v & simsimd_cap_neon_i8_k) switch (k) {
817
818
  case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_i8_neon, *c = simsimd_cap_neon_i8_k; return;
@@ -865,9 +866,9 @@ SIMSIMD_INTERNAL void _simsimd_find_metric_punned_i8(simsimd_capability_t v, sim
865
866
  default: break;
866
867
  }
867
868
  }
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;
869
+ SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_u8(simsimd_capability_t v, simsimd_metric_kind_t k,
870
+ simsimd_kernel_punned_t *m, simsimd_capability_t *c) {
871
+ typedef simsimd_kernel_punned_t m_t;
871
872
  #if SIMSIMD_TARGET_NEON_I8
872
873
  if (v & simsimd_cap_neon_i8_k) switch (k) {
873
874
  case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_u8_neon, *c = simsimd_cap_neon_i8_k; return;
@@ -922,9 +923,9 @@ SIMSIMD_INTERNAL void _simsimd_find_metric_punned_u8(simsimd_capability_t v, sim
922
923
  }
923
924
  }
924
925
 
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;
926
+ SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_b8(simsimd_capability_t v, simsimd_metric_kind_t k,
927
+ simsimd_kernel_punned_t *m, simsimd_capability_t *c) {
928
+ typedef simsimd_kernel_punned_t m_t;
928
929
  #if SIMSIMD_TARGET_SVE
929
930
  if (v & simsimd_cap_sve_k) switch (k) {
930
931
  case simsimd_metric_hamming_k: *m = (m_t)&simsimd_hamming_b8_sve, *c = simsimd_cap_sve_k; return;
@@ -960,9 +961,9 @@ SIMSIMD_INTERNAL void _simsimd_find_metric_punned_b8(simsimd_capability_t v, sim
960
961
  }
961
962
  }
962
963
 
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;
964
+ SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_f64c(simsimd_capability_t v, simsimd_metric_kind_t k,
965
+ simsimd_kernel_punned_t *m, simsimd_capability_t *c) {
966
+ typedef simsimd_kernel_punned_t m_t;
966
967
  #if SIMSIMD_TARGET_SVE
967
968
  if (v & simsimd_cap_sve_k) switch (k) {
968
969
  case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f64c_sve, *c = simsimd_cap_sve_k; return;
@@ -984,9 +985,9 @@ SIMSIMD_INTERNAL void _simsimd_find_metric_punned_f64c(simsimd_capability_t v, s
984
985
  }
985
986
  }
986
987
 
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;
988
+ SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_f32c(simsimd_capability_t v, simsimd_metric_kind_t k,
989
+ simsimd_kernel_punned_t *m, simsimd_capability_t *c) {
990
+ typedef simsimd_kernel_punned_t m_t;
990
991
  #if SIMSIMD_TARGET_SVE
991
992
  if (v & simsimd_cap_sve_k) switch (k) {
992
993
  case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32c_sve, *c = simsimd_cap_sve_k; return;
@@ -1022,9 +1023,9 @@ SIMSIMD_INTERNAL void _simsimd_find_metric_punned_f32c(simsimd_capability_t v, s
1022
1023
  }
1023
1024
  }
1024
1025
 
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;
1026
+ SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_f16c(simsimd_capability_t v, simsimd_metric_kind_t k,
1027
+ simsimd_kernel_punned_t *m, simsimd_capability_t *c) {
1028
+ typedef simsimd_kernel_punned_t m_t;
1028
1029
  #if SIMSIMD_TARGET_SVE_F16
1029
1030
  if (v & simsimd_cap_sve_k) switch (k) {
1030
1031
  case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16c_sve, *c = simsimd_cap_sve_f16_k; return;
@@ -1060,9 +1061,9 @@ SIMSIMD_INTERNAL void _simsimd_find_metric_punned_f16c(simsimd_capability_t v, s
1060
1061
  }
1061
1062
  }
1062
1063
 
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;
1064
+ SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_bf16c(simsimd_capability_t v, simsimd_metric_kind_t k,
1065
+ simsimd_kernel_punned_t *m, simsimd_capability_t *c) {
1066
+ typedef simsimd_kernel_punned_t m_t;
1066
1067
  #if SIMSIMD_TARGET_NEON_BF16
1067
1068
  if (v & simsimd_cap_neon_bf16_k) switch (k) {
1068
1069
  case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_bf16c_neon, *c = simsimd_cap_neon_bf16_k; return;
@@ -1084,9 +1085,9 @@ SIMSIMD_INTERNAL void _simsimd_find_metric_punned_bf16c(simsimd_capability_t v,
1084
1085
  }
1085
1086
  }
1086
1087
 
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;
1088
+ SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_u16(simsimd_capability_t v, simsimd_metric_kind_t k,
1089
+ simsimd_kernel_punned_t *m, simsimd_capability_t *c) {
1090
+ typedef simsimd_kernel_punned_t m_t;
1090
1091
  #if SIMSIMD_TARGET_SVE2
1091
1092
  if (v & simsimd_cap_sve2_k) switch (k) {
1092
1093
  case simsimd_metric_intersect_k: *m = (m_t)&simsimd_intersect_u16_sve2, *c = simsimd_cap_sve2_k; return;
@@ -1125,9 +1126,9 @@ SIMSIMD_INTERNAL void _simsimd_find_metric_punned_u16(simsimd_capability_t v, si
1125
1126
  }
1126
1127
  }
1127
1128
 
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;
1129
+ SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_u32(simsimd_capability_t v, simsimd_metric_kind_t k,
1130
+ simsimd_kernel_punned_t *m, simsimd_capability_t *c) {
1131
+ typedef simsimd_kernel_punned_t m_t;
1131
1132
  #if SIMSIMD_TARGET_SVE2
1132
1133
  if (v & simsimd_cap_sve2_k) switch (k) {
1133
1134
  case simsimd_metric_intersect_k: *m = (m_t)&simsimd_intersect_u32_sve2, *c = simsimd_cap_sve2_k; return;
@@ -1166,15 +1167,15 @@ SIMSIMD_INTERNAL void _simsimd_find_metric_punned_u32(simsimd_capability_t v, si
1166
1167
  * @param datatype The data type for which the metric needs to be evaluated.
1167
1168
  * @param supported The hardware capabilities supported by the CPU.
1168
1169
  * @param allowed The hardware capabilities allowed for use.
1169
- * @param metric_output Output variable for the selected similarity function.
1170
+ * @param kernel_output Output variable for the selected similarity function.
1170
1171
  * @param capability_output Output variable for the utilized hardware capabilities.
1171
1172
  */
1172
- SIMSIMD_INTERNAL void _simsimd_find_metric_punned_implementation( //
1173
+ SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_implementation( //
1173
1174
  simsimd_metric_kind_t kind, //
1174
1175
  simsimd_datatype_t datatype, //
1175
1176
  simsimd_capability_t supported, //
1176
1177
  simsimd_capability_t allowed, //
1177
- simsimd_metric_punned_t *metric_output, //
1178
+ simsimd_kernel_punned_t *kernel_output, //
1178
1179
  simsimd_capability_t *capability_output) {
1179
1180
 
1180
1181
  // Modern compilers abso-freaking-lutely love optimizing-out my logic!
@@ -1186,25 +1187,25 @@ SIMSIMD_INTERNAL void _simsimd_find_metric_punned_implementation( //
1186
1187
  __asm__ __volatile__("" ::: "memory");
1187
1188
  #endif
1188
1189
 
1189
- simsimd_metric_punned_t *m = metric_output;
1190
+ simsimd_kernel_punned_t *m = kernel_output;
1190
1191
  simsimd_capability_t *c = capability_output;
1191
1192
  simsimd_capability_t viable = (simsimd_capability_t)(supported & allowed);
1192
1193
 
1193
1194
  switch (datatype) {
1194
1195
 
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;
1196
+ case simsimd_datatype_f64_k: _simsimd_find_kernel_punned_f64(viable, kind, m, c); return;
1197
+ case simsimd_datatype_f32_k: _simsimd_find_kernel_punned_f32(viable, kind, m, c); return;
1198
+ case simsimd_datatype_f16_k: _simsimd_find_kernel_punned_f16(viable, kind, m, c); return;
1199
+ case simsimd_datatype_bf16_k: _simsimd_find_kernel_punned_bf16(viable, kind, m, c); return;
1200
+ case simsimd_datatype_i8_k: _simsimd_find_kernel_punned_i8(viable, kind, m, c); return;
1201
+ case simsimd_datatype_u8_k: _simsimd_find_kernel_punned_u8(viable, kind, m, c); return;
1202
+ case simsimd_datatype_b8_k: _simsimd_find_kernel_punned_b8(viable, kind, m, c); return;
1203
+ case simsimd_datatype_f32c_k: _simsimd_find_kernel_punned_f32c(viable, kind, m, c); return;
1204
+ case simsimd_datatype_f64c_k: _simsimd_find_kernel_punned_f64c(viable, kind, m, c); return;
1205
+ case simsimd_datatype_f16c_k: _simsimd_find_kernel_punned_f16c(viable, kind, m, c); return;
1206
+ case simsimd_datatype_bf16c_k: _simsimd_find_kernel_punned_bf16c(viable, kind, m, c); return;
1207
+ case simsimd_datatype_u16_k: _simsimd_find_kernel_punned_u16(viable, kind, m, c); return;
1208
+ case simsimd_datatype_u32_k: _simsimd_find_kernel_punned_u32(viable, kind, m, c); return;
1208
1209
 
1209
1210
  // These data-types are not supported yet
1210
1211
  case simsimd_datatype_i4x2_k: break;
@@ -1217,7 +1218,7 @@ SIMSIMD_INTERNAL void _simsimd_find_metric_punned_implementation( //
1217
1218
  }
1218
1219
 
1219
1220
  // Replace with zeros if no suitable implementation was found
1220
- *m = (simsimd_metric_punned_t)0;
1221
+ *m = (simsimd_kernel_punned_t)0;
1221
1222
  *c = (simsimd_capability_t)0;
1222
1223
 
1223
1224
  // Modern compilers abso-freaking-lutely love optimizing-out my logic!
@@ -1242,15 +1243,15 @@ SIMSIMD_INTERNAL void _simsimd_find_metric_punned_implementation( //
1242
1243
  * @param allowed The hardware capabilities allowed for use.
1243
1244
  * @return A function pointer to the selected metric implementation.
1244
1245
  */
1245
- SIMSIMD_PUBLIC simsimd_metric_punned_t simsimd_metric_punned( //
1246
+ SIMSIMD_PUBLIC simsimd_kernel_punned_t simsimd_metric_punned( //
1246
1247
  simsimd_metric_kind_t kind, //
1247
1248
  simsimd_datatype_t datatype, //
1248
1249
  simsimd_capability_t allowed) {
1249
1250
 
1250
- simsimd_metric_punned_t result = 0;
1251
+ simsimd_kernel_punned_t result = 0;
1251
1252
  simsimd_capability_t c = simsimd_cap_serial_k;
1252
1253
  simsimd_capability_t supported = simsimd_capabilities();
1253
- simsimd_find_metric_punned(kind, datatype, supported, allowed, &result, &c);
1254
+ simsimd_find_kernel_punned(kind, datatype, supported, allowed, &result, &c);
1254
1255
  return result;
1255
1256
  }
1256
1257
 
@@ -1301,6 +1302,10 @@ SIMSIMD_DYNAMIC int simsimd_uses_sierra(void);
1301
1302
  * @note The dot product is zero if and only if the two vectors are orthogonal.
1302
1303
  * @note Defined only for floating-point and integer data types.
1303
1304
  */
1305
+ SIMSIMD_DYNAMIC void simsimd_dot_i8(simsimd_i8_t const *a, simsimd_i8_t const *b, simsimd_size_t n,
1306
+ simsimd_distance_t *d);
1307
+ SIMSIMD_DYNAMIC void simsimd_dot_u8(simsimd_u8_t const *a, simsimd_u8_t const *b, simsimd_size_t n,
1308
+ simsimd_distance_t *d);
1304
1309
  SIMSIMD_DYNAMIC void simsimd_dot_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_size_t n,
1305
1310
  simsimd_distance_t *d);
1306
1311
  SIMSIMD_DYNAMIC void simsimd_dot_bf16(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_size_t n,
@@ -1458,14 +1463,14 @@ SIMSIMD_PUBLIC int simsimd_uses_turin(void) { return _SIMSIMD_TARGET_X86 && SIMS
1458
1463
  SIMSIMD_PUBLIC int simsimd_uses_sierra(void) { return _SIMSIMD_TARGET_X86 && SIMSIMD_TARGET_SIERRA; }
1459
1464
  SIMSIMD_PUBLIC int simsimd_uses_dynamic_dispatch(void) { return 0; }
1460
1465
  SIMSIMD_PUBLIC simsimd_capability_t simsimd_capabilities(void) { return _simsimd_capabilities_implementation(); }
1461
- SIMSIMD_PUBLIC void simsimd_find_metric_punned( //
1466
+ SIMSIMD_PUBLIC void simsimd_find_kernel_punned( //
1462
1467
  simsimd_metric_kind_t kind, //
1463
1468
  simsimd_datatype_t datatype, //
1464
1469
  simsimd_capability_t supported, //
1465
1470
  simsimd_capability_t allowed, //
1466
- simsimd_metric_punned_t* metric_output, //
1471
+ simsimd_kernel_punned_t* kernel_output, //
1467
1472
  simsimd_capability_t* capability_output) {
1468
- _simsimd_find_metric_punned_implementation(kind, datatype, supported, allowed, metric_output, capability_output);
1473
+ _simsimd_find_kernel_punned_implementation(kind, datatype, supported, allowed, kernel_output, capability_output);
1469
1474
  }
1470
1475
  // clang-format on
1471
1476
 
@@ -34,7 +34,7 @@
34
34
  #elif defined(__GNUC__) || defined(__clang__)
35
35
  #define SIMSIMD_DYNAMIC __attribute__((visibility("default")))
36
36
  #define SIMSIMD_PUBLIC __attribute__((unused)) inline static
37
- #define SIMSIMD_INTERNAL __attribute__((always_inline)) inline static
37
+ #define SIMSIMD_INTERNAL inline static
38
38
  #else
39
39
  #define SIMSIMD_DYNAMIC
40
40
  #define SIMSIMD_PUBLIC inline static
@@ -436,16 +436,20 @@ SIMSIMD_STATIC_ASSERT(sizeof(simsimd_bf16_t) == 2, simsimd_bf16_t_must_be_2_byte
436
436
  #endif
437
437
 
438
438
  #if !defined(SIMSIMD_F32_TO_I8)
439
- #define SIMSIMD_F32_TO_I8(x, y) *(y) = (simsimd_i8_t)fminf(fmaxf(roundf(x), -128), 127)
439
+ #define SIMSIMD_F32_TO_I8(x, y) \
440
+ *(y) = (simsimd_i8_t)((x) > 127 ? 127 : ((x) < -128 ? -128 : (int)((x) + ((x) < 0 ? -0.5f : 0.5f))))
440
441
  #endif
441
442
  #if !defined(SIMSIMD_F32_TO_U8)
442
- #define SIMSIMD_F32_TO_U8(x, y) *(y) = (simsimd_u8_t)fminf(fmaxf(roundf(x), 0), 255)
443
+ #define SIMSIMD_F32_TO_U8(x, y) \
444
+ *(y) = (simsimd_u8_t)((x) > 255 ? 255 : ((x) < 0 ? 0 : (int)((x) + ((x) < 0 ? -0.5f : 0.5f))))
443
445
  #endif
444
446
  #if !defined(SIMSIMD_F64_TO_I8)
445
- #define SIMSIMD_F64_TO_I8(x, y) *(y) = (simsimd_i8_t)fmin(fmax(round(x), -128), 127)
447
+ #define SIMSIMD_F64_TO_I8(x, y) \
448
+ *(y) = (simsimd_i8_t)((x) > 127 ? 127 : ((x) < -128 ? -128 : (int)((x) + ((x) < 0 ? -0.5 : 0.5))))
446
449
  #endif
447
450
  #if !defined(SIMSIMD_F64_TO_U8)
448
- #define SIMSIMD_F64_TO_U8(x, y) *(y) = (simsimd_u8_t)fmin(fmax(round(x), 0), 255)
451
+ #define SIMSIMD_F64_TO_U8(x, y) \
452
+ *(y) = (simsimd_u8_t)((x) > 255 ? 255 : ((x) < 0 ? 0 : (int)((x) + ((x) < 0 ? -0.5 : 0.5))))
449
453
  #endif
450
454
 
451
455
  /** @brief Convenience type for half-precision floating-point type conversions. */
@@ -467,20 +471,33 @@ typedef union {
467
471
  * https://web.archive.org/web/20210208132927/http://assemblyrequired.crashworks.org/timing-square-root/
468
472
  * https://stackoverflow.com/a/41460625/2766161
469
473
  */
470
- SIMSIMD_PUBLIC simsimd_f32_t simsimd_approximate_inverse_square_root(simsimd_f32_t number) {
474
+ SIMSIMD_INTERNAL simsimd_f32_t simsimd_approximate_inverse_square_root(simsimd_f32_t number) {
471
475
  simsimd_f32i32_t conv;
472
476
  conv.f = number;
473
477
  conv.i = 0x5F1FFFF9 - (conv.i >> 1);
478
+ // Refine using a Newton-Raphson step for better accuracy
474
479
  conv.f *= 0.703952253f * (2.38924456f - number * conv.f * conv.f);
475
480
  return conv.f;
476
481
  }
477
482
 
483
+ /**
484
+ * @brief Approximates `sqrt(x)` using the fast inverse square root trick
485
+ * with adjustments for direct square root approximation.
486
+ *
487
+ * Similar to `rsqrt` approximation but multiplies by `number` to get `sqrt`.
488
+ * This technique is useful where `sqrt` approximation is needed in performance-critical code,
489
+ * though modern hardware provides optimized alternatives.
490
+ */
491
+ SIMSIMD_INTERNAL simsimd_f32_t simsimd_approximate_square_root(simsimd_f32_t number) {
492
+ return number * simsimd_approximate_inverse_square_root(number);
493
+ }
494
+
478
495
  /**
479
496
  * @brief Computes `log(x)` using the Mercator series.
480
497
  * The series converges to the natural logarithm for args between -1 and 1.
481
498
  * Published in 1668 in "Logarithmotechnia".
482
499
  */
483
- SIMSIMD_PUBLIC simsimd_f32_t simsimd_approximate_log(simsimd_f32_t number) {
500
+ SIMSIMD_INTERNAL simsimd_f32_t simsimd_approximate_log(simsimd_f32_t number) {
484
501
  simsimd_f32_t x = number - 1;
485
502
  simsimd_f32_t x2 = x * x;
486
503
  simsimd_f32_t x3 = x * x * x;
@@ -497,7 +514,7 @@ SIMSIMD_PUBLIC simsimd_f32_t simsimd_approximate_log(simsimd_f32_t number) {
497
514
  * https://gist.github.com/milhidaka/95863906fe828198f47991c813dbe233
498
515
  * https://github.com/OpenCyphal/libcanard/blob/636795f4bc395f56af8d2c61d3757b5e762bb9e5/canard.c#L811-L834
499
516
  */
500
- SIMSIMD_PUBLIC simsimd_f32_t simsimd_f16_to_f32(simsimd_f16_t const *x_ptr) {
517
+ SIMSIMD_INTERNAL simsimd_f32_t simsimd_f16_to_f32(simsimd_f16_t const *x_ptr) {
501
518
  unsigned short x = *(unsigned short const *)x_ptr;
502
519
  unsigned int exponent = (x & 0x7C00) >> 10;
503
520
  unsigned int mantissa = (x & 0x03FF) << 13;
@@ -519,7 +536,7 @@ SIMSIMD_PUBLIC simsimd_f32_t simsimd_f16_to_f32(simsimd_f16_t const *x_ptr) {
519
536
  * https://gist.github.com/milhidaka/95863906fe828198f47991c813dbe233
520
537
  * https://github.com/OpenCyphal/libcanard/blob/636795f4bc395f56af8d2c61d3757b5e762bb9e5/canard.c#L811-L834
521
538
  */
522
- SIMSIMD_PUBLIC void simsimd_f32_to_f16(simsimd_f32_t x, simsimd_f16_t *result_ptr) {
539
+ SIMSIMD_INTERNAL void simsimd_f32_to_f16(simsimd_f32_t x, simsimd_f16_t *result_ptr) {
523
540
  simsimd_f32i32_t conv;
524
541
  conv.f = x;
525
542
  unsigned int b = conv.i + 0x00001000;
@@ -538,7 +555,7 @@ SIMSIMD_PUBLIC void simsimd_f32_to_f16(simsimd_f32_t x, simsimd_f16_t *result_pt
538
555
  * https://stackoverflow.com/questions/55253233/convert-fp32-to-bfloat16-in-c/55254307#55254307
539
556
  * https://cloud.google.com/blog/products/ai-machine-learning/bfloat16-the-secret-to-high-performance-on-cloud-tpus
540
557
  */
541
- SIMSIMD_PUBLIC simsimd_f32_t simsimd_bf16_to_f32(simsimd_bf16_t const *x_ptr) {
558
+ SIMSIMD_INTERNAL simsimd_f32_t simsimd_bf16_to_f32(simsimd_bf16_t const *x_ptr) {
542
559
  unsigned short x = *(unsigned short const *)x_ptr;
543
560
  simsimd_f32i32_t conv;
544
561
  conv.i = x << 16; // Zero extends the mantissa
@@ -551,7 +568,7 @@ SIMSIMD_PUBLIC simsimd_f32_t simsimd_bf16_to_f32(simsimd_bf16_t const *x_ptr) {
551
568
  * https://stackoverflow.com/questions/55253233/convert-fp32-to-bfloat16-in-c/55254307#55254307
552
569
  * https://cloud.google.com/blog/products/ai-machine-learning/bfloat16-the-secret-to-high-performance-on-cloud-tpus
553
570
  */
554
- SIMSIMD_PUBLIC void simsimd_f32_to_bf16(simsimd_f32_t x, simsimd_bf16_t *result_ptr) {
571
+ SIMSIMD_INTERNAL void simsimd_f32_to_bf16(simsimd_f32_t x, simsimd_bf16_t *result_ptr) {
555
572
  simsimd_f32i32_t conv;
556
573
  conv.f = x;
557
574
  conv.i += 0x8000; // Rounding is optional
@@ -561,12 +578,12 @@ SIMSIMD_PUBLIC void simsimd_f32_to_bf16(simsimd_f32_t x, simsimd_bf16_t *result_
561
578
  *(unsigned short *)result_ptr = (unsigned short)conv.i;
562
579
  }
563
580
 
564
- SIMSIMD_PUBLIC simsimd_u32_t simsimd_u32_rol(simsimd_u32_t x, int n) { return (x << n) | (x >> (32 - n)); }
565
- SIMSIMD_PUBLIC simsimd_u16_t simsimd_u16_rol(simsimd_u16_t x, int n) { return (x << n) | (x >> (16 - n)); }
566
- SIMSIMD_PUBLIC simsimd_u8_t simsimd_u8_rol(simsimd_u8_t x, int n) { return (x << n) | (x >> (8 - n)); }
567
- SIMSIMD_PUBLIC simsimd_u32_t simsimd_u32_ror(simsimd_u32_t x, int n) { return (x >> n) | (x << (32 - n)); }
568
- SIMSIMD_PUBLIC simsimd_u16_t simsimd_u16_ror(simsimd_u16_t x, int n) { return (x >> n) | (x << (16 - n)); }
569
- SIMSIMD_PUBLIC simsimd_u8_t simsimd_u8_ror(simsimd_u8_t x, int n) { return (x >> n) | (x << (8 - n)); }
581
+ SIMSIMD_INTERNAL simsimd_u32_t simsimd_u32_rol(simsimd_u32_t x, int n) { return (x << n) | (x >> (32 - n)); }
582
+ SIMSIMD_INTERNAL simsimd_u16_t simsimd_u16_rol(simsimd_u16_t x, int n) { return (x << n) | (x >> (16 - n)); }
583
+ SIMSIMD_INTERNAL simsimd_u8_t simsimd_u8_rol(simsimd_u8_t x, int n) { return (x << n) | (x >> (8 - n)); }
584
+ SIMSIMD_INTERNAL simsimd_u32_t simsimd_u32_ror(simsimd_u32_t x, int n) { return (x >> n) | (x << (32 - n)); }
585
+ SIMSIMD_INTERNAL simsimd_u16_t simsimd_u16_ror(simsimd_u16_t x, int n) { return (x >> n) | (x << (16 - n)); }
586
+ SIMSIMD_INTERNAL simsimd_u8_t simsimd_u8_ror(simsimd_u8_t x, int n) { return (x >> n) | (x << (8 - n)); }
570
587
 
571
588
  #ifdef __cplusplus
572
589
  } // extern "C"
@@ -28,13 +28,13 @@ export function dot(a: Float64Array | Float32Array, b: Float64Array | Float32Arr
28
28
 
29
29
  /**
30
30
  * @brief Computes the squared Euclidean distance between two vectors.
31
- * @param {Float64Array|Float32Array|Int8Array} a - The first vector.
32
- * @param {Float64Array|Float32Array|Int8Array} b - The second vector.
31
+ * @param {Float64Array|Float32Array|Int8Array|Uint8Array} a - The first vector.
32
+ * @param {Float64Array|Float32Array|Int8Array|Uint8Array} b - The second vector.
33
33
  * @returns {number} The squared Euclidean distance between vectors a and b.
34
34
  */
35
35
  export function sqeuclidean(
36
- a: Float64Array | Float32Array | Int8Array,
37
- b: Float64Array | Float32Array | Int8Array
36
+ a: Float64Array | Float32Array | Int8Array | Uint8Array,
37
+ b: Float64Array | Float32Array | Int8Array | Uint8Array
38
38
  ): number {
39
39
  if (a.length !== b.length) {
40
40
  throw new Error("Vectors must have the same length");
@@ -47,6 +47,28 @@ export function sqeuclidean(
47
47
  return result;
48
48
  }
49
49
 
50
+ /**
51
+ * @brief Computes the L2 Euclidean distance between two vectors.
52
+ * @param {Float64Array|Float32Array|Int8Array | Uint8Array} a - The first vector.
53
+ * @param {Float64Array|Float32Array|Int8Array | Uint8Array} b - The second vector.
54
+ * @returns {number} The L2 euclidean distance between vectors a and b.
55
+ */
56
+ export function euclidean(
57
+ a: Float64Array | Float32Array | Int8Array | Uint8Array,
58
+ b: Float64Array | Float32Array | Int8Array | Uint8Array
59
+ ): number {
60
+ if (a.length !== b.length) {
61
+ throw new Error("Vectors must have the same length");
62
+ }
63
+
64
+ let result = 0;
65
+ for (let i = 0; i < a.length; i++) {
66
+ result += (a[i] - b[i]) * (a[i] - b[i]);
67
+ }
68
+ return Math.sqrt(result);
69
+ }
70
+
71
+
50
72
  /**
51
73
  * @brief Computes the cosine distance between two vectors.
52
74
  * @param {Float64Array|Float32Array|Int8Array} a - The first vector.
@@ -194,6 +216,7 @@ export const jensenshannon = (a: Float64Array | Float32Array, b: Float64Array |
194
216
 
195
217
  export default {
196
218
  sqeuclidean,
219
+ euclidean,
197
220
  cosine,
198
221
  inner,
199
222
  hamming,
@@ -14,7 +14,8 @@
14
14
  /// @brief Global variable that caches the CPU capabilities, and is computed just onc, when the module is loaded.
15
15
  simsimd_capability_t static_capabilities = simsimd_cap_serial_k;
16
16
 
17
- napi_value runAPI(napi_env env, napi_callback_info info, simsimd_metric_kind_t metric_kind) {
17
+ napi_value dense(napi_env env, napi_callback_info info, simsimd_metric_kind_t metric_kind,
18
+ simsimd_datatype_t datatype) {
18
19
  size_t argc = 2;
19
20
  napi_value args[2];
20
21
  napi_status status;
@@ -44,18 +45,18 @@ napi_value runAPI(napi_env env, napi_callback_info info, simsimd_metric_kind_t m
44
45
  return NULL;
45
46
  }
46
47
 
47
- simsimd_datatype_t datatype = simsimd_datatype_unknown_k;
48
- switch (type_a) {
49
- case napi_float64_array: datatype = simsimd_datatype_f64_k; break;
50
- case napi_float32_array: datatype = simsimd_datatype_f32_k; break;
51
- case napi_int8_array: datatype = simsimd_datatype_i8_k; break;
52
- case napi_uint8_array: datatype = simsimd_datatype_b8_k; break;
53
- default: break;
54
- }
48
+ if (datatype == simsimd_datatype_unknown_k) switch (type_a) {
49
+ case napi_float64_array: datatype = simsimd_datatype_f64_k; break;
50
+ case napi_float32_array: datatype = simsimd_datatype_f32_k; break;
51
+ case napi_int8_array: datatype = simsimd_datatype_i8_k; break;
52
+ case napi_uint8_array: datatype = simsimd_datatype_u8_k; break;
53
+ default: break;
54
+ }
55
55
 
56
- simsimd_metric_punned_t metric = NULL;
56
+ simsimd_metric_dense_punned_t metric = NULL;
57
57
  simsimd_capability_t capability = simsimd_cap_serial_k;
58
- simsimd_find_metric_punned(metric_kind, datatype, static_capabilities, simsimd_cap_any_k, &metric, &capability);
58
+ simsimd_find_kernel_punned(metric_kind, datatype, static_capabilities, simsimd_cap_any_k,
59
+ (simsimd_kernel_punned_t *)&metric, &capability);
59
60
  if (metric == NULL) {
60
61
  napi_throw_error(env, NULL, "Unsupported datatype for given metric");
61
62
  return NULL;
@@ -72,32 +73,51 @@ napi_value runAPI(napi_env env, napi_callback_info info, simsimd_metric_kind_t m
72
73
  return js_result;
73
74
  }
74
75
 
75
- napi_value ipAPI(napi_env env, napi_callback_info info) { return runAPI(env, info, simsimd_metric_dot_k); }
76
- napi_value cosAPI(napi_env env, napi_callback_info info) { return runAPI(env, info, simsimd_metric_cosine_k); }
77
- napi_value l2sqAPI(napi_env env, napi_callback_info info) { return runAPI(env, info, simsimd_metric_sqeuclidean_k); }
78
- napi_value klAPI(napi_env env, napi_callback_info info) { return runAPI(env, info, simsimd_metric_kl_k); }
79
- napi_value jsAPI(napi_env env, napi_callback_info info) { return runAPI(env, info, simsimd_metric_js_k); }
80
- napi_value hammingAPI(napi_env env, napi_callback_info info) { return runAPI(env, info, simsimd_metric_hamming_k); }
81
- napi_value jaccardAPI(napi_env env, napi_callback_info info) { return runAPI(env, info, simsimd_metric_jaccard_k); }
76
+ napi_value api_ip(napi_env env, napi_callback_info info) {
77
+ return dense(env, info, simsimd_metric_dot_k, simsimd_datatype_unknown_k);
78
+ }
79
+ napi_value api_cos(napi_env env, napi_callback_info info) {
80
+ return dense(env, info, simsimd_metric_cosine_k, simsimd_datatype_unknown_k);
81
+ }
82
+ napi_value api_l2sq(napi_env env, napi_callback_info info) {
83
+ return dense(env, info, simsimd_metric_sqeuclidean_k, simsimd_datatype_unknown_k);
84
+ }
85
+ napi_value api_l2(napi_env env, napi_callback_info info) {
86
+ return dense(env, info, simsimd_metric_l2_k, simsimd_datatype_unknown_k);
87
+ }
88
+ napi_value api_kl(napi_env env, napi_callback_info info) {
89
+ return dense(env, info, simsimd_metric_kl_k, simsimd_datatype_unknown_k);
90
+ }
91
+ napi_value api_js(napi_env env, napi_callback_info info) {
92
+ return dense(env, info, simsimd_metric_js_k, simsimd_datatype_unknown_k);
93
+ }
94
+ napi_value api_hamming(napi_env env, napi_callback_info info) {
95
+ return dense(env, info, simsimd_metric_hamming_k, simsimd_datatype_b8_k);
96
+ }
97
+ napi_value api_jaccard(napi_env env, napi_callback_info info) {
98
+ return dense(env, info, simsimd_metric_jaccard_k, simsimd_datatype_b8_k);
99
+ }
82
100
 
83
101
  napi_value Init(napi_env env, napi_value exports) {
84
102
 
85
103
  // Define an array of property descriptors
86
- napi_property_descriptor dotDesc = {"dot", 0, ipAPI, 0, 0, 0, napi_default, 0};
87
- napi_property_descriptor innerDesc = {"inner", 0, ipAPI, 0, 0, 0, napi_default, 0};
88
- napi_property_descriptor sqeuclideanDesc = {"sqeuclidean", 0, l2sqAPI, 0, 0, 0, napi_default, 0};
89
- napi_property_descriptor cosineDesc = {"cosine", 0, cosAPI, 0, 0, 0, napi_default, 0};
90
- napi_property_descriptor hammingDesc = {"hamming", 0, hammingAPI, 0, 0, 0, napi_default, 0};
91
- napi_property_descriptor jaccardDesc = {"jaccard", 0, jaccardAPI, 0, 0, 0, napi_default, 0};
92
- napi_property_descriptor klDesc = {"kullbackleibler", 0, klAPI, 0, 0, 0, napi_default, 0};
93
- napi_property_descriptor jsDesc = {"jensenshannon", 0, jsAPI, 0, 0, 0, napi_default, 0};
104
+ napi_property_descriptor dot_descriptor = {"dot", 0, api_ip, 0, 0, 0, napi_default, 0};
105
+ napi_property_descriptor inner_descriptor = {"inner", 0, api_ip, 0, 0, 0, napi_default, 0};
106
+ napi_property_descriptor sqeuclidean_descriptor = {"sqeuclidean", 0, api_l2sq, 0, 0, 0, napi_default, 0};
107
+ napi_property_descriptor euclidean_descriptor = {"euclidean", 0, api_l2, 0, 0, 0, napi_default, 0};
108
+ napi_property_descriptor cosine_descriptor = {"cosine", 0, api_cos, 0, 0, 0, napi_default, 0};
109
+ napi_property_descriptor hamming_descriptor = {"hamming", 0, api_hamming, 0, 0, 0, napi_default, 0};
110
+ napi_property_descriptor jaccard_descriptor = {"jaccard", 0, api_jaccard, 0, 0, 0, napi_default, 0};
111
+ napi_property_descriptor kl_descriptor = {"kullbackleibler", 0, api_kl, 0, 0, 0, napi_default, 0};
112
+ napi_property_descriptor js_descriptor = {"jensenshannon", 0, api_js, 0, 0, 0, napi_default, 0};
94
113
  napi_property_descriptor properties[] = {
95
- dotDesc, innerDesc, sqeuclideanDesc, cosineDesc, hammingDesc, jaccardDesc, klDesc, jsDesc,
114
+ dot_descriptor, inner_descriptor, sqeuclidean_descriptor, euclidean_descriptor, cosine_descriptor,
115
+ hamming_descriptor, jaccard_descriptor, kl_descriptor, js_descriptor,
96
116
  };
97
117
 
98
118
  // Define the properties on the `exports` object
99
- size_t propertyCount = sizeof(properties) / sizeof(properties[0]);
100
- napi_define_properties(env, exports, propertyCount, properties);
119
+ size_t property_count = sizeof(properties) / sizeof(properties[0]);
120
+ napi_define_properties(env, exports, property_count, properties);
101
121
 
102
122
  static_capabilities = simsimd_capabilities();
103
123
  return exports;