usearch 2.9.2 → 2.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -38
- 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} +199 -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 -361
- 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 -382
- 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 -2213
- 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/CONTRIBUTING.md +0 -88
- package/simsimd/Cargo.lock +0 -709
- package/simsimd/Cargo.toml +0 -44
- package/simsimd/LICENSE +0 -201
- package/simsimd/README.md +0 -317
- package/simsimd/binding.gyp +0 -36
- package/simsimd/build.rs +0 -20
- package/simsimd/include/simsimd/binary.h +0 -245
- package/simsimd/include/simsimd/complex.h +0 -174
- package/simsimd/include/simsimd/probability.h +0 -548
- package/simsimd/include/simsimd/simsimd.h +0 -465
- package/simsimd/include/simsimd/spatial.h +0 -1267
- package/simsimd/include/simsimd/types.h +0 -208
- 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 -30
- package/simsimd/rust/benches/sqeuclidean.rs +0 -27
- package/simsimd/rust/lib.c +0 -45
- package/simsimd/rust/lib.rs +0 -550
- package/sqlite/README.md +0 -178
- package/sqlite/lib.cpp +0 -325
- package/stringzilla/CONTRIBUTING.md +0 -446
- package/stringzilla/Cargo.lock +0 -25
- package/stringzilla/Cargo.toml +0 -26
- package/stringzilla/LICENSE +0 -201
- package/stringzilla/README.md +0 -1422
- 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 -87
- package/stringzilla/c/lib.c +0 -337
- package/stringzilla/cli/README.md +0 -65
- package/stringzilla/cli/__init__.py +0 -0
- package/stringzilla/cli/split.py +0 -105
- package/stringzilla/cli/wc.py +0 -117
- package/stringzilla/include/stringzilla/experimental.h +0 -845
- package/stringzilla/include/stringzilla/module.modulemap +0 -9
- package/stringzilla/include/stringzilla/stringzilla.h +0 -5370
- package/stringzilla/include/stringzilla/stringzilla.hpp +0 -3838
- 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 -873
- 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,245 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @brief SIMD-accelerated Binary Similarity Measures.
|
|
3
|
-
* @author Ash Vardanian
|
|
4
|
-
* @date July 1, 2023
|
|
5
|
-
*
|
|
6
|
-
* Contains:
|
|
7
|
-
* - Hamming distance
|
|
8
|
-
* - Jaccard similarity (Tanimoto coefficient)
|
|
9
|
-
*
|
|
10
|
-
* For datatypes:
|
|
11
|
-
* - 8-bit bitsets
|
|
12
|
-
*
|
|
13
|
-
* For hardware architectures:
|
|
14
|
-
* - Arm (NEON, SVE)
|
|
15
|
-
* - x86 (AVX512)
|
|
16
|
-
*
|
|
17
|
-
* x86 intrinsics: https://www.intel.com/content/www/us/en/docs/intrinsics-guide/
|
|
18
|
-
* Arm intrinsics: https://developer.arm.com/architectures/instruction-sets/intrinsics/
|
|
19
|
-
*/
|
|
20
|
-
#ifndef SIMSIMD_BINARY_H
|
|
21
|
-
#define SIMSIMD_BINARY_H
|
|
22
|
-
|
|
23
|
-
#include "types.h"
|
|
24
|
-
|
|
25
|
-
#ifdef __cplusplus
|
|
26
|
-
extern "C" {
|
|
27
|
-
#endif
|
|
28
|
-
|
|
29
|
-
inline static unsigned char simsimd_popcount_b8(simsimd_b8_t x) {
|
|
30
|
-
static unsigned char lookup_table[] = {
|
|
31
|
-
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, //
|
|
32
|
-
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
|
33
|
-
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
|
34
|
-
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
|
35
|
-
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
|
36
|
-
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
|
37
|
-
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
|
38
|
-
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8};
|
|
39
|
-
return lookup_table[x];
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
inline static simsimd_f32_t simsimd_serial_b8_hamming( //
|
|
43
|
-
simsimd_b8_t const* a, simsimd_b8_t const* b, simsimd_size_t n_words) {
|
|
44
|
-
simsimd_i32_t differences = 0;
|
|
45
|
-
for (simsimd_size_t i = 0; i != n_words; ++i)
|
|
46
|
-
differences += simsimd_popcount_b8(a[i] ^ b[i]);
|
|
47
|
-
return (simsimd_f32_t)differences;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
inline static simsimd_f32_t simsimd_serial_b8_jaccard( //
|
|
51
|
-
simsimd_b8_t const* a, simsimd_b8_t const* b, simsimd_size_t n_words) {
|
|
52
|
-
simsimd_i32_t intersection = 0, union_ = 0;
|
|
53
|
-
for (simsimd_size_t i = 0; i != n_words; ++i)
|
|
54
|
-
intersection += simsimd_popcount_b8(a[i] & b[i]), union_ += simsimd_popcount_b8(a[i] | b[i]);
|
|
55
|
-
return (union_ != 0) ? 1 - (simsimd_f32_t)intersection / (simsimd_f32_t)union_ : 0;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
#if SIMSIMD_TARGET_ARM
|
|
59
|
-
#if SIMSIMD_TARGET_ARM_NEON
|
|
60
|
-
|
|
61
|
-
__attribute__((target("+simd"))) //
|
|
62
|
-
inline static simsimd_f32_t
|
|
63
|
-
simsimd_neon_b8_hamming(simsimd_b8_t const* a, simsimd_b8_t const* b, simsimd_size_t n_words) {
|
|
64
|
-
simsimd_i32_t differences = 0;
|
|
65
|
-
simsimd_size_t i = 0;
|
|
66
|
-
for (; i + 16 <= n_words; i += 16) {
|
|
67
|
-
uint8x16_t a_first = vld1q_u8(a + i);
|
|
68
|
-
uint8x16_t b_first = vld1q_u8(b + i);
|
|
69
|
-
differences += vaddvq_u8(vcntq_u8(veorq_u8(a_first, b_first)));
|
|
70
|
-
}
|
|
71
|
-
// Handle the tail
|
|
72
|
-
for (; i != n_words; ++i)
|
|
73
|
-
differences += simsimd_popcount_b8(a[i] ^ b[i]);
|
|
74
|
-
return (simsimd_f32_t)differences;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
__attribute__((target("+simd"))) //
|
|
78
|
-
inline static simsimd_f32_t
|
|
79
|
-
simsimd_neon_b8_jaccard(simsimd_b8_t const* a, simsimd_b8_t const* b, simsimd_size_t n_words) {
|
|
80
|
-
simsimd_i32_t intersection = 0, union_ = 0;
|
|
81
|
-
simsimd_size_t i = 0;
|
|
82
|
-
for (; i + 16 <= n_words; i += 16) {
|
|
83
|
-
uint8x16_t a_first = vld1q_u8(a + i);
|
|
84
|
-
uint8x16_t b_first = vld1q_u8(b + i);
|
|
85
|
-
intersection += vaddvq_u8(vcntq_u8(vandq_u8(a_first, b_first)));
|
|
86
|
-
union_ += vaddvq_u8(vcntq_u8(vorrq_u8(a_first, b_first)));
|
|
87
|
-
}
|
|
88
|
-
// Handle the tail
|
|
89
|
-
for (; i != n_words; ++i)
|
|
90
|
-
intersection += simsimd_popcount_b8(a[i] & b[i]), union_ += simsimd_popcount_b8(a[i] | b[i]);
|
|
91
|
-
return (union_ != 0) ? 1 - (simsimd_f32_t)intersection / (simsimd_f32_t)union_ : 0;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
#endif // SIMSIMD_TARGET_ARM_NEON
|
|
95
|
-
|
|
96
|
-
#if SIMSIMD_TARGET_ARM_SVE
|
|
97
|
-
|
|
98
|
-
__attribute__((target("+sve"))) //
|
|
99
|
-
inline static simsimd_f32_t
|
|
100
|
-
simsimd_sve_b8_hamming(simsimd_b8_t const* a, simsimd_b8_t const* b, simsimd_size_t n_words) {
|
|
101
|
-
simsimd_size_t i = 0;
|
|
102
|
-
simsimd_i32_t differences = 0;
|
|
103
|
-
do {
|
|
104
|
-
svbool_t pg_vec = svwhilelt_b8((unsigned int)i, (unsigned int)n_words);
|
|
105
|
-
svuint8_t a_vec = svld1_u8(pg_vec, a + i);
|
|
106
|
-
svuint8_t b_vec = svld1_u8(pg_vec, b + i);
|
|
107
|
-
differences += svaddv_u8(svptrue_b8(), svcnt_u8_x(svptrue_b8(), sveor_u8_m(svptrue_b8(), a_vec, b_vec)));
|
|
108
|
-
i += svcntb();
|
|
109
|
-
} while (i < n_words);
|
|
110
|
-
return (simsimd_f32_t)differences;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
__attribute__((target("+sve"))) //
|
|
114
|
-
inline static simsimd_f32_t
|
|
115
|
-
simsimd_sve_b8_jaccard(simsimd_b8_t const* a, simsimd_b8_t const* b, simsimd_size_t n_words) {
|
|
116
|
-
simsimd_size_t i = 0;
|
|
117
|
-
simsimd_i32_t intersection = 0, union_ = 0;
|
|
118
|
-
do {
|
|
119
|
-
svbool_t pg_vec = svwhilelt_b8((unsigned int)i, (unsigned int)n_words);
|
|
120
|
-
svuint8_t a_vec = svld1_u8(pg_vec, a + i);
|
|
121
|
-
svuint8_t b_vec = svld1_u8(pg_vec, b + i);
|
|
122
|
-
intersection += svaddv_u8(svptrue_b8(), svcnt_u8_x(svptrue_b8(), svand_u8_m(svptrue_b8(), a_vec, b_vec)));
|
|
123
|
-
union_ += svaddv_u8(svptrue_b8(), svcnt_u8_x(svptrue_b8(), svorr_u8_m(svptrue_b8(), a_vec, b_vec)));
|
|
124
|
-
i += svcntb();
|
|
125
|
-
} while (i < n_words);
|
|
126
|
-
return (union_ != 0) ? 1 - (simsimd_f32_t)intersection / (simsimd_f32_t)union_ : 0;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
#endif // SIMSIMD_TARGET_ARM_SVE
|
|
130
|
-
|
|
131
|
-
#endif // SIMSIMD_TARGET_ARM
|
|
132
|
-
|
|
133
|
-
#if SIMSIMD_TARGET_X86
|
|
134
|
-
|
|
135
|
-
#if SIMSIMD_TARGET_X86_AVX512
|
|
136
|
-
|
|
137
|
-
__attribute__((target("avx512vpopcntdq,avx512vl,avx512bw,avx512f,bmi2"))) //
|
|
138
|
-
inline static simsimd_f32_t
|
|
139
|
-
simsimd_avx512_b8_hamming(simsimd_b8_t const* a, simsimd_b8_t const* b, simsimd_size_t n_words) {
|
|
140
|
-
__m512i differences_vec = _mm512_setzero_si512();
|
|
141
|
-
__m512i a_vec, b_vec;
|
|
142
|
-
|
|
143
|
-
simsimd_avx512_b8_hamming_cycle:
|
|
144
|
-
if (n_words < 64) {
|
|
145
|
-
__mmask64 mask = _bzhi_u64(0xFFFFFFFFFFFFFFFF, n_words);
|
|
146
|
-
a_vec = _mm512_maskz_loadu_epi8(mask, a);
|
|
147
|
-
b_vec = _mm512_maskz_loadu_epi8(mask, b);
|
|
148
|
-
n_words = 0;
|
|
149
|
-
} else {
|
|
150
|
-
a_vec = _mm512_loadu_epi8(a);
|
|
151
|
-
b_vec = _mm512_loadu_epi8(b);
|
|
152
|
-
a += 64, b += 64, n_words -= 64;
|
|
153
|
-
}
|
|
154
|
-
__m512i xor_vec = _mm512_xor_si512(a_vec, b_vec);
|
|
155
|
-
differences_vec = _mm512_add_epi64(differences_vec, _mm512_popcnt_epi64(xor_vec));
|
|
156
|
-
if (n_words)
|
|
157
|
-
goto simsimd_avx512_b8_hamming_cycle;
|
|
158
|
-
|
|
159
|
-
simsimd_size_t differences = _mm512_reduce_add_epi64(differences_vec);
|
|
160
|
-
return (simsimd_f32_t)differences;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
__attribute__((target("avx512vpopcntdq,avx512vl,avx512bw,avx512f,bmi2"))) //
|
|
164
|
-
inline static simsimd_f32_t
|
|
165
|
-
simsimd_avx512_b8_jaccard(simsimd_b8_t const* a, simsimd_b8_t const* b, simsimd_size_t n_words) {
|
|
166
|
-
__m512i intersection_vec = _mm512_setzero_si512(), union_vec = _mm512_setzero_si512();
|
|
167
|
-
__m512i a_vec, b_vec;
|
|
168
|
-
|
|
169
|
-
simsimd_avx512_b8_jaccard_cycle:
|
|
170
|
-
if (n_words < 64) {
|
|
171
|
-
__mmask64 mask = _bzhi_u64(0xFFFFFFFFFFFFFFFF, n_words);
|
|
172
|
-
a_vec = _mm512_maskz_loadu_epi8(mask, a);
|
|
173
|
-
b_vec = _mm512_maskz_loadu_epi8(mask, b);
|
|
174
|
-
n_words = 0;
|
|
175
|
-
} else {
|
|
176
|
-
a_vec = _mm512_loadu_epi8(a);
|
|
177
|
-
b_vec = _mm512_loadu_epi8(b);
|
|
178
|
-
a += 64, b += 64, n_words -= 64;
|
|
179
|
-
}
|
|
180
|
-
__m512i and_vec = _mm512_and_si512(a_vec, b_vec);
|
|
181
|
-
__m512i or_vec = _mm512_or_si512(a_vec, b_vec);
|
|
182
|
-
intersection_vec = _mm512_add_epi64(intersection_vec, _mm512_popcnt_epi64(and_vec));
|
|
183
|
-
union_vec = _mm512_add_epi64(union_vec, _mm512_popcnt_epi64(or_vec));
|
|
184
|
-
if (n_words)
|
|
185
|
-
goto simsimd_avx512_b8_jaccard_cycle;
|
|
186
|
-
|
|
187
|
-
simsimd_size_t intersection = _mm512_reduce_add_epi64(intersection_vec),
|
|
188
|
-
union_ = _mm512_reduce_add_epi64(union_vec);
|
|
189
|
-
return (union_ != 0) ? 1 - (simsimd_f32_t)intersection / (simsimd_f32_t)union_ : 0;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
#endif // SIMSIMD_TARGET_X86_AVX512
|
|
193
|
-
|
|
194
|
-
/*
|
|
195
|
-
* @file x86_avx2_b8.h
|
|
196
|
-
* @brief x86 AVX2 implementation of the most common similarity metrics for bitsets.
|
|
197
|
-
* @author Ash Vardanian
|
|
198
|
-
*
|
|
199
|
-
* - Implements: Hamming and Jaccard similarity.
|
|
200
|
-
* - Requires compiler capabilities: avx2.
|
|
201
|
-
*
|
|
202
|
-
* AVX2 provides no built-in functionality for popcount, so we use the BMI2 instruction set.
|
|
203
|
-
* Wojciech Mu la, Nathan Kurz and Daniel Lemire propose an alternative solution based on Harley-Seal
|
|
204
|
-
* transforms and lookup tables. Those are very fast on large vectors, but on short vectors they lose
|
|
205
|
-
* to built-in scalar population counts. https://arxiv.org/pdf/1611.07612.pdf
|
|
206
|
-
*/
|
|
207
|
-
|
|
208
|
-
#if SIMSIMD_TARGET_X86_AVX2
|
|
209
|
-
|
|
210
|
-
__attribute__((target("popcnt"))) //
|
|
211
|
-
inline static simsimd_f32_t
|
|
212
|
-
simsimd_avx2_b8_hamming(simsimd_b8_t const* a, simsimd_b8_t const* b, simsimd_size_t n_words) {
|
|
213
|
-
// x86 supports unaligned loads and works just fine with the scalar version for small vectors.
|
|
214
|
-
simsimd_size_t differences = 0;
|
|
215
|
-
for (; n_words >= 8; n_words -= 8, a += 8, b += 8)
|
|
216
|
-
differences += _mm_popcnt_u64(*(simsimd_u64_t const*)a ^ *(simsimd_u64_t const*)b);
|
|
217
|
-
for (; n_words; --n_words, ++a, ++b)
|
|
218
|
-
differences += _mm_popcnt_u32(*a ^ *b);
|
|
219
|
-
return (simsimd_f32_t)differences;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
__attribute__((target("popcnt"))) //
|
|
223
|
-
inline static simsimd_f32_t
|
|
224
|
-
simsimd_avx2_b8_jaccard(simsimd_b8_t const* a, simsimd_b8_t const* b, simsimd_size_t n_words) {
|
|
225
|
-
// x86 supports unaligned loads and works just fine with the scalar version for small vectors.
|
|
226
|
-
simsimd_size_t intersection = 0, union_ = 0;
|
|
227
|
-
for (; n_words >= 8; n_words -= 8, a += 8, b += 8)
|
|
228
|
-
intersection += _mm_popcnt_u64(*(simsimd_u64_t const*)a & *(simsimd_u64_t const*)b),
|
|
229
|
-
union_ += _mm_popcnt_u64(*(simsimd_u64_t const*)a | *(simsimd_u64_t const*)b);
|
|
230
|
-
for (; n_words; --n_words, ++a, ++b)
|
|
231
|
-
intersection += _mm_popcnt_u32(*a & *b), union_ += _mm_popcnt_u32(*a | *b);
|
|
232
|
-
return (union_ != 0) ? 1 - (simsimd_f32_t)intersection / (simsimd_f32_t)union_ : 0;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
#endif // SIMSIMD_TARGET_X86_AVX2
|
|
236
|
-
|
|
237
|
-
#endif // SIMSIMD_TARGET_X86
|
|
238
|
-
|
|
239
|
-
#undef popcount64
|
|
240
|
-
|
|
241
|
-
#ifdef __cplusplus
|
|
242
|
-
}
|
|
243
|
-
#endif
|
|
244
|
-
|
|
245
|
-
#endif
|
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @brief SIMD-accelerated Similarity Measures for Complex Vectors.
|
|
3
|
-
* @author Ash Vardanian
|
|
4
|
-
* @date February 24, 2024
|
|
5
|
-
*
|
|
6
|
-
* Contains:
|
|
7
|
-
* - Inner Product
|
|
8
|
-
* - Cosine Distance
|
|
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_COMPLEX_H
|
|
22
|
-
#define SIMSIMD_COMPLEX_H
|
|
23
|
-
|
|
24
|
-
#include "types.h"
|
|
25
|
-
|
|
26
|
-
#define SIMSIMD_MAKE_COMPLEX_IP(name, input_type, accumulator_type, converter, epsilon) \
|
|
27
|
-
inline static simsimd_f32_t simsimd_##name##_##input_type##_complex_ip( \
|
|
28
|
-
simsimd_##input_type##_t const* a, simsimd_##input_type##_t const* b, simsimd_size_t n, \
|
|
29
|
-
simsimd_f32_t* real_out, simsimd_f32_t* imag_out) { \
|
|
30
|
-
simsimd_##accumulator_type##_t ab_real, ab_imag; \
|
|
31
|
-
for (simsimd_size_t i = 0; i + 2 <= n; i += 2) { \
|
|
32
|
-
simsimd_##accumulator_type##_t ar = converter(a[i]); \
|
|
33
|
-
simsimd_##accumulator_type##_t br = converter(b[i]); \
|
|
34
|
-
simsimd_##accumulator_type##_t ai = converter(a[i + 1]); \
|
|
35
|
-
simsimd_##accumulator_type##_t bi = converter(b[i + 1]); \
|
|
36
|
-
ab_real += ar * br + ai * bi; \
|
|
37
|
-
ab_imag += ai * br - ar * bi; \
|
|
38
|
-
} \
|
|
39
|
-
*real_out = ab_real; \
|
|
40
|
-
*imag_out = ab_imag; \
|
|
41
|
-
return 1 - ab_real; \
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
#define SIMSIMD_MAKE_COMPLEX_COS(name, input_type, accumulator_type, converter, epsilon) \
|
|
45
|
-
inline static simsimd_f32_t simsimd_##name##_##input_type##_complex_cos( \
|
|
46
|
-
simsimd_##input_type##_t const* a, simsimd_##input_type##_t const* b, simsimd_size_t n, \
|
|
47
|
-
simsimd_f32_t* real_out, simsimd_f32_t* imag_out) { \
|
|
48
|
-
simsimd_##accumulator_type##_t ab_real, ab_imag, a2_sum, b2_sum; \
|
|
49
|
-
for (simsimd_size_t i = 0; i + 2 <= n; i += 2) { \
|
|
50
|
-
simsimd_##accumulator_type##_t ar = converter(a[i]); \
|
|
51
|
-
simsimd_##accumulator_type##_t br = converter(b[i]); \
|
|
52
|
-
simsimd_##accumulator_type##_t ai = converter(a[i + 1]); \
|
|
53
|
-
simsimd_##accumulator_type##_t bi = converter(b[i + 1]); \
|
|
54
|
-
ab_real += ar * br + ai * bi; \
|
|
55
|
-
ab_imag += ai * br - ar * bi; \
|
|
56
|
-
a2_sum += ar * ar + ai * ai; \
|
|
57
|
-
b2_sum += br * br + bi * bi; \
|
|
58
|
-
} \
|
|
59
|
-
*real_out = ab_real; \
|
|
60
|
-
*imag_out = ab_imag; \
|
|
61
|
-
simsimd_##accumulator_type##_t ab_angle = ab_real * SIMSIMD_RSQRT(a2_sum) * SIMSIMD_RSQRT(b2_sum); \
|
|
62
|
-
return 1 - ab_angle; \
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
#ifdef __cplusplus
|
|
66
|
-
extern "C" {
|
|
67
|
-
#endif
|
|
68
|
-
|
|
69
|
-
SIMSIMD_MAKE_COMPLEX_IP(serial, f64, f64, SIMSIMD_IDENTIFY,
|
|
70
|
-
SIMSIMD_F32_DIVISION_EPSILON) // simsimd_serial_f64_complex_ip
|
|
71
|
-
SIMSIMD_MAKE_COMPLEX_COS(serial, f64, f64, SIMSIMD_IDENTIFY,
|
|
72
|
-
SIMSIMD_F32_DIVISION_EPSILON) // simsimd_serial_f64_complex_cos
|
|
73
|
-
|
|
74
|
-
SIMSIMD_MAKE_COMPLEX_IP(serial, f32, f32, SIMSIMD_IDENTIFY,
|
|
75
|
-
SIMSIMD_F32_DIVISION_EPSILON) // simsimd_serial_f32_complex_ip
|
|
76
|
-
SIMSIMD_MAKE_COMPLEX_COS(serial, f32, f32, SIMSIMD_IDENTIFY,
|
|
77
|
-
SIMSIMD_F32_DIVISION_EPSILON) // simsimd_serial_f32_complex_cos
|
|
78
|
-
|
|
79
|
-
SIMSIMD_MAKE_COMPLEX_IP(serial, f16, f32, SIMSIMD_UNCOMPRESS_F16,
|
|
80
|
-
SIMSIMD_F32_DIVISION_EPSILON) // simsimd_serial_f16_complex_ip
|
|
81
|
-
SIMSIMD_MAKE_COMPLEX_COS(serial, f16, f32, SIMSIMD_UNCOMPRESS_F16,
|
|
82
|
-
SIMSIMD_F32_DIVISION_EPSILON) // simsimd_serial_f16_complex_cos
|
|
83
|
-
|
|
84
|
-
SIMSIMD_MAKE_COMPLEX_IP(accurate, f32, f64, SIMSIMD_IDENTIFY,
|
|
85
|
-
SIMSIMD_F32_DIVISION_EPSILON) // simsimd_accurate_f32_complex_ip
|
|
86
|
-
SIMSIMD_MAKE_COMPLEX_COS(accurate, f32, f64, SIMSIMD_IDENTIFY,
|
|
87
|
-
SIMSIMD_F32_DIVISION_EPSILON) // simsimd_accurate_f32_complex_cos
|
|
88
|
-
|
|
89
|
-
SIMSIMD_MAKE_COMPLEX_IP(accurate, f16, f64, SIMSIMD_UNCOMPRESS_F16,
|
|
90
|
-
SIMSIMD_F32_DIVISION_EPSILON) // simsimd_accurate_f16_complex_ip
|
|
91
|
-
SIMSIMD_MAKE_COMPLEX_COS(accurate, f16, f64, SIMSIMD_UNCOMPRESS_F16,
|
|
92
|
-
SIMSIMD_F32_DIVISION_EPSILON) // simsimd_accurate_f16_complex_cos
|
|
93
|
-
|
|
94
|
-
#if SIMSIMD_TARGET_ARM
|
|
95
|
-
#if SIMSIMD_TARGET_ARM_NEON
|
|
96
|
-
|
|
97
|
-
/*
|
|
98
|
-
* @file arm_neon_f32.h
|
|
99
|
-
* @brief Arm NEON implementation of the most common similarity metrics for 32-bit floating point numbers.
|
|
100
|
-
* @author Ash Vardanian
|
|
101
|
-
*
|
|
102
|
-
* - Implements: Kullback-Leibler and Jensen–Shannon divergence.
|
|
103
|
-
* - Uses `f32` for storage and `f32` for accumulation.
|
|
104
|
-
* - Requires compiler capabilities: +simd.
|
|
105
|
-
*/
|
|
106
|
-
|
|
107
|
-
__attribute__((target("+simd"))) //
|
|
108
|
-
inline static simsimd_f32_t
|
|
109
|
-
simsimd_neon_f32_complex_cos(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n, //
|
|
110
|
-
simsimd_f32_t* real_out, simsimd_f32_t* imag_out) {
|
|
111
|
-
float32x4_t ab_real_vec = vdupq_n_f32(0);
|
|
112
|
-
float32x4_t ab_imag_vec = vdupq_n_f32(0);
|
|
113
|
-
float32x4_t a2_vec = vdupq_n_f32(0);
|
|
114
|
-
float32x4_t b2_vec = vdupq_n_f32(0);
|
|
115
|
-
simsimd_size_t i = 0;
|
|
116
|
-
for (; i + 8 <= n; i += 8) {
|
|
117
|
-
// Unpack the input arrays into real and imaginary parts:
|
|
118
|
-
// a_real = a[::2]
|
|
119
|
-
// a_imag = a[1::2]
|
|
120
|
-
// b_real = b[::2]
|
|
121
|
-
// b_imag = b[1::2]
|
|
122
|
-
float32x4x2_t a_vec = vld2q_f32(a + i);
|
|
123
|
-
float32x4x2_t b_vec = vld2q_f32(b + i);
|
|
124
|
-
float32x4_t a_real_vec = a_vec.val[0];
|
|
125
|
-
float32x4_t a_imag_vec = a_vec.val[1];
|
|
126
|
-
float32x4_t b_real_vec = b_vec.val[0];
|
|
127
|
-
float32x4_t b_imag_vec = b_vec.val[1];
|
|
128
|
-
|
|
129
|
-
// Compute the dot product:
|
|
130
|
-
// ab_real = sum(ar * br + ai * bi for ar, ai, br, bi in zip(a_real, a_imag, b_real, b_imag))
|
|
131
|
-
// ab_imag = sum(ai * br - ar * bi for ar, ai, br, bi in zip(a_real, a_imag, b_real, b_imag))
|
|
132
|
-
ab_real_vec = vfmaq_f32(ab_real_vec, a_real_vec, b_real_vec);
|
|
133
|
-
ab_real_vec = vfmaq_f32(ab_real_vec, a_imag_vec, b_imag_vec);
|
|
134
|
-
ab_imag_vec = vfmaq_f32(ab_imag_vec, a_imag_vec, b_real_vec);
|
|
135
|
-
ab_imag_vec = vfmsq_f32(ab_imag_vec, a_real_vec, b_imag_vec);
|
|
136
|
-
|
|
137
|
-
// Compute the vector norms:
|
|
138
|
-
// a2 = sum(ar * ar + ai * ai for ar, ai in zip(a_real, a_imag))
|
|
139
|
-
// b2 = sum(br * br + bi * bi for br, bi in zip(b_real, b_imag))
|
|
140
|
-
a2_vec = vfmaq_f32(a2_vec, a_real_vec, a_real_vec);
|
|
141
|
-
a2_vec = vfmaq_f32(a2_vec, a_imag_vec, a_imag_vec);
|
|
142
|
-
b2_vec = vfmaq_f32(b2_vec, b_real_vec, b_real_vec);
|
|
143
|
-
b2_vec = vfmaq_f32(b2_vec, b_imag_vec, b_imag_vec);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Reduce horizontal sums:
|
|
147
|
-
simsimd_f32_t ab_real = vaddvq_f32(ab_real_vec);
|
|
148
|
-
simsimd_f32_t ab_imag = vaddvq_f32(ab_imag_vec);
|
|
149
|
-
simsimd_f32_t a2 = vaddvq_f32(a2_vec);
|
|
150
|
-
simsimd_f32_t b2 = vaddvq_f32(b2_vec);
|
|
151
|
-
|
|
152
|
-
// Handle the tail:
|
|
153
|
-
for (; i < n; i += 2) {
|
|
154
|
-
simsimd_f32_t ar = a[i], ai = a[i + 1], br = b[i], bi = b[i + 1];
|
|
155
|
-
ab_real += ar * br + ai * bi, ab_imag += ai * br - ar * bi;
|
|
156
|
-
a2 += ar * ar + ai * ai, b2 += br * br + bi * bi;
|
|
157
|
-
}
|
|
158
|
-
*real_out = ab_real;
|
|
159
|
-
*imag_out = ab_imag;
|
|
160
|
-
|
|
161
|
-
// Avoid `simsimd_approximate_inverse_square_root` on Arm NEON
|
|
162
|
-
simsimd_f32_t a2_b2_arr[2] = {a2, b2};
|
|
163
|
-
vst1_f32(a2_b2_arr, vrsqrte_f32(vld1_f32(a2_b2_arr)));
|
|
164
|
-
return ab_real != 0 ? 1 - ab_real * a2_b2_arr[0] * a2_b2_arr[1] : 1;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
#endif // SIMSIMD_TARGET_ARM_NEON
|
|
168
|
-
#endif // SIMSIMD_TARGET_ARM
|
|
169
|
-
|
|
170
|
-
#ifdef __cplusplus
|
|
171
|
-
}
|
|
172
|
-
#endif
|
|
173
|
-
|
|
174
|
-
#endif
|