usearch 2.9.1 → 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.
- package/README.md +50 -52
- package/javascript/{types → dist/cjs}/usearch.d.ts +90 -115
- package/javascript/dist/cjs/usearch.js +531 -0
- package/javascript/dist/esm/usearch.d.ts +212 -0
- package/javascript/{usearch.js → dist/esm/usearch.js} +202 -153
- package/package.json +25 -23
- 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-ia32/usearch.node +0 -0
- package/prebuilds/win32-x64/usearch.node +0 -0
- package/.clang-format +0 -10
- package/.clang-tidy +0 -60
- package/.cmake-format.py +0 -19
- package/.dockerignore +0 -93
- package/.gitattributes +0 -9
- package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -90
- package/.github/ISSUE_TEMPLATE/config.yml +0 -5
- package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -64
- package/.github/workflows/Dockerfile.libs +0 -36
- package/.github/workflows/prerelease.yml +0 -331
- package/.github/workflows/release.yml +0 -722
- package/.github/workflows/update_version.sh +0 -15
- package/.gitmodules +0 -9
- package/.releaserc +0 -90
- package/CITATION.cff +0 -11
- package/CMakeLists.txt +0 -324
- package/CODE_OF_CONDUCT.md +0 -128
- package/CONTRIBUTING.md +0 -353
- package/Cargo.toml +0 -19
- package/Dockerfile +0 -16
- package/VERSION +0 -1
- package/assets/unum.png +0 -0
- package/assets/usearch-approaches-transparent.png +0 -0
- package/assets/usearch-approaches-white.png +0 -0
- package/assets/usearch-neighbor-types.png +0 -0
- package/binding.gyp +0 -87
- package/build.gradle +0 -204
- package/build.rs +0 -18
- package/c/CMakeLists.txt +0 -25
- package/c/README.md +0 -34
- package/c/lib.cpp +0 -358
- package/c/test.c +0 -374
- package/c/usearch.h +0 -311
- package/cmake/clipp.cmake +0 -7
- package/cmake/config.cmake.in +0 -15
- package/cmake/emscripten.cmake +0 -8
- package/cmake/jemalloc.cmake +0 -62
- package/cmake/pkg-config.pc.in +0 -4
- package/cmake/usearchConfigVersion.cmake.in +0 -20
- package/conanfile.py +0 -26
- package/cpp/CMakeLists.txt +0 -14
- package/cpp/README.md +0 -161
- package/cpp/bench.cpp +0 -618
- package/cpp/test.cpp +0 -323
- package/fp16/CMakeLists.txt +0 -176
- package/fp16/LICENSE +0 -11
- package/fp16/README.md +0 -20
- package/fp16/bench/alt-element.cc +0 -89
- package/fp16/bench/from-alt-array.cc +0 -175
- package/fp16/bench/from-ieee-array.cc +0 -399
- package/fp16/bench/ieee-element.cc +0 -272
- package/fp16/bench/to-alt-array.cc +0 -91
- package/fp16/bench/to-ieee-array.cc +0 -303
- package/fp16/cmake/DownloadGoogleBenchmark.cmake +0 -15
- package/fp16/cmake/DownloadGoogleTest.cmake +0 -15
- package/fp16/cmake/DownloadPSimd.cmake +0 -15
- package/fp16/configure.py +0 -65
- package/fp16/confu.yaml +0 -8
- package/fp16/include/fp16/__init__.py +0 -0
- package/fp16/include/fp16/avx.py +0 -50
- package/fp16/include/fp16/avx2.py +0 -53
- package/fp16/include/fp16/bitcasts.h +0 -92
- package/fp16/include/fp16/fp16.h +0 -451
- package/fp16/include/fp16/psimd.h +0 -131
- package/fp16/include/fp16.h +0 -11
- package/fp16/jni/Android.mk +0 -6
- package/fp16/jni/Application.mk +0 -4
- package/fp16/test/alt-from-fp32-value.cc +0 -498
- package/fp16/test/alt-to-fp32-bits.cc +0 -263
- package/fp16/test/alt-to-fp32-psimd.cc +0 -145
- package/fp16/test/alt-to-fp32-value.cc +0 -348
- package/fp16/test/alt-to-fp32x2-psimd.cc +0 -245
- package/fp16/test/bitcasts.cc +0 -56
- package/fp16/test/ieee-from-fp32-value.cc +0 -523
- package/fp16/test/ieee-to-fp32-bits.cc +0 -333
- package/fp16/test/ieee-to-fp32-psimd.cc +0 -312
- package/fp16/test/ieee-to-fp32-value.cc +0 -420
- package/fp16/test/ieee-to-fp32x2-psimd.cc +0 -541
- package/fp16/test/peachpy/alt-xmm-to-fp32-xmm-avx.cc +0 -96
- package/fp16/test/peachpy/alt-xmm-to-fp32-ymm-avx2.cc +0 -96
- package/fp16/test/peachpy/stubs.py +0 -38
- package/fp16/test/tables.cc +0 -530
- package/fp16/test/tables.h +0 -13
- package/fp16/third-party/THHalf.h +0 -92
- package/fp16/third-party/eigen-half.h +0 -170
- package/fp16/third-party/float16-compressor.h +0 -80
- package/fp16/third-party/half.hpp +0 -2916
- package/fp16/third-party/npy-halffloat.h +0 -328
- package/include/usearch/index.hpp +0 -3836
- package/include/usearch/index_dense.hpp +0 -2004
- package/include/usearch/index_plugins.hpp +0 -2203
- package/javascript/lib.cpp +0 -341
- package/javascript/types/usearch.d.ts.map +0 -1
- package/javascript/usearch.test.js +0 -74
- package/package-ci.json +0 -10
- package/pyproject.toml +0 -51
- package/setup.py +0 -201
- package/simsimd/.releaserc +0 -86
- package/simsimd/Cargo.lock +0 -708
- package/simsimd/Cargo.toml +0 -36
- package/simsimd/LICENSE +0 -201
- package/simsimd/README.md +0 -275
- package/simsimd/binding.gyp +0 -36
- package/simsimd/build.rs +0 -20
- package/simsimd/include/simsimd/binary.h +0 -201
- package/simsimd/include/simsimd/probability.h +0 -548
- package/simsimd/include/simsimd/simsimd.h +0 -456
- package/simsimd/include/simsimd/spatial.h +0 -1175
- package/simsimd/include/simsimd/types.h +0 -207
- package/simsimd/javascript/bench.js +0 -127
- package/simsimd/javascript/fallback.ts +0 -193
- package/simsimd/javascript/lib.c +0 -102
- package/simsimd/javascript/node-gyp-build.d.ts +0 -1
- package/simsimd/javascript/simsimd.ts +0 -124
- package/simsimd/javascript/test.mjs +0 -153
- package/simsimd/javascript/tsconfig-base.json +0 -25
- package/simsimd/javascript/tsconfig-cjs.json +0 -8
- package/simsimd/javascript/tsconfig-esm.json +0 -8
- package/simsimd/package-lock.json +0 -1688
- package/simsimd/package.json +0 -61
- package/simsimd/rust/benches/cosine.rs +0 -27
- package/simsimd/rust/benches/native.rs +0 -27
- package/simsimd/rust/benches/sqeuclidean.rs +0 -27
- package/simsimd/rust/lib.c +0 -68
- package/simsimd/rust/lib.rs +0 -232
- package/sqlite/README.md +0 -178
- package/sqlite/lib.cpp +0 -325
- package/stringzilla/CONTRIBUTING.md +0 -429
- package/stringzilla/Cargo.lock +0 -25
- package/stringzilla/Cargo.toml +0 -26
- package/stringzilla/LICENSE +0 -201
- package/stringzilla/README.md +0 -1281
- package/stringzilla/VERSION +0 -1
- package/stringzilla/assets/cover-strinzilla.jpeg +0 -0
- package/stringzilla/assets/meme-stringzilla-v2.jpeg +0 -0
- package/stringzilla/assets/meme-stringzilla-v3.jpeg +0 -0
- package/stringzilla/binding.gyp +0 -16
- package/stringzilla/build.rs +0 -14
- package/stringzilla/c/lib.c +0 -304
- package/stringzilla/cli/README.md +0 -48
- package/stringzilla/cli/split.py +0 -72
- package/stringzilla/cli/wc.py +0 -37
- package/stringzilla/include/stringzilla/experimental.h +0 -724
- package/stringzilla/include/stringzilla/module.modulemap +0 -9
- package/stringzilla/include/stringzilla/stringzilla.h +0 -5240
- package/stringzilla/include/stringzilla/stringzilla.hpp +0 -3830
- package/stringzilla/javascript/lib.c +0 -125
- package/stringzilla/javascript/stringzilla.js +0 -22
- package/stringzilla/package-ci.json +0 -10
- package/stringzilla/package.json +0 -32
- package/stringzilla/rust/lib.rs +0 -362
- package/stringzilla/swift/StringProtocol+StringZilla.swift +0 -280
- package/stringzilla/swift/Test.swift +0 -60
- package/tsconfig.json +0 -21
- package/wasmer.toml +0 -12
- package/winlibinstaller.bat +0 -42
- /package/{simsimd/javascript/dist-package-cjs.json → javascript/dist/cjs/package.json} +0 -0
- /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
|