usearch 2.15.2 → 2.16.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 (54) hide show
  1. package/README.md +1 -1
  2. package/binding.gyp +1 -1
  3. package/c/CMakeLists.txt +10 -3
  4. package/cpp/README.md +1 -1
  5. package/cpp/bench.cpp +2 -2
  6. package/cpp/test.cpp +16 -0
  7. package/include/usearch/index.hpp +44 -17
  8. package/include/usearch/index_dense.hpp +51 -89
  9. package/include/usearch/index_plugins.hpp +468 -43
  10. package/javascript/lib.cpp +17 -5
  11. package/javascript/usearch.test.js +205 -34
  12. package/package.json +1 -1
  13. package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
  14. package/prebuilds/linux-arm64/usearch.node +0 -0
  15. package/prebuilds/linux-x64/usearch.node +0 -0
  16. package/simsimd/.git-blame-ignore-revs +2 -0
  17. package/simsimd/CODE_OF_CONDUCT.md +128 -0
  18. package/simsimd/CONTRIBUTING.md +84 -26
  19. package/simsimd/Cargo.lock +1 -1
  20. package/simsimd/Cargo.toml +4 -4
  21. package/simsimd/MANIFEST.in +3 -0
  22. package/simsimd/Package.swift +15 -3
  23. package/simsimd/README.md +534 -177
  24. package/simsimd/binding.gyp +6 -2
  25. package/simsimd/build.rs +13 -1
  26. package/simsimd/c/lib.c +266 -53
  27. package/simsimd/include/simsimd/binary.h +321 -112
  28. package/simsimd/include/simsimd/curved.h +803 -0
  29. package/simsimd/include/simsimd/dot.h +694 -521
  30. package/simsimd/include/simsimd/elementwise.h +1437 -0
  31. package/simsimd/include/simsimd/geospatial.h +9 -3
  32. package/simsimd/include/simsimd/mesh.h +69 -0
  33. package/simsimd/include/simsimd/probability.h +234 -206
  34. package/simsimd/include/simsimd/simsimd.h +1476 -617
  35. package/simsimd/include/simsimd/sparse.h +1428 -0
  36. package/simsimd/include/simsimd/spatial.h +1556 -742
  37. package/simsimd/include/simsimd/types.h +276 -132
  38. package/simsimd/javascript/lib.c +1 -2
  39. package/simsimd/javascript/simsimd.ts +4 -4
  40. package/simsimd/package.json +4 -4
  41. package/simsimd/rust/lib.rs +179 -1
  42. package/simsimd/scripts/bench.cxx +1070 -0
  43. package/simsimd/scripts/bench.ipynb +187 -0
  44. package/simsimd/{javascript → scripts}/bench.js +1 -1
  45. package/simsimd/{rust/benches/sqeuclidean.rs → scripts/bench_sqeuclidean.rs} +6 -6
  46. package/simsimd/scripts/bench_vectors.py +700 -0
  47. package/simsimd/scripts/bench_vectors_live.py +213 -0
  48. package/simsimd/scripts/test.c +155 -0
  49. package/simsimd/{javascript → scripts}/test.mjs +2 -2
  50. package/simsimd/scripts/test.py +1410 -0
  51. package/simsimd/swift/{source/SimSIMD.swift → SimSIMD.swift} +6 -2
  52. package/simsimd/swift/{tests/SimSIMDTests.swift → Test.swift} +1 -1
  53. /package/simsimd/{rust/benches/cosine.rs → scripts/bench_cosine.rs} +0 -0
  54. /package/simsimd/{rust/benches/native.rs → scripts/bench_native.rs} +0 -0
@@ -6,18 +6,19 @@
6
6
  *
7
7
  * Defines:
8
8
  * - Sized aliases for numeric types, like: `simsimd_i32_t` and `simsimd_f64_t`.
9
- * - Macros for compiler/hardware checks, like: `SIMSIMD_TARGET_NEON`
9
+ * - Macros for internal compiler/hardware checks, like: `_SIMSIMD_TARGET_ARM`.
10
+ * - Macros for feature controls, like: `SIMSIMD_TARGET_NEON`
10
11
  */
11
12
  #ifndef SIMSIMD_TYPES_H
12
13
  #define SIMSIMD_TYPES_H
13
14
 
14
15
  // Inferring target OS: Windows, MacOS, or Linux
15
16
  #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
16
- #define SIMSIMD_DEFINED_WINDOWS
17
+ #define _SIMSIMD_DEFINED_WINDOWS 1
17
18
  #elif defined(__APPLE__) && defined(__MACH__)
18
- #define SIMSIMD_DEFINED_APPLE
19
+ #define _SIMSIMD_DEFINED_APPLE 1
19
20
  #elif defined(__linux__)
20
- #define SIMSIMD_DEFINED_LINUX
21
+ #define _SIMSIMD_DEFINED_LINUX 1
21
22
  #endif
22
23
 
23
24
  // Annotation for the public API symbols:
@@ -35,68 +36,118 @@
35
36
  #define SIMSIMD_PUBLIC __attribute__((unused)) inline static
36
37
  #define SIMSIMD_INTERNAL __attribute__((always_inline)) inline static
37
38
  #else
38
- #define SIMSIMD_DYNAMIC inline static
39
+ #define SIMSIMD_DYNAMIC
39
40
  #define SIMSIMD_PUBLIC inline static
40
41
  #define SIMSIMD_INTERNAL inline static
41
42
  #endif
42
43
 
43
- // Compiling for Arm: SIMSIMD_TARGET_ARM
44
- #if !defined(SIMSIMD_TARGET_ARM)
44
+ // Compiling for Arm: _SIMSIMD_TARGET_ARM
45
+ #if !defined(_SIMSIMD_TARGET_ARM)
45
46
  #if defined(__aarch64__) || defined(_M_ARM64)
46
- #define SIMSIMD_TARGET_ARM 1
47
+ #define _SIMSIMD_TARGET_ARM 1
47
48
  #else
48
- #define SIMSIMD_TARGET_ARM 0
49
+ #define _SIMSIMD_TARGET_ARM 0
49
50
  #endif // defined(__aarch64__) || defined(_M_ARM64)
50
- #endif // !defined(SIMSIMD_TARGET_ARM)
51
+ #endif // !defined(_SIMSIMD_TARGET_ARM)
51
52
 
52
- // Compiling for x86: SIMSIMD_TARGET_X86
53
- #if !defined(SIMSIMD_TARGET_X86)
53
+ // Compiling for x86: _SIMSIMD_TARGET_X86
54
+ #if !defined(_SIMSIMD_TARGET_X86)
54
55
  #if defined(__x86_64__) || defined(_M_X64)
55
- #define SIMSIMD_TARGET_X86 1
56
+ #define _SIMSIMD_TARGET_X86 1
56
57
  #else
57
- #define SIMSIMD_TARGET_X86 0
58
+ #define _SIMSIMD_TARGET_X86 0
58
59
  #endif // defined(__x86_64__) || defined(_M_X64)
59
- #endif // !defined(SIMSIMD_TARGET_X86)
60
+ #endif // !defined(_SIMSIMD_TARGET_X86)
60
61
 
61
62
  // Compiling for Arm: SIMSIMD_TARGET_NEON
62
- #if !defined(SIMSIMD_TARGET_NEON) || (SIMSIMD_TARGET_NEON && !SIMSIMD_TARGET_ARM)
63
+ #if !defined(SIMSIMD_TARGET_NEON) || (SIMSIMD_TARGET_NEON && !_SIMSIMD_TARGET_ARM)
63
64
  #if defined(__ARM_NEON)
64
- #define SIMSIMD_TARGET_NEON SIMSIMD_TARGET_ARM
65
+ #define SIMSIMD_TARGET_NEON _SIMSIMD_TARGET_ARM
65
66
  #else
66
67
  #undef SIMSIMD_TARGET_NEON
67
68
  #define SIMSIMD_TARGET_NEON 0
68
69
  #endif // defined(__ARM_NEON)
69
- #endif // !defined(SIMSIMD_TARGET_NEON)
70
-
71
- #if !defined(SIMSIMD_TARGET_NEON_I8)
72
- #define SIMSIMD_TARGET_NEON_I8 SIMSIMD_TARGET_NEON
73
- #endif // !defined(SIMSIMD_TARGET_NEON_I8)
74
- #if !defined(SIMSIMD_TARGET_NEON_F16)
75
- #define SIMSIMD_TARGET_NEON_F16 SIMSIMD_TARGET_NEON
76
- #endif // !defined(SIMSIMD_TARGET_NEON_F16)
77
- #if !defined(SIMSIMD_TARGET_NEON_BF16)
78
- #define SIMSIMD_TARGET_NEON_BF16 SIMSIMD_TARGET_NEON
79
- #endif // !defined(SIMSIMD_TARGET_NEON_BF16)
70
+ #endif // !defined(SIMSIMD_TARGET_NEON) || ...
71
+
72
+ // Compiling for Arm: SIMSIMD_TARGET_NEON_I8
73
+ #if !defined(SIMSIMD_TARGET_NEON_I8) || (SIMSIMD_TARGET_NEON_I8 && !_SIMSIMD_TARGET_ARM)
74
+ #if defined(__ARM_NEON)
75
+ #define SIMSIMD_TARGET_NEON_I8 _SIMSIMD_TARGET_ARM
76
+ #else
77
+ #undef SIMSIMD_TARGET_NEON_I8
78
+ #define SIMSIMD_TARGET_NEON_I8 0
79
+ #endif // defined(__ARM_NEON)
80
+ #endif // !defined(SIMSIMD_TARGET_NEON_I8) || ...
81
+
82
+ // Compiling for Arm: SIMSIMD_TARGET_NEON_F16
83
+ #if !defined(SIMSIMD_TARGET_NEON_F16) || (SIMSIMD_TARGET_NEON_F16 && !_SIMSIMD_TARGET_ARM)
84
+ #if defined(__ARM_NEON)
85
+ #define SIMSIMD_TARGET_NEON_F16 _SIMSIMD_TARGET_ARM
86
+ #else
87
+ #undef SIMSIMD_TARGET_NEON_F16
88
+ #define SIMSIMD_TARGET_NEON_F16 0
89
+ #endif // defined(__ARM_NEON)
90
+ #endif // !defined(SIMSIMD_TARGET_NEON_F16) || ...
91
+
92
+ // Compiling for Arm: SIMSIMD_TARGET_NEON_BF16
93
+ #if !defined(SIMSIMD_TARGET_NEON_BF16) || (SIMSIMD_TARGET_NEON_BF16 && !_SIMSIMD_TARGET_ARM)
94
+ #if defined(__ARM_NEON)
95
+ #define SIMSIMD_TARGET_NEON_BF16 _SIMSIMD_TARGET_ARM
96
+ #else
97
+ #undef SIMSIMD_TARGET_NEON_BF16
98
+ #define SIMSIMD_TARGET_NEON_BF16 0
99
+ #endif // defined(__ARM_NEON)
100
+ #endif // !defined(SIMSIMD_TARGET_NEON_BF16) || ...
80
101
 
81
102
  // Compiling for Arm: SIMSIMD_TARGET_SVE
82
- #if !defined(SIMSIMD_TARGET_SVE) || (SIMSIMD_TARGET_SVE && !SIMSIMD_TARGET_ARM)
103
+ #if !defined(SIMSIMD_TARGET_SVE) || (SIMSIMD_TARGET_SVE && !_SIMSIMD_TARGET_ARM)
83
104
  #if defined(__ARM_FEATURE_SVE)
84
- #define SIMSIMD_TARGET_SVE SIMSIMD_TARGET_ARM
105
+ #define SIMSIMD_TARGET_SVE _SIMSIMD_TARGET_ARM
85
106
  #else
86
107
  #undef SIMSIMD_TARGET_SVE
87
108
  #define SIMSIMD_TARGET_SVE 0
88
109
  #endif // defined(__ARM_FEATURE_SVE)
89
- #endif // !defined(SIMSIMD_TARGET_SVE)
90
-
91
- #if !defined(SIMSIMD_TARGET_SVE_I8)
92
- #define SIMSIMD_TARGET_SVE_I8 SIMSIMD_TARGET_SVE
93
- #endif // !defined(SIMSIMD_TARGET_SVE_I8)
94
- #if !defined(SIMSIMD_TARGET_SVE_F16)
95
- #define SIMSIMD_TARGET_SVE_F16 SIMSIMD_TARGET_SVE
96
- #endif // !defined(SIMSIMD_TARGET_SVE_F16)
97
- #if !defined(SIMSIMD_TARGET_SVE_BF16)
98
- #define SIMSIMD_TARGET_SVE_BF16 SIMSIMD_TARGET_SVE
99
- #endif // !defined(SIMSIMD_TARGET_SVE_BF16)
110
+ #endif // !defined(SIMSIMD_TARGET_SVE) || ...
111
+
112
+ // Compiling for Arm: SIMSIMD_TARGET_SVE_I8
113
+ #if !defined(SIMSIMD_TARGET_SVE_I8) || (SIMSIMD_TARGET_SVE_I8 && !_SIMSIMD_TARGET_ARM)
114
+ #if defined(__ARM_FEATURE_SVE)
115
+ #define SIMSIMD_TARGET_SVE_I8 _SIMSIMD_TARGET_ARM
116
+ #else
117
+ #undef SIMSIMD_TARGET_SVE_I8
118
+ #define SIMSIMD_TARGET_SVE_I8 0
119
+ #endif // defined(__ARM_FEATURE_SVE)
120
+ #endif // !defined(SIMSIMD_TARGET_SVE_I8) || ...
121
+
122
+ // Compiling for Arm: SIMSIMD_TARGET_SVE_F16
123
+ #if !defined(SIMSIMD_TARGET_SVE_F16) || (SIMSIMD_TARGET_SVE_F16 && !_SIMSIMD_TARGET_ARM)
124
+ #if defined(__ARM_FEATURE_SVE)
125
+ #define SIMSIMD_TARGET_SVE_F16 _SIMSIMD_TARGET_ARM
126
+ #else
127
+ #undef SIMSIMD_TARGET_SVE_F16
128
+ #define SIMSIMD_TARGET_SVE_F16 0
129
+ #endif // defined(__ARM_FEATURE_SVE)
130
+ #endif // !defined(SIMSIMD_TARGET_SVE_F16) || ...
131
+
132
+ // Compiling for Arm: SIMSIMD_TARGET_SVE_BF16
133
+ #if !defined(SIMSIMD_TARGET_SVE_BF16) || (SIMSIMD_TARGET_SVE_BF16 && !_SIMSIMD_TARGET_ARM)
134
+ #if defined(__ARM_FEATURE_SVE)
135
+ #define SIMSIMD_TARGET_SVE_BF16 _SIMSIMD_TARGET_ARM
136
+ #else
137
+ #undef SIMSIMD_TARGET_SVE_BF16
138
+ #define SIMSIMD_TARGET_SVE_BF16 0
139
+ #endif // defined(__ARM_FEATURE_SVE)
140
+ #endif // !defined(SIMSIMD_TARGET_SVE_BF16) || ...
141
+
142
+ // Compiling for Arm: SIMSIMD_TARGET_SVE2
143
+ #if !defined(SIMSIMD_TARGET_SVE2) || (SIMSIMD_TARGET_SVE2 && !_SIMSIMD_TARGET_ARM)
144
+ #if defined(__ARM_FEATURE_SVE)
145
+ #define SIMSIMD_TARGET_SVE2 _SIMSIMD_TARGET_ARM
146
+ #else
147
+ #undef SIMSIMD_TARGET_SVE2
148
+ #define SIMSIMD_TARGET_SVE2 0
149
+ #endif // defined(__ARM_FEATURE_SVE)
150
+ #endif // !defined(SIMSIMD_TARGET_SVE2) || ...
100
151
 
101
152
  // Compiling for x86: SIMSIMD_TARGET_HASWELL
102
153
  //
@@ -105,55 +156,72 @@
105
156
  // are supported on all CPUs starting with Jaguar 2009.
106
157
  // Starting with Sandy Bridge, Intel adds basic AVX support in their CPUs and in 2013
107
158
  // extends it with AVX2 in the Haswell generation. Moreover, Haswell adds FMA support.
108
- #if !defined(SIMSIMD_TARGET_HASWELL) || (SIMSIMD_TARGET_HASWELL && !SIMSIMD_TARGET_X86)
159
+ #if !defined(SIMSIMD_TARGET_HASWELL) || (SIMSIMD_TARGET_HASWELL && !_SIMSIMD_TARGET_X86)
109
160
  #if defined(__AVX2__) && defined(__FMA__) && defined(__F16C__)
110
161
  #define SIMSIMD_TARGET_HASWELL 1
111
162
  #else
112
163
  #undef SIMSIMD_TARGET_HASWELL
113
164
  #define SIMSIMD_TARGET_HASWELL 0
114
165
  #endif // defined(__AVX2__)
115
- #endif // !defined(SIMSIMD_TARGET_HASWELL)
166
+ #endif // !defined(SIMSIMD_TARGET_HASWELL) || ...
116
167
 
117
- // Compiling for x86: SIMSIMD_TARGET_SKYLAKE, SIMSIMD_TARGET_ICE, SIMSIMD_TARGET_SAPPHIRE
168
+ // Compiling for x86: SIMSIMD_TARGET_SKYLAKE, SIMSIMD_TARGET_ICE, SIMSIMD_TARGET_GENOA,
169
+ // SIMSIMD_TARGET_SAPPHIRE, SIMSIMD_TARGET_TURIN, SIMSIMD_TARGET_SIERRA
118
170
  //
119
171
  // To list all available macros for x86, take a recent compiler, like GCC 12 and run:
120
172
  // gcc-12 -march=sapphirerapids -dM -E - < /dev/null | egrep "SSE|AVX" | sort
121
173
  // On Arm machines you may want to check for other flags:
122
174
  // gcc-12 -march=native -dM -E - < /dev/null | egrep "NEON|SVE|FP16|FMA" | sort
123
- #if !defined(SIMSIMD_TARGET_SKYLAKE) || (SIMSIMD_TARGET_SKYLAKE && !SIMSIMD_TARGET_X86)
124
- #if defined(__AVX512F__) && defined(__AVX512CD__) && defined(__AVX512VL__) && defined(__AVX512DQ__) && \
175
+ #if !defined(SIMSIMD_TARGET_SKYLAKE) || (SIMSIMD_TARGET_SKYLAKE && !_SIMSIMD_TARGET_X86)
176
+ #if defined(__AVX512F__) && defined(__AVX512CD__) && defined(__AVX512VL__) && defined(__AVX512DQ__) && \
125
177
  defined(__AVX512BW__)
126
178
  #define SIMSIMD_TARGET_SKYLAKE 1
127
179
  #else
128
180
  #undef SIMSIMD_TARGET_SKYLAKE
129
181
  #define SIMSIMD_TARGET_SKYLAKE 0
130
182
  #endif
131
- #endif // !defined(SIMSIMD_TARGET_SKYLAKE)
132
- #if !defined(SIMSIMD_TARGET_ICE) || (SIMSIMD_TARGET_ICE && !SIMSIMD_TARGET_X86)
133
- #if defined(__AVX512VNNI__) && defined(__AVX512IFMA__) && defined(__AVX512BITALG__) && defined(__AVX512VBMI2__) && \
183
+ #endif // !defined(SIMSIMD_TARGET_SKYLAKE) || ...
184
+ #if !defined(SIMSIMD_TARGET_ICE) || (SIMSIMD_TARGET_ICE && !_SIMSIMD_TARGET_X86)
185
+ #if defined(__AVX512VNNI__) && defined(__AVX512IFMA__) && defined(__AVX512BITALG__) && defined(__AVX512VBMI2__) && \
134
186
  defined(__AVX512VPOPCNTDQ__)
135
187
  #define SIMSIMD_TARGET_ICE 1
136
188
  #else
137
189
  #undef SIMSIMD_TARGET_ICE
138
190
  #define SIMSIMD_TARGET_ICE 0
139
191
  #endif
140
- #endif // !defined(SIMSIMD_TARGET_ICE)
141
- #if !defined(SIMSIMD_TARGET_GENOA) || (SIMSIMD_TARGET_GENOA && !SIMSIMD_TARGET_X86)
192
+ #endif // !defined(SIMSIMD_TARGET_ICE) || ...
193
+ #if !defined(SIMSIMD_TARGET_GENOA) || (SIMSIMD_TARGET_GENOA && !_SIMSIMD_TARGET_X86)
142
194
  #if defined(__AVX512BF16__)
143
195
  #define SIMSIMD_TARGET_GENOA 1
144
196
  #else
145
197
  #undef SIMSIMD_TARGET_GENOA
146
198
  #define SIMSIMD_TARGET_GENOA 0
147
199
  #endif
148
- #endif // !defined(SIMSIMD_TARGET_GENOA)
149
- #if !defined(SIMSIMD_TARGET_SAPPHIRE) || (SIMSIMD_TARGET_SAPPHIRE && !SIMSIMD_TARGET_X86)
200
+ #endif // !defined(SIMSIMD_TARGET_GENOA) || ...
201
+ #if !defined(SIMSIMD_TARGET_SAPPHIRE) || (SIMSIMD_TARGET_SAPPHIRE && !_SIMSIMD_TARGET_X86)
150
202
  #if defined(__AVX512FP16__)
151
203
  #define SIMSIMD_TARGET_SAPPHIRE 1
152
204
  #else
153
205
  #undef SIMSIMD_TARGET_SAPPHIRE
154
206
  #define SIMSIMD_TARGET_SAPPHIRE 0
155
207
  #endif
156
- #endif // !defined(SIMSIMD_TARGET_SAPPHIRE)
208
+ #endif // !defined(SIMSIMD_TARGET_SAPPHIRE) || ...
209
+ #if !defined(SIMSIMD_TARGET_TURIN) || (SIMSIMD_TARGET_TURIN && !_SIMSIMD_TARGET_X86)
210
+ #if defined(__AVX512VP2INTERSECT__)
211
+ #define SIMSIMD_TARGET_TURIN 1
212
+ #else
213
+ #undef SIMSIMD_TARGET_TURIN
214
+ #define SIMSIMD_TARGET_TURIN 0
215
+ #endif
216
+ #endif // !defined(SIMSIMD_TARGET_TURIN) || ...
217
+ #if !defined(SIMSIMD_TARGET_SIERRA) || (SIMSIMD_TARGET_SIERRA && !_SIMSIMD_TARGET_X86)
218
+ #if defined(__AVX2_VNNI__)
219
+ #define SIMSIMD_TARGET_SIERRA 1
220
+ #else
221
+ #undef SIMSIMD_TARGET_SIERRA
222
+ #define SIMSIMD_TARGET_SIERRA 0
223
+ #endif
224
+ #endif // !defined(SIMSIMD_TARGET_SIERRA) || ...
157
225
 
158
226
  #ifdef _MSC_VER
159
227
  #include <intrin.h>
@@ -163,31 +231,37 @@
163
231
  #include <arm_neon.h>
164
232
  #endif
165
233
 
166
- #if SIMSIMD_TARGET_SVE
234
+ #if SIMSIMD_TARGET_SVE || SIMSIMD_TARGET_SVE2
167
235
  #include <arm_sve.h>
168
236
  #endif
169
237
 
170
- #if SIMSIMD_TARGET_HASWELL || SIMSIMD_TARGET_SKYLAKE
238
+ #if SIMSIMD_TARGET_HASWELL || SIMSIMD_TARGET_SKYLAKE || SIMSIMD_TARGET_ICE || SIMSIMD_TARGET_GENOA || \
239
+ SIMSIMD_TARGET_SAPPHIRE || SIMSIMD_TARGET_TURIN
171
240
  #include <immintrin.h>
172
241
  #endif
173
242
 
174
243
  #endif
175
244
 
176
- #ifndef SIMSIMD_RSQRT
245
+ #if !defined(SIMSIMD_SQRT)
177
246
  #include <math.h>
178
- #define SIMSIMD_RSQRT(x) (1 / sqrtf(x))
247
+ #define SIMSIMD_SQRT(x) (sqrt(x))
179
248
  #endif
180
249
 
181
- #ifndef SIMSIMD_LOG
250
+ #if !defined(SIMSIMD_RSQRT)
182
251
  #include <math.h>
183
- #define SIMSIMD_LOG(x) (logf(x))
252
+ #define SIMSIMD_RSQRT(x) (1 / SIMSIMD_SQRT(x))
184
253
  #endif
185
254
 
186
- #ifndef SIMSIMD_F32_DIVISION_EPSILON
255
+ #if !defined(SIMSIMD_LOG)
256
+ #include <math.h>
257
+ #define SIMSIMD_LOG(x) (log(x))
258
+ #endif
259
+
260
+ #if !defined(SIMSIMD_F32_DIVISION_EPSILON)
187
261
  #define SIMSIMD_F32_DIVISION_EPSILON (1e-7)
188
262
  #endif
189
263
 
190
- #ifndef SIMSIMD_F16_DIVISION_EPSILON
264
+ #if !defined(SIMSIMD_F16_DIVISION_EPSILON)
191
265
  #define SIMSIMD_F16_DIVISION_EPSILON (1e-3)
192
266
  #endif
193
267
 
@@ -195,14 +269,21 @@
195
269
  extern "C" {
196
270
  #endif
197
271
 
198
- typedef int simsimd_i32_t;
199
- typedef float simsimd_f32_t;
200
- typedef double simsimd_f64_t;
201
- typedef signed char simsimd_i8_t;
202
272
  typedef unsigned char simsimd_b8_t;
203
- typedef long long simsimd_i64_t;
273
+ typedef unsigned char simsimd_i4x2_t;
274
+
275
+ typedef signed char simsimd_i8_t;
276
+ typedef unsigned char simsimd_u8_t;
277
+ typedef signed short simsimd_i16_t;
278
+ typedef unsigned short simsimd_u16_t;
279
+ typedef signed int simsimd_i32_t;
280
+ typedef unsigned int simsimd_u32_t;
281
+ typedef signed long long simsimd_i64_t;
204
282
  typedef unsigned long long simsimd_u64_t;
205
283
 
284
+ typedef float simsimd_f32_t;
285
+ typedef double simsimd_f64_t;
286
+
206
287
  typedef simsimd_u64_t simsimd_size_t;
207
288
  typedef simsimd_f64_t simsimd_distance_t;
208
289
 
@@ -213,19 +294,21 @@ typedef simsimd_f64_t simsimd_distance_t;
213
294
  * - Default: `unsigned short`.
214
295
  */
215
296
  #if !defined(SIMSIMD_NATIVE_F16) || SIMSIMD_NATIVE_F16
216
- #if (defined(__GNUC__) || defined(__clang__)) && (defined(__ARM_ARCH) || defined(__aarch64__)) && \
297
+ #if (defined(__GNUC__) || defined(__clang__)) && (defined(__ARM_ARCH) || defined(__aarch64__)) && \
217
298
  (defined(__ARM_FP16_FORMAT_IEEE))
218
- #if !defined(SIMSIMD_NATIVE_F16)
299
+ #undef SIMSIMD_NATIVE_F16
219
300
  #define SIMSIMD_NATIVE_F16 1
220
- #endif
221
301
  typedef __fp16 simsimd_f16_t;
222
- #elif ((defined(__GNUC__) || defined(__clang__)) && (defined(__x86_64__) || defined(__i386__)) && \
223
- (defined(__SSE2__) || defined(__AVX512F__)))
302
+ #elif ((defined(__GNUC__) || defined(__clang__)) && (defined(__x86_64__) || defined(__i386__)) && \
303
+ (defined(__AVX512FP16__)))
224
304
  typedef _Float16 simsimd_f16_t;
225
- #if !defined(SIMSIMD_NATIVE_F16)
305
+ #undef SIMSIMD_NATIVE_F16
226
306
  #define SIMSIMD_NATIVE_F16 1
307
+ #else // Unknown compiler or architecture
308
+ #if defined(__GNUC__) || defined(__clang__) // Some compilers don't support warning pragmas
309
+ #warning "Unknown compiler or architecture for float16."
227
310
  #endif
228
- #else // Unknown compiler or architecture
311
+ #undef SIMSIMD_NATIVE_F16
229
312
  #define SIMSIMD_NATIVE_F16 0
230
313
  #endif // Unknown compiler or architecture
231
314
  #endif // !SIMSIMD_NATIVE_F16
@@ -242,23 +325,38 @@ typedef unsigned short simsimd_f16_t;
242
325
  * - GCC or Clang on 64-bit x86: `_BFloat16`.
243
326
  * - Default: `unsigned short`.
244
327
  *
328
+ * The compilers have added `__bf16` support in compliance with the x86-64 psABI spec.
329
+ * The motivation for this new special type is summed up as:
330
+ *
331
+ * Currently `__bfloat16` is a typedef of short, which creates a problem where the
332
+ * compiler does not raise any alarms if it is used to add, subtract, multiply or
333
+ * divide, but the result of the calculation is actually meaningless.
334
+ * To solve this problem, a real scalar type `__Bfloat16` needs to be introduced.
335
+ * It is mainly used for intrinsics, not available for C standard operators.
336
+ * `__Bfloat16` will also be used for movement like passing parameter, load and store,
337
+ * vector initialization, vector shuffle, and etc. It creates a need for a
338
+ * corresponding psABI.
339
+ *
245
340
  * @warning Apple Clang has hard time with bf16.
246
341
  * https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms
247
342
  * https://forums.developer.apple.com/forums/thread/726201
343
+ * https://www.phoronix.com/news/GCC-LLVM-bf16-BFloat16-Type
248
344
  */
249
- #if (defined(__GNUC__) || defined(__clang__)) && (defined(__ARM_ARCH) || defined(__aarch64__)) && \
345
+ #if (defined(__GNUC__) || defined(__clang__)) && (defined(__ARM_ARCH) || defined(__aarch64__)) && \
250
346
  (defined(__ARM_BF16_FORMAT_ALTERNATIVE))
251
- #if !defined(SIMSIMD_NATIVE_BF16)
347
+ #undef SIMSIMD_NATIVE_BF16
252
348
  #define SIMSIMD_NATIVE_BF16 1
253
- #endif
254
- typedef __fp16 simsimd_bf16_t;
255
- #elif ((defined(__GNUC__) || defined(__clang__)) && (defined(__x86_64__) || defined(__i386__)) && \
256
- (defined(__SSE2__) || defined(__AVX512F__)))
257
- typedef _Float16 simsimd_bf16_t;
258
- #if !defined(SIMSIMD_NATIVE_BF16)
349
+ typedef __bf16 simsimd_bf16_t;
350
+ #elif ((defined(__GNUC__) || defined(__clang__)) && (defined(__x86_64__) || defined(__i386__)) && \
351
+ (defined(__AVX512BF16__)))
352
+ typedef __bfloat16 simsimd_bf16_t;
353
+ #undef SIMSIMD_NATIVE_BF16
259
354
  #define SIMSIMD_NATIVE_BF16 1
355
+ #else // Unknown compiler or architecture
356
+ #if defined(__GNUC__) || defined(__clang__) // Some compilers don't support warning pragmas
357
+ #warning "Unknown compiler or architecture for bfloat16."
260
358
  #endif
261
- #else // Unknown compiler or architecture
359
+ #undef SIMSIMD_NATIVE_BF16
262
360
  #define SIMSIMD_NATIVE_BF16 0
263
361
  #endif // Unknown compiler or architecture
264
362
  #endif // !SIMSIMD_NATIVE_BF16
@@ -276,7 +374,7 @@ typedef unsigned short simsimd_bf16_t;
276
374
  * Some of those are defined as aliases, so we use `#define` preprocessor
277
375
  * directives instead of `typedef` to avoid errors.
278
376
  */
279
- #if SIMSIMD_TARGET_ARM
377
+ #if _SIMSIMD_TARGET_ARM
280
378
  #if defined(_MSC_VER)
281
379
  #define simsimd_f16_for_arm_simd_t simsimd_f16_t
282
380
  #define simsimd_bf16_for_arm_simd_t simsimd_bf16_t
@@ -286,17 +384,40 @@ typedef unsigned short simsimd_bf16_t;
286
384
  #endif
287
385
  #endif
288
386
 
289
- #define SIMSIMD_IDENTIFY(x) (x)
387
+ /*
388
+ * Let's make sure the sizes of the types are as expected.
389
+ * In C the `_Static_assert` is only available with C 11 and later.
390
+ */
391
+ #define SIMSIMD_STATIC_ASSERT(cond, msg) typedef char static_assertion_##msg[(cond) ? 1 : -1]
392
+ SIMSIMD_STATIC_ASSERT(sizeof(simsimd_b8_t) == 1, simsimd_b8_t_must_be_1_byte);
393
+ SIMSIMD_STATIC_ASSERT(sizeof(simsimd_i4x2_t) == 1, simsimd_i4x2_t_must_be_1_byte);
394
+ SIMSIMD_STATIC_ASSERT(sizeof(simsimd_i8_t) == 1, simsimd_i8_t_must_be_1_byte);
395
+ SIMSIMD_STATIC_ASSERT(sizeof(simsimd_u8_t) == 1, simsimd_u8_t_must_be_1_byte);
396
+ SIMSIMD_STATIC_ASSERT(sizeof(simsimd_i16_t) == 2, simsimd_i16_t_must_be_2_bytes);
397
+ SIMSIMD_STATIC_ASSERT(sizeof(simsimd_u16_t) == 2, simsimd_u16_t_must_be_2_bytes);
398
+ SIMSIMD_STATIC_ASSERT(sizeof(simsimd_i32_t) == 4, simsimd_i32_t_must_be_4_bytes);
399
+ SIMSIMD_STATIC_ASSERT(sizeof(simsimd_u32_t) == 4, simsimd_u32_t_must_be_4_bytes);
400
+ SIMSIMD_STATIC_ASSERT(sizeof(simsimd_i64_t) == 8, simsimd_i64_t_must_be_8_bytes);
401
+ SIMSIMD_STATIC_ASSERT(sizeof(simsimd_u64_t) == 8, simsimd_u64_t_must_be_8_bytes);
402
+ SIMSIMD_STATIC_ASSERT(sizeof(simsimd_f32_t) == 4, simsimd_f32_t_must_be_4_bytes);
403
+ SIMSIMD_STATIC_ASSERT(sizeof(simsimd_f64_t) == 8, simsimd_f64_t_must_be_8_bytes);
404
+ SIMSIMD_STATIC_ASSERT(sizeof(simsimd_f16_t) == 2, simsimd_f16_t_must_be_2_bytes);
405
+ SIMSIMD_STATIC_ASSERT(sizeof(simsimd_bf16_t) == 2, simsimd_bf16_t_must_be_2_bytes);
406
+
407
+ #define SIMSIMD_DEREFERENCE(x) (*(x))
408
+ #define SIMSIMD_EXPORT(x, y) *(y) = x
290
409
 
291
410
  /**
292
411
  * @brief Returns the value of the half-precision floating-point number,
293
412
  * potentially decompressed into single-precision.
294
413
  */
295
- #ifndef SIMSIMD_UNCOMPRESS_F16
414
+ #if !defined(SIMSIMD_F16_TO_F32)
296
415
  #if SIMSIMD_NATIVE_F16
297
- #define SIMSIMD_UNCOMPRESS_F16(x) (SIMSIMD_IDENTIFY(x))
416
+ #define SIMSIMD_F16_TO_F32(x) (SIMSIMD_DEREFERENCE(x))
417
+ #define SIMSIMD_F32_TO_F16(x, y) (SIMSIMD_EXPORT(x, y))
298
418
  #else
299
- #define SIMSIMD_UNCOMPRESS_F16(x) (simsimd_uncompress_f16(x))
419
+ #define SIMSIMD_F16_TO_F32(x) (simsimd_f16_to_f32(x))
420
+ #define SIMSIMD_F32_TO_F16(x, y) (simsimd_f32_to_f16(x, y))
300
421
  #endif
301
422
  #endif
302
423
 
@@ -304,22 +425,47 @@ typedef unsigned short simsimd_bf16_t;
304
425
  * @brief Returns the value of the half-precision brain floating-point number,
305
426
  * potentially decompressed into single-precision.
306
427
  */
307
- #ifndef SIMSIMD_UNCOMPRESS_BF16
428
+ #if !defined(SIMSIMD_BF16_TO_F32)
308
429
  #if SIMSIMD_NATIVE_BF16
309
- #define SIMSIMD_UNCOMPRESS_BF16(x) (SIMSIMD_IDENTIFY(x))
430
+ #define SIMSIMD_BF16_TO_F32(x) (SIMSIMD_DEREFERENCE(x))
431
+ #define SIMSIMD_F32_TO_BF16(x, y) (SIMSIMD_EXPORT(x, y))
310
432
  #else
311
- #define SIMSIMD_UNCOMPRESS_BF16(x) (simsimd_uncompress_bf16(x))
433
+ #define SIMSIMD_BF16_TO_F32(x) (simsimd_bf16_to_f32(x))
434
+ #define SIMSIMD_F32_TO_BF16(x, y) (simsimd_f32_to_bf16(x, y))
435
+ #endif
312
436
  #endif
437
+
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)
440
+ #endif
441
+ #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
+ #endif
444
+ #if !defined(SIMSIMD_F64_TO_I8)
445
+ #define SIMSIMD_F64_TO_I8(x, y) *(y) = (simsimd_i8_t)fmin(fmax(round(x), -128), 127)
446
+ #endif
447
+ #if !defined(SIMSIMD_F64_TO_U8)
448
+ #define SIMSIMD_F64_TO_U8(x, y) *(y) = (simsimd_u8_t)fmin(fmax(round(x), 0), 255)
313
449
  #endif
314
450
 
451
+ /** @brief Convenience type for half-precision floating-point type conversions. */
315
452
  typedef union {
316
453
  unsigned i;
317
454
  float f;
318
455
  } simsimd_f32i32_t;
319
456
 
320
457
  /**
321
- * @brief Computes `1/sqrt(x)` using the trick from Quake 3, replacing
322
- * magic numbers with the ones suggested by Jan Kadlec.
458
+ * @brief Computes `1/sqrt(x)` using the trick from Quake 3,
459
+ * replacing the magic numbers with the ones suggested by Jan Kadlec.
460
+ *
461
+ * Subsequent additions by hardware manufacturers have made this algorithm redundant for the most part.
462
+ * For example, on x86, Intel introduced the SSE instruction `rsqrtss` in 1999. In a 2009 benchmark on
463
+ * the Intel Core 2, this instruction took 0.85ns per float compared to 3.54ns for the fast inverse
464
+ * square root algorithm, and had less error. Carmack's Magic Number `rsqrt` had an average error
465
+ * of 0.0990%, while SSE `rsqrtss` had 0.0094%, a 10x improvement.
466
+ *
467
+ * https://web.archive.org/web/20210208132927/http://assemblyrequired.crashworks.org/timing-square-root/
468
+ * https://stackoverflow.com/a/41460625/2766161
323
469
  */
324
470
  SIMSIMD_PUBLIC simsimd_f32_t simsimd_approximate_inverse_square_root(simsimd_f32_t number) {
325
471
  simsimd_f32i32_t conv;
@@ -351,20 +497,17 @@ SIMSIMD_PUBLIC simsimd_f32_t simsimd_approximate_log(simsimd_f32_t number) {
351
497
  * https://gist.github.com/milhidaka/95863906fe828198f47991c813dbe233
352
498
  * https://github.com/OpenCyphal/libcanard/blob/636795f4bc395f56af8d2c61d3757b5e762bb9e5/canard.c#L811-L834
353
499
  */
354
- SIMSIMD_PUBLIC simsimd_f32_t simsimd_uncompress_f16(unsigned short x) {
355
- union float_or_unsigned_int_t {
356
- float f;
357
- unsigned int i;
358
- };
500
+ SIMSIMD_PUBLIC simsimd_f32_t simsimd_f16_to_f32(simsimd_f16_t const *x_ptr) {
501
+ unsigned short x = *(unsigned short const *)x_ptr;
359
502
  unsigned int exponent = (x & 0x7C00) >> 10;
360
503
  unsigned int mantissa = (x & 0x03FF) << 13;
361
- union float_or_unsigned_int_t mantissa_union;
362
- mantissa_union.f = (float)mantissa;
363
- unsigned int v = (mantissa_union.i) >> 23;
364
- union float_or_unsigned_int_t result_union;
365
- result_union.i = (x & 0x8000) << 16 | (exponent != 0) * ((exponent + 112) << 23 | mantissa) |
366
- ((exponent == 0) & (mantissa != 0)) * ((v - 37) << 23 | ((mantissa << (150 - v)) & 0x007FE000));
367
- return result_union.f;
504
+ simsimd_f32i32_t mantissa_conv;
505
+ mantissa_conv.f = (float)mantissa;
506
+ unsigned int v = (mantissa_conv.i) >> 23;
507
+ simsimd_f32i32_t conv;
508
+ conv.i = (x & 0x8000) << 16 | (exponent != 0) * ((exponent + 112) << 23 | mantissa) |
509
+ ((exponent == 0) & (mantissa != 0)) * ((v - 37) << 23 | ((mantissa << (150 - v)) & 0x007FE000));
510
+ return conv.f;
368
511
  }
369
512
 
370
513
  /**
@@ -376,20 +519,16 @@ SIMSIMD_PUBLIC simsimd_f32_t simsimd_uncompress_f16(unsigned short x) {
376
519
  * https://gist.github.com/milhidaka/95863906fe828198f47991c813dbe233
377
520
  * https://github.com/OpenCyphal/libcanard/blob/636795f4bc395f56af8d2c61d3757b5e762bb9e5/canard.c#L811-L834
378
521
  */
379
- SIMSIMD_PUBLIC unsigned short simsimd_compress_f16(simsimd_f32_t x) {
380
- union float_or_unsigned_int_t {
381
- float f;
382
- unsigned int i;
383
- } x_union;
384
- x_union.f = x;
385
-
386
- unsigned int b = x_union.i + 0x00001000;
522
+ SIMSIMD_PUBLIC void simsimd_f32_to_f16(simsimd_f32_t x, simsimd_f16_t *result_ptr) {
523
+ simsimd_f32i32_t conv;
524
+ conv.f = x;
525
+ unsigned int b = conv.i + 0x00001000;
387
526
  unsigned int e = (b & 0x7F800000) >> 23;
388
527
  unsigned int m = b & 0x007FFFFF;
389
528
  unsigned short result = ((b & 0x80000000) >> 16) | (e > 112) * ((((e - 112) << 10) & 0x7C00) | (m >> 13)) |
390
529
  ((e < 113) & (e > 101)) * ((((0x007FF000 + m) >> (125 - e)) + 1) >> 1) |
391
530
  ((e > 143) * 0x7FFF);
392
- return result;
531
+ *(unsigned short *)result_ptr = result;
393
532
  }
394
533
 
395
534
  /**
@@ -399,31 +538,36 @@ SIMSIMD_PUBLIC unsigned short simsimd_compress_f16(simsimd_f32_t x) {
399
538
  * https://stackoverflow.com/questions/55253233/convert-fp32-to-bfloat16-in-c/55254307#55254307
400
539
  * https://cloud.google.com/blog/products/ai-machine-learning/bfloat16-the-secret-to-high-performance-on-cloud-tpus
401
540
  */
402
- SIMSIMD_PUBLIC simsimd_f32_t simsimd_uncompress_bf16(unsigned short x) {
403
- union float_or_unsigned_int_t {
404
- float f;
405
- unsigned int i;
406
- };
407
- union float_or_unsigned_int_t result_union;
408
- result_union.i = x << 16; // Zero extends the mantissa
409
- return result_union.f;
541
+ SIMSIMD_PUBLIC simsimd_f32_t simsimd_bf16_to_f32(simsimd_bf16_t const *x_ptr) {
542
+ unsigned short x = *(unsigned short const *)x_ptr;
543
+ simsimd_f32i32_t conv;
544
+ conv.i = x << 16; // Zero extends the mantissa
545
+ return conv.f;
410
546
  }
411
547
 
412
548
  /**
413
549
  * @brief Compresses a `float` to a `bf16` representation.
550
+ *
551
+ * https://stackoverflow.com/questions/55253233/convert-fp32-to-bfloat16-in-c/55254307#55254307
552
+ * https://cloud.google.com/blog/products/ai-machine-learning/bfloat16-the-secret-to-high-performance-on-cloud-tpus
414
553
  */
415
- SIMSIMD_PUBLIC unsigned short simsimd_compress_bf16(simsimd_f32_t x) {
416
- union float_or_unsigned_int_t {
417
- float f;
418
- unsigned int i;
419
- };
420
- union float_or_unsigned_int_t value;
421
- value.f = x;
422
- value.i >>= 16;
423
- value.i &= 0xFFFF;
424
- return (unsigned short)value.i;
554
+ SIMSIMD_PUBLIC void simsimd_f32_to_bf16(simsimd_f32_t x, simsimd_bf16_t *result_ptr) {
555
+ simsimd_f32i32_t conv;
556
+ conv.f = x;
557
+ conv.i += 0x8000; // Rounding is optional
558
+ conv.i >>= 16;
559
+ // The top 16 bits will be zeroed out anyways
560
+ // conv.i &= 0xFFFF;
561
+ *(unsigned short *)result_ptr = (unsigned short)conv.i;
425
562
  }
426
563
 
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)); }
570
+
427
571
  #ifdef __cplusplus
428
572
  } // extern "C"
429
573
  #endif
@@ -67,8 +67,7 @@ napi_value runAPI(napi_env env, napi_callback_info info, simsimd_metric_kind_t m
67
67
  // Convert the result to a JavaScript number
68
68
  napi_value js_result;
69
69
  status = napi_create_double(env, result, &js_result);
70
- if (status != napi_ok)
71
- return NULL;
70
+ if (status != napi_ok) return NULL;
72
71
 
73
72
  return js_result;
74
73
  }
@@ -83,20 +83,20 @@ export const jaccard = (a: Uint8Array, b: Uint8Array): number => {
83
83
  };
84
84
 
85
85
  /**
86
- * @brief Computes the kullbackleibler similarity coefficient between two vectors.
86
+ * @brief Computes the Kullback-Leibler divergence between two vectors.
87
87
  * @param {Float64Array|Float32Array} a - The first vector.
88
88
  * @param {Float64Array|Float32Array} b - The second vector.
89
- * @returns {number} The Jaccard similarity coefficient between vectors a and b.
89
+ * @returns {number} The Kullback-Leibler divergence between vectors a and b.
90
90
  */
91
91
  export const kullbackleibler = (a: Float64Array | Float32Array, b: Float64Array | Float32Array): number => {
92
92
  return compiled.kullbackleibler(a, b);
93
93
  };
94
94
 
95
95
  /**
96
- * @brief Computes the jensenshannon similarity coefficient between two vectors.
96
+ * @brief Computes the Jensen-Shannon divergence between two vectors.
97
97
  * @param {Float64Array|Float32Array} a - The first vector.
98
98
  * @param {Float64Array|Float32Array} b - The second vector.
99
- * @returns {number} The Jaccard similarity coefficient between vectors a and b.
99
+ * @returns {number} The Jensen-Shannon divergence between vectors a and b.
100
100
  */
101
101
  export const jensenshannon = (a: Float64Array | Float32Array, b: Float64Array | Float32Array): number => {
102
102
  return compiled.jensenshannon(a, b);