usearch 2.10.3 → 2.11.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 +28 -8
- package/binding.gyp +101 -0
- package/c/CMakeLists.txt +27 -0
- package/c/README.md +244 -0
- package/c/lib.cpp +459 -0
- package/c/test.c +386 -0
- package/c/usearch.h +451 -0
- package/cmake/clipp.cmake +7 -0
- package/cmake/config.cmake.in +15 -0
- package/cmake/emscripten.cmake +8 -0
- package/cmake/jemalloc.cmake +62 -0
- package/cmake/pkg-config.pc.in +4 -0
- package/cmake/usearchConfigVersion.cmake.in +20 -0
- package/cpp/CMakeLists.txt +14 -0
- package/cpp/README.md +161 -0
- package/cpp/bench.cpp +616 -0
- package/cpp/test.cpp +335 -0
- package/fp16/CMakeLists.txt +176 -0
- package/fp16/LICENSE +11 -0
- package/fp16/README.md +20 -0
- package/fp16/bench/alt-element.cc +89 -0
- package/fp16/bench/from-alt-array.cc +175 -0
- package/fp16/bench/from-ieee-array.cc +399 -0
- package/fp16/bench/ieee-element.cc +272 -0
- package/fp16/bench/to-alt-array.cc +91 -0
- package/fp16/bench/to-ieee-array.cc +303 -0
- package/fp16/cmake/DownloadGoogleBenchmark.cmake +15 -0
- package/fp16/cmake/DownloadGoogleTest.cmake +15 -0
- package/fp16/cmake/DownloadPSimd.cmake +15 -0
- package/fp16/configure.py +65 -0
- package/fp16/confu.yaml +8 -0
- package/fp16/include/fp16/__init__.py +0 -0
- package/fp16/include/fp16/avx.py +50 -0
- package/fp16/include/fp16/avx2.py +53 -0
- package/fp16/include/fp16/bitcasts.h +92 -0
- package/fp16/include/fp16/fp16.h +451 -0
- package/fp16/include/fp16/psimd.h +131 -0
- package/fp16/include/fp16.h +11 -0
- package/fp16/jni/Android.mk +6 -0
- package/fp16/jni/Application.mk +4 -0
- package/fp16/test/alt-from-fp32-value.cc +498 -0
- package/fp16/test/alt-to-fp32-bits.cc +263 -0
- package/fp16/test/alt-to-fp32-psimd.cc +145 -0
- package/fp16/test/alt-to-fp32-value.cc +348 -0
- package/fp16/test/alt-to-fp32x2-psimd.cc +245 -0
- package/fp16/test/bitcasts.cc +56 -0
- package/fp16/test/ieee-from-fp32-value.cc +523 -0
- package/fp16/test/ieee-to-fp32-bits.cc +333 -0
- package/fp16/test/ieee-to-fp32-psimd.cc +312 -0
- package/fp16/test/ieee-to-fp32-value.cc +420 -0
- package/fp16/test/ieee-to-fp32x2-psimd.cc +541 -0
- package/fp16/test/peachpy/alt-xmm-to-fp32-xmm-avx.cc +96 -0
- package/fp16/test/peachpy/alt-xmm-to-fp32-ymm-avx2.cc +96 -0
- package/fp16/test/peachpy/stubs.py +38 -0
- package/fp16/test/tables.cc +530 -0
- package/fp16/test/tables.h +13 -0
- package/fp16/third-party/THHalf.h +92 -0
- package/fp16/third-party/eigen-half.h +170 -0
- package/fp16/third-party/float16-compressor.h +80 -0
- package/fp16/third-party/half.hpp +2916 -0
- package/fp16/third-party/npy-halffloat.h +328 -0
- package/include/usearch/index.hpp +3838 -0
- package/include/usearch/index_dense.hpp +2022 -0
- package/include/usearch/index_plugins.hpp +2317 -0
- package/javascript/dist/cjs/usearch.js +5 -5
- package/javascript/dist/esm/usearch.js +2 -2
- package/javascript/dist-package-cjs.json +3 -0
- package/javascript/dist-package-esm.json +3 -0
- package/javascript/lib.cpp +350 -0
- package/javascript/node-gyp-build.d.ts +1 -0
- package/javascript/tsconfig-base.json +25 -0
- package/javascript/tsconfig-cjs.json +8 -0
- package/javascript/tsconfig-esm.json +8 -0
- package/javascript/usearch.test.js +84 -0
- package/javascript/usearch.ts +640 -0
- package/package.json +14 -7
- 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/simsimd/.releaserc +87 -0
- package/simsimd/CONTRIBUTING.md +114 -0
- package/simsimd/Cargo.lock +709 -0
- package/simsimd/Cargo.toml +44 -0
- package/simsimd/LICENSE +201 -0
- package/simsimd/README.md +708 -0
- package/simsimd/binding.gyp +36 -0
- package/simsimd/build.rs +51 -0
- package/simsimd/c/lib.c +110 -0
- package/simsimd/include/simsimd/binary.h +258 -0
- package/simsimd/include/simsimd/dot.h +1237 -0
- package/simsimd/include/simsimd/geospatial.h +37 -0
- package/simsimd/include/simsimd/probability.h +563 -0
- package/simsimd/include/simsimd/simsimd.h +1129 -0
- package/simsimd/include/simsimd/spatial.h +1019 -0
- package/simsimd/include/simsimd/types.h +309 -0
- package/simsimd/javascript/bench.js +127 -0
- package/simsimd/javascript/dist-package-cjs.json +3 -0
- package/simsimd/javascript/dist-package-esm.json +3 -0
- package/simsimd/javascript/fallback.ts +203 -0
- package/simsimd/javascript/lib.c +107 -0
- package/simsimd/javascript/node-gyp-build.d.ts +1 -0
- package/simsimd/javascript/simsimd.ts +135 -0
- package/simsimd/javascript/test.mjs +179 -0
- package/simsimd/javascript/tsconfig-base.json +37 -0
- package/simsimd/javascript/tsconfig-cjs.json +8 -0
- package/simsimd/javascript/tsconfig-esm.json +8 -0
- package/simsimd/package-lock.json +1709 -0
- package/simsimd/package.json +61 -0
- package/simsimd/rust/benches/cosine.rs +27 -0
- package/simsimd/rust/benches/native.rs +30 -0
- package/simsimd/rust/benches/sqeuclidean.rs +27 -0
- package/simsimd/rust/lib.rs +778 -0
|
@@ -0,0 +1,1129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file simsimd.h
|
|
3
|
+
* @brief SIMD-accelerated Similarity Measures and Distance Functions.
|
|
4
|
+
* @author Ash Vardanian
|
|
5
|
+
* @date March 14, 2023
|
|
6
|
+
* @copyright Copyright (c) 2023
|
|
7
|
+
*
|
|
8
|
+
* References:
|
|
9
|
+
* x86 intrinsics: https://www.intel.com/content/www/us/en/docs/intrinsics-guide/
|
|
10
|
+
* Arm intrinsics: https://developer.arm.com/architectures/instruction-sets/intrinsics/
|
|
11
|
+
* Detecting target CPU features at compile time: https://stackoverflow.com/a/28939692/2766161
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
#ifndef SIMSIMD_H
|
|
15
|
+
#define SIMSIMD_H
|
|
16
|
+
|
|
17
|
+
#define SIMSIMD_VERSION_MAJOR 4
|
|
18
|
+
#define SIMSIMD_VERSION_MINOR 2
|
|
19
|
+
#define SIMSIMD_VERSION_PATCH 2
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @brief Removes compile-time dispatching, and replaces it with runtime dispatching.
|
|
23
|
+
* So the `simsimd_dot_f32` function will invoke the most advanced backend supported by the CPU,
|
|
24
|
+
* that runs the program, rather than the most advanced backend supported by the CPU
|
|
25
|
+
* used to compile the library or the downstream application.
|
|
26
|
+
*/
|
|
27
|
+
#ifndef SIMSIMD_DYNAMIC_DISPATCH
|
|
28
|
+
#define SIMSIMD_DYNAMIC_DISPATCH (0) // true or false
|
|
29
|
+
#endif
|
|
30
|
+
|
|
31
|
+
#include "binary.h" // Hamming, Jaccard
|
|
32
|
+
#include "dot.h" // Inner (dot) product, and its conjugate
|
|
33
|
+
#include "geospatial.h" // Haversine and Vincenty
|
|
34
|
+
#include "probability.h" // Kullback-Leibler, Jensen–Shannon
|
|
35
|
+
#include "spatial.h" // L2, Cosine
|
|
36
|
+
|
|
37
|
+
#if SIMSIMD_TARGET_ARM
|
|
38
|
+
#ifdef __linux__
|
|
39
|
+
#include <asm/hwcap.h>
|
|
40
|
+
#include <sys/auxv.h>
|
|
41
|
+
#endif
|
|
42
|
+
#endif
|
|
43
|
+
|
|
44
|
+
#ifdef __cplusplus
|
|
45
|
+
extern "C" {
|
|
46
|
+
#endif
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @brief Enumeration of supported metric kinds.
|
|
50
|
+
* Some have aliases for convenience.
|
|
51
|
+
*/
|
|
52
|
+
typedef enum {
|
|
53
|
+
simsimd_metric_unknown_k = 0, ///< Unknown metric kind
|
|
54
|
+
|
|
55
|
+
// Classics:
|
|
56
|
+
simsimd_metric_dot_k = 'i', ///< Inner product
|
|
57
|
+
simsimd_metric_inner_k = 'i', ///< Inner product alias
|
|
58
|
+
|
|
59
|
+
simsimd_metric_vdot_k = 'v', ///< Complex inner product
|
|
60
|
+
|
|
61
|
+
simsimd_metric_cos_k = 'c', ///< Cosine similarity
|
|
62
|
+
simsimd_metric_cosine_k = 'c', ///< Cosine similarity alias
|
|
63
|
+
simsimd_metric_angular_k = 'c', ///< Cosine similarity alias
|
|
64
|
+
|
|
65
|
+
simsimd_metric_l2sq_k = 'e', ///< Squared Euclidean distance
|
|
66
|
+
simsimd_metric_sqeuclidean_k = 'e', ///< Squared Euclidean distance alias
|
|
67
|
+
|
|
68
|
+
// Binary:
|
|
69
|
+
simsimd_metric_hamming_k = 'h', ///< Hamming distance
|
|
70
|
+
simsimd_metric_manhattan_k = 'h', ///< Manhattan distance is same as Hamming
|
|
71
|
+
|
|
72
|
+
simsimd_metric_jaccard_k = 'j', ///< Jaccard coefficient
|
|
73
|
+
simsimd_metric_tanimoto_k = 'j', ///< Tanimoto coefficient is same as Jaccard
|
|
74
|
+
|
|
75
|
+
// Probability:
|
|
76
|
+
simsimd_metric_kl_k = 'k', ///< Kullback-Leibler divergence
|
|
77
|
+
simsimd_metric_kullback_leibler_k = 'k', ///< Kullback-Leibler divergence alias
|
|
78
|
+
|
|
79
|
+
simsimd_metric_js_k = 's', ///< Jensen-Shannon divergence
|
|
80
|
+
simsimd_metric_jensen_shannon_k = 's', ///< Jensen-Shannon divergence alias
|
|
81
|
+
|
|
82
|
+
} simsimd_metric_kind_t;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* @brief Enumeration of SIMD capabilities of the target architecture.
|
|
86
|
+
*/
|
|
87
|
+
typedef enum {
|
|
88
|
+
simsimd_cap_serial_k = 1, ///< Serial (non-SIMD) capability
|
|
89
|
+
simsimd_cap_any_k = 0x7FFFFFFF, ///< Mask representing any capability with `INT_MAX`
|
|
90
|
+
|
|
91
|
+
simsimd_cap_neon_k = 1 << 10, ///< ARM NEON capability
|
|
92
|
+
simsimd_cap_sve_k = 1 << 11, ///< ARM SVE capability
|
|
93
|
+
simsimd_cap_sve2_k = 1 << 12, ///< ARM SVE2 capability
|
|
94
|
+
|
|
95
|
+
simsimd_cap_haswell_k = 1 << 20, ///< x86 AVX2 capability with FMA and F16C extensions
|
|
96
|
+
simsimd_cap_skylake_k = 1 << 21, ///< x86 AVX512 baseline capability
|
|
97
|
+
simsimd_cap_ice_k = 1 << 22, ///< x86 AVX512 capability with advanced integer algos
|
|
98
|
+
simsimd_cap_sapphire_k = 1 << 23, ///< x86 AVX512 capability with `f16` support
|
|
99
|
+
|
|
100
|
+
} simsimd_capability_t;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* @brief Enumeration of supported data types.
|
|
104
|
+
*
|
|
105
|
+
* Includes complex type descriptors which in C code would use the real counterparts,
|
|
106
|
+
* but the independent flags contain metadata to be passed between programming language
|
|
107
|
+
* interfaces.
|
|
108
|
+
*/
|
|
109
|
+
typedef enum {
|
|
110
|
+
simsimd_datatype_unknown_k, ///< Unknown data type
|
|
111
|
+
simsimd_datatype_f64_k, ///< Double precision floating point
|
|
112
|
+
simsimd_datatype_f32_k, ///< Single precision floating point
|
|
113
|
+
simsimd_datatype_f16_k, ///< Half precision floating point
|
|
114
|
+
simsimd_datatype_i8_k, ///< 8-bit integer
|
|
115
|
+
simsimd_datatype_b8_k, ///< Single-bit values packed into 8-bit words
|
|
116
|
+
|
|
117
|
+
simsimd_datatype_f64c_k, ///< Complex double precision floating point
|
|
118
|
+
simsimd_datatype_f32c_k, ///< Complex single precision floating point
|
|
119
|
+
simsimd_datatype_f16c_k, ///< Complex half precision floating point
|
|
120
|
+
} simsimd_datatype_t;
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* @brief Type-punned function pointer accepting two vectors and outputting their similarity/distance.
|
|
124
|
+
*
|
|
125
|
+
* @param[in] a Pointer to the first data array.
|
|
126
|
+
* @param[in] b Pointer to the second data array.
|
|
127
|
+
* @param[in] n Number of scalar words in the input arrays.
|
|
128
|
+
* @param[out] d Output value as a double-precision float.
|
|
129
|
+
* In complex dot-products @b two double-precision scalars are exported
|
|
130
|
+
* for the real and imaginary parts.
|
|
131
|
+
*/
|
|
132
|
+
typedef void (*simsimd_metric_punned_t)(void const* a, void const* b, simsimd_size_t n, simsimd_distance_t* d);
|
|
133
|
+
|
|
134
|
+
#if SIMSIMD_DYNAMIC_DISPATCH
|
|
135
|
+
SIMSIMD_DYNAMIC simsimd_capability_t simsimd_capabilities(void);
|
|
136
|
+
#else
|
|
137
|
+
SIMSIMD_PUBLIC simsimd_capability_t simsimd_capabilities(void);
|
|
138
|
+
#endif
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* @brief Function to determine the SIMD capabilities of the current machine at @b runtime.
|
|
142
|
+
* @return A bitmask of the SIMD capabilities represented as a `simsimd_capability_t` enum value.
|
|
143
|
+
*/
|
|
144
|
+
SIMSIMD_PUBLIC simsimd_capability_t simsimd_capabilities_implementation(void) {
|
|
145
|
+
|
|
146
|
+
#if SIMSIMD_TARGET_X86
|
|
147
|
+
|
|
148
|
+
/// The states of 4 registers populated for a specific "cpuid" assembly call
|
|
149
|
+
union four_registers_t {
|
|
150
|
+
int array[4];
|
|
151
|
+
struct separate_t {
|
|
152
|
+
unsigned eax, ebx, ecx, edx;
|
|
153
|
+
} named;
|
|
154
|
+
} info1, info7;
|
|
155
|
+
|
|
156
|
+
#ifdef _MSC_VER
|
|
157
|
+
__cpuidex(info1.array, 1, 0);
|
|
158
|
+
__cpuidex(info7.array, 7, 0);
|
|
159
|
+
#else
|
|
160
|
+
__asm__ __volatile__("cpuid"
|
|
161
|
+
: "=a"(info1.named.eax), "=b"(info1.named.ebx), "=c"(info1.named.ecx), "=d"(info1.named.edx)
|
|
162
|
+
: "a"(1), "c"(0));
|
|
163
|
+
__asm__ __volatile__("cpuid"
|
|
164
|
+
: "=a"(info7.named.eax), "=b"(info7.named.ebx), "=c"(info7.named.ecx), "=d"(info7.named.edx)
|
|
165
|
+
: "a"(7), "c"(0));
|
|
166
|
+
#endif
|
|
167
|
+
|
|
168
|
+
// Check for AVX2 (Function ID 7, EBX register)
|
|
169
|
+
// https://github.com/llvm/llvm-project/blob/50598f0ff44f3a4e75706f8c53f3380fe7faa896/clang/lib/Headers/cpuid.h#L148
|
|
170
|
+
unsigned supports_avx2 = (info7.named.ebx & 0x00000020) != 0;
|
|
171
|
+
// Check for F16C (Function ID 1, ECX register)
|
|
172
|
+
// https://github.com/llvm/llvm-project/blob/50598f0ff44f3a4e75706f8c53f3380fe7faa896/clang/lib/Headers/cpuid.h#L107
|
|
173
|
+
unsigned supports_f16c = (info1.named.ecx & 0x20000000) != 0;
|
|
174
|
+
unsigned supports_fma = (info1.named.ecx & 0x00001000) != 0;
|
|
175
|
+
// Check for AVX512F (Function ID 7, EBX register)
|
|
176
|
+
// https://github.com/llvm/llvm-project/blob/50598f0ff44f3a4e75706f8c53f3380fe7faa896/clang/lib/Headers/cpuid.h#L155
|
|
177
|
+
unsigned supports_avx512f = (info7.named.ebx & 0x00010000) != 0;
|
|
178
|
+
// Check for AVX512FP16 (Function ID 7, EDX register)
|
|
179
|
+
// https://github.com/llvm/llvm-project/blob/50598f0ff44f3a4e75706f8c53f3380fe7faa896/clang/lib/Headers/cpuid.h#L198C9-L198C23
|
|
180
|
+
unsigned supports_avx512fp16 = (info7.named.edx & 0x00800000) != 0;
|
|
181
|
+
// Check for AVX512VNNI (Function ID 7, ECX register)
|
|
182
|
+
unsigned supports_avx512vnni = (info7.named.ecx & 0x00000800) != 0;
|
|
183
|
+
// Check for AVX512IFMA (Function ID 7, EBX register)
|
|
184
|
+
unsigned supports_avx512ifma = (info7.named.ebx & 0x00200000) != 0;
|
|
185
|
+
// Check for AVX512BITALG (Function ID 7, ECX register)
|
|
186
|
+
unsigned supports_avx512bitalg = (info7.named.ecx & 0x00001000) != 0;
|
|
187
|
+
// Check for AVX512VBMI2 (Function ID 7, ECX register)
|
|
188
|
+
unsigned supports_avx512vbmi2 = (info7.named.ecx & 0x00000040) != 0;
|
|
189
|
+
// Check for AVX512VPOPCNTDQ (Function ID 7, ECX register)
|
|
190
|
+
unsigned supports_avx512vpopcntdq = (info7.named.ecx & 0x00004000) != 0;
|
|
191
|
+
|
|
192
|
+
// Convert specific features into CPU generations
|
|
193
|
+
unsigned supports_haswell = supports_avx2 && supports_f16c && supports_fma;
|
|
194
|
+
unsigned supports_skylake = supports_avx512f;
|
|
195
|
+
unsigned supports_ice = supports_avx512vnni && supports_avx512ifma && supports_avx512bitalg &&
|
|
196
|
+
supports_avx512vbmi2 && supports_avx512vpopcntdq;
|
|
197
|
+
unsigned supports_sapphire = supports_avx512fp16;
|
|
198
|
+
|
|
199
|
+
return (simsimd_capability_t)( //
|
|
200
|
+
(simsimd_cap_haswell_k * supports_haswell) | //
|
|
201
|
+
(simsimd_cap_skylake_k * supports_skylake) | //
|
|
202
|
+
(simsimd_cap_ice_k * supports_ice) | //
|
|
203
|
+
(simsimd_cap_sapphire_k * supports_sapphire) | //
|
|
204
|
+
(simsimd_cap_serial_k));
|
|
205
|
+
|
|
206
|
+
#endif // SIMSIMD_TARGET_X86
|
|
207
|
+
|
|
208
|
+
#if SIMSIMD_TARGET_ARM
|
|
209
|
+
|
|
210
|
+
// Every 64-bit Arm CPU supports NEON
|
|
211
|
+
unsigned supports_neon = 1;
|
|
212
|
+
unsigned supports_sve = 0;
|
|
213
|
+
unsigned supports_sve2 = 0;
|
|
214
|
+
|
|
215
|
+
#ifdef __linux__
|
|
216
|
+
unsigned long hwcap = getauxval(AT_HWCAP);
|
|
217
|
+
unsigned long hwcap2 = getauxval(AT_HWCAP2);
|
|
218
|
+
supports_sve = (hwcap & HWCAP_SVE) != 0;
|
|
219
|
+
supports_sve2 = (hwcap2 & HWCAP2_SVE2) != 0;
|
|
220
|
+
#endif
|
|
221
|
+
|
|
222
|
+
return (simsimd_capability_t)( //
|
|
223
|
+
(simsimd_cap_neon_k * supports_neon) | //
|
|
224
|
+
(simsimd_cap_sve_k * supports_sve) | //
|
|
225
|
+
(simsimd_cap_sve2_k * supports_sve2) | //
|
|
226
|
+
(simsimd_cap_serial_k));
|
|
227
|
+
|
|
228
|
+
#endif // SIMSIMD_TARGET_ARM
|
|
229
|
+
|
|
230
|
+
return simsimd_cap_serial_k;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
#pragma GCC diagnostic push
|
|
234
|
+
#pragma GCC diagnostic ignored "-Wcast-function-type"
|
|
235
|
+
#pragma clang diagnostic push
|
|
236
|
+
#pragma clang diagnostic ignored "-Wcast-function-type"
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* @brief Determines the best suited metric implementation based on the given datatype,
|
|
240
|
+
* supported and allowed by hardware capabilities.
|
|
241
|
+
*
|
|
242
|
+
* @param kind The kind of metric to be evaluated.
|
|
243
|
+
* @param datatype The data type for which the metric needs to be evaluated.
|
|
244
|
+
* @param supported The hardware capabilities supported by the CPU.
|
|
245
|
+
* @param allowed The hardware capabilities allowed for use.
|
|
246
|
+
* @param metric_output Output variable for the selected similarity function.
|
|
247
|
+
* @param capability_output Output variable for the utilized hardware capabilities.
|
|
248
|
+
*/
|
|
249
|
+
SIMSIMD_PUBLIC void simsimd_find_metric_punned( //
|
|
250
|
+
simsimd_metric_kind_t kind, //
|
|
251
|
+
simsimd_datatype_t datatype, //
|
|
252
|
+
simsimd_capability_t supported, //
|
|
253
|
+
simsimd_capability_t allowed, //
|
|
254
|
+
simsimd_metric_punned_t* metric_output, //
|
|
255
|
+
simsimd_capability_t* capability_output) {
|
|
256
|
+
|
|
257
|
+
simsimd_metric_punned_t* m = metric_output;
|
|
258
|
+
simsimd_capability_t* c = capability_output;
|
|
259
|
+
simsimd_capability_t viable = (simsimd_capability_t)(supported & allowed);
|
|
260
|
+
*m = (simsimd_metric_punned_t)0;
|
|
261
|
+
*c = (simsimd_capability_t)0;
|
|
262
|
+
|
|
263
|
+
typedef simsimd_metric_punned_t m_t;
|
|
264
|
+
switch (datatype) {
|
|
265
|
+
|
|
266
|
+
case simsimd_datatype_unknown_k: break;
|
|
267
|
+
|
|
268
|
+
// Double-precision floating-point vectors
|
|
269
|
+
case simsimd_datatype_f64_k:
|
|
270
|
+
|
|
271
|
+
#if SIMSIMD_TARGET_SVE
|
|
272
|
+
if (viable & simsimd_cap_skylake_k)
|
|
273
|
+
switch (kind) {
|
|
274
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f64_sve, *c = simsimd_cap_sve_k; return;
|
|
275
|
+
case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f64_sve, *c = simsimd_cap_sve_k; return;
|
|
276
|
+
case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f64_sve, *c = simsimd_cap_sve_k; return;
|
|
277
|
+
default: break;
|
|
278
|
+
}
|
|
279
|
+
#endif
|
|
280
|
+
#if SIMSIMD_TARGET_SKYLAKE
|
|
281
|
+
if (viable & simsimd_cap_skylake_k)
|
|
282
|
+
switch (kind) {
|
|
283
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f64_skylake, *c = simsimd_cap_skylake_k; return;
|
|
284
|
+
case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f64_skylake, *c = simsimd_cap_skylake_k; return;
|
|
285
|
+
case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f64_skylake, *c = simsimd_cap_skylake_k; return;
|
|
286
|
+
default: break;
|
|
287
|
+
}
|
|
288
|
+
#endif
|
|
289
|
+
if (viable & simsimd_cap_serial_k)
|
|
290
|
+
switch (kind) {
|
|
291
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f64_serial, *c = simsimd_cap_serial_k; return;
|
|
292
|
+
case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f64_serial, *c = simsimd_cap_serial_k; return;
|
|
293
|
+
case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f64_serial, *c = simsimd_cap_serial_k; return;
|
|
294
|
+
case simsimd_metric_js_k: *m = (m_t)&simsimd_js_f64_serial, *c = simsimd_cap_serial_k; return;
|
|
295
|
+
case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_f64_serial, *c = simsimd_cap_serial_k; return;
|
|
296
|
+
default: break;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
break;
|
|
300
|
+
|
|
301
|
+
// Single-precision floating-point vectors
|
|
302
|
+
case simsimd_datatype_f32_k:
|
|
303
|
+
|
|
304
|
+
#if SIMSIMD_TARGET_SVE
|
|
305
|
+
if (viable & simsimd_cap_sve_k)
|
|
306
|
+
switch (kind) {
|
|
307
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32_sve, *c = simsimd_cap_sve_k; return;
|
|
308
|
+
case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f32_sve, *c = simsimd_cap_sve_k; return;
|
|
309
|
+
case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f32_sve, *c = simsimd_cap_sve_k; return;
|
|
310
|
+
default: break;
|
|
311
|
+
}
|
|
312
|
+
#endif
|
|
313
|
+
#if SIMSIMD_TARGET_NEON
|
|
314
|
+
if (viable & simsimd_cap_neon_k)
|
|
315
|
+
switch (kind) {
|
|
316
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32_neon, *c = simsimd_cap_neon_k; return;
|
|
317
|
+
case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f32_neon, *c = simsimd_cap_neon_k; return;
|
|
318
|
+
case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f32_neon, *c = simsimd_cap_neon_k; return;
|
|
319
|
+
case simsimd_metric_js_k: *m = (m_t)&simsimd_js_f32_neon, *c = simsimd_cap_neon_k; return;
|
|
320
|
+
case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_f32_neon, *c = simsimd_cap_neon_k; return;
|
|
321
|
+
default: break;
|
|
322
|
+
}
|
|
323
|
+
#endif
|
|
324
|
+
#if SIMSIMD_TARGET_SKYLAKE
|
|
325
|
+
if (viable & simsimd_cap_skylake_k)
|
|
326
|
+
switch (kind) {
|
|
327
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32_skylake, *c = simsimd_cap_skylake_k; return;
|
|
328
|
+
case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f32_skylake, *c = simsimd_cap_skylake_k; return;
|
|
329
|
+
case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f32_skylake, *c = simsimd_cap_skylake_k; return;
|
|
330
|
+
case simsimd_metric_js_k: *m = (m_t)&simsimd_js_f32_skylake, *c = simsimd_cap_skylake_k; return;
|
|
331
|
+
case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_f32_skylake, *c = simsimd_cap_skylake_k; return;
|
|
332
|
+
default: break;
|
|
333
|
+
}
|
|
334
|
+
#endif
|
|
335
|
+
if (viable & simsimd_cap_serial_k)
|
|
336
|
+
switch (kind) {
|
|
337
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32_serial, *c = simsimd_cap_serial_k; return;
|
|
338
|
+
case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f32_serial, *c = simsimd_cap_serial_k; return;
|
|
339
|
+
case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f32_serial, *c = simsimd_cap_serial_k; return;
|
|
340
|
+
case simsimd_metric_js_k: *m = (m_t)&simsimd_js_f32_serial, *c = simsimd_cap_serial_k; return;
|
|
341
|
+
case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_f32_serial, *c = simsimd_cap_serial_k; return;
|
|
342
|
+
default: break;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
break;
|
|
346
|
+
|
|
347
|
+
// Half-precision floating-point vectors
|
|
348
|
+
case simsimd_datatype_f16_k:
|
|
349
|
+
|
|
350
|
+
#if SIMSIMD_TARGET_SVE
|
|
351
|
+
if (viable & simsimd_cap_sve_k)
|
|
352
|
+
switch (kind) {
|
|
353
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16_sve, *c = simsimd_cap_sve_k; return;
|
|
354
|
+
case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f16_sve, *c = simsimd_cap_sve_k; return;
|
|
355
|
+
case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f16_sve, *c = simsimd_cap_sve_k; return;
|
|
356
|
+
default: break;
|
|
357
|
+
}
|
|
358
|
+
#endif
|
|
359
|
+
#if SIMSIMD_TARGET_NEON
|
|
360
|
+
if (viable & simsimd_cap_neon_k)
|
|
361
|
+
switch (kind) {
|
|
362
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16_neon, *c = simsimd_cap_neon_k; return;
|
|
363
|
+
case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f16_neon, *c = simsimd_cap_neon_k; return;
|
|
364
|
+
case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f16_neon, *c = simsimd_cap_neon_k; return;
|
|
365
|
+
case simsimd_metric_js_k: *m = (m_t)&simsimd_js_f16_neon, *c = simsimd_cap_neon_k; return;
|
|
366
|
+
case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_f16_neon, *c = simsimd_cap_neon_k; return;
|
|
367
|
+
default: break;
|
|
368
|
+
}
|
|
369
|
+
#endif
|
|
370
|
+
#if SIMSIMD_TARGET_SAPPHIRE
|
|
371
|
+
if (viable & simsimd_cap_sapphire_k)
|
|
372
|
+
switch (kind) {
|
|
373
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16_sapphire, *c = simsimd_cap_sapphire_k; return;
|
|
374
|
+
case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f16_sapphire, *c = simsimd_cap_sapphire_k; return;
|
|
375
|
+
case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f16_sapphire, *c = simsimd_cap_sapphire_k; return;
|
|
376
|
+
case simsimd_metric_js_k: *m = (m_t)&simsimd_js_f16_sapphire, *c = simsimd_cap_sapphire_k; return;
|
|
377
|
+
case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_f16_sapphire, *c = simsimd_cap_sapphire_k; return;
|
|
378
|
+
default: break;
|
|
379
|
+
}
|
|
380
|
+
#endif
|
|
381
|
+
#if SIMSIMD_TARGET_HASWELL
|
|
382
|
+
if (viable & simsimd_cap_haswell_k)
|
|
383
|
+
switch (kind) {
|
|
384
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16_haswell, *c = simsimd_cap_haswell_k; return;
|
|
385
|
+
case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f16_haswell, *c = simsimd_cap_haswell_k; return;
|
|
386
|
+
case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f16_haswell, *c = simsimd_cap_haswell_k; return;
|
|
387
|
+
case simsimd_metric_js_k: *m = (m_t)&simsimd_js_f16_haswell, *c = simsimd_cap_haswell_k; return;
|
|
388
|
+
case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_f16_haswell, *c = simsimd_cap_haswell_k; return;
|
|
389
|
+
default: break;
|
|
390
|
+
}
|
|
391
|
+
#endif
|
|
392
|
+
|
|
393
|
+
if (viable & simsimd_cap_serial_k)
|
|
394
|
+
switch (kind) {
|
|
395
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16_serial, *c = simsimd_cap_serial_k; return;
|
|
396
|
+
case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f16_serial, *c = simsimd_cap_serial_k; return;
|
|
397
|
+
case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f16_serial, *c = simsimd_cap_serial_k; return;
|
|
398
|
+
case simsimd_metric_js_k: *m = (m_t)&simsimd_js_f16_serial, *c = simsimd_cap_serial_k; return;
|
|
399
|
+
case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_f16_serial, *c = simsimd_cap_serial_k; return;
|
|
400
|
+
default: break;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
break;
|
|
404
|
+
|
|
405
|
+
// Single-byte integer vectors
|
|
406
|
+
case simsimd_datatype_i8_k:
|
|
407
|
+
#if SIMSIMD_TARGET_NEON
|
|
408
|
+
if (viable & simsimd_cap_neon_k)
|
|
409
|
+
switch (kind) {
|
|
410
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_cos_i8_neon, *c = simsimd_cap_neon_k; return;
|
|
411
|
+
case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_i8_neon, *c = simsimd_cap_neon_k; return;
|
|
412
|
+
case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_i8_neon, *c = simsimd_cap_neon_k; return;
|
|
413
|
+
default: break;
|
|
414
|
+
}
|
|
415
|
+
#endif
|
|
416
|
+
#if SIMSIMD_TARGET_ICE
|
|
417
|
+
if (viable & simsimd_cap_ice_k)
|
|
418
|
+
switch (kind) {
|
|
419
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_cos_i8_ice, *c = simsimd_cap_ice_k; return;
|
|
420
|
+
case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_i8_ice, *c = simsimd_cap_ice_k; return;
|
|
421
|
+
case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_i8_ice, *c = simsimd_cap_ice_k; return;
|
|
422
|
+
default: break;
|
|
423
|
+
}
|
|
424
|
+
#endif
|
|
425
|
+
#if SIMSIMD_TARGET_HASWELL
|
|
426
|
+
if (viable & simsimd_cap_haswell_k)
|
|
427
|
+
switch (kind) {
|
|
428
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_cos_i8_haswell, *c = simsimd_cap_haswell_k; return;
|
|
429
|
+
case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_i8_haswell, *c = simsimd_cap_haswell_k; return;
|
|
430
|
+
case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_i8_haswell, *c = simsimd_cap_haswell_k; return;
|
|
431
|
+
default: break;
|
|
432
|
+
}
|
|
433
|
+
#endif
|
|
434
|
+
|
|
435
|
+
if (viable & simsimd_cap_serial_k)
|
|
436
|
+
switch (kind) {
|
|
437
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_cos_i8_serial, *c = simsimd_cap_serial_k; return;
|
|
438
|
+
case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_i8_serial, *c = simsimd_cap_serial_k; return;
|
|
439
|
+
case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_i8_serial, *c = simsimd_cap_serial_k; return;
|
|
440
|
+
default: break;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
break;
|
|
444
|
+
|
|
445
|
+
// Binary vectors
|
|
446
|
+
case simsimd_datatype_b8_k:
|
|
447
|
+
|
|
448
|
+
#if SIMSIMD_TARGET_SVE
|
|
449
|
+
if (viable & simsimd_cap_sve_k)
|
|
450
|
+
switch (kind) {
|
|
451
|
+
case simsimd_metric_hamming_k: *m = (m_t)&simsimd_hamming_b8_sve, *c = simsimd_cap_sve_k; return;
|
|
452
|
+
case simsimd_metric_jaccard_k: *m = (m_t)&simsimd_jaccard_b8_sve, *c = simsimd_cap_sve_k; return;
|
|
453
|
+
default: break;
|
|
454
|
+
}
|
|
455
|
+
#endif
|
|
456
|
+
#if SIMSIMD_TARGET_NEON
|
|
457
|
+
if (viable & simsimd_cap_neon_k)
|
|
458
|
+
switch (kind) {
|
|
459
|
+
case simsimd_metric_hamming_k: *m = (m_t)&simsimd_hamming_b8_neon, *c = simsimd_cap_neon_k; return;
|
|
460
|
+
case simsimd_metric_jaccard_k: *m = (m_t)&simsimd_jaccard_b8_neon, *c = simsimd_cap_neon_k; return;
|
|
461
|
+
default: break;
|
|
462
|
+
}
|
|
463
|
+
#endif
|
|
464
|
+
#if SIMSIMD_TARGET_ICE
|
|
465
|
+
if (viable & simsimd_cap_ice_k)
|
|
466
|
+
switch (kind) {
|
|
467
|
+
case simsimd_metric_hamming_k: *m = (m_t)&simsimd_hamming_b8_ice, *c = simsimd_cap_ice_k; return;
|
|
468
|
+
case simsimd_metric_jaccard_k: *m = (m_t)&simsimd_jaccard_b8_ice, *c = simsimd_cap_ice_k; return;
|
|
469
|
+
default: break;
|
|
470
|
+
}
|
|
471
|
+
#endif
|
|
472
|
+
#if SIMSIMD_TARGET_HASWELL
|
|
473
|
+
if (viable & simsimd_cap_haswell_k)
|
|
474
|
+
switch (kind) {
|
|
475
|
+
case simsimd_metric_hamming_k: *m = (m_t)&simsimd_hamming_b8_haswell, *c = simsimd_cap_haswell_k; return;
|
|
476
|
+
case simsimd_metric_jaccard_k: *m = (m_t)&simsimd_jaccard_b8_haswell, *c = simsimd_cap_haswell_k; return;
|
|
477
|
+
default: break;
|
|
478
|
+
}
|
|
479
|
+
#endif
|
|
480
|
+
|
|
481
|
+
if (viable & simsimd_cap_serial_k)
|
|
482
|
+
switch (kind) {
|
|
483
|
+
case simsimd_metric_hamming_k: *m = (m_t)&simsimd_hamming_b8_serial, *c = simsimd_cap_serial_k; return;
|
|
484
|
+
case simsimd_metric_jaccard_k: *m = (m_t)&simsimd_jaccard_b8_serial, *c = simsimd_cap_serial_k; return;
|
|
485
|
+
default: break;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
break;
|
|
489
|
+
|
|
490
|
+
case simsimd_datatype_f32c_k:
|
|
491
|
+
|
|
492
|
+
#if SIMSIMD_TARGET_SVE
|
|
493
|
+
if (viable & simsimd_cap_sve_k)
|
|
494
|
+
switch (kind) {
|
|
495
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32c_sve, *c = simsimd_cap_sve_k; return;
|
|
496
|
+
case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f32c_sve, *c = simsimd_cap_sve_k; return;
|
|
497
|
+
default: break;
|
|
498
|
+
}
|
|
499
|
+
#endif
|
|
500
|
+
#if SIMSIMD_TARGET_NEON
|
|
501
|
+
if (viable & simsimd_cap_neon_k)
|
|
502
|
+
switch (kind) {
|
|
503
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32c_neon, *c = simsimd_cap_neon_k; return;
|
|
504
|
+
case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f32c_neon, *c = simsimd_cap_neon_k; return;
|
|
505
|
+
default: break;
|
|
506
|
+
}
|
|
507
|
+
#endif
|
|
508
|
+
#if SIMSIMD_TARGET_HASWELL
|
|
509
|
+
if (viable & simsimd_cap_haswell_k)
|
|
510
|
+
switch (kind) {
|
|
511
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32c_haswell, *c = simsimd_cap_haswell_k; return;
|
|
512
|
+
case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f32c_haswell, *c = simsimd_cap_haswell_k; return;
|
|
513
|
+
default: break;
|
|
514
|
+
}
|
|
515
|
+
#endif
|
|
516
|
+
#if SIMSIMD_TARGET_SKYLAKE
|
|
517
|
+
if (viable & simsimd_cap_skylake_k)
|
|
518
|
+
switch (kind) {
|
|
519
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32c_skylake, *c = simsimd_cap_skylake_k; return;
|
|
520
|
+
case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f32c_skylake, *c = simsimd_cap_skylake_k; return;
|
|
521
|
+
default: break;
|
|
522
|
+
}
|
|
523
|
+
#endif
|
|
524
|
+
|
|
525
|
+
if (viable & simsimd_cap_serial_k)
|
|
526
|
+
switch (kind) {
|
|
527
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32c_serial, *c = simsimd_cap_serial_k; return;
|
|
528
|
+
case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f32c_serial, *c = simsimd_cap_serial_k; return;
|
|
529
|
+
default: break;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
break;
|
|
533
|
+
|
|
534
|
+
case simsimd_datatype_f64c_k:
|
|
535
|
+
|
|
536
|
+
#if SIMSIMD_TARGET_SVE
|
|
537
|
+
if (viable & simsimd_cap_sve_k)
|
|
538
|
+
switch (kind) {
|
|
539
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f64c_sve, *c = simsimd_cap_sve_k; return;
|
|
540
|
+
case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f64c_sve, *c = simsimd_cap_sve_k; return;
|
|
541
|
+
default: break;
|
|
542
|
+
}
|
|
543
|
+
#endif
|
|
544
|
+
#if SIMSIMD_TARGET_SKYLAKE
|
|
545
|
+
if (viable & simsimd_cap_skylake_k)
|
|
546
|
+
switch (kind) {
|
|
547
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f64c_skylake, *c = simsimd_cap_skylake_k; return;
|
|
548
|
+
case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f64c_skylake, *c = simsimd_cap_skylake_k; return;
|
|
549
|
+
default: break;
|
|
550
|
+
}
|
|
551
|
+
#endif
|
|
552
|
+
|
|
553
|
+
if (viable & simsimd_cap_serial_k)
|
|
554
|
+
switch (kind) {
|
|
555
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f64c_serial, *c = simsimd_cap_serial_k; return;
|
|
556
|
+
case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f64c_serial, *c = simsimd_cap_serial_k; return;
|
|
557
|
+
default: break;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
break;
|
|
561
|
+
|
|
562
|
+
case simsimd_datatype_f16c_k:
|
|
563
|
+
|
|
564
|
+
#if SIMSIMD_TARGET_SVE
|
|
565
|
+
if (viable & simsimd_cap_sve_k)
|
|
566
|
+
switch (kind) {
|
|
567
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16c_sve, *c = simsimd_cap_sve_k; return;
|
|
568
|
+
case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f16c_sve, *c = simsimd_cap_sve_k; return;
|
|
569
|
+
default: break;
|
|
570
|
+
}
|
|
571
|
+
#endif
|
|
572
|
+
#if SIMSIMD_TARGET_NEON
|
|
573
|
+
if (viable & simsimd_cap_neon_k)
|
|
574
|
+
switch (kind) {
|
|
575
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16c_neon, *c = simsimd_cap_neon_k; return;
|
|
576
|
+
case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f16c_neon, *c = simsimd_cap_neon_k; return;
|
|
577
|
+
default: break;
|
|
578
|
+
}
|
|
579
|
+
#endif
|
|
580
|
+
#if SIMSIMD_TARGET_HASWELL
|
|
581
|
+
if (viable & simsimd_cap_haswell_k)
|
|
582
|
+
switch (kind) {
|
|
583
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16c_haswell, *c = simsimd_cap_haswell_k; return;
|
|
584
|
+
case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f16c_haswell, *c = simsimd_cap_haswell_k; return;
|
|
585
|
+
default: break;
|
|
586
|
+
}
|
|
587
|
+
#endif
|
|
588
|
+
#if SIMSIMD_TARGET_SAPPHIRE
|
|
589
|
+
if (viable & simsimd_cap_sapphire_k)
|
|
590
|
+
switch (kind) {
|
|
591
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16c_sapphire, *c = simsimd_cap_sapphire_k; return;
|
|
592
|
+
case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f16c_sapphire, *c = simsimd_cap_sapphire_k; return;
|
|
593
|
+
default: break;
|
|
594
|
+
}
|
|
595
|
+
#endif
|
|
596
|
+
|
|
597
|
+
if (viable & simsimd_cap_serial_k)
|
|
598
|
+
switch (kind) {
|
|
599
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16c_serial, *c = simsimd_cap_serial_k; return;
|
|
600
|
+
case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f16c_serial, *c = simsimd_cap_serial_k; return;
|
|
601
|
+
default: break;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
break;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
#pragma clang diagnostic pop
|
|
609
|
+
#pragma GCC diagnostic pop
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* @brief Selects the most suitable metric implementation based on the given metric kind, datatype,
|
|
613
|
+
* and allowed capabilities. @b Don't call too often and prefer caching the `simsimd_capabilities()`.
|
|
614
|
+
*
|
|
615
|
+
* @param kind The kind of metric to be evaluated.
|
|
616
|
+
* @param datatype The data type for which the metric needs to be evaluated.
|
|
617
|
+
* @param allowed The hardware capabilities allowed for use.
|
|
618
|
+
* @return A function pointer to the selected metric implementation.
|
|
619
|
+
*/
|
|
620
|
+
SIMSIMD_PUBLIC simsimd_metric_punned_t simsimd_metric_punned( //
|
|
621
|
+
simsimd_metric_kind_t kind, //
|
|
622
|
+
simsimd_datatype_t datatype, //
|
|
623
|
+
simsimd_capability_t allowed) {
|
|
624
|
+
|
|
625
|
+
simsimd_metric_punned_t result = 0;
|
|
626
|
+
simsimd_capability_t c = simsimd_cap_serial_k;
|
|
627
|
+
simsimd_capability_t supported = simsimd_capabilities();
|
|
628
|
+
simsimd_find_metric_punned(kind, datatype, supported, allowed, &result, &c);
|
|
629
|
+
return result;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
#if SIMSIMD_DYNAMIC_DISPATCH
|
|
633
|
+
|
|
634
|
+
/* Run-time feature-testing functions
|
|
635
|
+
* - Check if the CPU supports NEON or SVE extensions on Arm
|
|
636
|
+
* - Check if the CPU supports AVX2 and F16C extensions on Haswell x86 CPUs and newer
|
|
637
|
+
* - Check if the CPU supports AVX512F and AVX512BW extensions on Skylake x86 CPUs and newer
|
|
638
|
+
* - Check if the CPU supports AVX512VNNI, AVX512IFMA, AVX512BITALG, AVX512VBMI2, and AVX512VPOPCNTDQ
|
|
639
|
+
* extensions on Ice Lake x86 CPUs and newer
|
|
640
|
+
* - Check if the CPU supports AVX512FP16 extensions on Sapphire Rapids x86 CPUs and newer
|
|
641
|
+
*
|
|
642
|
+
* @return 1 if the CPU supports the SIMD instruction set, 0 otherwise.
|
|
643
|
+
*/
|
|
644
|
+
SIMSIMD_DYNAMIC int simsimd_uses_neon(void);
|
|
645
|
+
SIMSIMD_DYNAMIC int simsimd_uses_sve(void);
|
|
646
|
+
SIMSIMD_DYNAMIC int simsimd_uses_haswell(void);
|
|
647
|
+
SIMSIMD_DYNAMIC int simsimd_uses_skylake(void);
|
|
648
|
+
SIMSIMD_DYNAMIC int simsimd_uses_ice(void);
|
|
649
|
+
SIMSIMD_DYNAMIC int simsimd_uses_sapphire(void);
|
|
650
|
+
SIMSIMD_DYNAMIC simsimd_capability_t simsimd_capabilities(void);
|
|
651
|
+
|
|
652
|
+
/* Inner products
|
|
653
|
+
* - Dot product: the sum of the products of the corresponding elements of two vectors.
|
|
654
|
+
* - Complex Dot product: dot product with a conjugate first argument.
|
|
655
|
+
* - Complex Conjugate Dot product: dot product with a conjugate first argument.
|
|
656
|
+
*
|
|
657
|
+
* @param a The first vector.
|
|
658
|
+
* @param b The second vector.
|
|
659
|
+
* @param n The number of elements in the vectors. Even for complex variants (the number of scalars).
|
|
660
|
+
* @param d The output distance value.
|
|
661
|
+
*
|
|
662
|
+
* @note The dot product can be negative, to use as a distance, take `1 - a * b`.
|
|
663
|
+
* @note The dot product is zero if and only if the two vectors are orthogonal.
|
|
664
|
+
* @note Defined only for floating-point and integer data types.
|
|
665
|
+
*/
|
|
666
|
+
SIMSIMD_DYNAMIC void simsimd_dot_f16(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
|
|
667
|
+
simsimd_distance_t* d);
|
|
668
|
+
SIMSIMD_DYNAMIC void simsimd_dot_f32(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
|
|
669
|
+
simsimd_distance_t* d);
|
|
670
|
+
SIMSIMD_DYNAMIC void simsimd_dot_f64(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
|
|
671
|
+
simsimd_distance_t* d);
|
|
672
|
+
SIMSIMD_DYNAMIC void simsimd_dot_f16c(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
|
|
673
|
+
simsimd_distance_t* d);
|
|
674
|
+
SIMSIMD_DYNAMIC void simsimd_dot_f32c(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
|
|
675
|
+
simsimd_distance_t* d);
|
|
676
|
+
SIMSIMD_DYNAMIC void simsimd_dot_f64c(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
|
|
677
|
+
simsimd_distance_t* d);
|
|
678
|
+
SIMSIMD_DYNAMIC void simsimd_vdot_f16c(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
|
|
679
|
+
simsimd_distance_t* d);
|
|
680
|
+
SIMSIMD_DYNAMIC void simsimd_vdot_f32c(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
|
|
681
|
+
simsimd_distance_t* d);
|
|
682
|
+
SIMSIMD_DYNAMIC void simsimd_vdot_f64c(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
|
|
683
|
+
simsimd_distance_t* d);
|
|
684
|
+
|
|
685
|
+
/* Spatial distances
|
|
686
|
+
* - Cosine distance: the cosine of the angle between two vectors.
|
|
687
|
+
* - L2 squared distance: the squared Euclidean distance between two vectors.
|
|
688
|
+
*
|
|
689
|
+
* @param a The first vector.
|
|
690
|
+
* @param b The second vector.
|
|
691
|
+
* @param n The number of elements in the vectors.
|
|
692
|
+
* @param d The output distance value.
|
|
693
|
+
*
|
|
694
|
+
* @note The output distance value is non-negative.
|
|
695
|
+
* @note The output distance value is zero if and only if the two vectors are identical.
|
|
696
|
+
* @note Defined only for floating-point and integer data types.
|
|
697
|
+
*/
|
|
698
|
+
SIMSIMD_DYNAMIC void simsimd_cos_i8(simsimd_i8_t const* a, simsimd_i8_t const* b, simsimd_size_t n,
|
|
699
|
+
simsimd_distance_t* d);
|
|
700
|
+
SIMSIMD_DYNAMIC void simsimd_cos_f16(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
|
|
701
|
+
simsimd_distance_t* d);
|
|
702
|
+
SIMSIMD_DYNAMIC void simsimd_cos_f32(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
|
|
703
|
+
simsimd_distance_t* d);
|
|
704
|
+
SIMSIMD_DYNAMIC void simsimd_cos_f64(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
|
|
705
|
+
simsimd_distance_t* d);
|
|
706
|
+
SIMSIMD_DYNAMIC void simsimd_l2sq_i8(simsimd_i8_t const* a, simsimd_i8_t const* b, simsimd_size_t n,
|
|
707
|
+
simsimd_distance_t* d);
|
|
708
|
+
SIMSIMD_DYNAMIC void simsimd_l2sq_f16(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
|
|
709
|
+
simsimd_distance_t* d);
|
|
710
|
+
SIMSIMD_DYNAMIC void simsimd_l2sq_f32(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
|
|
711
|
+
simsimd_distance_t* d);
|
|
712
|
+
SIMSIMD_DYNAMIC void simsimd_l2sq_f64(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
|
|
713
|
+
simsimd_distance_t* d);
|
|
714
|
+
|
|
715
|
+
/* Binary distances
|
|
716
|
+
* - Hamming distance: the number of positions at which the corresponding bits are different.
|
|
717
|
+
* - Jaccard distance: ratio of bit-level matching positions (intersection) to the total number of positions (union).
|
|
718
|
+
*
|
|
719
|
+
* @param a The first binary vector.
|
|
720
|
+
* @param b The second binary vector.
|
|
721
|
+
* @param n The number of 8-bit words in the vectors.
|
|
722
|
+
* @param d The output distance value.
|
|
723
|
+
*
|
|
724
|
+
* @note The output distance value is non-negative.
|
|
725
|
+
* @note The output distance value is zero if and only if the two vectors are identical.
|
|
726
|
+
* @note Defined only for binary data.
|
|
727
|
+
*/
|
|
728
|
+
SIMSIMD_DYNAMIC void simsimd_hamming_b8(simsimd_b8_t const* a, simsimd_b8_t const* b, simsimd_size_t n,
|
|
729
|
+
simsimd_distance_t* d);
|
|
730
|
+
SIMSIMD_DYNAMIC void simsimd_jaccard_b8(simsimd_b8_t const* a, simsimd_b8_t const* b, simsimd_size_t n,
|
|
731
|
+
simsimd_distance_t* d);
|
|
732
|
+
|
|
733
|
+
/* Probability distributions
|
|
734
|
+
* - Jensen-Shannon divergence: a measure of similarity between two probability distributions.
|
|
735
|
+
* - Kullback-Leibler divergence: a measure of how one probability distribution diverges from a second.
|
|
736
|
+
*
|
|
737
|
+
* @param a The first descrete probability distribution.
|
|
738
|
+
* @param b The second descrete probability distribution.
|
|
739
|
+
* @param n The number of elements in the descrete distributions.
|
|
740
|
+
* @param d The output divergence value.
|
|
741
|
+
*
|
|
742
|
+
* @note The distributions are assumed to be normalized.
|
|
743
|
+
* @note The output divergence value is non-negative.
|
|
744
|
+
* @note The output divergence value is zero if and only if the two distributions are identical.
|
|
745
|
+
* @note Defined only for floating-point data types.
|
|
746
|
+
*/
|
|
747
|
+
SIMSIMD_DYNAMIC void simsimd_kl_f16(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
|
|
748
|
+
simsimd_distance_t* d);
|
|
749
|
+
SIMSIMD_DYNAMIC void simsimd_kl_f32(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
|
|
750
|
+
simsimd_distance_t* d);
|
|
751
|
+
SIMSIMD_DYNAMIC void simsimd_kl_f64(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
|
|
752
|
+
simsimd_distance_t* d);
|
|
753
|
+
SIMSIMD_DYNAMIC void simsimd_js_f16(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
|
|
754
|
+
simsimd_distance_t* d);
|
|
755
|
+
SIMSIMD_DYNAMIC void simsimd_js_f32(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
|
|
756
|
+
simsimd_distance_t* d);
|
|
757
|
+
SIMSIMD_DYNAMIC void simsimd_js_f64(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
|
|
758
|
+
simsimd_distance_t* d);
|
|
759
|
+
|
|
760
|
+
#else
|
|
761
|
+
|
|
762
|
+
/* Compile-time feature-testing functions
|
|
763
|
+
* - Check if the CPU supports NEON or SVE extensions on Arm
|
|
764
|
+
* - Check if the CPU supports AVX2 and F16C extensions on Haswell x86 CPUs and newer
|
|
765
|
+
* - Check if the CPU supports AVX512F and AVX512BW extensions on Skylake x86 CPUs and newer
|
|
766
|
+
* - Check if the CPU supports AVX512VNNI, AVX512IFMA, AVX512BITALG, AVX512VBMI2, and AVX512VPOPCNTDQ
|
|
767
|
+
* extensions on Ice Lake x86 CPUs and newer
|
|
768
|
+
* - Check if the CPU supports AVX512FP16 extensions on Sapphire Rapids x86 CPUs and newer
|
|
769
|
+
*
|
|
770
|
+
* @return 1 if the CPU supports the SIMD instruction set, 0 otherwise.
|
|
771
|
+
*/
|
|
772
|
+
SIMSIMD_PUBLIC int simsimd_uses_neon(void) { return SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_NEON; }
|
|
773
|
+
SIMSIMD_PUBLIC int simsimd_uses_sve(void) { return SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_SVE; }
|
|
774
|
+
SIMSIMD_PUBLIC int simsimd_uses_haswell(void) { return SIMSIMD_TARGET_X86 && SIMSIMD_TARGET_HASWELL; }
|
|
775
|
+
SIMSIMD_PUBLIC int simsimd_uses_skylake(void) { return SIMSIMD_TARGET_X86 && SIMSIMD_TARGET_SKYLAKE; }
|
|
776
|
+
SIMSIMD_PUBLIC int simsimd_uses_ice(void) { return SIMSIMD_TARGET_X86 && SIMSIMD_TARGET_ICE; }
|
|
777
|
+
SIMSIMD_PUBLIC int simsimd_uses_sapphire(void) { return SIMSIMD_TARGET_X86 && SIMSIMD_TARGET_SAPPHIRE; }
|
|
778
|
+
SIMSIMD_PUBLIC simsimd_capability_t simsimd_capabilities(void) { return simsimd_capabilities_implementation(); }
|
|
779
|
+
|
|
780
|
+
/* Inner products
|
|
781
|
+
* - Dot product: the sum of the products of the corresponding elements of two vectors.
|
|
782
|
+
* - Complex Dot product: dot product with a conjugate first argument.
|
|
783
|
+
* - Complex Conjugate Dot product: dot product with a conjugate first argument.
|
|
784
|
+
*
|
|
785
|
+
* @param a The first vector.
|
|
786
|
+
* @param b The second vector.
|
|
787
|
+
* @param n The number of elements in the vectors. Even for complex variants (the number of scalars).
|
|
788
|
+
* @param d The output distance value.
|
|
789
|
+
*
|
|
790
|
+
* @note The dot product can be negative, to use as a distance, take `1 - a * b`.
|
|
791
|
+
* @note The dot product is zero if and only if the two vectors are orthogonal.
|
|
792
|
+
* @note Defined only for floating-point and integer data types.
|
|
793
|
+
*/
|
|
794
|
+
SIMSIMD_PUBLIC void simsimd_dot_f16(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
|
|
795
|
+
simsimd_distance_t* d) {
|
|
796
|
+
#if SIMSIMD_TARGET_SVE
|
|
797
|
+
simsimd_dot_f16_sve(a, b, n, d);
|
|
798
|
+
#elif SIMSIMD_TARGET_NEON
|
|
799
|
+
simsimd_dot_f16_neon(a, b, n, d);
|
|
800
|
+
#elif SIMSIMD_TARGET_HASWELL
|
|
801
|
+
simsimd_dot_f16_haswell(a, b, n, d);
|
|
802
|
+
#elif SIMSIMD_TARGET_SAPPHIRE
|
|
803
|
+
simsimd_dot_f16_sapphire(a, b, n, d);
|
|
804
|
+
#else
|
|
805
|
+
simsimd_dot_f16_serial(a, b, n, d);
|
|
806
|
+
#endif
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
SIMSIMD_PUBLIC void simsimd_dot_f32(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
|
|
810
|
+
simsimd_distance_t* d) {
|
|
811
|
+
#if SIMSIMD_TARGET_SVE
|
|
812
|
+
simsimd_dot_f32_sve(a, b, n, d);
|
|
813
|
+
#elif SIMSIMD_TARGET_NEON
|
|
814
|
+
simsimd_dot_f32_neon(a, b, n, d);
|
|
815
|
+
#elif SIMSIMD_TARGET_SKYLAKE
|
|
816
|
+
simsimd_dot_f32_skylake(a, b, n, d);
|
|
817
|
+
#else
|
|
818
|
+
simsimd_dot_f32_serial(a, b, n, d);
|
|
819
|
+
#endif
|
|
820
|
+
}
|
|
821
|
+
SIMSIMD_PUBLIC void simsimd_dot_f64(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
|
|
822
|
+
simsimd_distance_t* d) {
|
|
823
|
+
#if SIMSIMD_TARGET_SVE
|
|
824
|
+
simsimd_dot_f64_sve(a, b, n, d);
|
|
825
|
+
#elif SIMSIMD_TARGET_SKYLAKE
|
|
826
|
+
simsimd_dot_f64_skylake(a, b, n, d);
|
|
827
|
+
#else
|
|
828
|
+
simsimd_dot_f64_serial(a, b, n, d);
|
|
829
|
+
#endif
|
|
830
|
+
}
|
|
831
|
+
SIMSIMD_PUBLIC void simsimd_dot_f16c(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
|
|
832
|
+
simsimd_distance_t* d) {
|
|
833
|
+
#if SIMSIMD_TARGET_SVE
|
|
834
|
+
simsimd_dot_f16c_sve(a, b, n, d);
|
|
835
|
+
#elif SIMSIMD_TARGET_NEON
|
|
836
|
+
simsimd_dot_f16c_neon(a, b, n, d);
|
|
837
|
+
#elif SIMSIMD_TARGET_HASWELL
|
|
838
|
+
simsimd_dot_f16c_haswell(a, b, n, d);
|
|
839
|
+
#elif SIMSIMD_TARGET_sapphire
|
|
840
|
+
simsimd_dot_f16c_sapphire(a, b, n, d);
|
|
841
|
+
#else
|
|
842
|
+
simsimd_dot_f16c_serial(a, b, n, d);
|
|
843
|
+
#endif
|
|
844
|
+
}
|
|
845
|
+
SIMSIMD_PUBLIC void simsimd_dot_f32c(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
|
|
846
|
+
simsimd_distance_t* d) {
|
|
847
|
+
#if SIMSIMD_TARGET_SVE
|
|
848
|
+
simsimd_dot_f32c_sve(a, b, n, d);
|
|
849
|
+
#elif SIMSIMD_TARGET_NEON
|
|
850
|
+
simsimd_dot_f32c_neon(a, b, n, d);
|
|
851
|
+
#elif SIMSIMD_TARGET_HASWELL
|
|
852
|
+
simsimd_dot_f32c_haswell(a, b, n, d);
|
|
853
|
+
#elif SIMSIMD_TARGET_SKYLAKE
|
|
854
|
+
simsimd_dot_f32c_skylake(a, b, n, d);
|
|
855
|
+
#else
|
|
856
|
+
simsimd_dot_f32c_serial(a, b, n, d);
|
|
857
|
+
#endif
|
|
858
|
+
}
|
|
859
|
+
SIMSIMD_PUBLIC void simsimd_dot_f64c(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
|
|
860
|
+
simsimd_distance_t* d) {
|
|
861
|
+
#if SIMSIMD_TARGET_SVE
|
|
862
|
+
simsimd_dot_f64c_sve(a, b, n, d);
|
|
863
|
+
#elif SIMSIMD_TARGET_SKYLAKE
|
|
864
|
+
simsimd_dot_f64c_skylake(a, b, n, d);
|
|
865
|
+
#else
|
|
866
|
+
simsimd_dot_f64c_serial(a, b, n, d);
|
|
867
|
+
#endif
|
|
868
|
+
}
|
|
869
|
+
SIMSIMD_PUBLIC void simsimd_vdot_f16c(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
|
|
870
|
+
simsimd_distance_t* d) {
|
|
871
|
+
#if SIMSIMD_TARGET_SVE
|
|
872
|
+
simsimd_dot_f16c_sve(a, b, n, d);
|
|
873
|
+
#elif SIMSIMD_TARGET_NEON
|
|
874
|
+
simsimd_dot_f16c_neon(a, b, n, d);
|
|
875
|
+
#elif SIMSIMD_TARGET_HASWELL
|
|
876
|
+
simsimd_dot_f16c_haswell(a, b, n, d);
|
|
877
|
+
#elif SIMSIMD_TARGET_sapphire
|
|
878
|
+
simsimd_dot_f16c_sapphire(a, b, n, d);
|
|
879
|
+
#else
|
|
880
|
+
simsimd_dot_f16c_serial(a, b, n, d);
|
|
881
|
+
#endif
|
|
882
|
+
}
|
|
883
|
+
SIMSIMD_PUBLIC void simsimd_vdot_f32c(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
|
|
884
|
+
simsimd_distance_t* d) {
|
|
885
|
+
#if SIMSIMD_TARGET_SVE
|
|
886
|
+
simsimd_dot_f32c_sve(a, b, n, d);
|
|
887
|
+
#elif SIMSIMD_TARGET_NEON
|
|
888
|
+
simsimd_dot_f32c_neon(a, b, n, d);
|
|
889
|
+
#elif SIMSIMD_TARGET_HASWELL
|
|
890
|
+
simsimd_dot_f32c_haswell(a, b, n, d);
|
|
891
|
+
#elif SIMSIMD_TARGET_SKYLAKE
|
|
892
|
+
simsimd_dot_f32c_skylake(a, b, n, d);
|
|
893
|
+
#else
|
|
894
|
+
simsimd_dot_f32c_serial(a, b, n, d);
|
|
895
|
+
#endif
|
|
896
|
+
}
|
|
897
|
+
SIMSIMD_PUBLIC void simsimd_vdot_f64c(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
|
|
898
|
+
simsimd_distance_t* d) {
|
|
899
|
+
#if SIMSIMD_TARGET_SVE
|
|
900
|
+
simsimd_dot_f64c_sve(a, b, n, d);
|
|
901
|
+
#elif SIMSIMD_TARGET_SKYLAKE
|
|
902
|
+
simsimd_dot_f64c_skylake(a, b, n, d);
|
|
903
|
+
#else
|
|
904
|
+
simsimd_dot_f64c_serial(a, b, n, d);
|
|
905
|
+
#endif
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
/* Spatial distances
|
|
909
|
+
* - Cosine distance: the cosine of the angle between two vectors.
|
|
910
|
+
* - L2 squared distance: the squared Euclidean distance between two vectors.
|
|
911
|
+
*
|
|
912
|
+
* @param a The first vector.
|
|
913
|
+
* @param b The second vector.
|
|
914
|
+
* @param n The number of elements in the vectors.
|
|
915
|
+
* @param d The output distance value.
|
|
916
|
+
*
|
|
917
|
+
* @note The output distance value is non-negative.
|
|
918
|
+
* @note The output distance value is zero if and only if the two vectors are identical.
|
|
919
|
+
* @note Defined only for floating-point and integer data types.
|
|
920
|
+
*/
|
|
921
|
+
SIMSIMD_PUBLIC void simsimd_cos_i8(simsimd_i8_t const* a, simsimd_i8_t const* b, simsimd_size_t n,
|
|
922
|
+
simsimd_distance_t* d) {
|
|
923
|
+
#if SIMSIMD_TARGET_NEON
|
|
924
|
+
simsimd_cos_i8_neon(a, b, n, d);
|
|
925
|
+
#elif SIMSIMD_TARGET_ICE
|
|
926
|
+
simsimd_cos_i8_ice(a, b, n, d);
|
|
927
|
+
#elif SIMSIMD_TARGET_HASWELL
|
|
928
|
+
simsimd_cos_i8_haswell(a, b, n, d);
|
|
929
|
+
#else
|
|
930
|
+
simsimd_cos_i8_serial(a, b, n, d);
|
|
931
|
+
#endif
|
|
932
|
+
}
|
|
933
|
+
SIMSIMD_PUBLIC void simsimd_l2sq_i8(simsimd_i8_t const* a, simsimd_i8_t const* b, simsimd_size_t n,
|
|
934
|
+
simsimd_distance_t* d) {
|
|
935
|
+
#if SIMSIMD_TARGET_NEON
|
|
936
|
+
simsimd_l2sq_i8_neon(a, b, n, d);
|
|
937
|
+
#elif SIMSIMD_TARGET_ICE
|
|
938
|
+
simsimd_l2sq_i8_ice(a, b, n, d);
|
|
939
|
+
#elif SIMSIMD_TARGET_HASWELL
|
|
940
|
+
simsimd_l2sq_i8_haswell(a, b, n, d);
|
|
941
|
+
#else
|
|
942
|
+
simsimd_l2sq_i8_serial(a, b, n, d);
|
|
943
|
+
#endif
|
|
944
|
+
}
|
|
945
|
+
SIMSIMD_PUBLIC void simsimd_cos_f16(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
|
|
946
|
+
simsimd_distance_t* d) {
|
|
947
|
+
#if SIMSIMD_TARGET_SVE
|
|
948
|
+
simsimd_cos_f16_sve(a, b, n, d);
|
|
949
|
+
#elif SIMSIMD_TARGET_NEON
|
|
950
|
+
simsimd_cos_f16_neon(a, b, n, d);
|
|
951
|
+
#elif SIMSIMD_TARGET_SAPPHIRE
|
|
952
|
+
simsimd_cos_f16_sapphire(a, b, n, d);
|
|
953
|
+
#elif SIMSIMD_TARGET_HASWELL
|
|
954
|
+
simsimd_cos_f16_haswell(a, b, n, d);
|
|
955
|
+
#else
|
|
956
|
+
simsimd_cos_f16_serial(a, b, n, d);
|
|
957
|
+
#endif
|
|
958
|
+
}
|
|
959
|
+
SIMSIMD_PUBLIC void simsimd_cos_f32(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
|
|
960
|
+
simsimd_distance_t* d) {
|
|
961
|
+
#if SIMSIMD_TARGET_SVE
|
|
962
|
+
simsimd_cos_f32_sve(a, b, n, d);
|
|
963
|
+
#elif SIMSIMD_TARGET_NEON
|
|
964
|
+
simsimd_cos_f32_neon(a, b, n, d);
|
|
965
|
+
#elif SIMSIMD_TARGET_SKYLAKE
|
|
966
|
+
simsimd_cos_f32_skylake(a, b, n, d);
|
|
967
|
+
#else
|
|
968
|
+
simsimd_cos_f32_serial(a, b, n, d);
|
|
969
|
+
#endif
|
|
970
|
+
}
|
|
971
|
+
SIMSIMD_PUBLIC void simsimd_cos_f64(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
|
|
972
|
+
simsimd_distance_t* d) {
|
|
973
|
+
#if SIMSIMD_TARGET_SVE
|
|
974
|
+
simsimd_cos_f64_sve(a, b, n, d);
|
|
975
|
+
#elif SIMSIMD_TARGET_SKYLAKE
|
|
976
|
+
simsimd_cos_f64_skylake(a, b, n, d);
|
|
977
|
+
#else
|
|
978
|
+
simsimd_cos_f64_serial(a, b, n, d);
|
|
979
|
+
#endif
|
|
980
|
+
}
|
|
981
|
+
SIMSIMD_PUBLIC void simsimd_l2sq_f16(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
|
|
982
|
+
simsimd_distance_t* d) {
|
|
983
|
+
#if SIMSIMD_TARGET_SVE
|
|
984
|
+
simsimd_l2sq_f16_sve(a, b, n, d);
|
|
985
|
+
#elif SIMSIMD_TARGET_NEON
|
|
986
|
+
simsimd_l2sq_f16_neon(a, b, n, d);
|
|
987
|
+
#elif SIMSIMD_TARGET_sapphire
|
|
988
|
+
simsimd_l2sq_f16_sapphire(a, b, n, d);
|
|
989
|
+
#elif SIMSIMD_TARGET_HASWELL
|
|
990
|
+
simsimd_l2sq_f16_haswell(a, b, n, d);
|
|
991
|
+
#else
|
|
992
|
+
simsimd_l2sq_f16_serial(a, b, n, d);
|
|
993
|
+
#endif
|
|
994
|
+
}
|
|
995
|
+
SIMSIMD_PUBLIC void simsimd_l2sq_f32(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
|
|
996
|
+
simsimd_distance_t* d) {
|
|
997
|
+
#if SIMSIMD_TARGET_SVE
|
|
998
|
+
simsimd_l2sq_f32_sve(a, b, n, d);
|
|
999
|
+
#elif SIMSIMD_TARGET_NEON
|
|
1000
|
+
simsimd_l2sq_f32_neon(a, b, n, d);
|
|
1001
|
+
#elif SIMSIMD_TARGET_SKYLAKE
|
|
1002
|
+
simsimd_l2sq_f32_skylake(a, b, n, d);
|
|
1003
|
+
#else
|
|
1004
|
+
simsimd_l2sq_f32_serial(a, b, n, d);
|
|
1005
|
+
#endif
|
|
1006
|
+
}
|
|
1007
|
+
SIMSIMD_PUBLIC void simsimd_l2sq_f64(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
|
|
1008
|
+
simsimd_distance_t* d) {
|
|
1009
|
+
#if SIMSIMD_TARGET_SVE
|
|
1010
|
+
simsimd_l2sq_f64_sve(a, b, n, d);
|
|
1011
|
+
#elif SIMSIMD_TARGET_SKYLAKE
|
|
1012
|
+
simsimd_l2sq_f64_skylake(a, b, n, d);
|
|
1013
|
+
#else
|
|
1014
|
+
simsimd_l2sq_f64_serial(a, b, n, d);
|
|
1015
|
+
#endif
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
/* Binary distances
|
|
1019
|
+
* - Hamming distance: the number of positions at which the corresponding bits are different.
|
|
1020
|
+
* - Jaccard distance: ratio of bit-level matching positions (intersection) to the total number of positions (union).
|
|
1021
|
+
*
|
|
1022
|
+
* @param a The first binary vector.
|
|
1023
|
+
* @param b The second binary vector.
|
|
1024
|
+
* @param n The number of 8-bit words in the vectors.
|
|
1025
|
+
* @param d The output distance value.
|
|
1026
|
+
*
|
|
1027
|
+
* @note The output distance value is non-negative.
|
|
1028
|
+
* @note The output distance value is zero if and only if the two vectors are identical.
|
|
1029
|
+
* @note Defined only for binary data.
|
|
1030
|
+
*/
|
|
1031
|
+
SIMSIMD_PUBLIC void simsimd_hamming_b8(simsimd_b8_t const* a, simsimd_b8_t const* b, simsimd_size_t n,
|
|
1032
|
+
simsimd_distance_t* d) {
|
|
1033
|
+
#if SIMSIMD_TARGET_SVE
|
|
1034
|
+
simsimd_hamming_b8_sve(a, b, n, d);
|
|
1035
|
+
#elif SIMSIMD_TARGET_NEON
|
|
1036
|
+
simsimd_hamming_b8_neon(a, b, n, d);
|
|
1037
|
+
#elif SIMSIMD_TARGET_ICE
|
|
1038
|
+
simsimd_hamming_b8_ice(a, b, n, d);
|
|
1039
|
+
#elif SIMSIMD_TARGET_HASWELL
|
|
1040
|
+
simsimd_hamming_b8_haswell(a, b, n, d);
|
|
1041
|
+
#else
|
|
1042
|
+
simsimd_hamming_b8_serial(a, b, n, d);
|
|
1043
|
+
#endif
|
|
1044
|
+
}
|
|
1045
|
+
SIMSIMD_PUBLIC void simsimd_jaccard_b8(simsimd_b8_t const* a, simsimd_b8_t const* b, simsimd_size_t n,
|
|
1046
|
+
simsimd_distance_t* d) {
|
|
1047
|
+
#if SIMSIMD_TARGET_SVE
|
|
1048
|
+
simsimd_jaccard_b8_sve(a, b, n, d);
|
|
1049
|
+
#elif SIMSIMD_TARGET_NEON
|
|
1050
|
+
simsimd_jaccard_b8_neon(a, b, n, d);
|
|
1051
|
+
#elif SIMSIMD_TARGET_ICE
|
|
1052
|
+
simsimd_jaccard_b8_ice(a, b, n, d);
|
|
1053
|
+
#elif SIMSIMD_TARGET_HASWELL
|
|
1054
|
+
simsimd_jaccard_b8_haswell(a, b, n, d);
|
|
1055
|
+
#else
|
|
1056
|
+
simsimd_jaccard_b8_serial(a, b, n, d);
|
|
1057
|
+
#endif
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
/* Probability distributions
|
|
1061
|
+
* - Jensen-Shannon divergence: a measure of similarity between two probability distributions.
|
|
1062
|
+
* - Kullback-Leibler divergence: a measure of how one probability distribution diverges from a second.
|
|
1063
|
+
*
|
|
1064
|
+
* @param a The first descrete probability distribution.
|
|
1065
|
+
* @param b The second descrete probability distribution.
|
|
1066
|
+
* @param n The number of elements in the descrete distributions.
|
|
1067
|
+
* @param d The output divergence value.
|
|
1068
|
+
*
|
|
1069
|
+
* @note The distributions are assumed to be normalized.
|
|
1070
|
+
* @note The output divergence value is non-negative.
|
|
1071
|
+
* @note The output divergence value is zero if and only if the two distributions are identical.
|
|
1072
|
+
* @note Defined only for floating-point data types.
|
|
1073
|
+
*/
|
|
1074
|
+
SIMSIMD_PUBLIC void simsimd_kl_f16(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
|
|
1075
|
+
simsimd_distance_t* d) {
|
|
1076
|
+
#if SIMSIMD_TARGET_NEON
|
|
1077
|
+
simsimd_kl_f16_neon(a, b, n, d);
|
|
1078
|
+
#elif SIMSIMD_TARGET_HASWELL
|
|
1079
|
+
simsimd_kl_f16_haswell(a, b, n, d);
|
|
1080
|
+
#else
|
|
1081
|
+
simsimd_kl_f16_serial(a, b, n, d);
|
|
1082
|
+
#endif
|
|
1083
|
+
}
|
|
1084
|
+
SIMSIMD_PUBLIC void simsimd_kl_f32(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
|
|
1085
|
+
simsimd_distance_t* d) {
|
|
1086
|
+
#if SIMSIMD_TARGET_NEON
|
|
1087
|
+
simsimd_kl_f32_neon(a, b, n, d);
|
|
1088
|
+
#elif SIMSIMD_TARGET_SKYLAKE
|
|
1089
|
+
simsimd_kl_f32_skylake(a, b, n, d);
|
|
1090
|
+
#else
|
|
1091
|
+
simsimd_kl_f32_serial(a, b, n, d);
|
|
1092
|
+
#endif
|
|
1093
|
+
}
|
|
1094
|
+
SIMSIMD_PUBLIC void simsimd_kl_f64(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
|
|
1095
|
+
simsimd_distance_t* d) {
|
|
1096
|
+
simsimd_kl_f64_serial(a, b, n, d);
|
|
1097
|
+
}
|
|
1098
|
+
SIMSIMD_PUBLIC void simsimd_js_f16(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
|
|
1099
|
+
simsimd_distance_t* d) {
|
|
1100
|
+
#if SIMSIMD_TARGET_NEON
|
|
1101
|
+
simsimd_js_f16_neon(a, b, n, d);
|
|
1102
|
+
#elif SIMSIMD_TARGET_HASWELL
|
|
1103
|
+
simsimd_js_f16_haswell(a, b, n, d);
|
|
1104
|
+
#else
|
|
1105
|
+
simsimd_js_f16_serial(a, b, n, d);
|
|
1106
|
+
#endif
|
|
1107
|
+
}
|
|
1108
|
+
SIMSIMD_PUBLIC void simsimd_js_f32(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
|
|
1109
|
+
simsimd_distance_t* d) {
|
|
1110
|
+
#if SIMSIMD_TARGET_NEON
|
|
1111
|
+
simsimd_js_f32_neon(a, b, n, d);
|
|
1112
|
+
#elif SIMSIMD_TARGET_SKYLAKE
|
|
1113
|
+
simsimd_js_f32_skylake(a, b, n, d);
|
|
1114
|
+
#else
|
|
1115
|
+
simsimd_js_f32_serial(a, b, n, d);
|
|
1116
|
+
#endif
|
|
1117
|
+
}
|
|
1118
|
+
SIMSIMD_PUBLIC void simsimd_js_f64(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
|
|
1119
|
+
simsimd_distance_t* d) {
|
|
1120
|
+
simsimd_js_f64_serial(a, b, n, d);
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
#endif
|
|
1124
|
+
|
|
1125
|
+
#ifdef __cplusplus
|
|
1126
|
+
}
|
|
1127
|
+
#endif
|
|
1128
|
+
|
|
1129
|
+
#endif // SIMSIMD_H
|