usearch 2.9.2 → 2.10.0

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 (172) hide show
  1. package/README.md +39 -38
  2. package/javascript/{types → dist/cjs}/usearch.d.ts +90 -115
  3. package/javascript/dist/cjs/usearch.js +531 -0
  4. package/javascript/dist/esm/usearch.d.ts +212 -0
  5. package/javascript/{usearch.js → dist/esm/usearch.js} +199 -153
  6. package/package.json +25 -23
  7. package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
  8. package/prebuilds/linux-arm64/usearch.node +0 -0
  9. package/prebuilds/linux-x64/usearch.node +0 -0
  10. package/prebuilds/win32-ia32/usearch.node +0 -0
  11. package/prebuilds/win32-x64/usearch.node +0 -0
  12. package/.clang-format +0 -10
  13. package/.clang-tidy +0 -60
  14. package/.cmake-format.py +0 -19
  15. package/.dockerignore +0 -93
  16. package/.gitattributes +0 -9
  17. package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -90
  18. package/.github/ISSUE_TEMPLATE/config.yml +0 -5
  19. package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -64
  20. package/.github/workflows/Dockerfile.libs +0 -36
  21. package/.github/workflows/prerelease.yml +0 -331
  22. package/.github/workflows/release.yml +0 -722
  23. package/.github/workflows/update_version.sh +0 -15
  24. package/.gitmodules +0 -9
  25. package/.releaserc +0 -90
  26. package/CITATION.cff +0 -11
  27. package/CMakeLists.txt +0 -324
  28. package/CODE_OF_CONDUCT.md +0 -128
  29. package/CONTRIBUTING.md +0 -361
  30. package/Cargo.toml +0 -19
  31. package/Dockerfile +0 -16
  32. package/VERSION +0 -1
  33. package/assets/unum.png +0 -0
  34. package/assets/usearch-approaches-transparent.png +0 -0
  35. package/assets/usearch-approaches-white.png +0 -0
  36. package/assets/usearch-neighbor-types.png +0 -0
  37. package/binding.gyp +0 -87
  38. package/build.gradle +0 -204
  39. package/build.rs +0 -18
  40. package/c/CMakeLists.txt +0 -25
  41. package/c/README.md +0 -34
  42. package/c/lib.cpp +0 -358
  43. package/c/test.c +0 -382
  44. package/c/usearch.h +0 -311
  45. package/cmake/clipp.cmake +0 -7
  46. package/cmake/config.cmake.in +0 -15
  47. package/cmake/emscripten.cmake +0 -8
  48. package/cmake/jemalloc.cmake +0 -62
  49. package/cmake/pkg-config.pc.in +0 -4
  50. package/cmake/usearchConfigVersion.cmake.in +0 -20
  51. package/conanfile.py +0 -26
  52. package/cpp/CMakeLists.txt +0 -14
  53. package/cpp/README.md +0 -161
  54. package/cpp/bench.cpp +0 -618
  55. package/cpp/test.cpp +0 -323
  56. package/fp16/CMakeLists.txt +0 -176
  57. package/fp16/LICENSE +0 -11
  58. package/fp16/README.md +0 -20
  59. package/fp16/bench/alt-element.cc +0 -89
  60. package/fp16/bench/from-alt-array.cc +0 -175
  61. package/fp16/bench/from-ieee-array.cc +0 -399
  62. package/fp16/bench/ieee-element.cc +0 -272
  63. package/fp16/bench/to-alt-array.cc +0 -91
  64. package/fp16/bench/to-ieee-array.cc +0 -303
  65. package/fp16/cmake/DownloadGoogleBenchmark.cmake +0 -15
  66. package/fp16/cmake/DownloadGoogleTest.cmake +0 -15
  67. package/fp16/cmake/DownloadPSimd.cmake +0 -15
  68. package/fp16/configure.py +0 -65
  69. package/fp16/confu.yaml +0 -8
  70. package/fp16/include/fp16/__init__.py +0 -0
  71. package/fp16/include/fp16/avx.py +0 -50
  72. package/fp16/include/fp16/avx2.py +0 -53
  73. package/fp16/include/fp16/bitcasts.h +0 -92
  74. package/fp16/include/fp16/fp16.h +0 -451
  75. package/fp16/include/fp16/psimd.h +0 -131
  76. package/fp16/include/fp16.h +0 -11
  77. package/fp16/jni/Android.mk +0 -6
  78. package/fp16/jni/Application.mk +0 -4
  79. package/fp16/test/alt-from-fp32-value.cc +0 -498
  80. package/fp16/test/alt-to-fp32-bits.cc +0 -263
  81. package/fp16/test/alt-to-fp32-psimd.cc +0 -145
  82. package/fp16/test/alt-to-fp32-value.cc +0 -348
  83. package/fp16/test/alt-to-fp32x2-psimd.cc +0 -245
  84. package/fp16/test/bitcasts.cc +0 -56
  85. package/fp16/test/ieee-from-fp32-value.cc +0 -523
  86. package/fp16/test/ieee-to-fp32-bits.cc +0 -333
  87. package/fp16/test/ieee-to-fp32-psimd.cc +0 -312
  88. package/fp16/test/ieee-to-fp32-value.cc +0 -420
  89. package/fp16/test/ieee-to-fp32x2-psimd.cc +0 -541
  90. package/fp16/test/peachpy/alt-xmm-to-fp32-xmm-avx.cc +0 -96
  91. package/fp16/test/peachpy/alt-xmm-to-fp32-ymm-avx2.cc +0 -96
  92. package/fp16/test/peachpy/stubs.py +0 -38
  93. package/fp16/test/tables.cc +0 -530
  94. package/fp16/test/tables.h +0 -13
  95. package/fp16/third-party/THHalf.h +0 -92
  96. package/fp16/third-party/eigen-half.h +0 -170
  97. package/fp16/third-party/float16-compressor.h +0 -80
  98. package/fp16/third-party/half.hpp +0 -2916
  99. package/fp16/third-party/npy-halffloat.h +0 -328
  100. package/include/usearch/index.hpp +0 -3836
  101. package/include/usearch/index_dense.hpp +0 -2004
  102. package/include/usearch/index_plugins.hpp +0 -2213
  103. package/javascript/lib.cpp +0 -341
  104. package/javascript/types/usearch.d.ts.map +0 -1
  105. package/javascript/usearch.test.js +0 -74
  106. package/package-ci.json +0 -10
  107. package/pyproject.toml +0 -51
  108. package/setup.py +0 -201
  109. package/simsimd/.releaserc +0 -86
  110. package/simsimd/CONTRIBUTING.md +0 -88
  111. package/simsimd/Cargo.lock +0 -709
  112. package/simsimd/Cargo.toml +0 -44
  113. package/simsimd/LICENSE +0 -201
  114. package/simsimd/README.md +0 -317
  115. package/simsimd/binding.gyp +0 -36
  116. package/simsimd/build.rs +0 -20
  117. package/simsimd/include/simsimd/binary.h +0 -245
  118. package/simsimd/include/simsimd/complex.h +0 -174
  119. package/simsimd/include/simsimd/probability.h +0 -548
  120. package/simsimd/include/simsimd/simsimd.h +0 -465
  121. package/simsimd/include/simsimd/spatial.h +0 -1267
  122. package/simsimd/include/simsimd/types.h +0 -208
  123. package/simsimd/javascript/bench.js +0 -127
  124. package/simsimd/javascript/fallback.ts +0 -193
  125. package/simsimd/javascript/lib.c +0 -102
  126. package/simsimd/javascript/node-gyp-build.d.ts +0 -1
  127. package/simsimd/javascript/simsimd.ts +0 -124
  128. package/simsimd/javascript/test.mjs +0 -153
  129. package/simsimd/javascript/tsconfig-base.json +0 -25
  130. package/simsimd/javascript/tsconfig-cjs.json +0 -8
  131. package/simsimd/javascript/tsconfig-esm.json +0 -8
  132. package/simsimd/package-lock.json +0 -1688
  133. package/simsimd/package.json +0 -61
  134. package/simsimd/rust/benches/cosine.rs +0 -27
  135. package/simsimd/rust/benches/native.rs +0 -30
  136. package/simsimd/rust/benches/sqeuclidean.rs +0 -27
  137. package/simsimd/rust/lib.c +0 -45
  138. package/simsimd/rust/lib.rs +0 -550
  139. package/sqlite/README.md +0 -178
  140. package/sqlite/lib.cpp +0 -325
  141. package/stringzilla/CONTRIBUTING.md +0 -446
  142. package/stringzilla/Cargo.lock +0 -25
  143. package/stringzilla/Cargo.toml +0 -26
  144. package/stringzilla/LICENSE +0 -201
  145. package/stringzilla/README.md +0 -1422
  146. package/stringzilla/VERSION +0 -1
  147. package/stringzilla/assets/cover-strinzilla.jpeg +0 -0
  148. package/stringzilla/assets/meme-stringzilla-v2.jpeg +0 -0
  149. package/stringzilla/assets/meme-stringzilla-v3.jpeg +0 -0
  150. package/stringzilla/binding.gyp +0 -16
  151. package/stringzilla/build.rs +0 -87
  152. package/stringzilla/c/lib.c +0 -337
  153. package/stringzilla/cli/README.md +0 -65
  154. package/stringzilla/cli/__init__.py +0 -0
  155. package/stringzilla/cli/split.py +0 -105
  156. package/stringzilla/cli/wc.py +0 -117
  157. package/stringzilla/include/stringzilla/experimental.h +0 -845
  158. package/stringzilla/include/stringzilla/module.modulemap +0 -9
  159. package/stringzilla/include/stringzilla/stringzilla.h +0 -5370
  160. package/stringzilla/include/stringzilla/stringzilla.hpp +0 -3838
  161. package/stringzilla/javascript/lib.c +0 -125
  162. package/stringzilla/javascript/stringzilla.js +0 -22
  163. package/stringzilla/package-ci.json +0 -10
  164. package/stringzilla/package.json +0 -32
  165. package/stringzilla/rust/lib.rs +0 -873
  166. package/stringzilla/swift/StringProtocol+StringZilla.swift +0 -280
  167. package/stringzilla/swift/Test.swift +0 -60
  168. package/tsconfig.json +0 -21
  169. package/wasmer.toml +0 -12
  170. package/winlibinstaller.bat +0 -42
  171. /package/{simsimd/javascript/dist-package-cjs.json → javascript/dist/cjs/package.json} +0 -0
  172. /package/{simsimd/javascript/dist-package-esm.json → javascript/dist/esm/package.json} +0 -0
@@ -1,548 +0,0 @@
1
- /**
2
- * @brief SIMD-accelerated Similarity Measures for Probability Distributions.
3
- * @author Ash Vardanian
4
- * @date October 20, 2023
5
- *
6
- * Contains:
7
- * - Kullback-Leibler divergence
8
- * - Jensen–Shannon divergence
9
- *
10
- * For datatypes:
11
- * - 32-bit floating point numbers
12
- * - 16-bit floating point numbers
13
- *
14
- * For hardware architectures:
15
- * - Arm (NEON, SVE)
16
- * - x86 (AVX2, AVX512)
17
- *
18
- * x86 intrinsics: https://www.intel.com/content/www/us/en/docs/intrinsics-guide/
19
- * Arm intrinsics: https://developer.arm.com/architectures/instruction-sets/intrinsics/
20
- */
21
- #ifndef SIMSIMD_PROBABILITY_H
22
- #define SIMSIMD_PROBABILITY_H
23
-
24
- #include "types.h"
25
-
26
- #define SIMSIMD_MAKE_KL(name, input_type, accumulator_type, converter, epsilon) \
27
- inline static simsimd_f32_t simsimd_##name##_##input_type##_kl( \
28
- simsimd_##input_type##_t const* a, simsimd_##input_type##_t const* b, simsimd_size_t n) { \
29
- simsimd_##accumulator_type##_t d = 0; \
30
- for (simsimd_size_t i = 0; i != n; ++i) { \
31
- simsimd_##accumulator_type##_t ai = converter(a[i]); \
32
- simsimd_##accumulator_type##_t bi = converter(b[i]); \
33
- d += ai * SIMSIMD_LOG((ai + epsilon) / (bi + epsilon)); \
34
- } \
35
- return (simsimd_f32_t)d; \
36
- }
37
-
38
- #define SIMSIMD_MAKE_JS(name, input_type, accumulator_type, converter, epsilon) \
39
- inline static simsimd_f32_t simsimd_##name##_##input_type##_js( \
40
- simsimd_##input_type##_t const* a, simsimd_##input_type##_t const* b, simsimd_size_t n) { \
41
- simsimd_##accumulator_type##_t d = 0; \
42
- for (simsimd_size_t i = 0; i != n; ++i) { \
43
- simsimd_##accumulator_type##_t ai = converter(a[i]); \
44
- simsimd_##accumulator_type##_t bi = converter(b[i]); \
45
- simsimd_##accumulator_type##_t mi = (ai + bi) / 2; \
46
- d += ai * SIMSIMD_LOG((ai + epsilon) / (mi + epsilon)); \
47
- d += bi * SIMSIMD_LOG((bi + epsilon) / (mi + epsilon)); \
48
- } \
49
- return (simsimd_f32_t)d / 2; \
50
- }
51
-
52
- #ifdef __cplusplus
53
- extern "C" {
54
- #endif
55
-
56
- SIMSIMD_MAKE_KL(serial, f64, f64, SIMSIMD_IDENTIFY, SIMSIMD_F32_DIVISION_EPSILON) // simsimd_serial_f64_kl
57
- SIMSIMD_MAKE_JS(serial, f64, f64, SIMSIMD_IDENTIFY, SIMSIMD_F32_DIVISION_EPSILON) // simsimd_serial_f64_js
58
-
59
- SIMSIMD_MAKE_KL(serial, f32, f32, SIMSIMD_IDENTIFY, SIMSIMD_F32_DIVISION_EPSILON) // simsimd_serial_f32_kl
60
- SIMSIMD_MAKE_JS(serial, f32, f32, SIMSIMD_IDENTIFY, SIMSIMD_F32_DIVISION_EPSILON) // simsimd_serial_f32_js
61
-
62
- SIMSIMD_MAKE_KL(serial, f16, f32, SIMSIMD_UNCOMPRESS_F16, SIMSIMD_F32_DIVISION_EPSILON) // simsimd_serial_f16_kl
63
- SIMSIMD_MAKE_JS(serial, f16, f32, SIMSIMD_UNCOMPRESS_F16, SIMSIMD_F32_DIVISION_EPSILON) // simsimd_serial_f16_js
64
-
65
- SIMSIMD_MAKE_KL(accurate, f32, f64, SIMSIMD_IDENTIFY, SIMSIMD_F32_DIVISION_EPSILON) // simsimd_accurate_f32_kl
66
- SIMSIMD_MAKE_JS(accurate, f32, f64, SIMSIMD_IDENTIFY, SIMSIMD_F32_DIVISION_EPSILON) // simsimd_accurate_f32_js
67
-
68
- SIMSIMD_MAKE_KL(accurate, f16, f64, SIMSIMD_UNCOMPRESS_F16, SIMSIMD_F32_DIVISION_EPSILON) // simsimd_accurate_f16_kl
69
- SIMSIMD_MAKE_JS(accurate, f16, f64, SIMSIMD_UNCOMPRESS_F16, SIMSIMD_F32_DIVISION_EPSILON) // simsimd_accurate_f16_js
70
-
71
- #if SIMSIMD_TARGET_ARM
72
- #if SIMSIMD_TARGET_ARM_NEON
73
-
74
- /*
75
- * @file arm_neon_f32.h
76
- * @brief Arm NEON implementation of the most common similarity metrics for 32-bit floating point numbers.
77
- * @author Ash Vardanian
78
- *
79
- * - Implements: Kullback-Leibler and Jensen–Shannon divergence.
80
- * - Uses `f32` for storage and `f32` for accumulation.
81
- * - Requires compiler capabilities: +simd.
82
- */
83
-
84
- __attribute__((target("+simd"))) //
85
- inline float32x4_t
86
- simsimd_neon_f32_log2(float32x4_t x) {
87
- // Extracting the exponent
88
- int32x4_t i = vreinterpretq_s32_f32(x);
89
- int32x4_t e = vsubq_s32(vshrq_n_s32(vandq_s32(i, vdupq_n_s32(0x7F800000)), 23), vdupq_n_s32(127));
90
- float32x4_t e_float = vcvtq_f32_s32(e);
91
-
92
- // Extracting the mantissa
93
- float32x4_t m = vreinterpretq_f32_s32(vorrq_s32(vandq_s32(i, vdupq_n_s32(0x007FFFFF)), vdupq_n_s32(0x3F800000)));
94
-
95
- // Constants for polynomial
96
- float32x4_t one = vdupq_n_f32(1.0f);
97
- float32x4_t p = vdupq_n_f32(-3.4436006e-2f);
98
-
99
- // Compute polynomial using Horner's method
100
- p = vmlaq_f32(vdupq_n_f32(3.1821337e-1f), m, p);
101
- p = vmlaq_f32(vdupq_n_f32(-1.2315303f), m, p);
102
- p = vmlaq_f32(vdupq_n_f32(2.5988452f), m, p);
103
- p = vmlaq_f32(vdupq_n_f32(-3.3241990f), m, p);
104
- p = vmlaq_f32(vdupq_n_f32(3.1157899f), m, p);
105
-
106
- // Final computation
107
- float32x4_t result = vaddq_f32(vmulq_f32(p, vsubq_f32(m, one)), e_float);
108
- return result;
109
- }
110
-
111
- __attribute__((target("+simd"))) //
112
- inline static simsimd_f32_t
113
- simsimd_neon_f32_kl(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n) {
114
- float32x4_t sum_vec = vdupq_n_f32(0);
115
- simsimd_f32_t epsilon = SIMSIMD_F32_DIVISION_EPSILON;
116
- float32x4_t epsilon_vec = vdupq_n_f32(epsilon);
117
- simsimd_size_t i = 0;
118
- for (; i + 4 <= n; i += 4) {
119
- float32x4_t a_vec = vld1q_f32(a + i);
120
- float32x4_t b_vec = vld1q_f32(b + i);
121
- float32x4_t ratio_vec = vdivq_f32(vaddq_f32(a_vec, epsilon_vec), vaddq_f32(b_vec, epsilon_vec));
122
- float32x4_t log_ratio_vec = simsimd_neon_f32_log2(ratio_vec);
123
- float32x4_t prod_vec = vmulq_f32(a_vec, log_ratio_vec);
124
- sum_vec = vaddq_f32(sum_vec, prod_vec);
125
- }
126
- simsimd_f32_t log2_normalizer = 0.693147181f;
127
- simsimd_f32_t sum = vaddvq_f32(sum_vec) * log2_normalizer;
128
- for (; i < n; ++i)
129
- sum += a[i] * SIMSIMD_LOG((a[i] + epsilon) / (b[i] + epsilon));
130
- return sum;
131
- }
132
-
133
- __attribute__((target("+simd"))) inline static simsimd_f32_t
134
- simsimd_neon_f32_js(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n) {
135
- float32x4_t sum_vec = vdupq_n_f32(0);
136
- simsimd_f32_t epsilon = SIMSIMD_F32_DIVISION_EPSILON;
137
- float32x4_t epsilon_vec = vdupq_n_f32(epsilon);
138
- simsimd_size_t i = 0;
139
- for (; i + 4 <= n; i += 4) {
140
- float32x4_t a_vec = vld1q_f32(a + i);
141
- float32x4_t b_vec = vld1q_f32(b + i);
142
- float32x4_t m_vec = vmulq_f32(vaddq_f32(a_vec, b_vec), vdupq_n_f32(0.5));
143
- float32x4_t ratio_a_vec = vdivq_f32(vaddq_f32(a_vec, epsilon_vec), vaddq_f32(m_vec, epsilon_vec));
144
- float32x4_t ratio_b_vec = vdivq_f32(vaddq_f32(b_vec, epsilon_vec), vaddq_f32(m_vec, epsilon_vec));
145
- float32x4_t log_ratio_a_vec = simsimd_neon_f32_log2(ratio_a_vec);
146
- float32x4_t log_ratio_b_vec = simsimd_neon_f32_log2(ratio_b_vec);
147
- float32x4_t prod_a_vec = vmulq_f32(a_vec, log_ratio_a_vec);
148
- float32x4_t prod_b_vec = vmulq_f32(b_vec, log_ratio_b_vec);
149
- sum_vec = vaddq_f32(sum_vec, vaddq_f32(prod_a_vec, prod_b_vec));
150
- }
151
- simsimd_f32_t log2_normalizer = 0.693147181f;
152
- simsimd_f32_t sum = vaddvq_f32(sum_vec) * log2_normalizer;
153
- for (; i < n; ++i) {
154
- simsimd_f32_t mi = 0.5f * (a[i] + b[i]);
155
- sum += a[i] * SIMSIMD_LOG((a[i] + epsilon) / (mi + epsilon));
156
- sum += b[i] * SIMSIMD_LOG((b[i] + epsilon) / (mi + epsilon));
157
- }
158
- return sum;
159
- }
160
-
161
- /*
162
- * @file arm_neon_f16.h
163
- * @brief Arm NEON implementation of the most common similarity metrics for 16-bit floating point numbers.
164
- * @author Ash Vardanian
165
- *
166
- * - Implements: Kullback-Leibler and Jensen–Shannon divergence.
167
- * - Uses `f16` for storage and `f32` for accumulation, as the 16-bit FMA may not always be available.
168
- * - Requires compiler capabilities: +simd+fp16.
169
- */
170
-
171
- __attribute__((target("+simd+fp16"))) //
172
- inline static simsimd_f32_t
173
- simsimd_neon_f16_kl(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n) {
174
- float32x4_t sum_vec = vdupq_n_f32(0);
175
- simsimd_f32_t epsilon = SIMSIMD_F32_DIVISION_EPSILON;
176
- float32x4_t epsilon_vec = vdupq_n_f32(epsilon);
177
- simsimd_size_t i = 0;
178
- for (; i + 4 <= n; i += 4) {
179
- float32x4_t a_vec = vcvt_f32_f16(vld1_f16((float16_t const*)a + i));
180
- float32x4_t b_vec = vcvt_f32_f16(vld1_f16((float16_t const*)b + i));
181
- float32x4_t ratio_vec = vdivq_f32(vaddq_f32(a_vec, epsilon_vec), vaddq_f32(b_vec, epsilon_vec));
182
- float32x4_t log_ratio_vec = simsimd_neon_f32_log2(ratio_vec);
183
- float32x4_t prod_vec = vmulq_f32(a_vec, log_ratio_vec);
184
- sum_vec = vaddq_f32(sum_vec, prod_vec);
185
- }
186
- simsimd_f32_t log2_normalizer = 0.693147181f;
187
- simsimd_f32_t sum = vaddvq_f32(sum_vec) * log2_normalizer;
188
- for (; i < n; ++i)
189
- sum += SIMSIMD_UNCOMPRESS_F16(a[i]) *
190
- SIMSIMD_LOG((SIMSIMD_UNCOMPRESS_F16(a[i]) + epsilon) / (SIMSIMD_UNCOMPRESS_F16(b[i]) + epsilon));
191
- return sum;
192
- }
193
-
194
- __attribute__((target("+simd+fp16"))) //
195
- inline static simsimd_f32_t
196
- simsimd_neon_f16_js(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n) {
197
- float32x4_t sum_vec = vdupq_n_f32(0);
198
- simsimd_f32_t epsilon = SIMSIMD_F32_DIVISION_EPSILON;
199
- float32x4_t epsilon_vec = vdupq_n_f32(epsilon);
200
- simsimd_size_t i = 0;
201
- for (; i + 4 <= n; i += 4) {
202
- float32x4_t a_vec = vcvt_f32_f16(vld1_f16((float16_t const*)a + i));
203
- float32x4_t b_vec = vcvt_f32_f16(vld1_f16((float16_t const*)b + i));
204
- float32x4_t m_vec = vmulq_f32(vaddq_f32(a_vec, b_vec), vdupq_n_f32(0.5));
205
- float32x4_t ratio_a_vec = vdivq_f32(vaddq_f32(a_vec, epsilon_vec), vaddq_f32(m_vec, epsilon_vec));
206
- float32x4_t ratio_b_vec = vdivq_f32(vaddq_f32(b_vec, epsilon_vec), vaddq_f32(m_vec, epsilon_vec));
207
- float32x4_t log_ratio_a_vec = simsimd_neon_f32_log2(ratio_a_vec);
208
- float32x4_t log_ratio_b_vec = simsimd_neon_f32_log2(ratio_b_vec);
209
- float32x4_t prod_a_vec = vmulq_f32(a_vec, log_ratio_a_vec);
210
- float32x4_t prod_b_vec = vmulq_f32(b_vec, log_ratio_b_vec);
211
- sum_vec = vaddq_f32(sum_vec, vaddq_f32(prod_a_vec, prod_b_vec));
212
- }
213
- simsimd_f32_t log2_normalizer = 0.693147181f;
214
- simsimd_f32_t sum = vaddvq_f32(sum_vec) * log2_normalizer;
215
- for (; i < n; ++i) {
216
- simsimd_f32_t ai = SIMSIMD_UNCOMPRESS_F16(a[i]);
217
- simsimd_f32_t bi = SIMSIMD_UNCOMPRESS_F16(b[i]);
218
- simsimd_f32_t mi = 0.5f * (ai + bi);
219
- sum += ai * SIMSIMD_LOG((ai + epsilon) / (mi + epsilon));
220
- sum += bi * SIMSIMD_LOG((bi + epsilon) / (mi + epsilon));
221
- }
222
- return sum;
223
- }
224
-
225
- #endif // SIMSIMD_TARGET_ARM_NEON
226
- #endif // SIMSIMD_TARGET_ARM
227
-
228
- #if SIMSIMD_TARGET_X86
229
- #if SIMSIMD_TARGET_X86_AVX2
230
-
231
- /*
232
- * @file x86_avx2_f16.h
233
- * @brief x86 AVX2 implementation of the most common similarity metrics for 16-bit floating point numbers.
234
- * @author Ash Vardanian
235
- *
236
- * - Implements: Kullback-Leibler and Jensen–Shannon divergence.
237
- * - As AVX2 doesn't support masked loads of 16-bit words, implementations have a separate `for`-loop for tails.
238
- * - Uses `f16` for both storage and `f32` for accumulation.
239
- * - Requires compiler capabilities: avx2, f16c, fma.
240
- */
241
-
242
- __attribute__((target("avx2,f16c,fma"))) //
243
- inline __m256
244
- simsimd_avx2_f32_log2(__m256 x) {
245
- // Extracting the exponent
246
- __m256i i = _mm256_castps_si256(x);
247
- __m256i e = _mm256_srli_epi32(_mm256_and_si256(i, _mm256_set1_epi32(0x7F800000)), 23);
248
- e = _mm256_sub_epi32(e, _mm256_set1_epi32(127)); // removing the bias
249
- __m256 e_float = _mm256_cvtepi32_ps(e);
250
-
251
- // Extracting the mantissa
252
- __m256 m = _mm256_castsi256_ps(
253
- _mm256_or_si256(_mm256_and_si256(i, _mm256_set1_epi32(0x007FFFFF)), _mm256_set1_epi32(0x3F800000)));
254
-
255
- // Constants for polynomial
256
- __m256 one = _mm256_set1_ps(1.0f);
257
- __m256 p = _mm256_set1_ps(-3.4436006e-2f);
258
-
259
- // Compute the polynomial using Horner's method
260
- p = _mm256_fmadd_ps(m, p, _mm256_set1_ps(3.1821337e-1f));
261
- p = _mm256_fmadd_ps(m, p, _mm256_set1_ps(-1.2315303f));
262
- p = _mm256_fmadd_ps(m, p, _mm256_set1_ps(2.5988452f));
263
- p = _mm256_fmadd_ps(m, p, _mm256_set1_ps(-3.3241990f));
264
- p = _mm256_fmadd_ps(m, p, _mm256_set1_ps(3.1157899f));
265
-
266
- // Final computation
267
- __m256 result = _mm256_add_ps(_mm256_mul_ps(p, _mm256_sub_ps(m, one)), e_float);
268
- return result;
269
- }
270
-
271
- __attribute__((target("avx2,f16c,fma"))) //
272
- inline static simsimd_f32_t
273
- simsimd_avx2_f16_kl(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n) {
274
- __m256 sum_vec = _mm256_setzero_ps();
275
- simsimd_f32_t epsilon = SIMSIMD_F32_DIVISION_EPSILON;
276
- __m256 epsilon_vec = _mm256_set1_ps(epsilon);
277
- simsimd_size_t i = 0;
278
- for (; i + 8 <= n; i += 8) {
279
- __m256 a_vec = _mm256_cvtph_ps(_mm_loadu_si128((__m128i const*)(a + i)));
280
- __m256 b_vec = _mm256_cvtph_ps(_mm_loadu_si128((__m128i const*)(b + i)));
281
- __m256 ratio_vec = _mm256_div_ps(_mm256_add_ps(a_vec, epsilon_vec), _mm256_add_ps(b_vec, epsilon_vec));
282
- __m256 log_ratio_vec = simsimd_avx2_f32_log2(ratio_vec);
283
- __m256 prod_vec = _mm256_mul_ps(a_vec, log_ratio_vec);
284
- sum_vec = _mm256_add_ps(sum_vec, prod_vec);
285
- }
286
-
287
- sum_vec = _mm256_add_ps(_mm256_permute2f128_ps(sum_vec, sum_vec, 1), sum_vec);
288
- sum_vec = _mm256_hadd_ps(sum_vec, sum_vec);
289
- sum_vec = _mm256_hadd_ps(sum_vec, sum_vec);
290
-
291
- simsimd_f32_t log2_normalizer = 0.693147181f;
292
- simsimd_f32_t sum;
293
- _mm_store_ss(&sum, _mm256_castps256_ps128(sum_vec));
294
- sum *= log2_normalizer;
295
-
296
- // Accumulate the tail:
297
- for (; i < n; ++i)
298
- sum += SIMSIMD_UNCOMPRESS_F16(a[i]) *
299
- SIMSIMD_LOG((SIMSIMD_UNCOMPRESS_F16(a[i]) + epsilon) / (SIMSIMD_UNCOMPRESS_F16(b[i]) + epsilon));
300
- return sum;
301
- }
302
-
303
- __attribute__((target("avx2,f16c,fma"))) //
304
- inline static simsimd_f32_t
305
- simsimd_avx2_f16_js(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n) {
306
- __m256 sum_vec = _mm256_setzero_ps();
307
- simsimd_f32_t epsilon = SIMSIMD_F32_DIVISION_EPSILON;
308
- __m256 epsilon_vec = _mm256_set1_ps(epsilon);
309
- simsimd_size_t i = 0;
310
- for (; i + 8 <= n; i += 8) {
311
- __m256 a_vec = _mm256_add_ps(_mm256_cvtph_ps(_mm_loadu_si128((__m128i const*)(a + i))), epsilon_vec);
312
- __m256 b_vec = _mm256_add_ps(_mm256_cvtph_ps(_mm_loadu_si128((__m128i const*)(b + i))), epsilon_vec);
313
- __m256 m_vec = _mm256_mul_ps(_mm256_add_ps(a_vec, b_vec), _mm256_set1_ps(0.5f)); // M = (P + Q) / 2
314
- __m256 ratio_a_vec = _mm256_div_ps(a_vec, m_vec);
315
- __m256 ratio_b_vec = _mm256_div_ps(b_vec, m_vec);
316
- __m256 log_ratio_a_vec = simsimd_avx2_f32_log2(ratio_a_vec);
317
- __m256 log_ratio_b_vec = simsimd_avx2_f32_log2(ratio_b_vec);
318
- __m256 prod_a_vec = _mm256_mul_ps(a_vec, log_ratio_a_vec);
319
- __m256 prod_b_vec = _mm256_mul_ps(b_vec, log_ratio_b_vec);
320
- sum_vec = _mm256_add_ps(sum_vec, prod_a_vec);
321
- sum_vec = _mm256_add_ps(sum_vec, prod_b_vec);
322
- }
323
-
324
- sum_vec = _mm256_add_ps(_mm256_permute2f128_ps(sum_vec, sum_vec, 1), sum_vec);
325
- sum_vec = _mm256_hadd_ps(sum_vec, sum_vec);
326
- sum_vec = _mm256_hadd_ps(sum_vec, sum_vec);
327
-
328
- simsimd_f32_t log2_normalizer = 0.693147181f;
329
- simsimd_f32_t sum;
330
- _mm_store_ss(&sum, _mm256_castps256_ps128(sum_vec));
331
- sum *= log2_normalizer;
332
-
333
- // Accumulate the tail:
334
- for (; i < n; ++i) {
335
- simsimd_f32_t ai = SIMSIMD_UNCOMPRESS_F16(a[i]);
336
- simsimd_f32_t bi = SIMSIMD_UNCOMPRESS_F16(b[i]);
337
- simsimd_f32_t mi = ai + bi;
338
- sum += ai * SIMSIMD_LOG((ai + epsilon) / (mi + epsilon));
339
- sum += bi * SIMSIMD_LOG((bi + epsilon) / (mi + epsilon));
340
- }
341
- return sum / 2;
342
- }
343
-
344
- #endif // SIMSIMD_TARGET_X86_AVX2
345
-
346
- #if SIMSIMD_TARGET_X86_AVX512
347
-
348
- /*
349
- * @file x86_avx512_f32.h
350
- * @brief x86 AVX-512 implementation of the most common similarity metrics for 32-bit floating point numbers.
351
- * @author Ash Vardanian
352
- *
353
- * - Implements: Kullback-Leibler and Jensen–Shannon divergence.
354
- * - Uses `f32` for storage and `f32` for accumulation.
355
- * - Requires compiler capabilities: avx512f, avx512vl.
356
- */
357
-
358
- __attribute__((target("avx512f,avx512vl"))) //
359
- inline __m512
360
- simsimd_avx512_f32_log2(__m512 x) {
361
- // Extract the exponent and mantissa
362
- __m512 one = _mm512_set1_ps(1.0f);
363
- __m512 e = _mm512_getexp_ps(x);
364
- __m512 m = _mm512_getmant_ps(x, _MM_MANT_NORM_1_2, _MM_MANT_SIGN_src);
365
-
366
- // Compute the polynomial using Horner's method
367
- __m512 p = _mm512_set1_ps(-3.4436006e-2f);
368
- p = _mm512_fmadd_ps(m, p, _mm512_set1_ps(3.1821337e-1f));
369
- p = _mm512_fmadd_ps(m, p, _mm512_set1_ps(-1.2315303f));
370
- p = _mm512_fmadd_ps(m, p, _mm512_set1_ps(2.5988452f));
371
- p = _mm512_fmadd_ps(m, p, _mm512_set1_ps(-3.3241990f));
372
- p = _mm512_fmadd_ps(m, p, _mm512_set1_ps(3.1157899f));
373
-
374
- return _mm512_add_ps(_mm512_mul_ps(p, _mm512_sub_ps(m, one)), e);
375
- }
376
-
377
- __attribute__((target("avx512f,avx512vl,bmi2"))) //
378
- inline static simsimd_f32_t
379
- simsimd_avx512_f32_kl(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n) {
380
- __m512 sum_vec = _mm512_setzero();
381
- simsimd_f32_t epsilon = SIMSIMD_F32_DIVISION_EPSILON;
382
- __m512 epsilon_vec = _mm512_set1_ps(epsilon);
383
- __m512 a_vec, b_vec;
384
-
385
- simsimd_avx512_f32_kl_cycle:
386
- if (n < 16) {
387
- __mmask16 mask = _bzhi_u32(0xFFFFFFFF, n);
388
- a_vec = _mm512_add_ps(_mm512_maskz_loadu_ps(mask, a), epsilon_vec);
389
- b_vec = _mm512_add_ps(_mm512_maskz_loadu_ps(mask, b), epsilon_vec);
390
- n = 0;
391
- } else {
392
- a_vec = _mm512_add_ps(_mm512_loadu_ps(a), epsilon_vec);
393
- b_vec = _mm512_add_ps(_mm512_loadu_ps(b), epsilon_vec);
394
- a += 16, b += 16, n -= 16;
395
- }
396
- __m512 ratio_vec = _mm512_div_ps(a_vec, b_vec);
397
- __m512 log_ratio_vec = simsimd_avx512_f32_log2(ratio_vec);
398
- __m512 prod_vec = _mm512_mul_ps(a_vec, log_ratio_vec);
399
- sum_vec = _mm512_add_ps(sum_vec, prod_vec);
400
- if (n)
401
- goto simsimd_avx512_f32_kl_cycle;
402
-
403
- simsimd_f32_t log2_normalizer = 0.693147181f;
404
- return _mm512_reduce_add_ps(sum_vec) * log2_normalizer;
405
- }
406
-
407
- __attribute__((target("avx512f,avx512vl,bmi2"))) //
408
- inline static simsimd_f32_t
409
- simsimd_avx512_f32_js(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n) {
410
- __m512 sum_a_vec = _mm512_setzero();
411
- __m512 sum_b_vec = _mm512_setzero();
412
- simsimd_f32_t epsilon = SIMSIMD_F32_DIVISION_EPSILON;
413
- __m512 epsilon_vec = _mm512_set1_ps(epsilon);
414
- __m512 a_vec, b_vec;
415
-
416
- simsimd_avx512_f32_js_cycle:
417
- if (n < 16) {
418
- __mmask16 mask = _bzhi_u32(0xFFFFFFFF, n);
419
- a_vec = _mm512_maskz_loadu_ps(mask, a);
420
- b_vec = _mm512_maskz_loadu_ps(mask, b);
421
- n = 0;
422
- } else {
423
- a_vec = _mm512_loadu_ps(a);
424
- b_vec = _mm512_loadu_ps(b);
425
- a += 16, b += 16, n -= 16;
426
- }
427
- __m512 m_vec = _mm512_mul_ps(_mm512_add_ps(a_vec, b_vec), _mm512_set1_ps(0.5f));
428
- __mmask16 nonzero_mask_a = _mm512_cmp_ps_mask(a_vec, epsilon_vec, _CMP_GE_OQ);
429
- __mmask16 nonzero_mask_b = _mm512_cmp_ps_mask(b_vec, epsilon_vec, _CMP_GE_OQ);
430
- __mmask16 nonzero_mask = nonzero_mask_a & nonzero_mask_b;
431
- __m512 m_recip_approx = _mm512_rcp14_ps(m_vec);
432
- __m512 ratio_a_vec = _mm512_mul_ps(a_vec, m_recip_approx);
433
- __m512 ratio_b_vec = _mm512_mul_ps(b_vec, m_recip_approx);
434
- __m512 log_ratio_a_vec = simsimd_avx512_f32_log2(ratio_a_vec);
435
- __m512 log_ratio_b_vec = simsimd_avx512_f32_log2(ratio_b_vec);
436
- sum_a_vec = _mm512_maskz_fmadd_ps(nonzero_mask, a_vec, log_ratio_a_vec, sum_a_vec);
437
- sum_b_vec = _mm512_maskz_fmadd_ps(nonzero_mask, b_vec, log_ratio_b_vec, sum_b_vec);
438
- if (n)
439
- goto simsimd_avx512_f32_js_cycle;
440
-
441
- simsimd_f32_t log2_normalizer = 0.693147181f;
442
- return _mm512_reduce_add_ps(_mm512_add_ps(sum_a_vec, sum_b_vec)) * 0.5f * log2_normalizer;
443
- }
444
-
445
- /*
446
- * @file x86_avx512_f16.h
447
- * @brief x86 AVX-512 implementation of the most common similarity metrics for 16-bit floating point numbers.
448
- * @author Ash Vardanian
449
- *
450
- * - Implements: Kullback-Leibler and Jensen–Shannon divergence.
451
- * - Uses `_mm512_maskz_loadu_epi16` intrinsics to perform masked unaligned loads.
452
- * - Uses `f16` for both storage and accumulation, assuming it's resolution is enough for average case.
453
- * - Requires compiler capabilities: avx512fp16, avx512f, avx512vl.
454
- */
455
-
456
- __attribute__((target("avx512f,avx512vl,avx512fp16"))) //
457
- inline __m512h
458
- simsimd_avx512_f16_log2(__m512h x) {
459
- // Extract the exponent and mantissa
460
- __m512h one = _mm512_set1_ph((_Float16)1);
461
- __m512h e = _mm512_getexp_ph(x);
462
- __m512h m = _mm512_getmant_ph(x, _MM_MANT_NORM_1_2, _MM_MANT_SIGN_src);
463
-
464
- // Compute the polynomial using Horner's method
465
- __m512h p = _mm512_set1_ph((_Float16)-3.4436006e-2f);
466
- p = _mm512_fmadd_ph(m, p, _mm512_set1_ph((_Float16)3.1821337e-1f));
467
- p = _mm512_fmadd_ph(m, p, _mm512_set1_ph((_Float16)-1.2315303f));
468
- p = _mm512_fmadd_ph(m, p, _mm512_set1_ph((_Float16)2.5988452f));
469
- p = _mm512_fmadd_ph(m, p, _mm512_set1_ph((_Float16)-3.3241990f));
470
- p = _mm512_fmadd_ph(m, p, _mm512_set1_ph((_Float16)3.1157899f));
471
-
472
- return _mm512_add_ph(_mm512_mul_ph(p, _mm512_sub_ph(m, one)), e);
473
- }
474
-
475
- __attribute__((target("avx512f,avx512vl,avx512fp16,bmi2"))) //
476
- inline static simsimd_f32_t
477
- simsimd_avx512_f16_kl(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n) {
478
- __m512h sum_vec = _mm512_set1_ph((_Float16)0);
479
- __m512h epsilon_vec = _mm512_set1_ph((_Float16)SIMSIMD_F16_DIVISION_EPSILON);
480
- __m512h a_vec, b_vec;
481
-
482
- simsimd_avx512_f16_kl_cycle:
483
- if (n < 32) {
484
- __mmask32 mask = _bzhi_u32(0xFFFFFFFF, n);
485
- a_vec = _mm512_maskz_add_ph(mask, _mm512_castsi512_ph(_mm512_maskz_loadu_epi16(mask, a)), epsilon_vec);
486
- b_vec = _mm512_maskz_add_ph(mask, _mm512_castsi512_ph(_mm512_maskz_loadu_epi16(mask, b)), epsilon_vec);
487
- n = 0;
488
- } else {
489
- a_vec = _mm512_add_ph(_mm512_castsi512_ph(_mm512_loadu_epi16(a)), epsilon_vec);
490
- b_vec = _mm512_add_ph(_mm512_castsi512_ph(_mm512_loadu_epi16(b)), epsilon_vec);
491
- a += 32, b += 32, n -= 32;
492
- }
493
- __m512h ratio_vec = _mm512_div_ph(a_vec, b_vec);
494
- __m512h log_ratio_vec = simsimd_avx512_f16_log2(ratio_vec);
495
- __m512h prod_vec = _mm512_mul_ph(a_vec, log_ratio_vec);
496
- sum_vec = _mm512_add_ph(sum_vec, prod_vec);
497
- if (n)
498
- goto simsimd_avx512_f16_kl_cycle;
499
-
500
- simsimd_f32_t log2_normalizer = 0.693147181f;
501
- return _mm512_reduce_add_ph(sum_vec) * log2_normalizer;
502
- }
503
-
504
- __attribute__((target("avx512f,avx512vl,avx512fp16,bmi2"))) //
505
- inline static simsimd_f32_t
506
- simsimd_avx512_f16_js(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n) {
507
- __m512h sum_a_vec = _mm512_set1_ph((_Float16)0);
508
- __m512h sum_b_vec = _mm512_set1_ph((_Float16)0);
509
- __m512h epsilon_vec = _mm512_set1_ph((_Float16)SIMSIMD_F16_DIVISION_EPSILON);
510
- __m512h a_vec, b_vec;
511
-
512
- simsimd_avx512_f16_js_cycle:
513
- if (n < 32) {
514
- __mmask32 mask = _bzhi_u32(0xFFFFFFFF, n);
515
- a_vec = _mm512_castsi512_ph(_mm512_maskz_loadu_epi16(mask, a));
516
- b_vec = _mm512_castsi512_ph(_mm512_maskz_loadu_epi16(mask, b));
517
- n = 0;
518
- } else {
519
- a_vec = _mm512_castsi512_ph(_mm512_loadu_epi16(a));
520
- b_vec = _mm512_castsi512_ph(_mm512_loadu_epi16(b));
521
- a += 32, b += 32, n -= 32;
522
- }
523
- __m512h m_vec = _mm512_mul_ph(_mm512_add_ph(a_vec, b_vec), _mm512_set1_ph((_Float16)0.5f));
524
- __mmask32 nonzero_mask_a = _mm512_cmp_ph_mask(a_vec, epsilon_vec, _CMP_GE_OQ);
525
- __mmask32 nonzero_mask_b = _mm512_cmp_ph_mask(b_vec, epsilon_vec, _CMP_GE_OQ);
526
- __mmask32 nonzero_mask = nonzero_mask_a & nonzero_mask_b;
527
- __m512h m_recip_approx = _mm512_rcp_ph(m_vec);
528
- __m512h ratio_a_vec = _mm512_mul_ph(a_vec, m_recip_approx);
529
- __m512h ratio_b_vec = _mm512_mul_ph(b_vec, m_recip_approx);
530
- __m512h log_ratio_a_vec = simsimd_avx512_f16_log2(ratio_a_vec);
531
- __m512h log_ratio_b_vec = simsimd_avx512_f16_log2(ratio_b_vec);
532
- sum_a_vec = _mm512_maskz_fmadd_ph(nonzero_mask, a_vec, log_ratio_a_vec, sum_a_vec);
533
- sum_b_vec = _mm512_maskz_fmadd_ph(nonzero_mask, b_vec, log_ratio_b_vec, sum_b_vec);
534
- if (n)
535
- goto simsimd_avx512_f16_js_cycle;
536
-
537
- simsimd_f32_t log2_normalizer = 0.693147181f;
538
- return _mm512_reduce_add_ph(_mm512_add_ph(sum_a_vec, sum_b_vec)) * 0.5f * log2_normalizer;
539
- }
540
-
541
- #endif // SIMSIMD_TARGET_X86_AVX512
542
- #endif // SIMSIMD_TARGET_X86
543
-
544
- #ifdef __cplusplus
545
- }
546
- #endif
547
-
548
- #endif