usearch 2.26.0 → 2.26.2
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 +2 -2
- package/cpp/test.cpp +66 -3
- package/include/usearch/index.hpp +9 -1
- package/include/usearch/index_dense.hpp +16 -5
- package/numkong/CITATION.cff +13 -9
- package/numkong/CONTRIBUTING.md +29 -24
- package/numkong/Cargo.toml +1 -1
- package/numkong/README.md +21 -7
- package/numkong/binding.gyp +47 -31
- package/numkong/build.rs +15 -5
- package/numkong/c/dispatch.h +0 -1
- package/numkong/c/parallel.c +139 -0
- package/numkong/c/parallel.h +47 -0
- package/numkong/cmake/toolchain-wasi.cmake +39 -5
- package/numkong/include/README.md +24 -17
- package/numkong/include/numkong/attention/sapphireamx.h +6 -6
- package/numkong/include/numkong/attention/sme.h +2 -2
- package/numkong/include/numkong/capabilities.h +2 -2
- package/numkong/include/numkong/cast/README.md +9 -7
- package/numkong/include/numkong/cast/loongsonasx.h +48 -40
- package/numkong/include/numkong/cast/serial.h +89 -11
- package/numkong/include/numkong/cast.h +3 -3
- package/numkong/include/numkong/curved/README.md +10 -10
- package/numkong/include/numkong/curved/neon.h +1 -0
- package/numkong/include/numkong/curved/neonbfdot.h +1 -0
- package/numkong/include/numkong/curved/smef64.h +1 -0
- package/numkong/include/numkong/dot/README.md +18 -18
- package/numkong/include/numkong/dot/alder.h +8 -8
- package/numkong/include/numkong/dot/haswell.h +8 -8
- package/numkong/include/numkong/dot/icelake.h +12 -12
- package/numkong/include/numkong/dot/loongsonasx.h +6 -6
- package/numkong/include/numkong/dot/neon.h +2 -1
- package/numkong/include/numkong/dot/neonbfdot.h +1 -0
- package/numkong/include/numkong/dot/neonfhm.h +1 -0
- package/numkong/include/numkong/dot/neonsdot.h +1 -0
- package/numkong/include/numkong/dot/powervsx.h +3 -3
- package/numkong/include/numkong/dot/serial.h +19 -6
- package/numkong/include/numkong/dot/skylake.h +4 -4
- package/numkong/include/numkong/dot/svehalf.h +1 -1
- package/numkong/include/numkong/dot/v128relaxed.h +24 -23
- package/numkong/include/numkong/dots/README.md +26 -26
- package/numkong/include/numkong/dots/genoa.h +3 -1
- package/numkong/include/numkong/dots/icelake.h +1 -0
- package/numkong/include/numkong/dots/powervsx.h +1 -1
- package/numkong/include/numkong/dots/serial.h +32 -33
- package/numkong/include/numkong/dots/sierra.h +4 -3
- package/numkong/include/numkong/each/README.md +5 -3
- package/numkong/include/numkong/each/sapphire.h +2 -0
- package/numkong/include/numkong/each/skylake.h +1 -0
- package/numkong/include/numkong/geospatial/README.md +6 -6
- package/numkong/include/numkong/geospatial/v128relaxed.h +1 -0
- package/numkong/include/numkong/maxsim/README.md +5 -5
- package/numkong/include/numkong/maxsim/genoa.h +4 -0
- package/numkong/include/numkong/maxsim/icelake.h +1 -0
- package/numkong/include/numkong/maxsim/serial.h +22 -9
- package/numkong/include/numkong/maxsim/sme.h +3 -2
- package/numkong/include/numkong/mesh/README.md +7 -4
- package/numkong/include/numkong/mesh/genoa.h +2 -2
- package/numkong/include/numkong/mesh/haswell.h +8 -8
- package/numkong/include/numkong/mesh/neon.h +6 -6
- package/numkong/include/numkong/mesh/neonbfdot.h +3 -2
- package/numkong/include/numkong/mesh/neonfhm.h +3 -2
- package/numkong/include/numkong/mesh/rvv.h +4 -4
- package/numkong/include/numkong/mesh/serial.h +17 -17
- package/numkong/include/numkong/mesh/skylake.h +4 -4
- package/numkong/include/numkong/mesh/v128relaxed.h +4 -4
- package/numkong/include/numkong/mesh.hpp +2 -2
- package/numkong/include/numkong/numkong.h +1 -1
- package/numkong/include/numkong/numkong.hpp +1 -1
- package/numkong/include/numkong/probability/README.md +17 -15
- package/numkong/include/numkong/probability/skylake.h +1 -1
- package/numkong/include/numkong/reduce/README.md +27 -21
- package/numkong/include/numkong/reduce/genoa.h +2 -1
- package/numkong/include/numkong/reduce/icelake.h +1 -0
- package/numkong/include/numkong/reduce/neon.h +1 -1
- package/numkong/include/numkong/reduce/serial.h +9 -9
- package/numkong/include/numkong/reduce/skylake.h +4 -4
- package/numkong/include/numkong/reduce.hpp +38 -0
- package/numkong/include/numkong/scalar/README.md +29 -28
- package/numkong/include/numkong/set/README.md +17 -14
- package/numkong/include/numkong/set/haswell.h +15 -16
- package/numkong/include/numkong/set/icelake.h +15 -16
- package/numkong/include/numkong/set/loongsonasx.h +12 -10
- package/numkong/include/numkong/set/neon.h +15 -19
- package/numkong/include/numkong/set/powervsx.h +15 -21
- package/numkong/include/numkong/set/serial.h +19 -20
- package/numkong/include/numkong/set/v128relaxed.h +10 -8
- package/numkong/include/numkong/sets/icelake.h +1 -0
- package/numkong/include/numkong/sparse/README.md +4 -4
- package/numkong/include/numkong/sparse/icelake.h +1 -0
- package/numkong/include/numkong/sparse/neon.h +1 -0
- package/numkong/include/numkong/sparse/serial.h +10 -3
- package/numkong/include/numkong/sparse/turin.h +1 -0
- package/numkong/include/numkong/spatial/README.md +25 -24
- package/numkong/include/numkong/spatial/alder.h +2 -1
- package/numkong/include/numkong/spatial/haswell.h +48 -40
- package/numkong/include/numkong/spatial/icelake.h +2 -1
- package/numkong/include/numkong/spatial/neon.h +54 -46
- package/numkong/include/numkong/spatial/neonbfdot.h +1 -1
- package/numkong/include/numkong/spatial/powervsx.h +54 -46
- package/numkong/include/numkong/spatial/serial.h +56 -46
- package/numkong/include/numkong/spatial/sierra.h +4 -3
- package/numkong/include/numkong/spatial/skylake.h +27 -22
- package/numkong/include/numkong/spatial/sve.h +6 -6
- package/numkong/include/numkong/spatial/svebfdot.h +1 -1
- package/numkong/include/numkong/spatial/svehalf.h +1 -1
- package/numkong/include/numkong/spatial/v128relaxed.h +36 -30
- package/numkong/include/numkong/spatials/README.md +15 -15
- package/numkong/include/numkong/spatials/genoa.h +3 -0
- package/numkong/include/numkong/spatials/graniteamx.h +2 -0
- package/numkong/include/numkong/spatials/icelake.h +1 -0
- package/numkong/include/numkong/spatials/sierra.h +1 -0
- package/numkong/include/numkong/tensor.hpp +236 -123
- package/numkong/include/numkong/trigonometry/README.md +4 -4
- package/numkong/include/numkong/trigonometry/serial.h +6 -6
- package/numkong/include/numkong/trigonometry/v128relaxed.h +1 -0
- package/numkong/include/numkong/types.hpp +46 -16
- package/numkong/include/numkong/vector.hpp +116 -23
- package/numkong/javascript/@numkong-darwin-arm64/package.json +1 -1
- package/numkong/javascript/@numkong-darwin-x64/package.json +1 -1
- package/numkong/javascript/@numkong-linux-arm64/package.json +1 -1
- package/numkong/javascript/@numkong-linux-x64/package.json +1 -1
- package/numkong/javascript/@numkong-win32-arm64/package.json +1 -1
- package/numkong/javascript/@numkong-win32-x64/package.json +1 -1
- package/numkong/javascript/README.md +18 -16
- package/numkong/javascript/numkong.c +70 -40
- package/numkong/package.json +8 -8
- package/numkong/rust/README.md +19 -9
- package/numkong/rust/cast.rs +52 -1
- package/numkong/rust/each.rs +480 -7
- package/numkong/rust/matrix.rs +877 -216
- package/numkong/rust/numkong.rs +12 -8
- package/numkong/rust/reduce.rs +433 -5
- package/numkong/rust/tensor.rs +450 -842
- package/numkong/rust/vector.rs +520 -101
- package/numkong/swift/README.md +5 -3
- package/numkong/test/README.md +4 -4
- package/numkong/test/test-wasi.mjs +17 -0
- package/numkong/test/test_each.cpp +30 -1
- package/numkong/test/test_each.py +74 -1
- package/numkong/test/test_reduce.cpp +51 -0
- package/numkong/test/test_tensor.cpp +2 -63
- package/numkong/test/test_tensor.py +93 -0
- 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/prebuilds/win32-x64/usearch.node +0 -0
|
@@ -25,8 +25,10 @@
|
|
|
25
25
|
#if NK_TARGET_SKYLAKE
|
|
26
26
|
|
|
27
27
|
#include "numkong/types.h"
|
|
28
|
-
#include "numkong/reduce/skylake.h"
|
|
29
|
-
#include "numkong/dot/skylake.h"
|
|
28
|
+
#include "numkong/reduce/skylake.h" // `nk_reduce_add_f32x16_skylake_`
|
|
29
|
+
#include "numkong/dot/skylake.h" // `nk_dot_f64x8_state_skylake_t`
|
|
30
|
+
#include "numkong/scalar/haswell.h" // `nk_f32_sqrt_haswell`, `nk_f64_sqrt_haswell`
|
|
31
|
+
#include "numkong/spatial/haswell.h" // `nk_angular_normalize_f32_haswell_`
|
|
30
32
|
|
|
31
33
|
#if defined(__cplusplus)
|
|
32
34
|
extern "C" {
|
|
@@ -224,61 +226,64 @@ nk_angular_f64_skylake_cycle:
|
|
|
224
226
|
}
|
|
225
227
|
|
|
226
228
|
/** @brief Angular from_dot for native f64: 1 − dot / √(query_sumsq × target_sumsq) for 4 pairs. */
|
|
227
|
-
NK_INTERNAL void nk_angular_f64x4_from_dot_skylake_(nk_b256_vec_t
|
|
228
|
-
nk_b256_vec_t
|
|
229
|
-
__m256d dots_f64x4 =
|
|
229
|
+
NK_INTERNAL void nk_angular_f64x4_from_dot_skylake_(nk_b256_vec_t const *dots_vec, nk_f64_t query_sumsq,
|
|
230
|
+
nk_b256_vec_t const *target_sumsqs_vec, nk_b256_vec_t *result_vec) {
|
|
231
|
+
__m256d dots_f64x4 = dots_vec->ymm_pd;
|
|
230
232
|
__m256d query_sumsq_f64x4 = _mm256_set1_pd(query_sumsq);
|
|
231
|
-
__m256d products_f64x4 = _mm256_mul_pd(query_sumsq_f64x4,
|
|
233
|
+
__m256d products_f64x4 = _mm256_mul_pd(query_sumsq_f64x4, target_sumsqs_vec->ymm_pd);
|
|
232
234
|
__m256d sqrt_products_f64x4 = _mm256_sqrt_pd(products_f64x4);
|
|
233
235
|
__m256d normalized_f64x4 = _mm256_div_pd(dots_f64x4, sqrt_products_f64x4);
|
|
234
236
|
__m256d ones_f64x4 = _mm256_set1_pd(1.0);
|
|
235
237
|
__m256d angular_f64x4 = _mm256_sub_pd(ones_f64x4, normalized_f64x4);
|
|
236
|
-
|
|
238
|
+
result_vec->ymm_pd = _mm256_max_pd(angular_f64x4, _mm256_setzero_pd());
|
|
237
239
|
}
|
|
238
240
|
|
|
239
241
|
/** @brief Euclidean from_dot for native f64: √(query_sumsq + target_sumsq − 2 × dot) for 4 pairs. */
|
|
240
|
-
NK_INTERNAL void nk_euclidean_f64x4_from_dot_skylake_(nk_b256_vec_t
|
|
241
|
-
nk_b256_vec_t
|
|
242
|
-
|
|
242
|
+
NK_INTERNAL void nk_euclidean_f64x4_from_dot_skylake_(nk_b256_vec_t const *dots_vec, nk_f64_t query_sumsq,
|
|
243
|
+
nk_b256_vec_t const *target_sumsqs_vec,
|
|
244
|
+
nk_b256_vec_t *result_vec) {
|
|
245
|
+
__m256d dots_f64x4 = dots_vec->ymm_pd;
|
|
243
246
|
__m256d query_sumsq_f64x4 = _mm256_set1_pd(query_sumsq);
|
|
244
247
|
__m256d two_f64x4 = _mm256_set1_pd(2.0);
|
|
245
|
-
__m256d sum_sq_f64x4 = _mm256_add_pd(query_sumsq_f64x4,
|
|
248
|
+
__m256d sum_sq_f64x4 = _mm256_add_pd(query_sumsq_f64x4, target_sumsqs_vec->ymm_pd);
|
|
246
249
|
__m256d dist_sq_f64x4 = _mm256_fnmadd_pd(two_f64x4, dots_f64x4, sum_sq_f64x4);
|
|
247
250
|
__m256d zeros_f64x4 = _mm256_setzero_pd();
|
|
248
251
|
__m256d clamped_f64x4 = _mm256_max_pd(dist_sq_f64x4, zeros_f64x4);
|
|
249
|
-
|
|
252
|
+
result_vec->ymm_pd = _mm256_sqrt_pd(clamped_f64x4);
|
|
250
253
|
}
|
|
251
254
|
|
|
252
255
|
/** @brief Angular from_dot: f32 dots upcast to f64 for precision. Output via nk_b128_vec_t (f32). */
|
|
253
|
-
NK_INTERNAL void nk_angular_through_f64_from_dot_skylake_(nk_b128_vec_t
|
|
254
|
-
nk_b128_vec_t
|
|
255
|
-
|
|
256
|
+
NK_INTERNAL void nk_angular_through_f64_from_dot_skylake_(nk_b128_vec_t const *dots_vec, nk_f32_t query_sumsq,
|
|
257
|
+
nk_b128_vec_t const *target_sumsqs_vec,
|
|
258
|
+
nk_b128_vec_t *result_vec) {
|
|
259
|
+
__m128 dots_f32x4 = dots_vec->xmm_ps;
|
|
256
260
|
__m256d dots_f64x4 = _mm256_cvtps_pd(dots_f32x4);
|
|
257
261
|
__m256d query_sumsq_f64x4 = _mm256_set1_pd((nk_f64_t)query_sumsq);
|
|
258
|
-
__m256d target_sumsqs_f64x4 = _mm256_cvtps_pd(
|
|
262
|
+
__m256d target_sumsqs_f64x4 = _mm256_cvtps_pd(target_sumsqs_vec->xmm_ps);
|
|
259
263
|
__m256d products_f64x4 = _mm256_mul_pd(query_sumsq_f64x4, target_sumsqs_f64x4);
|
|
260
264
|
__m256d sqrt_products_f64x4 = _mm256_sqrt_pd(products_f64x4);
|
|
261
265
|
__m256d normalized_f64x4 = _mm256_div_pd(dots_f64x4, sqrt_products_f64x4);
|
|
262
266
|
__m256d ones_f64x4 = _mm256_set1_pd(1.0);
|
|
263
267
|
__m256d angular_f64x4 = _mm256_sub_pd(ones_f64x4, normalized_f64x4);
|
|
264
268
|
angular_f64x4 = _mm256_max_pd(angular_f64x4, _mm256_setzero_pd());
|
|
265
|
-
|
|
269
|
+
result_vec->xmm_ps = _mm256_cvtpd_ps(angular_f64x4);
|
|
266
270
|
}
|
|
267
271
|
|
|
268
272
|
/** @brief Euclidean from_dot: f32 dots upcast to f64 for precision. Output via nk_b128_vec_t (f32). */
|
|
269
|
-
NK_INTERNAL void nk_euclidean_through_f64_from_dot_skylake_(nk_b128_vec_t
|
|
270
|
-
nk_b128_vec_t
|
|
271
|
-
|
|
273
|
+
NK_INTERNAL void nk_euclidean_through_f64_from_dot_skylake_(nk_b128_vec_t const *dots_vec, nk_f32_t query_sumsq,
|
|
274
|
+
nk_b128_vec_t const *target_sumsqs_vec,
|
|
275
|
+
nk_b128_vec_t *result_vec) {
|
|
276
|
+
__m128 dots_f32x4 = dots_vec->xmm_ps;
|
|
272
277
|
__m256d dots_f64x4 = _mm256_cvtps_pd(dots_f32x4);
|
|
273
278
|
__m256d query_sumsq_f64x4 = _mm256_set1_pd((nk_f64_t)query_sumsq);
|
|
274
|
-
__m256d target_sumsqs_f64x4 = _mm256_cvtps_pd(
|
|
279
|
+
__m256d target_sumsqs_f64x4 = _mm256_cvtps_pd(target_sumsqs_vec->xmm_ps);
|
|
275
280
|
__m256d two_f64x4 = _mm256_set1_pd(2.0);
|
|
276
281
|
__m256d sum_sq_f64x4 = _mm256_add_pd(query_sumsq_f64x4, target_sumsqs_f64x4);
|
|
277
282
|
__m256d dist_sq_f64x4 = _mm256_fnmadd_pd(two_f64x4, dots_f64x4, sum_sq_f64x4);
|
|
278
283
|
__m256d zeros_f64x4 = _mm256_setzero_pd();
|
|
279
284
|
__m256d clamped_f64x4 = _mm256_max_pd(dist_sq_f64x4, zeros_f64x4);
|
|
280
285
|
__m256d dist_f64x4 = _mm256_sqrt_pd(clamped_f64x4);
|
|
281
|
-
|
|
286
|
+
result_vec->xmm_ps = _mm256_cvtpd_ps(dist_f64x4);
|
|
282
287
|
}
|
|
283
288
|
|
|
284
289
|
#pragma endregion F32 and F64 Floats
|
|
@@ -60,9 +60,9 @@ extern "C" {
|
|
|
60
60
|
* Marked `__arm_streaming_compatible` so the helper is callable from both streaming
|
|
61
61
|
* (SME) and non-streaming (SVE) contexts without mode transitions.
|
|
62
62
|
*
|
|
63
|
-
* @param
|
|
64
|
-
* @param x
|
|
65
|
-
* @return
|
|
63
|
+
* @param predicate_b32x Active-lane mask
|
|
64
|
+
* @param x Input vector (must be positive for meaningful results)
|
|
65
|
+
* @return Approximate 1/sqrt(x) with ~23-bit mantissa accuracy
|
|
66
66
|
*/
|
|
67
67
|
NK_INTERNAL svfloat32_t nk_rsqrt_f32x_sve_(svbool_t predicate_b32x, svfloat32_t x) NK_STREAMING_COMPATIBLE_ {
|
|
68
68
|
svfloat32_t r = svrsqrte_f32(x);
|
|
@@ -80,9 +80,9 @@ NK_INTERNAL svfloat32_t nk_rsqrt_f32x_sve_(svbool_t predicate_b32x, svfloat32_t
|
|
|
80
80
|
* Marked `__arm_streaming_compatible` so the helper is callable from both streaming
|
|
81
81
|
* (SME) and non-streaming (SVE) contexts without mode transitions.
|
|
82
82
|
*
|
|
83
|
-
* @param
|
|
84
|
-
* @param x
|
|
85
|
-
* @return
|
|
83
|
+
* @param predicate_b64x Active-lane mask
|
|
84
|
+
* @param x Input vector (must be positive for meaningful results)
|
|
85
|
+
* @return Approximate 1/sqrt(x) with ~52-bit mantissa accuracy
|
|
86
86
|
*/
|
|
87
87
|
NK_INTERNAL svfloat64_t nk_rsqrt_f64x_sve_(svbool_t predicate_b64x, svfloat64_t x) NK_STREAMING_COMPATIBLE_ {
|
|
88
88
|
svfloat64_t r = svrsqrte_f64(x);
|
|
@@ -618,75 +618,81 @@ nk_angular_e3m2_v128relaxed_cycle:
|
|
|
618
618
|
#pragma region Spatial From Dot Helpers
|
|
619
619
|
|
|
620
620
|
/** @brief Angular from_dot: computes 1 − dot / √(query_sumsq × target_sumsq) for 4 pairs in f32. */
|
|
621
|
-
NK_INTERNAL void nk_angular_through_f32_from_dot_v128relaxed_(nk_b128_vec_t
|
|
622
|
-
nk_b128_vec_t
|
|
623
|
-
|
|
621
|
+
NK_INTERNAL void nk_angular_through_f32_from_dot_v128relaxed_(nk_b128_vec_t const *dots_vec, nk_f32_t query_sumsq,
|
|
622
|
+
nk_b128_vec_t const *target_sumsqs_vec,
|
|
623
|
+
nk_b128_vec_t *result_vec) {
|
|
624
|
+
v128_t dots_f32x4 = dots_vec->v128;
|
|
624
625
|
v128_t query_sumsq_f32x4 = wasm_f32x4_splat(query_sumsq);
|
|
625
|
-
v128_t products_f32x4 = wasm_f32x4_mul(query_sumsq_f32x4,
|
|
626
|
+
v128_t products_f32x4 = wasm_f32x4_mul(query_sumsq_f32x4, target_sumsqs_vec->v128);
|
|
626
627
|
v128_t sqrt_products_f32x4 = wasm_f32x4_sqrt(products_f32x4);
|
|
627
628
|
v128_t normalized_f32x4 = wasm_f32x4_div(dots_f32x4, sqrt_products_f32x4);
|
|
628
629
|
v128_t angular_f32x4 = wasm_f32x4_sub(wasm_f32x4_splat(1.0f), normalized_f32x4);
|
|
629
|
-
|
|
630
|
+
result_vec->v128 = wasm_f32x4_max(angular_f32x4, wasm_f32x4_splat(0.0f));
|
|
630
631
|
}
|
|
631
632
|
|
|
632
633
|
/** @brief Euclidean from_dot: computes √(query_sumsq + target_sumsq − 2 × dot) for 4 pairs in f32. */
|
|
633
|
-
NK_INTERNAL void nk_euclidean_through_f32_from_dot_v128relaxed_(nk_b128_vec_t
|
|
634
|
-
nk_b128_vec_t
|
|
635
|
-
|
|
634
|
+
NK_INTERNAL void nk_euclidean_through_f32_from_dot_v128relaxed_(nk_b128_vec_t const *dots_vec, nk_f32_t query_sumsq,
|
|
635
|
+
nk_b128_vec_t const *target_sumsqs_vec,
|
|
636
|
+
nk_b128_vec_t *result_vec) {
|
|
637
|
+
v128_t dots_f32x4 = dots_vec->v128;
|
|
636
638
|
v128_t query_sumsq_f32x4 = wasm_f32x4_splat(query_sumsq);
|
|
637
639
|
v128_t two_f32x4 = wasm_f32x4_splat(2.0f);
|
|
638
|
-
v128_t sum_sq_f32x4 = wasm_f32x4_add(query_sumsq_f32x4,
|
|
640
|
+
v128_t sum_sq_f32x4 = wasm_f32x4_add(query_sumsq_f32x4, target_sumsqs_vec->v128);
|
|
639
641
|
v128_t dist_sq_f32x4 = wasm_f32x4_relaxed_nmadd(two_f32x4, dots_f32x4, sum_sq_f32x4);
|
|
640
642
|
dist_sq_f32x4 = wasm_f32x4_max(dist_sq_f32x4, wasm_f32x4_splat(0.0f));
|
|
641
|
-
|
|
643
|
+
result_vec->v128 = wasm_f32x4_sqrt(dist_sq_f32x4);
|
|
642
644
|
}
|
|
643
645
|
|
|
644
646
|
/** @brief Angular from_dot for i32 accumulators: cast to f32, then angular normalization. 4 pairs. */
|
|
645
|
-
NK_INTERNAL void nk_angular_through_i32_from_dot_v128relaxed_(nk_b128_vec_t
|
|
646
|
-
nk_b128_vec_t
|
|
647
|
-
|
|
647
|
+
NK_INTERNAL void nk_angular_through_i32_from_dot_v128relaxed_(nk_b128_vec_t const *dots_vec, nk_i32_t query_sumsq,
|
|
648
|
+
nk_b128_vec_t const *target_sumsqs_vec,
|
|
649
|
+
nk_b128_vec_t *result_vec) {
|
|
650
|
+
v128_t dots_f32x4 = wasm_f32x4_convert_i32x4(dots_vec->v128);
|
|
648
651
|
v128_t query_sumsq_f32x4 = wasm_f32x4_splat((nk_f32_t)query_sumsq);
|
|
649
|
-
v128_t products_f32x4 = wasm_f32x4_mul(query_sumsq_f32x4, wasm_f32x4_convert_i32x4(
|
|
652
|
+
v128_t products_f32x4 = wasm_f32x4_mul(query_sumsq_f32x4, wasm_f32x4_convert_i32x4(target_sumsqs_vec->v128));
|
|
650
653
|
v128_t sqrt_products_f32x4 = wasm_f32x4_sqrt(products_f32x4);
|
|
651
654
|
v128_t normalized_f32x4 = wasm_f32x4_div(dots_f32x4, sqrt_products_f32x4);
|
|
652
655
|
v128_t angular_f32x4 = wasm_f32x4_sub(wasm_f32x4_splat(1.0f), normalized_f32x4);
|
|
653
|
-
|
|
656
|
+
result_vec->v128 = wasm_f32x4_max(angular_f32x4, wasm_f32x4_splat(0.0f));
|
|
654
657
|
}
|
|
655
658
|
|
|
656
659
|
/** @brief Euclidean from_dot for i32 accumulators: cast to f32, then √(a² + b² − 2ab). 4 pairs. */
|
|
657
|
-
NK_INTERNAL void nk_euclidean_through_i32_from_dot_v128relaxed_(nk_b128_vec_t
|
|
658
|
-
nk_b128_vec_t
|
|
659
|
-
|
|
660
|
+
NK_INTERNAL void nk_euclidean_through_i32_from_dot_v128relaxed_(nk_b128_vec_t const *dots_vec, nk_i32_t query_sumsq,
|
|
661
|
+
nk_b128_vec_t const *target_sumsqs_vec,
|
|
662
|
+
nk_b128_vec_t *result_vec) {
|
|
663
|
+
v128_t dots_f32x4 = wasm_f32x4_convert_i32x4(dots_vec->v128);
|
|
660
664
|
v128_t query_sumsq_f32x4 = wasm_f32x4_splat((nk_f32_t)query_sumsq);
|
|
661
665
|
v128_t two_f32x4 = wasm_f32x4_splat(2.0f);
|
|
662
|
-
v128_t sum_sq_f32x4 = wasm_f32x4_add(query_sumsq_f32x4, wasm_f32x4_convert_i32x4(
|
|
666
|
+
v128_t sum_sq_f32x4 = wasm_f32x4_add(query_sumsq_f32x4, wasm_f32x4_convert_i32x4(target_sumsqs_vec->v128));
|
|
663
667
|
v128_t dist_sq_f32x4 = wasm_f32x4_relaxed_nmadd(two_f32x4, dots_f32x4, sum_sq_f32x4);
|
|
664
668
|
dist_sq_f32x4 = wasm_f32x4_max(dist_sq_f32x4, wasm_f32x4_splat(0.0f));
|
|
665
|
-
|
|
669
|
+
result_vec->v128 = wasm_f32x4_sqrt(dist_sq_f32x4);
|
|
666
670
|
}
|
|
667
671
|
|
|
668
672
|
/** @brief Angular from_dot for u32 accumulators: cast to f32, then angular normalization. 4 pairs. */
|
|
669
|
-
NK_INTERNAL void nk_angular_through_u32_from_dot_v128relaxed_(nk_b128_vec_t
|
|
670
|
-
nk_b128_vec_t
|
|
671
|
-
|
|
673
|
+
NK_INTERNAL void nk_angular_through_u32_from_dot_v128relaxed_(nk_b128_vec_t const *dots_vec, nk_u32_t query_sumsq,
|
|
674
|
+
nk_b128_vec_t const *target_sumsqs_vec,
|
|
675
|
+
nk_b128_vec_t *result_vec) {
|
|
676
|
+
v128_t dots_f32x4 = wasm_f32x4_convert_u32x4(dots_vec->v128);
|
|
672
677
|
v128_t query_sumsq_f32x4 = wasm_f32x4_splat((nk_f32_t)query_sumsq);
|
|
673
|
-
v128_t products_f32x4 = wasm_f32x4_mul(query_sumsq_f32x4, wasm_f32x4_convert_u32x4(
|
|
678
|
+
v128_t products_f32x4 = wasm_f32x4_mul(query_sumsq_f32x4, wasm_f32x4_convert_u32x4(target_sumsqs_vec->v128));
|
|
674
679
|
v128_t sqrt_products_f32x4 = wasm_f32x4_sqrt(products_f32x4);
|
|
675
680
|
v128_t normalized_f32x4 = wasm_f32x4_div(dots_f32x4, sqrt_products_f32x4);
|
|
676
681
|
v128_t angular_f32x4 = wasm_f32x4_sub(wasm_f32x4_splat(1.0f), normalized_f32x4);
|
|
677
|
-
|
|
682
|
+
result_vec->v128 = wasm_f32x4_max(angular_f32x4, wasm_f32x4_splat(0.0f));
|
|
678
683
|
}
|
|
679
684
|
|
|
680
685
|
/** @brief Euclidean from_dot for u32 accumulators: cast to f32, then √(a² + b² − 2ab). 4 pairs. */
|
|
681
|
-
NK_INTERNAL void nk_euclidean_through_u32_from_dot_v128relaxed_(nk_b128_vec_t
|
|
682
|
-
nk_b128_vec_t
|
|
683
|
-
|
|
686
|
+
NK_INTERNAL void nk_euclidean_through_u32_from_dot_v128relaxed_(nk_b128_vec_t const *dots_vec, nk_u32_t query_sumsq,
|
|
687
|
+
nk_b128_vec_t const *target_sumsqs_vec,
|
|
688
|
+
nk_b128_vec_t *result_vec) {
|
|
689
|
+
v128_t dots_f32x4 = wasm_f32x4_convert_u32x4(dots_vec->v128);
|
|
684
690
|
v128_t query_sumsq_f32x4 = wasm_f32x4_splat((nk_f32_t)query_sumsq);
|
|
685
691
|
v128_t two_f32x4 = wasm_f32x4_splat(2.0f);
|
|
686
|
-
v128_t sum_sq_f32x4 = wasm_f32x4_add(query_sumsq_f32x4, wasm_f32x4_convert_u32x4(
|
|
692
|
+
v128_t sum_sq_f32x4 = wasm_f32x4_add(query_sumsq_f32x4, wasm_f32x4_convert_u32x4(target_sumsqs_vec->v128));
|
|
687
693
|
v128_t dist_sq_f32x4 = wasm_f32x4_relaxed_nmadd(two_f32x4, dots_f32x4, sum_sq_f32x4);
|
|
688
694
|
dist_sq_f32x4 = wasm_f32x4_max(dist_sq_f32x4, wasm_f32x4_splat(0.0f));
|
|
689
|
-
|
|
695
|
+
result_vec->v128 = wasm_f32x4_sqrt(dist_sq_f32x4);
|
|
690
696
|
}
|
|
691
697
|
|
|
692
698
|
#pragma endregion Spatial From Dot Helpers
|
|
@@ -34,20 +34,20 @@ def euclideans_packed(a: np.ndarray, b: np.ndarray) -> np.ndarray:
|
|
|
34
34
|
|
|
35
35
|
## Input & Output Types
|
|
36
36
|
|
|
37
|
-
| Input Type | Output Type | Description
|
|
38
|
-
| ---------- | ----------- |
|
|
39
|
-
| `f64` | `f64` | 64-bit IEEE 754 double precision
|
|
40
|
-
| `f32` | `
|
|
41
|
-
| `f16` | `f32` | 16-bit IEEE 754 half precision, widened output
|
|
42
|
-
| `bf16` | `f32` | 16-bit brain float, widened output
|
|
43
|
-
| `e4m3` | `f32` | 8-bit Float8: 4 exponent, 3 mantissa bits
|
|
44
|
-
| `e5m2` | `f32` | 8-bit Float8: 5 exponent, 2 mantissa bits
|
|
45
|
-
| `e2m3` | `f32` | 8-bit MX format: 2 exponent, 3 mantissa bits
|
|
46
|
-
| `e3m2` | `f32` | 8-bit MX format: 3 exponent, 2 mantissa bits
|
|
47
|
-
| `i8` | `f32` | 8-bit signed integers, float output
|
|
48
|
-
| `u8` | `f32` | 8-bit unsigned integers, float output
|
|
49
|
-
| `i4` | `f32` | 4-bit signed integers, float output
|
|
50
|
-
| `u4` | `f32` | 4-bit unsigned integers, float output
|
|
37
|
+
| Input Type | Output Type | Description |
|
|
38
|
+
| ---------- | ----------- | ------------------------------------------------ |
|
|
39
|
+
| `f64` | `f64` | 64-bit IEEE 754 double precision |
|
|
40
|
+
| `f32` | `f64` | 32-bit IEEE 754 single precision, widened output |
|
|
41
|
+
| `f16` | `f32` | 16-bit IEEE 754 half precision, widened output |
|
|
42
|
+
| `bf16` | `f32` | 16-bit brain float, widened output |
|
|
43
|
+
| `e4m3` | `f32` | 8-bit Float8: 4 exponent, 3 mantissa bits |
|
|
44
|
+
| `e5m2` | `f32` | 8-bit Float8: 5 exponent, 2 mantissa bits |
|
|
45
|
+
| `e2m3` | `f32` | 8-bit MX format: 2 exponent, 3 mantissa bits |
|
|
46
|
+
| `e3m2` | `f32` | 8-bit MX format: 3 exponent, 2 mantissa bits |
|
|
47
|
+
| `i8` | `f32` | 8-bit signed integers, float output |
|
|
48
|
+
| `u8` | `f32` | 8-bit unsigned integers, float output |
|
|
49
|
+
| `i4` | `f32` | 4-bit signed integers, float output |
|
|
50
|
+
| `u4` | `f32` | 4-bit unsigned integers, float output |
|
|
51
51
|
|
|
52
52
|
## Optimizations
|
|
53
53
|
|
|
@@ -65,7 +65,7 @@ The singular `spatial/` kernels compute these three sums ($\sum a_i b_i$, $\sum
|
|
|
65
65
|
`nk_angular_through_f32_from_dot_haswell_` replaces this with hardware `_mm_rsqrt_ps` (~12-bit approximation, 5cy latency, 1/cy on port 0) plus one Newton-Raphson refinement step (~22–24 correct bits).
|
|
66
66
|
`nk_euclidean_through_f32_from_dot_serial_` computes `sqrt(x)` as `x * rsqrt(x)` — reusing the same rsqrt path.
|
|
67
67
|
`nk_euclidean_through_f32_from_dot_haswell_` uses exact `_mm_sqrt_ps` (11cy latency, 7cy throughput for XMM) instead of the rsqrt approximation — the subtraction $\|a\|^2 + \|b\|^2 - 2 \cdot \text{dot}$ can produce values near zero where rsqrt error would be amplified by the subsequent multiply.
|
|
68
|
-
For Float64,
|
|
68
|
+
For Float64, the SIMD backends use exact division and sqrt — no fast rsqrt approximation, since reaching 52 mantissa bits of precision would need 4+ Newton-Raphson iterations, negating the speed advantage — while `nk_angular_through_f64_from_dot_serial_` still routes through `nk_f64_rsqrt_serial` and its four iterations.
|
|
69
69
|
The 4-wide finalizer batching amortizes these costs: one rsqrt or sqrt call processes 4 output elements simultaneously, hiding the latency behind the GEMM tile's computation.
|
|
70
70
|
|
|
71
71
|
### Norm Precomputation in Packed Buffers
|
|
@@ -14,6 +14,9 @@
|
|
|
14
14
|
|
|
15
15
|
#include "numkong/spatial/haswell.h"
|
|
16
16
|
#include "numkong/dots/genoa.h"
|
|
17
|
+
#include "numkong/cast/icelake.h" // `nk_e5m2x32_to_bf16x32_icelake_`
|
|
18
|
+
#include "numkong/dot/skylake.h" // `nk_dot_through_f32_finalize_skylake_`
|
|
19
|
+
#include "numkong/reduce/skylake.h" // `nk_reduce_add_f32x16_skylake_`
|
|
17
20
|
|
|
18
21
|
#if defined(__cplusplus)
|
|
19
22
|
extern "C" {
|
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
#include "numkong/spatial/skylake.h"
|
|
16
16
|
#include "numkong/spatial/serial.h"
|
|
17
17
|
#include "numkong/dots/graniteamx.h"
|
|
18
|
+
#include "numkong/dots/sapphireamx.h" // `nk_compiler_barrier_sapphireamx_`
|
|
19
|
+
#include "numkong/spatials/sapphireamx.h" // `nk_angulars_row_f32dots_sapphireamx_`
|
|
18
20
|
|
|
19
21
|
#if defined(__cplusplus)
|
|
20
22
|
extern "C" {
|