usearch 2.16.8 → 2.16.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/include/usearch/index.hpp +1 -1
- package/package.json +1 -1
- package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
- package/prebuilds/linux-arm64/usearch.node +0 -0
- package/prebuilds/linux-x64/usearch.node +0 -0
- package/simsimd/CONTRIBUTING.md +69 -12
- package/simsimd/Cargo.lock +1 -1
- package/simsimd/Cargo.toml +1 -1
- package/simsimd/README.md +253 -40
- package/simsimd/c/lib.c +114 -109
- package/simsimd/include/simsimd/binary.h +33 -17
- package/simsimd/include/simsimd/curved.h +867 -129
- package/simsimd/include/simsimd/dot.h +562 -569
- package/simsimd/include/simsimd/probability.h +14 -9
- package/simsimd/include/simsimd/simsimd.h +102 -46
- package/simsimd/include/simsimd/spatial.h +28 -18
- package/simsimd/include/simsimd/types.h +24 -0
- package/simsimd/javascript/fallback.ts +26 -15
- package/simsimd/javascript/simsimd.ts +1 -1
- package/simsimd/package-lock.json +10 -9
- package/simsimd/package.json +2 -2
- package/simsimd/rust/lib.rs +218 -5
- package/simsimd/scripts/bench.cxx +156 -97
- package/simsimd/scripts/test.c +14 -8
- package/simsimd/scripts/test.mjs +158 -145
- package/simsimd/scripts/test.py +71 -52
|
@@ -108,7 +108,7 @@ SIMSIMD_PUBLIC void simsimd_js_f16_sapphire(simsimd_f16_t const* a, simsimd_f16_
|
|
|
108
108
|
d += ai * SIMSIMD_LOG((ai + epsilon) / (mi + epsilon)); \
|
|
109
109
|
d += bi * SIMSIMD_LOG((bi + epsilon) / (mi + epsilon)); \
|
|
110
110
|
} \
|
|
111
|
-
*result = (simsimd_distance_t)d / 2;
|
|
111
|
+
*result = SIMSIMD_SQRT(((simsimd_distance_t)d / 2)); \
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
SIMSIMD_MAKE_KL(serial, f64, f64, SIMSIMD_DEREFERENCE, SIMSIMD_F32_DIVISION_EPSILON) // simsimd_kl_f64_serial
|
|
@@ -219,12 +219,13 @@ simsimd_js_f32_neon_cycle:
|
|
|
219
219
|
float32x4_t log_ratio_b_vec = _simsimd_log2_f32_neon(ratio_b_vec);
|
|
220
220
|
float32x4_t prod_a_vec = vmulq_f32(a_vec, log_ratio_a_vec);
|
|
221
221
|
float32x4_t prod_b_vec = vmulq_f32(b_vec, log_ratio_b_vec);
|
|
222
|
+
|
|
222
223
|
sum_vec = vaddq_f32(sum_vec, vaddq_f32(prod_a_vec, prod_b_vec));
|
|
223
224
|
if (n != 0) goto simsimd_js_f32_neon_cycle;
|
|
224
225
|
|
|
225
226
|
simsimd_f32_t log2_normalizer = 0.693147181f;
|
|
226
|
-
simsimd_f32_t sum = vaddvq_f32(sum_vec) * log2_normalizer;
|
|
227
|
-
*result = sum
|
|
227
|
+
simsimd_f32_t sum = vaddvq_f32(sum_vec) * log2_normalizer / 2;
|
|
228
|
+
*result = _simsimd_sqrt_f32_neon(sum);
|
|
228
229
|
}
|
|
229
230
|
|
|
230
231
|
#pragma clang attribute pop
|
|
@@ -296,8 +297,8 @@ simsimd_js_f16_neon_cycle:
|
|
|
296
297
|
if (n) goto simsimd_js_f16_neon_cycle;
|
|
297
298
|
|
|
298
299
|
simsimd_f32_t log2_normalizer = 0.693147181f;
|
|
299
|
-
simsimd_f32_t sum = vaddvq_f32(sum_vec) * log2_normalizer;
|
|
300
|
-
*result = sum
|
|
300
|
+
simsimd_f32_t sum = vaddvq_f32(sum_vec) * log2_normalizer / 2;
|
|
301
|
+
*result = _simsimd_sqrt_f32_neon(sum);
|
|
301
302
|
}
|
|
302
303
|
|
|
303
304
|
#pragma clang attribute pop
|
|
@@ -403,8 +404,8 @@ simsimd_js_f16_haswell_cycle:
|
|
|
403
404
|
|
|
404
405
|
simsimd_f32_t log2_normalizer = 0.693147181f;
|
|
405
406
|
simsimd_f32_t sum = _simsimd_reduce_f32x8_haswell(sum_vec);
|
|
406
|
-
sum *= log2_normalizer;
|
|
407
|
-
*result = sum
|
|
407
|
+
sum *= log2_normalizer / 2;
|
|
408
|
+
*result = _simsimd_sqrt_f32_haswell(sum);
|
|
408
409
|
}
|
|
409
410
|
|
|
410
411
|
#pragma clang attribute pop
|
|
@@ -496,7 +497,9 @@ simsimd_js_f32_skylake_cycle:
|
|
|
496
497
|
if (n) goto simsimd_js_f32_skylake_cycle;
|
|
497
498
|
|
|
498
499
|
simsimd_f32_t log2_normalizer = 0.693147181f;
|
|
499
|
-
|
|
500
|
+
simsimd_f32_t sum = _mm512_reduce_add_ps(_mm512_add_ps(sum_a_vec, sum_b_vec));
|
|
501
|
+
sum *= log2_normalizer / 2;
|
|
502
|
+
*result = _simsimd_sqrt_f32_haswell(sum);
|
|
500
503
|
}
|
|
501
504
|
|
|
502
505
|
#pragma clang attribute pop
|
|
@@ -586,7 +589,9 @@ simsimd_js_f16_sapphire_cycle:
|
|
|
586
589
|
if (n) goto simsimd_js_f16_sapphire_cycle;
|
|
587
590
|
|
|
588
591
|
simsimd_f32_t log2_normalizer = 0.693147181f;
|
|
589
|
-
|
|
592
|
+
simsimd_f32_t sum = _mm512_reduce_add_ph(_mm512_add_ph(sum_a_vec, sum_b_vec));
|
|
593
|
+
sum *= log2_normalizer / 2;
|
|
594
|
+
*result = _simsimd_sqrt_f32_haswell(sum);
|
|
590
595
|
}
|
|
591
596
|
|
|
592
597
|
#pragma clang attribute pop
|
|
@@ -89,8 +89,8 @@
|
|
|
89
89
|
#define SIMSIMD_H
|
|
90
90
|
|
|
91
91
|
#define SIMSIMD_VERSION_MAJOR 6
|
|
92
|
-
#define SIMSIMD_VERSION_MINOR
|
|
93
|
-
#define SIMSIMD_VERSION_PATCH
|
|
92
|
+
#define SIMSIMD_VERSION_MINOR 2
|
|
93
|
+
#define SIMSIMD_VERSION_PATCH 3
|
|
94
94
|
|
|
95
95
|
/**
|
|
96
96
|
* @brief Removes compile-time dispatching, and replaces it with runtime dispatching.
|
|
@@ -434,7 +434,7 @@ SIMSIMD_PUBLIC simsimd_capability_t _simsimd_capabilities_x86(void) {
|
|
|
434
434
|
SIMSIMD_PUBLIC simsimd_capability_t _simsimd_capabilities_arm(void) {
|
|
435
435
|
#if defined(_SIMSIMD_DEFINED_APPLE)
|
|
436
436
|
// On Apple Silicon, `mrs` is not allowed in user-space, so we need to use the `sysctl` API.
|
|
437
|
-
|
|
437
|
+
unsigned supports_neon = 0, supports_fp16 = 0, supports_bf16 = 0, supports_i8mm = 0;
|
|
438
438
|
size_t size = sizeof(supports_neon);
|
|
439
439
|
if (sysctlbyname("hw.optional.neon", &supports_neon, &size, NULL, 0) != 0) supports_neon = 0;
|
|
440
440
|
if (sysctlbyname("hw.optional.arm.FEAT_FP16", &supports_fp16, &size, NULL, 0) != 0) supports_fp16 = 0;
|
|
@@ -975,12 +975,14 @@ SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_f64c(simsimd_capability_t v, s
|
|
|
975
975
|
if (v & simsimd_cap_skylake_k) switch (k) {
|
|
976
976
|
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f64c_skylake, *c = simsimd_cap_skylake_k; return;
|
|
977
977
|
case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f64c_skylake, *c = simsimd_cap_skylake_k; return;
|
|
978
|
+
case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f64c_skylake, *c = simsimd_cap_skylake_k; return;
|
|
978
979
|
default: break;
|
|
979
980
|
}
|
|
980
981
|
#endif
|
|
981
982
|
if (v & simsimd_cap_serial_k) switch (k) {
|
|
982
983
|
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f64c_serial, *c = simsimd_cap_serial_k; return;
|
|
983
984
|
case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f64c_serial, *c = simsimd_cap_serial_k; return;
|
|
985
|
+
case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f64c_serial, *c = simsimd_cap_serial_k; return;
|
|
984
986
|
default: break;
|
|
985
987
|
}
|
|
986
988
|
}
|
|
@@ -999,6 +1001,7 @@ SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_f32c(simsimd_capability_t v, s
|
|
|
999
1001
|
if (v & simsimd_cap_neon_k) switch (k) {
|
|
1000
1002
|
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32c_neon, *c = simsimd_cap_neon_k; return;
|
|
1001
1003
|
case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f32c_neon, *c = simsimd_cap_neon_k; return;
|
|
1004
|
+
case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f32c_neon, *c = simsimd_cap_neon_k; return;
|
|
1002
1005
|
default: break;
|
|
1003
1006
|
}
|
|
1004
1007
|
#endif
|
|
@@ -1006,6 +1009,7 @@ SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_f32c(simsimd_capability_t v, s
|
|
|
1006
1009
|
if (v & simsimd_cap_skylake_k) switch (k) {
|
|
1007
1010
|
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32c_skylake, *c = simsimd_cap_skylake_k; return;
|
|
1008
1011
|
case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f32c_skylake, *c = simsimd_cap_skylake_k; return;
|
|
1012
|
+
case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f32c_skylake, *c = simsimd_cap_skylake_k; return;
|
|
1009
1013
|
default: break;
|
|
1010
1014
|
}
|
|
1011
1015
|
#endif
|
|
@@ -1019,6 +1023,7 @@ SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_f32c(simsimd_capability_t v, s
|
|
|
1019
1023
|
if (v & simsimd_cap_serial_k) switch (k) {
|
|
1020
1024
|
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32c_serial, *c = simsimd_cap_serial_k; return;
|
|
1021
1025
|
case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f32c_serial, *c = simsimd_cap_serial_k; return;
|
|
1026
|
+
case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f32c_serial, *c = simsimd_cap_serial_k; return;
|
|
1022
1027
|
default: break;
|
|
1023
1028
|
}
|
|
1024
1029
|
}
|
|
@@ -1037,6 +1042,7 @@ SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_f16c(simsimd_capability_t v, s
|
|
|
1037
1042
|
if (v & simsimd_cap_neon_f16_k) switch (k) {
|
|
1038
1043
|
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16c_neon, *c = simsimd_cap_neon_f16_k; return;
|
|
1039
1044
|
case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f16c_neon, *c = simsimd_cap_neon_f16_k; return;
|
|
1045
|
+
case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f16c_neon, *c = simsimd_cap_neon_bf16_k; return;
|
|
1040
1046
|
default: break;
|
|
1041
1047
|
}
|
|
1042
1048
|
#endif
|
|
@@ -1044,6 +1050,7 @@ SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_f16c(simsimd_capability_t v, s
|
|
|
1044
1050
|
if (v & simsimd_cap_sapphire_k) switch (k) {
|
|
1045
1051
|
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16c_sapphire, *c = simsimd_cap_sapphire_k; return;
|
|
1046
1052
|
case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f16c_sapphire, *c = simsimd_cap_sapphire_k; return;
|
|
1053
|
+
case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f16c_sapphire, *c = simsimd_cap_sapphire_k; return;
|
|
1047
1054
|
default: break;
|
|
1048
1055
|
}
|
|
1049
1056
|
#endif
|
|
@@ -1057,6 +1064,7 @@ SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_f16c(simsimd_capability_t v, s
|
|
|
1057
1064
|
if (v & simsimd_cap_serial_k) switch (k) {
|
|
1058
1065
|
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16c_serial, *c = simsimd_cap_serial_k; return;
|
|
1059
1066
|
case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f16c_serial, *c = simsimd_cap_serial_k; return;
|
|
1067
|
+
case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f16c_serial, *c = simsimd_cap_serial_k; return;
|
|
1060
1068
|
default: break;
|
|
1061
1069
|
}
|
|
1062
1070
|
}
|
|
@@ -1068,6 +1076,7 @@ SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_bf16c(simsimd_capability_t v,
|
|
|
1068
1076
|
if (v & simsimd_cap_neon_bf16_k) switch (k) {
|
|
1069
1077
|
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_bf16c_neon, *c = simsimd_cap_neon_bf16_k; return;
|
|
1070
1078
|
case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_bf16c_neon, *c = simsimd_cap_neon_bf16_k; return;
|
|
1079
|
+
case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_bf16c_neon, *c = simsimd_cap_neon_bf16_k; return;
|
|
1071
1080
|
default: break;
|
|
1072
1081
|
}
|
|
1073
1082
|
#endif
|
|
@@ -1075,12 +1084,14 @@ SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_bf16c(simsimd_capability_t v,
|
|
|
1075
1084
|
if (v & simsimd_cap_genoa_k) switch (k) {
|
|
1076
1085
|
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_bf16c_genoa, *c = simsimd_cap_genoa_k; return;
|
|
1077
1086
|
case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_bf16c_genoa, *c = simsimd_cap_genoa_k; return;
|
|
1087
|
+
case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_bf16c_genoa, *c = simsimd_cap_genoa_k; return;
|
|
1078
1088
|
default: break;
|
|
1079
1089
|
}
|
|
1080
1090
|
#endif
|
|
1081
1091
|
if (v & simsimd_cap_serial_k) switch (k) {
|
|
1082
1092
|
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_bf16c_serial, *c = simsimd_cap_serial_k; return;
|
|
1083
1093
|
case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_bf16c_serial, *c = simsimd_cap_serial_k; return;
|
|
1094
|
+
case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_bf16c_serial, *c = simsimd_cap_serial_k; return;
|
|
1084
1095
|
default: break;
|
|
1085
1096
|
}
|
|
1086
1097
|
}
|
|
@@ -1314,21 +1325,21 @@ SIMSIMD_DYNAMIC void simsimd_dot_f32(simsimd_f32_t const *a, simsimd_f32_t const
|
|
|
1314
1325
|
simsimd_distance_t *d);
|
|
1315
1326
|
SIMSIMD_DYNAMIC void simsimd_dot_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_size_t n,
|
|
1316
1327
|
simsimd_distance_t *d);
|
|
1317
|
-
SIMSIMD_DYNAMIC void simsimd_dot_f16c(
|
|
1328
|
+
SIMSIMD_DYNAMIC void simsimd_dot_f16c(simsimd_f16c_t const *a, simsimd_f16c_t const *b, simsimd_size_t n,
|
|
1318
1329
|
simsimd_distance_t *d);
|
|
1319
|
-
SIMSIMD_DYNAMIC void simsimd_dot_bf16c(
|
|
1330
|
+
SIMSIMD_DYNAMIC void simsimd_dot_bf16c(simsimd_bf16c_t const *a, simsimd_bf16c_t const *b, simsimd_size_t n,
|
|
1320
1331
|
simsimd_distance_t *d);
|
|
1321
|
-
SIMSIMD_DYNAMIC void simsimd_dot_f32c(
|
|
1332
|
+
SIMSIMD_DYNAMIC void simsimd_dot_f32c(simsimd_f32c_t const *a, simsimd_f32c_t const *b, simsimd_size_t n,
|
|
1322
1333
|
simsimd_distance_t *d);
|
|
1323
|
-
SIMSIMD_DYNAMIC void simsimd_dot_f64c(
|
|
1334
|
+
SIMSIMD_DYNAMIC void simsimd_dot_f64c(simsimd_f64c_t const *a, simsimd_f64c_t const *b, simsimd_size_t n,
|
|
1324
1335
|
simsimd_distance_t *d);
|
|
1325
|
-
SIMSIMD_DYNAMIC void simsimd_vdot_f16c(
|
|
1336
|
+
SIMSIMD_DYNAMIC void simsimd_vdot_f16c(simsimd_f16c_t const *a, simsimd_f16c_t const *b, simsimd_size_t n,
|
|
1326
1337
|
simsimd_distance_t *d);
|
|
1327
|
-
SIMSIMD_DYNAMIC void simsimd_vdot_bf16c(
|
|
1338
|
+
SIMSIMD_DYNAMIC void simsimd_vdot_bf16c(simsimd_bf16c_t const *a, simsimd_bf16c_t const *b, simsimd_size_t n,
|
|
1328
1339
|
simsimd_distance_t *d);
|
|
1329
|
-
SIMSIMD_DYNAMIC void simsimd_vdot_f32c(
|
|
1340
|
+
SIMSIMD_DYNAMIC void simsimd_vdot_f32c(simsimd_f32c_t const *a, simsimd_f32c_t const *b, simsimd_size_t n,
|
|
1330
1341
|
simsimd_distance_t *d);
|
|
1331
|
-
SIMSIMD_DYNAMIC void simsimd_vdot_f64c(
|
|
1342
|
+
SIMSIMD_DYNAMIC void simsimd_vdot_f64c(simsimd_f64c_t const *a, simsimd_f64c_t const *b, simsimd_size_t n,
|
|
1332
1343
|
simsimd_distance_t *d);
|
|
1333
1344
|
|
|
1334
1345
|
/* Spatial distances
|
|
@@ -1562,7 +1573,7 @@ SIMSIMD_PUBLIC void simsimd_dot_f64(simsimd_f64_t const *a, simsimd_f64_t const
|
|
|
1562
1573
|
simsimd_dot_f64_serial(a, b, n, d);
|
|
1563
1574
|
#endif
|
|
1564
1575
|
}
|
|
1565
|
-
SIMSIMD_PUBLIC void simsimd_dot_f16c(
|
|
1576
|
+
SIMSIMD_PUBLIC void simsimd_dot_f16c(simsimd_f16c_t const *a, simsimd_f16c_t const *b, simsimd_size_t n,
|
|
1566
1577
|
simsimd_distance_t *d) {
|
|
1567
1578
|
#if SIMSIMD_TARGET_SVE_F16
|
|
1568
1579
|
simsimd_dot_f16c_sve(a, b, n, d);
|
|
@@ -1576,7 +1587,7 @@ SIMSIMD_PUBLIC void simsimd_dot_f16c(simsimd_f16_t const *a, simsimd_f16_t const
|
|
|
1576
1587
|
simsimd_dot_f16c_serial(a, b, n, d);
|
|
1577
1588
|
#endif
|
|
1578
1589
|
}
|
|
1579
|
-
SIMSIMD_PUBLIC void simsimd_dot_bf16c(
|
|
1590
|
+
SIMSIMD_PUBLIC void simsimd_dot_bf16c(simsimd_bf16c_t const *a, simsimd_bf16c_t const *b, simsimd_size_t n,
|
|
1580
1591
|
simsimd_distance_t *d) {
|
|
1581
1592
|
#if SIMSIMD_TARGET_GENOA
|
|
1582
1593
|
simsimd_dot_bf16c_genoa(a, b, n, d);
|
|
@@ -1586,7 +1597,7 @@ SIMSIMD_PUBLIC void simsimd_dot_bf16c(simsimd_bf16_t const *a, simsimd_bf16_t co
|
|
|
1586
1597
|
simsimd_dot_bf16c_serial(a, b, n, d);
|
|
1587
1598
|
#endif
|
|
1588
1599
|
}
|
|
1589
|
-
SIMSIMD_PUBLIC void simsimd_dot_f32c(
|
|
1600
|
+
SIMSIMD_PUBLIC void simsimd_dot_f32c(simsimd_f32c_t const *a, simsimd_f32c_t const *b, simsimd_size_t n,
|
|
1590
1601
|
simsimd_distance_t *d) {
|
|
1591
1602
|
#if SIMSIMD_TARGET_SVE
|
|
1592
1603
|
simsimd_dot_f32c_sve(a, b, n, d);
|
|
@@ -1600,7 +1611,7 @@ SIMSIMD_PUBLIC void simsimd_dot_f32c(simsimd_f32_t const *a, simsimd_f32_t const
|
|
|
1600
1611
|
simsimd_dot_f32c_serial(a, b, n, d);
|
|
1601
1612
|
#endif
|
|
1602
1613
|
}
|
|
1603
|
-
SIMSIMD_PUBLIC void simsimd_dot_f64c(
|
|
1614
|
+
SIMSIMD_PUBLIC void simsimd_dot_f64c(simsimd_f64c_t const *a, simsimd_f64c_t const *b, simsimd_size_t n,
|
|
1604
1615
|
simsimd_distance_t *d) {
|
|
1605
1616
|
#if SIMSIMD_TARGET_SVE
|
|
1606
1617
|
simsimd_dot_f64c_sve(a, b, n, d);
|
|
@@ -1610,7 +1621,7 @@ SIMSIMD_PUBLIC void simsimd_dot_f64c(simsimd_f64_t const *a, simsimd_f64_t const
|
|
|
1610
1621
|
simsimd_dot_f64c_serial(a, b, n, d);
|
|
1611
1622
|
#endif
|
|
1612
1623
|
}
|
|
1613
|
-
SIMSIMD_PUBLIC void simsimd_vdot_f16c(
|
|
1624
|
+
SIMSIMD_PUBLIC void simsimd_vdot_f16c(simsimd_f16c_t const *a, simsimd_f16c_t const *b, simsimd_size_t n,
|
|
1614
1625
|
simsimd_distance_t *d) {
|
|
1615
1626
|
#if SIMSIMD_TARGET_SVE
|
|
1616
1627
|
simsimd_vdot_f16c_sve(a, b, n, d);
|
|
@@ -1624,7 +1635,7 @@ SIMSIMD_PUBLIC void simsimd_vdot_f16c(simsimd_f16_t const *a, simsimd_f16_t cons
|
|
|
1624
1635
|
simsimd_vdot_f16c_serial(a, b, n, d);
|
|
1625
1636
|
#endif
|
|
1626
1637
|
}
|
|
1627
|
-
SIMSIMD_PUBLIC void simsimd_vdot_bf16c(
|
|
1638
|
+
SIMSIMD_PUBLIC void simsimd_vdot_bf16c(simsimd_bf16c_t const *a, simsimd_bf16c_t const *b, simsimd_size_t n,
|
|
1628
1639
|
simsimd_distance_t *d) {
|
|
1629
1640
|
#if SIMSIMD_TARGET_GENOA
|
|
1630
1641
|
simsimd_vdot_bf16c_genoa(a, b, n, d);
|
|
@@ -1634,7 +1645,7 @@ SIMSIMD_PUBLIC void simsimd_vdot_bf16c(simsimd_bf16_t const *a, simsimd_bf16_t c
|
|
|
1634
1645
|
simsimd_vdot_bf16c_serial(a, b, n, d);
|
|
1635
1646
|
#endif
|
|
1636
1647
|
}
|
|
1637
|
-
SIMSIMD_PUBLIC void simsimd_vdot_f32c(
|
|
1648
|
+
SIMSIMD_PUBLIC void simsimd_vdot_f32c(simsimd_f32c_t const *a, simsimd_f32c_t const *b, simsimd_size_t n,
|
|
1638
1649
|
simsimd_distance_t *d) {
|
|
1639
1650
|
#if SIMSIMD_TARGET_SVE
|
|
1640
1651
|
simsimd_vdot_f32c_sve(a, b, n, d);
|
|
@@ -1648,7 +1659,7 @@ SIMSIMD_PUBLIC void simsimd_vdot_f32c(simsimd_f32_t const *a, simsimd_f32_t cons
|
|
|
1648
1659
|
simsimd_vdot_f32c_serial(a, b, n, d);
|
|
1649
1660
|
#endif
|
|
1650
1661
|
}
|
|
1651
|
-
SIMSIMD_PUBLIC void simsimd_vdot_f64c(
|
|
1662
|
+
SIMSIMD_PUBLIC void simsimd_vdot_f64c(simsimd_f64c_t const *a, simsimd_f64c_t const *b, simsimd_size_t n,
|
|
1652
1663
|
simsimd_distance_t *d) {
|
|
1653
1664
|
#if SIMSIMD_TARGET_SVE
|
|
1654
1665
|
simsimd_vdot_f64c_sve(a, b, n, d);
|
|
@@ -2102,12 +2113,11 @@ SIMSIMD_PUBLIC void simsimd_spdot_weights_u16(simsimd_u16_t const *a, simsimd_u1
|
|
|
2102
2113
|
*/
|
|
2103
2114
|
SIMSIMD_PUBLIC void simsimd_bilinear_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_f64_t const *c,
|
|
2104
2115
|
simsimd_size_t n, simsimd_distance_t *d) {
|
|
2105
|
-
|
|
2116
|
+
#if SIMSIMD_TARGET_SKYLAKE
|
|
2117
|
+
simsimd_bilinear_f64_skylake(a, b, c, n, d);
|
|
2118
|
+
#else
|
|
2106
2119
|
simsimd_bilinear_f64_serial(a, b, c, n, d);
|
|
2107
|
-
|
|
2108
|
-
SIMSIMD_PUBLIC void simsimd_mahalanobis_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_f64_t const *c,
|
|
2109
|
-
simsimd_size_t n, simsimd_distance_t *d) {
|
|
2110
|
-
simsimd_mahalanobis_f64_serial(a, b, c, n, d);
|
|
2120
|
+
#endif
|
|
2111
2121
|
}
|
|
2112
2122
|
SIMSIMD_PUBLIC void simsimd_bilinear_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_f32_t const *c,
|
|
2113
2123
|
simsimd_size_t n, simsimd_distance_t *d) {
|
|
@@ -2119,16 +2129,6 @@ SIMSIMD_PUBLIC void simsimd_bilinear_f32(simsimd_f32_t const *a, simsimd_f32_t c
|
|
|
2119
2129
|
simsimd_bilinear_f32_serial(a, b, c, n, d);
|
|
2120
2130
|
#endif
|
|
2121
2131
|
}
|
|
2122
|
-
SIMSIMD_PUBLIC void simsimd_mahalanobis_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_f32_t const *c,
|
|
2123
|
-
simsimd_size_t n, simsimd_distance_t *d) {
|
|
2124
|
-
#if SIMSIMD_TARGET_SKYLAKE
|
|
2125
|
-
simsimd_mahalanobis_f32_skylake(a, b, c, n, d);
|
|
2126
|
-
#elif SIMSIMD_TARGET_NEON
|
|
2127
|
-
simsimd_mahalanobis_f32_neon(a, b, c, n, d);
|
|
2128
|
-
#else
|
|
2129
|
-
simsimd_mahalanobis_f32_serial(a, b, c, n, d);
|
|
2130
|
-
#endif
|
|
2131
|
-
}
|
|
2132
2132
|
SIMSIMD_PUBLIC void simsimd_bilinear_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_f16_t const *c,
|
|
2133
2133
|
simsimd_size_t n, simsimd_distance_t *d) {
|
|
2134
2134
|
#if SIMSIMD_TARGET_SAPPHIRE
|
|
@@ -2141,18 +2141,6 @@ SIMSIMD_PUBLIC void simsimd_bilinear_f16(simsimd_f16_t const *a, simsimd_f16_t c
|
|
|
2141
2141
|
simsimd_bilinear_f16_serial(a, b, c, n, d);
|
|
2142
2142
|
#endif
|
|
2143
2143
|
}
|
|
2144
|
-
SIMSIMD_PUBLIC void simsimd_mahalanobis_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_f16_t const *c,
|
|
2145
|
-
simsimd_size_t n, simsimd_distance_t *d) {
|
|
2146
|
-
#if SIMSIMD_TARGET_SAPPHIRE
|
|
2147
|
-
simsimd_mahalanobis_f16_sapphire(a, b, c, n, d);
|
|
2148
|
-
#elif SIMSIMD_TARGET_HASWELL
|
|
2149
|
-
simsimd_mahalanobis_f16_haswell(a, b, c, n, d);
|
|
2150
|
-
#elif SIMSIMD_TARGET_NEON
|
|
2151
|
-
simsimd_mahalanobis_f16_neon(a, b, c, n, d);
|
|
2152
|
-
#else
|
|
2153
|
-
simsimd_mahalanobis_f16_serial(a, b, c, n, d);
|
|
2154
|
-
#endif
|
|
2155
|
-
}
|
|
2156
2144
|
SIMSIMD_PUBLIC void simsimd_bilinear_bf16(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_bf16_t const *c,
|
|
2157
2145
|
simsimd_size_t n, simsimd_distance_t *d) {
|
|
2158
2146
|
#if SIMSIMD_TARGET_GENOA
|
|
@@ -2165,6 +2153,74 @@ SIMSIMD_PUBLIC void simsimd_bilinear_bf16(simsimd_bf16_t const *a, simsimd_bf16_
|
|
|
2165
2153
|
simsimd_bilinear_bf16_serial(a, b, c, n, d);
|
|
2166
2154
|
#endif
|
|
2167
2155
|
}
|
|
2156
|
+
SIMSIMD_PUBLIC void simsimd_bilinear_f64c(simsimd_f64c_t const *a, simsimd_f64c_t const *b, simsimd_f64c_t const *c,
|
|
2157
|
+
simsimd_size_t n, simsimd_distance_t *d) {
|
|
2158
|
+
#if SIMSIMD_TARGET_SKYLAKE
|
|
2159
|
+
simsimd_bilinear_f64c_skylake(a, b, c, n, d);
|
|
2160
|
+
#else
|
|
2161
|
+
simsimd_bilinear_f64c_serial(a, b, c, n, d);
|
|
2162
|
+
#endif
|
|
2163
|
+
}
|
|
2164
|
+
SIMSIMD_PUBLIC void simsimd_bilinear_f32c(simsimd_f32c_t const *a, simsimd_f32c_t const *b, simsimd_f32c_t const *c,
|
|
2165
|
+
simsimd_size_t n, simsimd_distance_t *d) {
|
|
2166
|
+
#if SIMSIMD_TARGET_SKYLAKE
|
|
2167
|
+
simsimd_bilinear_f32c_skylake(a, b, c, n, d);
|
|
2168
|
+
#elif SIMSIMD_TARGET_NEON
|
|
2169
|
+
simsimd_bilinear_f32c_neon(a, b, c, n, d);
|
|
2170
|
+
#else
|
|
2171
|
+
simsimd_bilinear_f32c_serial(a, b, c, n, d);
|
|
2172
|
+
#endif
|
|
2173
|
+
}
|
|
2174
|
+
SIMSIMD_PUBLIC void simsimd_bilinear_f16c(simsimd_f16c_t const *a, simsimd_f16c_t const *b, simsimd_f16c_t const *c,
|
|
2175
|
+
simsimd_size_t n, simsimd_distance_t *d) {
|
|
2176
|
+
#if SIMSIMD_TARGET_SAPPHIRE
|
|
2177
|
+
simsimd_bilinear_f16c_sapphire(a, b, c, n, d);
|
|
2178
|
+
#elif SIMSIMD_TARGET_NEON
|
|
2179
|
+
simsimd_bilinear_f16c_neon(a, b, c, n, d);
|
|
2180
|
+
#else
|
|
2181
|
+
simsimd_bilinear_f16c_serial(a, b, c, n, d);
|
|
2182
|
+
#endif
|
|
2183
|
+
}
|
|
2184
|
+
SIMSIMD_PUBLIC void simsimd_bilinear_bf16c(simsimd_bf16c_t const *a, simsimd_bf16c_t const *b, simsimd_bf16c_t const *c,
|
|
2185
|
+
simsimd_size_t n, simsimd_distance_t *d) {
|
|
2186
|
+
#if SIMSIMD_TARGET_GENOA
|
|
2187
|
+
simsimd_bilinear_bf16c_genoa(a, b, c, n, d);
|
|
2188
|
+
#elif SIMSIMD_TARGET_NEON
|
|
2189
|
+
simsimd_bilinear_bf16c_neon(a, b, c, n, d);
|
|
2190
|
+
#else
|
|
2191
|
+
simsimd_bilinear_bf16c_serial(a, b, c, n, d);
|
|
2192
|
+
#endif
|
|
2193
|
+
}
|
|
2194
|
+
SIMSIMD_PUBLIC void simsimd_mahalanobis_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_f64_t const *c,
|
|
2195
|
+
simsimd_size_t n, simsimd_distance_t *d) {
|
|
2196
|
+
#if SIMSIMD_TARGET_SKYLAKE
|
|
2197
|
+
simsimd_mahalanobis_f64_skylake(a, b, c, n, d);
|
|
2198
|
+
#else
|
|
2199
|
+
simsimd_mahalanobis_f64_serial(a, b, c, n, d);
|
|
2200
|
+
#endif
|
|
2201
|
+
}
|
|
2202
|
+
SIMSIMD_PUBLIC void simsimd_mahalanobis_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_f32_t const *c,
|
|
2203
|
+
simsimd_size_t n, simsimd_distance_t *d) {
|
|
2204
|
+
#if SIMSIMD_TARGET_SKYLAKE
|
|
2205
|
+
simsimd_mahalanobis_f32_skylake(a, b, c, n, d);
|
|
2206
|
+
#elif SIMSIMD_TARGET_NEON
|
|
2207
|
+
simsimd_mahalanobis_f32_neon(a, b, c, n, d);
|
|
2208
|
+
#else
|
|
2209
|
+
simsimd_mahalanobis_f32_serial(a, b, c, n, d);
|
|
2210
|
+
#endif
|
|
2211
|
+
}
|
|
2212
|
+
SIMSIMD_PUBLIC void simsimd_mahalanobis_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_f16_t const *c,
|
|
2213
|
+
simsimd_size_t n, simsimd_distance_t *d) {
|
|
2214
|
+
#if SIMSIMD_TARGET_SAPPHIRE
|
|
2215
|
+
simsimd_mahalanobis_f16_sapphire(a, b, c, n, d);
|
|
2216
|
+
#elif SIMSIMD_TARGET_HASWELL
|
|
2217
|
+
simsimd_mahalanobis_f16_haswell(a, b, c, n, d);
|
|
2218
|
+
#elif SIMSIMD_TARGET_NEON
|
|
2219
|
+
simsimd_mahalanobis_f16_neon(a, b, c, n, d);
|
|
2220
|
+
#else
|
|
2221
|
+
simsimd_mahalanobis_f16_serial(a, b, c, n, d);
|
|
2222
|
+
#endif
|
|
2223
|
+
}
|
|
2168
2224
|
SIMSIMD_PUBLIC void simsimd_mahalanobis_bf16(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_bf16_t const *c,
|
|
2169
2225
|
simsimd_size_t n, simsimd_distance_t *d) {
|
|
2170
2226
|
#if SIMSIMD_TARGET_GENOA
|
|
@@ -139,6 +139,16 @@ SIMSIMD_PUBLIC void simsimd_cos_f64_haswell(simsimd_f64_t const* a, simsimd_f64_
|
|
|
139
139
|
/* SIMD-powered backends for AVX512 CPUs of Skylake generation and newer, using 32-bit arithmetic over 512-bit words.
|
|
140
140
|
* Skylake was launched in 2015, and discontinued in 2019. Skylake had support for F, CD, VL, DQ, and BW extensions,
|
|
141
141
|
* as well as masked operations. This is enough to supersede auto-vectorization on `f32` and `f64` types.
|
|
142
|
+
*
|
|
143
|
+
* Sadly, we can't effectively interleave different kinds of arithmetic instructions to utilize more ports:
|
|
144
|
+
*
|
|
145
|
+
* > Like Intel server architectures since Skylake-X, SPR cores feature two 512-bit FMA units, and organize them in a similar fashion.
|
|
146
|
+
* > One 512-bit FMA unit is created by fusing two 256-bit ones on port 0 and port 1. The other is added to port 5, as a server-specific
|
|
147
|
+
* > core extension. The FMA units on port 0 and 1 are configured into 2×256-bit or 1×512-bit mode depending on whether 512-bit FMA
|
|
148
|
+
* > instructions are present in the scheduler. That means a mix of 256-bit and 512-bit FMA instructions will not achieve higher IPC
|
|
149
|
+
* > than executing 512-bit instructions alone.
|
|
150
|
+
*
|
|
151
|
+
* Source: https://chipsandcheese.com/p/a-peek-at-sapphire-rapids
|
|
142
152
|
*/
|
|
143
153
|
SIMSIMD_PUBLIC void simsimd_l2_f32_skylake(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n, simsimd_distance_t* d);
|
|
144
154
|
SIMSIMD_PUBLIC void simsimd_l2sq_f32_skylake(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n, simsimd_distance_t* d);
|
|
@@ -595,10 +605,10 @@ SIMSIMD_PUBLIC void simsimd_l2sq_i8_neon(simsimd_i8_t const *a, simsimd_i8_t con
|
|
|
595
605
|
uint8x16_t d_vec = vreinterpretq_u8_s8(vabdq_s8(a_vec, b_vec));
|
|
596
606
|
d2_vec = vdotq_u32(d2_vec, d_vec, d_vec);
|
|
597
607
|
}
|
|
598
|
-
|
|
608
|
+
simsimd_u32_t d2 = vaddvq_u32(d2_vec);
|
|
599
609
|
for (; i < n; ++i) {
|
|
600
|
-
|
|
601
|
-
d2 += (
|
|
610
|
+
simsimd_i32_t n = (simsimd_i32_t)a[i] - b[i];
|
|
611
|
+
d2 += (simsimd_u32_t)(n * n);
|
|
602
612
|
}
|
|
603
613
|
*result = d2;
|
|
604
614
|
}
|
|
@@ -693,9 +703,9 @@ SIMSIMD_PUBLIC void simsimd_cos_i8_neon(simsimd_i8_t const *a, simsimd_i8_t cons
|
|
|
693
703
|
// products_high_vec = vmmlaq_s32(products_high_vec, v_vec, y_w_vecs.val[1]);
|
|
694
704
|
// }
|
|
695
705
|
// int32x4_t products_vec = vaddq_s32(products_high_vec, products_low_vec);
|
|
696
|
-
//
|
|
697
|
-
//
|
|
698
|
-
//
|
|
706
|
+
// simsimd_i32_t a2 = products_vec[0];
|
|
707
|
+
// simsimd_i32_t ab = products_vec[1];
|
|
708
|
+
// simsimd_i32_t b2 = products_vec[3];
|
|
699
709
|
//
|
|
700
710
|
// That solution is elegant, but it requires the additional `+i8mm` extension and is currently slower,
|
|
701
711
|
// at least on AWS Graviton 3.
|
|
@@ -709,13 +719,13 @@ SIMSIMD_PUBLIC void simsimd_cos_i8_neon(simsimd_i8_t const *a, simsimd_i8_t cons
|
|
|
709
719
|
a2_vec = vdotq_s32(a2_vec, a_vec, a_vec);
|
|
710
720
|
b2_vec = vdotq_s32(b2_vec, b_vec, b_vec);
|
|
711
721
|
}
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
722
|
+
simsimd_i32_t ab = vaddvq_s32(ab_vec);
|
|
723
|
+
simsimd_i32_t a2 = vaddvq_s32(a2_vec);
|
|
724
|
+
simsimd_i32_t b2 = vaddvq_s32(b2_vec);
|
|
715
725
|
|
|
716
726
|
// Take care of the tail:
|
|
717
727
|
for (; i < n; ++i) {
|
|
718
|
-
|
|
728
|
+
simsimd_i32_t ai = a[i], bi = b[i];
|
|
719
729
|
ab += ai * bi, a2 += ai * ai, b2 += bi * bi;
|
|
720
730
|
}
|
|
721
731
|
|
|
@@ -737,10 +747,10 @@ SIMSIMD_PUBLIC void simsimd_l2sq_u8_neon(simsimd_u8_t const *a, simsimd_u8_t con
|
|
|
737
747
|
uint8x16_t d_vec = vabdq_u8(a_vec, b_vec);
|
|
738
748
|
d2_vec = vdotq_u32(d2_vec, d_vec, d_vec);
|
|
739
749
|
}
|
|
740
|
-
|
|
750
|
+
simsimd_u32_t d2 = vaddvq_u32(d2_vec);
|
|
741
751
|
for (; i < n; ++i) {
|
|
742
|
-
|
|
743
|
-
d2 += (
|
|
752
|
+
simsimd_i32_t n = (simsimd_i32_t)a[i] - b[i];
|
|
753
|
+
d2 += (simsimd_u32_t)(n * n);
|
|
744
754
|
}
|
|
745
755
|
*result = d2;
|
|
746
756
|
}
|
|
@@ -759,13 +769,13 @@ SIMSIMD_PUBLIC void simsimd_cos_u8_neon(simsimd_u8_t const *a, simsimd_u8_t cons
|
|
|
759
769
|
a2_vec = vdotq_u32(a2_vec, a_vec, a_vec);
|
|
760
770
|
b2_vec = vdotq_u32(b2_vec, b_vec, b_vec);
|
|
761
771
|
}
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
772
|
+
simsimd_u32_t ab = vaddvq_u32(ab_vec);
|
|
773
|
+
simsimd_u32_t a2 = vaddvq_u32(a2_vec);
|
|
774
|
+
simsimd_u32_t b2 = vaddvq_u32(b2_vec);
|
|
765
775
|
|
|
766
776
|
// Take care of the tail:
|
|
767
777
|
for (; i < n; ++i) {
|
|
768
|
-
|
|
778
|
+
simsimd_u32_t ai = a[i], bi = b[i];
|
|
769
779
|
ab += ai * bi, a2 += ai * ai, b2 += bi * bi;
|
|
770
780
|
}
|
|
771
781
|
|
|
@@ -1050,7 +1060,7 @@ SIMSIMD_INTERNAL simsimd_distance_t _simsimd_cos_normalize_f32_haswell(simsimd_f
|
|
|
1050
1060
|
// Load the squares into an __m128 register for single-precision floating-point operations
|
|
1051
1061
|
__m128 squares = _mm_set_ps(a2, b2, a2, b2); // We replicate to make use of full register
|
|
1052
1062
|
|
|
1053
|
-
// Compute the reciprocal square root of the squares using _mm_rsqrt_ps (single-precision)
|
|
1063
|
+
// Compute the reciprocal square root of the squares using `_mm_rsqrt_ps` (single-precision)
|
|
1054
1064
|
__m128 rsqrts = _mm_rsqrt_ps(squares);
|
|
1055
1065
|
|
|
1056
1066
|
// Perform one iteration of Newton-Raphson refinement to improve the precision of rsqrt:
|
|
@@ -458,6 +458,30 @@ typedef union {
|
|
|
458
458
|
float f;
|
|
459
459
|
} simsimd_f32i32_t;
|
|
460
460
|
|
|
461
|
+
/** @brief Convenience type addressing the real and imaginary parts of a half-precision complex number. */
|
|
462
|
+
typedef struct {
|
|
463
|
+
simsimd_f16_t real;
|
|
464
|
+
simsimd_f16_t imag;
|
|
465
|
+
} simsimd_f16c_t;
|
|
466
|
+
|
|
467
|
+
/** @brief Convenience type addressing the real and imaginary parts of a half-precision brain-float complex number. */
|
|
468
|
+
typedef struct {
|
|
469
|
+
simsimd_bf16_t real;
|
|
470
|
+
simsimd_bf16_t imag;
|
|
471
|
+
} simsimd_bf16c_t;
|
|
472
|
+
|
|
473
|
+
/** @brief Convenience type addressing the real and imaginary parts of a single-precision complex number. */
|
|
474
|
+
typedef struct {
|
|
475
|
+
simsimd_f32_t real;
|
|
476
|
+
simsimd_f32_t imag;
|
|
477
|
+
} simsimd_f32c_t;
|
|
478
|
+
|
|
479
|
+
/** @brief Convenience type addressing the real and imaginary parts of a double-precision complex number. */
|
|
480
|
+
typedef struct {
|
|
481
|
+
simsimd_f64_t real;
|
|
482
|
+
simsimd_f64_t imag;
|
|
483
|
+
} simsimd_f64c_t;
|
|
484
|
+
|
|
461
485
|
/**
|
|
462
486
|
* @brief Computes `1/sqrt(x)` using the trick from Quake 3,
|
|
463
487
|
* replacing the magic numbers with the ones suggested by Jan Kadlec.
|
|
@@ -171,7 +171,7 @@ export const jaccard = (a: Uint8Array, b: Uint8Array): number => {
|
|
|
171
171
|
};
|
|
172
172
|
|
|
173
173
|
/**
|
|
174
|
-
* @brief Computes the
|
|
174
|
+
* @brief Computes the Kullback-Leibler divergence between two probability distributions.
|
|
175
175
|
* @param {Float64Array|Float32Array} a - The first vector.
|
|
176
176
|
* @param {Float64Array|Float32Array} b - The second vector.
|
|
177
177
|
* @returns {number} The Jaccard similarity coefficient between vectors a and b.
|
|
@@ -182,38 +182,49 @@ export const kullbackleibler = (a: Float64Array | Float32Array, b: Float64Array
|
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
let divergence = 0.0;
|
|
185
|
-
|
|
186
185
|
for (let i = 0; i < a.length; i++) {
|
|
187
|
-
if (a[i]
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
186
|
+
if (a[i] < 0 || b[i] < 0) {
|
|
187
|
+
throw new Error("Negative values are not allowed in probability distributions");
|
|
188
|
+
}
|
|
189
|
+
if (b[i] === 0) {
|
|
190
|
+
throw new Error(
|
|
191
|
+
"Division by zero encountered in KL divergence calculation"
|
|
192
|
+
);
|
|
194
193
|
}
|
|
194
|
+
divergence += a[i] * Math.log(a[i] / b[i]);
|
|
195
195
|
}
|
|
196
196
|
|
|
197
197
|
return divergence;
|
|
198
198
|
};
|
|
199
199
|
|
|
200
200
|
/**
|
|
201
|
-
* @brief Computes the
|
|
202
|
-
* @param {Float64Array|Float32Array} a - The first
|
|
203
|
-
* @param {Float64Array|Float32Array} b - The second
|
|
204
|
-
* @returns {number} The
|
|
201
|
+
* @brief Computes the Jensen-Shannon distance between two probability distributions.
|
|
202
|
+
* @param {Float64Array|Float32Array} a - The first probability distribution.
|
|
203
|
+
* @param {Float64Array|Float32Array} b - The second probability distribution.
|
|
204
|
+
* @returns {number} The Jensen-Shannon distance between distributions a and b.
|
|
205
205
|
*/
|
|
206
206
|
export const jensenshannon = (a: Float64Array | Float32Array, b: Float64Array | Float32Array): number => {
|
|
207
207
|
if (a.length !== b.length) {
|
|
208
208
|
throw new Error("Arrays must be of the same length");
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
-
|
|
211
|
+
let divergence = 0;
|
|
212
|
+
for (let i = 0; i < a.length; i++) {
|
|
213
|
+
if (a[i] < 0 || b[i] < 0) {
|
|
214
|
+
throw new Error("Negative values are not allowed in probability distributions");
|
|
215
|
+
}
|
|
216
|
+
const m = (a[i] + b[i]) / 2;
|
|
217
|
+
if (m > 0) {
|
|
218
|
+
if (a[i] > 0) divergence += a[i] * Math.log(a[i] / m);
|
|
219
|
+
if (b[i] > 0) divergence += b[i] * Math.log(b[i] / m);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
212
222
|
|
|
213
|
-
|
|
223
|
+
divergence /= 2;
|
|
214
224
|
return Math.sqrt(divergence);
|
|
215
225
|
};
|
|
216
226
|
|
|
227
|
+
|
|
217
228
|
export default {
|
|
218
229
|
sqeuclidean,
|
|
219
230
|
euclidean,
|
|
@@ -33,7 +33,7 @@ export const sqeuclidean = (
|
|
|
33
33
|
* @brief Computes the Euclidean distance between two vectors.
|
|
34
34
|
* @param {Float64Array|Float32Array|Int8Array|Uint8Array} a - The first vector.
|
|
35
35
|
* @param {Float64Array|Float32Array|Int8Array|Uint8Array} b - The second vector.
|
|
36
|
-
* @returns {number} The
|
|
36
|
+
* @returns {number} The Euclidean distance between vectors a and b.
|
|
37
37
|
*/
|
|
38
38
|
export const euclidean = (
|
|
39
39
|
a: Float64Array | Float32Array | Int8Array | Uint8Array,
|