usearch 2.1.3 → 2.2.1
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/.github/workflows/prerelease.yml +12 -3
- package/Cargo.toml +1 -1
- package/conanfile.py +1 -1
- package/include/usearch/index_plugins.hpp +87 -13
- package/package.json +1 -1
- package/python/lib.cpp +11 -0
- package/python/usearch/index.py +17 -4
- package/simsimd/.github/workflows/prerelease.yml +4 -6
- package/simsimd/.github/workflows/release.yml +9 -3
- package/simsimd/include/simsimd/simsimd.h +181 -11
- package/simsimd/pyproject.toml +2 -1
- package/simsimd/python/lib.c +16 -0
- package/wasmer.toml +1 -1
|
@@ -148,7 +148,10 @@ jobs:
|
|
|
148
148
|
- uses: actions/setup-node@v3
|
|
149
149
|
with:
|
|
150
150
|
node-version: 18
|
|
151
|
-
- run:
|
|
151
|
+
- run: |
|
|
152
|
+
export CC=/usr/bin/gcc-12
|
|
153
|
+
export CXX=/usr/bin/g++-12
|
|
154
|
+
npm install
|
|
152
155
|
- run: npm ci
|
|
153
156
|
- run: npm test
|
|
154
157
|
|
|
@@ -176,7 +179,10 @@ jobs:
|
|
|
176
179
|
- name: Setup Gradle
|
|
177
180
|
uses: gradle/gradle-build-action@v2.4.2
|
|
178
181
|
- name: Execute Gradle build
|
|
179
|
-
run:
|
|
182
|
+
run:
|
|
183
|
+
export CC=/usr/bin/gcc-12
|
|
184
|
+
export CXX=/usr/bin/g++-12
|
|
185
|
+
gradle clean build
|
|
180
186
|
|
|
181
187
|
test_swift:
|
|
182
188
|
name: Test ObjC & Swift
|
|
@@ -251,7 +257,10 @@ jobs:
|
|
|
251
257
|
|
|
252
258
|
- name: Build library
|
|
253
259
|
run: |
|
|
254
|
-
cd golang
|
|
260
|
+
cd golang/
|
|
261
|
+
export CC=/usr/bin/gcc-12
|
|
262
|
+
export CXX=/usr/bin/g++-12
|
|
263
|
+
make -C ../c libusearch_c.so
|
|
255
264
|
sudo mv ../c/libusearch_c.so /usr/local/lib/libusearch.a
|
|
256
265
|
sudo mv ../c/usearch.h /usr/local/include/usearch.h
|
|
257
266
|
|
package/Cargo.toml
CHANGED
package/conanfile.py
CHANGED
|
@@ -4,7 +4,7 @@ from conans import ConanFile
|
|
|
4
4
|
class USearchConan(ConanFile):
|
|
5
5
|
|
|
6
6
|
name = 'USearch'
|
|
7
|
-
version = '2.1
|
|
7
|
+
version = '2.2.1'
|
|
8
8
|
license = 'Apache 2.0'
|
|
9
9
|
url = 'https://github.com/unum-cloud/usearch'
|
|
10
10
|
description = 'Smaller & Faster Single-File Vector Search Engine from Unum'
|
|
@@ -42,13 +42,9 @@
|
|
|
42
42
|
|
|
43
43
|
#if USEARCH_USE_SIMSIMD
|
|
44
44
|
#if __linux__
|
|
45
|
-
#define SIMSIMD_TARGET_ARM_NEON 1
|
|
46
|
-
#define SIMSIMD_TARGET_X86_AVX2 1
|
|
47
|
-
#define SIMSIMD_TARGET_ARM_SVE 1
|
|
48
|
-
#define SIMSIMD_TARGET_X86_AVX512 1
|
|
49
|
-
#endif
|
|
50
45
|
#include <simsimd/simsimd.h>
|
|
51
46
|
#endif
|
|
47
|
+
#endif
|
|
52
48
|
|
|
53
49
|
namespace unum {
|
|
54
50
|
namespace usearch {
|
|
@@ -133,7 +129,9 @@ enum class isa_kind_t {
|
|
|
133
129
|
neon_k,
|
|
134
130
|
sve_k,
|
|
135
131
|
avx2_k,
|
|
132
|
+
avx2f16_k,
|
|
136
133
|
avx512_k,
|
|
134
|
+
avx512f16_k,
|
|
137
135
|
};
|
|
138
136
|
|
|
139
137
|
enum class prefetching_kind_t {
|
|
@@ -199,6 +197,8 @@ inline char const* isa_name(isa_kind_t isa_kind) noexcept {
|
|
|
199
197
|
case isa_kind_t::sve_k: return "sve";
|
|
200
198
|
case isa_kind_t::avx2_k: return "avx2";
|
|
201
199
|
case isa_kind_t::avx512_k: return "avx512";
|
|
200
|
+
case isa_kind_t::avx2f16_k: return "avx2+f16";
|
|
201
|
+
case isa_kind_t::avx512f16_k: return "avx512+f16";
|
|
202
202
|
default: return "";
|
|
203
203
|
}
|
|
204
204
|
}
|
|
@@ -217,12 +217,47 @@ inline bool hardware_supports(isa_kind_t isa_kind) noexcept {
|
|
|
217
217
|
#endif
|
|
218
218
|
|
|
219
219
|
// When compiling with GCC, one may use the "built-ins", including ones
|
|
220
|
-
// designed for CPU capability detection.
|
|
221
|
-
|
|
222
|
-
|
|
220
|
+
// designed for CPU capability detection, but they are not fully compatible with Clang.
|
|
221
|
+
// So instead I've decided to add a pinch of inline assembly.
|
|
222
|
+
#if defined(USEARCH_DEFINED_X86)
|
|
223
|
+
auto check_cpu_feature = [](std::uint64_t feature_mask, int function_id, int register_id) -> bool {
|
|
224
|
+
std::uint32_t eax, ebx, ecx, edx;
|
|
225
|
+
// Execute CPUID instruction and store results in eax, ebx, ecx, edx
|
|
226
|
+
// Setting %ecx to 0 as well
|
|
227
|
+
__asm__ volatile("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(function_id), "c"(0));
|
|
228
|
+
std::uint32_t register_value;
|
|
229
|
+
switch (register_id) {
|
|
230
|
+
case 0: register_value = eax; break;
|
|
231
|
+
case 1: register_value = ebx; break;
|
|
232
|
+
case 2: register_value = ecx; break;
|
|
233
|
+
case 3: register_value = edx; break;
|
|
234
|
+
default: return false;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return (register_value & feature_mask) != 0;
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
// Check for AVX2 (Function ID 7, EBX register)
|
|
241
|
+
// https://github.com/llvm/llvm-project/blob/50598f0ff44f3a4e75706f8c53f3380fe7faa896/clang/lib/Headers/cpuid.h#L148
|
|
242
|
+
bool supports_avx2 = check_cpu_feature(1 << 5, 7, 1);
|
|
243
|
+
|
|
244
|
+
// Check for F16C (Function ID 1, ECX register)
|
|
245
|
+
// https://github.com/llvm/llvm-project/blob/50598f0ff44f3a4e75706f8c53f3380fe7faa896/clang/lib/Headers/cpuid.h#L107
|
|
246
|
+
bool supports_f16c = check_cpu_feature(1 << 29, 1, 2);
|
|
247
|
+
|
|
248
|
+
// Check for AVX512F (Function ID 7, EBX register)
|
|
249
|
+
// https://github.com/llvm/llvm-project/blob/50598f0ff44f3a4e75706f8c53f3380fe7faa896/clang/lib/Headers/cpuid.h#L155
|
|
250
|
+
bool supports_avx512f = check_cpu_feature(1 << 16, 7, 1);
|
|
251
|
+
|
|
252
|
+
// Check for AVX512FP16 (Function ID 7, EDX register)
|
|
253
|
+
// https://github.com/llvm/llvm-project/blob/50598f0ff44f3a4e75706f8c53f3380fe7faa896/clang/lib/Headers/cpuid.h#L198C9-L198C23
|
|
254
|
+
bool supports_avx512fp16 = check_cpu_feature(1 << 23, 7, 3);
|
|
255
|
+
|
|
223
256
|
switch (isa_kind) {
|
|
224
|
-
case isa_kind_t::
|
|
225
|
-
case isa_kind_t::
|
|
257
|
+
case isa_kind_t::avx2f16_k: return supports_avx2 && supports_f16c;
|
|
258
|
+
case isa_kind_t::avx512f16_k: return supports_avx512fp16 && supports_avx512f;
|
|
259
|
+
case isa_kind_t::avx2_k: return supports_avx2;
|
|
260
|
+
case isa_kind_t::avx512_k: return supports_avx512f;
|
|
226
261
|
default: return false;
|
|
227
262
|
}
|
|
228
263
|
#endif
|
|
@@ -1404,20 +1439,59 @@ class metric_punned_t {
|
|
|
1404
1439
|
static metric_punned_t cos_metric_f16_(std::size_t bytes_per_vector) {
|
|
1405
1440
|
#if USEARCH_USE_SIMSIMD
|
|
1406
1441
|
#if SIMSIMD_TARGET_X86_AVX512
|
|
1407
|
-
if (hardware_supports(isa_kind_t::
|
|
1442
|
+
if (hardware_supports(isa_kind_t::avx512f16_k) && bytes_per_vector % 32 == 0) return {pun_stl_<simsimd_f16_t>([=](simsimd_f16_t const* a, simsimd_f16_t const* b) { return simsimd_cos_f16x16_avx512(a, b, bytes_per_vector / 2); }), bytes_per_vector, metric_kind_t::cos_k, scalar_kind_t::f16_k, isa_kind_t::avx512f16_k};
|
|
1443
|
+
#endif
|
|
1444
|
+
#if SIMSIMD_TARGET_X86_AVX2
|
|
1445
|
+
if (hardware_supports(isa_kind_t::avx2f16_k) && bytes_per_vector % 16 == 0) return {pun_stl_<simsimd_f16_t>([=](simsimd_f16_t const* a, simsimd_f16_t const* b) { return simsimd_cos_f16x8_avx2(a, b, bytes_per_vector / 2); }), bytes_per_vector, metric_kind_t::cos_k, scalar_kind_t::f16_k, isa_kind_t::avx2f16_k};
|
|
1408
1446
|
#endif
|
|
1409
1447
|
#if SIMSIMD_TARGET_ARM_NEON
|
|
1410
1448
|
if (hardware_supports(isa_kind_t::neon_k) && bytes_per_vector % 8 == 0) return {pun_stl_<simsimd_f16_t>([=](simsimd_f16_t const* a, simsimd_f16_t const* b) { return simsimd_cos_f16x4_neon(a, b, bytes_per_vector / 2); }), bytes_per_vector, metric_kind_t::cos_k, scalar_kind_t::f16_k, isa_kind_t::neon_k};
|
|
1411
1449
|
#endif
|
|
1450
|
+
#if SIMSIMD_TARGET_ARM_SVE
|
|
1451
|
+
if (hardware_supports(isa_kind_t::sve_k)) return {pun_stl_<simsimd_f16_t>([=](simsimd_f16_t const* a, simsimd_f16_t const* b) { return simsimd_cos_f16_sve(a, b, bytes_per_vector / 4); }), bytes_per_vector, metric_kind_t::cos_k, scalar_kind_t::f16_k, isa_kind_t::sve_k};
|
|
1452
|
+
#endif
|
|
1412
1453
|
#endif
|
|
1413
1454
|
return {to_stl_<metric_cos_gt<f16_t, f32_t>>(bytes_per_vector), bytes_per_vector, metric_kind_t::cos_k, scalar_kind_t::f16_k, isa_kind_t::auto_k};
|
|
1414
1455
|
}
|
|
1415
1456
|
|
|
1457
|
+
static metric_punned_t ip_metric_f16_(std::size_t bytes_per_vector) {
|
|
1458
|
+
#if USEARCH_USE_SIMSIMD
|
|
1459
|
+
#if SIMSIMD_TARGET_X86_AVX512
|
|
1460
|
+
if (hardware_supports(isa_kind_t::avx512f16_k) && bytes_per_vector % 32 == 0) return {pun_stl_<simsimd_f16_t>([=](simsimd_f16_t const* a, simsimd_f16_t const* b) { return simsimd_dot_f16x16_avx512(a, b, bytes_per_vector / 2); }), bytes_per_vector, metric_kind_t::ip_k, scalar_kind_t::f16_k, isa_kind_t::avx512f16_k};
|
|
1461
|
+
#endif
|
|
1462
|
+
#if SIMSIMD_TARGET_X86_AVX2
|
|
1463
|
+
if (hardware_supports(isa_kind_t::avx2f16_k) && bytes_per_vector % 16 == 0) return {pun_stl_<simsimd_f16_t>([=](simsimd_f16_t const* a, simsimd_f16_t const* b) { return simsimd_dot_f16x8_avx2(a, b, bytes_per_vector / 2); }), bytes_per_vector, metric_kind_t::ip_k, scalar_kind_t::f16_k, isa_kind_t::avx2f16_k};
|
|
1464
|
+
#endif
|
|
1465
|
+
#if SIMSIMD_TARGET_ARM_NEON
|
|
1466
|
+
if (hardware_supports(isa_kind_t::neon_k) && bytes_per_vector % 8 == 0) return {pun_stl_<simsimd_f16_t>([=](simsimd_f16_t const* a, simsimd_f16_t const* b) { return simsimd_dot_f16x4_neon(a, b, bytes_per_vector / 2); }), bytes_per_vector, metric_kind_t::ip_k, scalar_kind_t::f16_k, isa_kind_t::neon_k};
|
|
1467
|
+
#endif
|
|
1468
|
+
#endif
|
|
1469
|
+
return {to_stl_<metric_cos_gt<f16_t, f32_t>>(bytes_per_vector), bytes_per_vector, metric_kind_t::ip_k, scalar_kind_t::f16_k, isa_kind_t::auto_k};
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1472
|
+
static metric_punned_t l2sq_metric_f16_(std::size_t bytes_per_vector) {
|
|
1473
|
+
#if USEARCH_USE_SIMSIMD
|
|
1474
|
+
#if SIMSIMD_TARGET_X86_AVX512
|
|
1475
|
+
if (hardware_supports(isa_kind_t::avx512f16_k) && bytes_per_vector % 32 == 0) return {pun_stl_<simsimd_f16_t>([=](simsimd_f16_t const* a, simsimd_f16_t const* b) { return simsimd_l2sq_f16x16_avx512(a, b, bytes_per_vector / 2); }), bytes_per_vector, metric_kind_t::cos_k, scalar_kind_t::f16_k, isa_kind_t::avx512f16_k};
|
|
1476
|
+
#endif
|
|
1477
|
+
#if SIMSIMD_TARGET_X86_AVX2
|
|
1478
|
+
if (hardware_supports(isa_kind_t::avx2f16_k) && bytes_per_vector % 16 == 0) return {pun_stl_<simsimd_f16_t>([=](simsimd_f16_t const* a, simsimd_f16_t const* b) { return simsimd_l2sq_f16x8_avx2(a, b, bytes_per_vector / 2); }), bytes_per_vector, metric_kind_t::cos_k, scalar_kind_t::f16_k, isa_kind_t::avx2f16_k};
|
|
1479
|
+
#endif
|
|
1480
|
+
#if SIMSIMD_TARGET_ARM_SVE
|
|
1481
|
+
if (hardware_supports(isa_kind_t::sve_k)) return {pun_stl_<simsimd_f16_t>([=](simsimd_f16_t const* a, simsimd_f16_t const* b) { return simsimd_l2sq_f16_sve(a, b, bytes_per_vector / 4); }), bytes_per_vector, metric_kind_t::l2sq_k, scalar_kind_t::f16_k, isa_kind_t::sve_k};
|
|
1482
|
+
#endif
|
|
1483
|
+
#endif
|
|
1484
|
+
return {to_stl_<metric_l2sq_gt<f16_t, f32_t>>(bytes_per_vector), bytes_per_vector, metric_kind_t::l2sq_k, scalar_kind_t::f16_k, isa_kind_t::auto_k};
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1416
1487
|
static metric_punned_t cos_metric_i8_(std::size_t bytes_per_vector) {
|
|
1417
1488
|
#if USEARCH_USE_SIMSIMD
|
|
1418
1489
|
#if SIMSIMD_TARGET_ARM_NEON
|
|
1419
1490
|
if (hardware_supports(isa_kind_t::neon_k) && bytes_per_vector % 16 == 0) return {pun_stl_<int8_t>([=](int8_t const* a, int8_t const* b) { return simsimd_cos_i8x16_neon(a, b, bytes_per_vector); }), bytes_per_vector, metric_kind_t::cos_k, scalar_kind_t::i8_k, isa_kind_t::neon_k};
|
|
1420
1491
|
#endif
|
|
1492
|
+
#if SIMSIMD_TARGET_X86_AVX2
|
|
1493
|
+
if (hardware_supports(isa_kind_t::avx2_k) && bytes_per_vector % 32 == 0) return {pun_stl_<int8_t>([=](int8_t const* a, int8_t const* b) { return simsimd_cos_i8x32_avx2(a, b, bytes_per_vector); }), bytes_per_vector, metric_kind_t::cos_k, scalar_kind_t::i8_k, isa_kind_t::avx2_k};
|
|
1494
|
+
#endif
|
|
1421
1495
|
#endif
|
|
1422
1496
|
return {to_stl_<cos_i8_t>(bytes_per_vector), bytes_per_vector, metric_kind_t::cos_k, scalar_kind_t::i8_k, isa_kind_t::auto_k};
|
|
1423
1497
|
}
|
|
@@ -1425,7 +1499,7 @@ class metric_punned_t {
|
|
|
1425
1499
|
static metric_punned_t ip_metric_(std::size_t bytes_per_vector, scalar_kind_t scalar_kind) {
|
|
1426
1500
|
switch (scalar_kind) { // The two most common numeric types for the most common metric have optimized versions
|
|
1427
1501
|
case scalar_kind_t::f32_k: return ip_metric_f32_(bytes_per_vector);
|
|
1428
|
-
case scalar_kind_t::f16_k: return
|
|
1502
|
+
case scalar_kind_t::f16_k: return ip_metric_f16_(bytes_per_vector);
|
|
1429
1503
|
case scalar_kind_t::i8_k: return cos_metric_i8_(bytes_per_vector);
|
|
1430
1504
|
case scalar_kind_t::f64_k: return {to_stl_<metric_ip_gt<f64_t>>(bytes_per_vector), bytes_per_vector, metric_kind_t::ip_k, scalar_kind_t::f64_k, isa_kind_t::auto_k};
|
|
1431
1505
|
default: return {};
|
|
@@ -1435,7 +1509,7 @@ class metric_punned_t {
|
|
|
1435
1509
|
static metric_punned_t l2sq_metric_(std::size_t bytes_per_vector, scalar_kind_t scalar_kind) {
|
|
1436
1510
|
switch (scalar_kind) {
|
|
1437
1511
|
case scalar_kind_t::i8_k: return {to_stl_<l2sq_i8_t>(bytes_per_vector), bytes_per_vector, metric_kind_t::l2sq_k, scalar_kind_t::i8_k, isa_kind_t::auto_k};
|
|
1438
|
-
case scalar_kind_t::f16_k: return
|
|
1512
|
+
case scalar_kind_t::f16_k: return l2sq_metric_f16_(bytes_per_vector);
|
|
1439
1513
|
case scalar_kind_t::f32_k: return {to_stl_<metric_l2sq_gt<f32_t>>(bytes_per_vector), bytes_per_vector, metric_kind_t::l2sq_k, scalar_kind_t::f32_k, isa_kind_t::auto_k};
|
|
1440
1514
|
case scalar_kind_t::f64_k: return {to_stl_<metric_l2sq_gt<f64_t>>(bytes_per_vector), bytes_per_vector, metric_kind_t::l2sq_k, scalar_kind_t::f64_k, isa_kind_t::auto_k};
|
|
1441
1515
|
default: return {};
|
package/package.json
CHANGED
package/python/lib.cpp
CHANGED
|
@@ -957,6 +957,17 @@ PYBIND11_MODULE(compiled, m) {
|
|
|
957
957
|
py::arg("metric_pointer") = 0 //
|
|
958
958
|
);
|
|
959
959
|
|
|
960
|
+
m.def(
|
|
961
|
+
"hardware_acceleration",
|
|
962
|
+
[](scalar_kind_t scalar_kind, std::size_t dimensions, metric_kind_t metric_kind) -> bool {
|
|
963
|
+
return metric_t(dimensions, metric_kind, scalar_kind).isa_kind() != isa_kind_t::auto_k;
|
|
964
|
+
},
|
|
965
|
+
py::kw_only(), //
|
|
966
|
+
py::arg("dtype") = scalar_kind_t::f32_k, //
|
|
967
|
+
py::arg("ndim") = 0, //
|
|
968
|
+
py::arg("metric_kind") = metric_kind_t::cos_k //
|
|
969
|
+
);
|
|
970
|
+
|
|
960
971
|
auto i = py::class_<dense_index_py_t, std::shared_ptr<dense_index_py_t>>(m, "Index");
|
|
961
972
|
|
|
962
973
|
i.def(py::init(&make_index), //
|
package/python/usearch/index.py
CHANGED
|
@@ -29,6 +29,7 @@ from usearch.compiled import (
|
|
|
29
29
|
index_dense_metadata_from_path as _index_dense_metadata_from_path,
|
|
30
30
|
index_dense_metadata_from_buffer as _index_dense_metadata_from_buffer,
|
|
31
31
|
exact_search as _exact_search,
|
|
32
|
+
hardware_acceleration as _hardware_acceleration,
|
|
32
33
|
)
|
|
33
34
|
|
|
34
35
|
# Precompiled symbols that will be exposed
|
|
@@ -72,9 +73,17 @@ NoneType = type(None)
|
|
|
72
73
|
PathOrBuffer = Union[str, os.PathLike, bytes]
|
|
73
74
|
|
|
74
75
|
|
|
75
|
-
def _normalize_dtype(
|
|
76
|
+
def _normalize_dtype(
|
|
77
|
+
dtype,
|
|
78
|
+
ndim: int = 0,
|
|
79
|
+
metric: MetricKind = MetricKind.Cos,
|
|
80
|
+
) -> ScalarKind:
|
|
76
81
|
if dtype is None or dtype == "":
|
|
77
|
-
|
|
82
|
+
if metric in MetricKindBitwise:
|
|
83
|
+
return ScalarKind.B1
|
|
84
|
+
if _hardware_acceleration(dtype=ScalarKind.F16, ndim=ndim, metric_kind=metric):
|
|
85
|
+
return ScalarKind.F16
|
|
86
|
+
return ScalarKind.F32
|
|
78
87
|
|
|
79
88
|
if isinstance(dtype, ScalarKind):
|
|
80
89
|
return dtype
|
|
@@ -491,8 +500,12 @@ class Index:
|
|
|
491
500
|
:type dtype: Optional[DTypeLike], defaults to None
|
|
492
501
|
For continuous metrics can be: f16, f32, f64, or i8.
|
|
493
502
|
For bitwise metrics it's implementation-defined, and can't change.
|
|
503
|
+
If nothing is provided, the optimal data type is selected based on the metric
|
|
504
|
+
kind and hardware support.
|
|
494
505
|
Example: you can use the `f16` index with `f32` vectors in Euclidean space,
|
|
495
|
-
which will be automatically downcasted.
|
|
506
|
+
which will be automatically downcasted. Moreover, if `dtype=None` is passed,
|
|
507
|
+
and hardware supports `f16` SIMD-instructions, this choice will be done for you.
|
|
508
|
+
You can later double-check the used representation with `index.dtype`.
|
|
496
509
|
|
|
497
510
|
:param connectivity: Connections per node in HNSW
|
|
498
511
|
:type connectivity: Optional[int], defaults to None
|
|
@@ -548,7 +561,7 @@ class Index:
|
|
|
548
561
|
)
|
|
549
562
|
|
|
550
563
|
# Validate, that the right scalar type is defined
|
|
551
|
-
dtype = _normalize_dtype(dtype, self._metric_kind)
|
|
564
|
+
dtype = _normalize_dtype(dtype, ndim, self._metric_kind)
|
|
552
565
|
self._compiled = _CompiledIndex(
|
|
553
566
|
ndim=ndim,
|
|
554
567
|
dtype=dtype,
|
|
@@ -23,7 +23,7 @@ jobs:
|
|
|
23
23
|
strategy:
|
|
24
24
|
fail-fast: false
|
|
25
25
|
matrix:
|
|
26
|
-
os: [ubuntu-22.04
|
|
26
|
+
os: [ubuntu-22.04, macOS-11] # windows-2022
|
|
27
27
|
python-version: ["3.11"]
|
|
28
28
|
|
|
29
29
|
steps:
|
|
@@ -35,7 +35,7 @@ jobs:
|
|
|
35
35
|
python-version: ${{ matrix.python-version }}
|
|
36
36
|
|
|
37
37
|
- name: Set up Clang
|
|
38
|
-
run: brew install
|
|
38
|
+
run: brew install gcc@12
|
|
39
39
|
if: ${{ matrix.os == 'macOS-11' }}
|
|
40
40
|
|
|
41
41
|
- name: Set up MinGW
|
|
@@ -59,10 +59,8 @@ jobs:
|
|
|
59
59
|
|
|
60
60
|
- name: Build locally on MacOS
|
|
61
61
|
run: |
|
|
62
|
-
export
|
|
63
|
-
export
|
|
64
|
-
export CC=/usr/local/opt/llvm/bin/clang
|
|
65
|
-
export CXX=/usr/local/opt/llvm/bin/clang++
|
|
62
|
+
export CC=/usr/local/bin/gcc-12
|
|
63
|
+
export CXX=/usr/local/bin/g++-12
|
|
66
64
|
python -m pip install .
|
|
67
65
|
if: ${{ matrix.os == 'macOS-11' }}
|
|
68
66
|
|
|
@@ -57,8 +57,7 @@ jobs:
|
|
|
57
57
|
needs: versioning
|
|
58
58
|
strategy:
|
|
59
59
|
matrix:
|
|
60
|
-
os: [ubuntu-20.04
|
|
61
|
-
|
|
60
|
+
os: [ubuntu-20.04, macOS-11] # windows-2022
|
|
62
61
|
steps:
|
|
63
62
|
- uses: actions/checkout@v3
|
|
64
63
|
with:
|
|
@@ -76,8 +75,15 @@ jobs:
|
|
|
76
75
|
- name: Install CIBuildWheel
|
|
77
76
|
run: python -m pip install --no-cache-dir cibuildwheel
|
|
78
77
|
|
|
79
|
-
- name: Build wheels
|
|
78
|
+
- name: Build wheels on Ubuntu
|
|
79
|
+
run: python -m cibuildwheel
|
|
80
|
+
if: matrix.os == 'ubuntu-20.04'
|
|
81
|
+
|
|
82
|
+
- name: Build wheels on MacOS
|
|
80
83
|
run: python -m cibuildwheel
|
|
84
|
+
env:
|
|
85
|
+
CIBW_ENVIRONMENT: CC=/usr/local/bin/gcc-12 CXX=/usr/local/bin/g++-12
|
|
86
|
+
if: matrix.os == 'macOS-11'
|
|
81
87
|
|
|
82
88
|
- uses: actions/upload-artifact@v3
|
|
83
89
|
with:
|
|
@@ -45,6 +45,9 @@
|
|
|
45
45
|
#endif
|
|
46
46
|
#endif
|
|
47
47
|
|
|
48
|
+
#undef SIMSIMD_TARGET_X86
|
|
49
|
+
#undef SIMSIMD_TARGET_X86_AVX2
|
|
50
|
+
#undef SIMSIMD_TARGET_X86_AVX512
|
|
48
51
|
#define SIMSIMD_TARGET_X86 0
|
|
49
52
|
#define SIMSIMD_TARGET_X86_AVX2 0
|
|
50
53
|
#define SIMSIMD_TARGET_X86_AVX512 0
|
|
@@ -71,6 +74,9 @@
|
|
|
71
74
|
#endif
|
|
72
75
|
#endif
|
|
73
76
|
|
|
77
|
+
#undef SIMSIMD_TARGET_ARM
|
|
78
|
+
#undef SIMSIMD_TARGET_ARM_NEON
|
|
79
|
+
#undef SIMSIMD_TARGET_ARM_SVE
|
|
74
80
|
#define SIMSIMD_TARGET_ARM 0
|
|
75
81
|
#define SIMSIMD_TARGET_ARM_NEON 0
|
|
76
82
|
#define SIMSIMD_TARGET_ARM_SVE 0
|
|
@@ -143,7 +149,7 @@ simsimd_cos_f32_sve(simsimd_f32_t const* a, simsimd_f32_t const* b, size_t d) {
|
|
|
143
149
|
simsimd_f32_t ab = svaddv_f32(svptrue_b32(), ab_vec);
|
|
144
150
|
simsimd_f32_t a2 = svaddv_f32(svptrue_b32(), a2_vec);
|
|
145
151
|
simsimd_f32_t b2 = svaddv_f32(svptrue_b32(), b2_vec);
|
|
146
|
-
return 1 - ab / (
|
|
152
|
+
return 1 - ab / (sqrtf(a2) * sqrtf(b2));
|
|
147
153
|
}
|
|
148
154
|
|
|
149
155
|
__attribute__((target("+sve"))) inline static simsimd_f32_t //
|
|
@@ -160,7 +166,7 @@ simsimd_l2sq_f32_sve(simsimd_f32_t const* a, simsimd_f32_t const* b, size_t d) {
|
|
|
160
166
|
pg_vec = svwhilelt_b32(i, d);
|
|
161
167
|
} while (svptest_any(svptrue_b32(), pg_vec));
|
|
162
168
|
simsimd_f32_t d2 = svaddv_f32(svptrue_b32(), d2_vec);
|
|
163
|
-
return
|
|
169
|
+
return d2;
|
|
164
170
|
}
|
|
165
171
|
|
|
166
172
|
__attribute__((target("+sve+fp16"))) inline static simsimd_f32_t //
|
|
@@ -184,7 +190,7 @@ simsimd_cos_f16_sve(simsimd_f16_t const* a_enum, simsimd_f16_t const* b_enum, si
|
|
|
184
190
|
simsimd_f16_t ab = svaddv_f16(svptrue_b16(), ab_vec);
|
|
185
191
|
simsimd_f16_t a2 = svaddv_f16(svptrue_b16(), a2_vec);
|
|
186
192
|
simsimd_f16_t b2 = svaddv_f16(svptrue_b16(), b2_vec);
|
|
187
|
-
return 1 - ab / (
|
|
193
|
+
return 1 - ab / (sqrtf(a2) * sqrtf(b2));
|
|
188
194
|
}
|
|
189
195
|
|
|
190
196
|
__attribute__((target("+sve+fp16"))) inline static simsimd_f32_t //
|
|
@@ -235,6 +241,18 @@ simsimd_dot_f32x4_neon(simsimd_f32_t const* a, simsimd_f32_t const* b, size_t d)
|
|
|
235
241
|
return 1 - vaddvq_f32(ab_vec);
|
|
236
242
|
}
|
|
237
243
|
|
|
244
|
+
__attribute__((target("+simd+fp16"))) inline static simsimd_f32_t //
|
|
245
|
+
simsimd_dot_f16x4_neon(simsimd_f16_t const* a, simsimd_f16_t const* b, size_t d) {
|
|
246
|
+
|
|
247
|
+
float32x4_t ab_vec = vdupq_n_f32(0);
|
|
248
|
+
for (size_t i = 0; i != d; i += 4) {
|
|
249
|
+
float32x4_t a_vec = vcvt_f32_f16(vld1_f16((float16_t const*)a + i));
|
|
250
|
+
float32x4_t b_vec = vcvt_f32_f16(vld1_f16((float16_t const*)b + i));
|
|
251
|
+
ab_vec = vfmaq_f32(ab_vec, a_vec, b_vec);
|
|
252
|
+
}
|
|
253
|
+
return 1 - vaddvq_f32(ab_vec);
|
|
254
|
+
}
|
|
255
|
+
|
|
238
256
|
__attribute__((target("+simd+fp16"))) inline static simsimd_f32_t //
|
|
239
257
|
simsimd_cos_f16x4_neon(simsimd_f16_t const* a, simsimd_f16_t const* b, size_t d) {
|
|
240
258
|
|
|
@@ -252,7 +270,7 @@ simsimd_cos_f16x4_neon(simsimd_f16_t const* a, simsimd_f16_t const* b, size_t d)
|
|
|
252
270
|
simsimd_f32_t ab = vaddvq_f32(ab_vec);
|
|
253
271
|
simsimd_f32_t a2 = vaddvq_f32(a2_vec);
|
|
254
272
|
simsimd_f32_t b2 = vaddvq_f32(b2_vec);
|
|
255
|
-
return 1 - ab / (
|
|
273
|
+
return 1 - ab / (sqrtf(a2) * sqrtf(b2));
|
|
256
274
|
}
|
|
257
275
|
|
|
258
276
|
__attribute__((target("+simd"))) inline static simsimd_f32_t //
|
|
@@ -290,7 +308,7 @@ simsimd_cos_i8x16_neon(int8_t const* a, int8_t const* b, size_t d) {
|
|
|
290
308
|
int32_t a2 = vget_lane_s32(vpadd_s32(a2_part, a2_part), 0);
|
|
291
309
|
int32x2_t b2_part = vadd_s32(vget_high_s32(b2_vec), vget_low_s32(b2_vec));
|
|
292
310
|
int32_t b2 = vget_lane_s32(vpadd_s32(b2_part, b2_part), 0);
|
|
293
|
-
return 1 - ab / (
|
|
311
|
+
return 1 - ab / (sqrtf(a2) * sqrtf(b2));
|
|
294
312
|
}
|
|
295
313
|
|
|
296
314
|
__attribute__((target("+simd"))) inline static simsimd_f32_t //
|
|
@@ -308,7 +326,7 @@ simsimd_l2sq_i8x16_neon(int8_t const* a, int8_t const* b, size_t d) {
|
|
|
308
326
|
|
|
309
327
|
int32x2_t d2_part = vadd_s32(vget_high_s32(d2_vec), vget_low_s32(d2_vec));
|
|
310
328
|
int32_t d2 = vget_lane_s32(vpadd_s32(d2_part, d2_part), 0);
|
|
311
|
-
return
|
|
329
|
+
return d2;
|
|
312
330
|
}
|
|
313
331
|
|
|
314
332
|
__attribute__((target("+simd"))) inline static simsimd_f32_t //
|
|
@@ -327,7 +345,7 @@ simsimd_cos_f32x4_neon(simsimd_f32_t const* a, simsimd_f32_t const* b, size_t d)
|
|
|
327
345
|
simsimd_f32_t ab = vaddvq_f32(ab_vec);
|
|
328
346
|
simsimd_f32_t a2 = vaddvq_f32(a2_vec);
|
|
329
347
|
simsimd_f32_t b2 = vaddvq_f32(b2_vec);
|
|
330
|
-
return 1 - ab / (
|
|
348
|
+
return 1 - ab / (sqrtf(a2) * sqrtf(b2));
|
|
331
349
|
}
|
|
332
350
|
|
|
333
351
|
__attribute__((target("+sve"))) inline static simsimd_f32_t //
|
|
@@ -349,7 +367,7 @@ simsimd_hamming_b1x128_sve(uint8_t const* a, uint8_t const* b, size_t d) {
|
|
|
349
367
|
#if SIMSIMD_TARGET_X86
|
|
350
368
|
#if SIMSIMD_TARGET_X86_AVX2
|
|
351
369
|
|
|
352
|
-
__attribute__((target("avx2")))
|
|
370
|
+
__attribute__((target("avx2"))) //
|
|
353
371
|
__attribute__((target("fma"))) inline static simsimd_f32_t //
|
|
354
372
|
simsimd_dot_f32x4_avx2(simsimd_f32_t const* a, simsimd_f32_t const* b, size_t d) {
|
|
355
373
|
__m128 ab_vec = _mm_set1_ps(0);
|
|
@@ -362,7 +380,7 @@ simsimd_dot_f32x4_avx2(simsimd_f32_t const* a, simsimd_f32_t const* b, size_t d)
|
|
|
362
380
|
return 1 - ab_union.f;
|
|
363
381
|
}
|
|
364
382
|
|
|
365
|
-
__attribute__((target("avx2")))
|
|
383
|
+
__attribute__((target("avx2"))) //
|
|
366
384
|
__attribute__((target("fma"))) inline static simsimd_f32_t //
|
|
367
385
|
simsimd_cos_f32x4_avx2(simsimd_f32_t const* a, simsimd_f32_t const* b, size_t d) {
|
|
368
386
|
|
|
@@ -385,13 +403,151 @@ simsimd_cos_f32x4_avx2(simsimd_f32_t const* a, simsimd_f32_t const* b, size_t d)
|
|
|
385
403
|
union simsimd_f32i32_t ab_union = {_mm_cvtsi128_si32(_mm_castps_si128(ab_vec))};
|
|
386
404
|
union simsimd_f32i32_t a2_union = {_mm_cvtsi128_si32(_mm_castps_si128(a2_vec))};
|
|
387
405
|
union simsimd_f32i32_t b2_union = {_mm_cvtsi128_si32(_mm_castps_si128(b2_vec))};
|
|
388
|
-
return 1 - ab_union.f / (
|
|
406
|
+
return 1 - ab_union.f / (sqrtf(a2_union.f) * sqrtf(b2_union.f));
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
__attribute__((target("avx2"))) //
|
|
410
|
+
__attribute__((target("fma"))) inline static simsimd_f32_t //
|
|
411
|
+
simsimd_l2sq_f32x4_avx2(simsimd_f32_t const* a, simsimd_f32_t const* b, size_t d) {
|
|
412
|
+
__m128 sum_vec = _mm_set1_ps(0);
|
|
413
|
+
for (size_t i = 0; i != d; i += 4) {
|
|
414
|
+
__m128 diff_vec = _mm_sub_ps(_mm_loadu_ps(a + i), _mm_loadu_ps(b + i));
|
|
415
|
+
sum_vec = _mm_fmadd_ps(diff_vec, diff_vec, sum_vec);
|
|
416
|
+
}
|
|
417
|
+
sum_vec = _mm_hadd_ps(sum_vec, sum_vec);
|
|
418
|
+
sum_vec = _mm_hadd_ps(sum_vec, sum_vec);
|
|
419
|
+
float result[1];
|
|
420
|
+
_mm_store_ss(result, sum_vec);
|
|
421
|
+
return result[0];
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
__attribute__((target("avx2"))) //
|
|
425
|
+
__attribute__((target("f16c"))) //
|
|
426
|
+
__attribute__((target("fma"))) inline static simsimd_f32_t //
|
|
427
|
+
simsimd_dot_f16x8_avx2(simsimd_f16_t const* a, simsimd_f16_t const* b, size_t d) {
|
|
428
|
+
__m256 ab_vec = _mm256_set1_ps(0);
|
|
429
|
+
for (size_t i = 0; i != d; i += 8) {
|
|
430
|
+
__m256 a_vec = _mm256_cvtph_ps(_mm_loadu_si128((__m128i const*)(a + i)));
|
|
431
|
+
__m256 b_vec = _mm256_cvtph_ps(_mm_loadu_si128((__m128i const*)(b + i)));
|
|
432
|
+
ab_vec = _mm256_fmadd_ps(a_vec, b_vec, ab_vec);
|
|
433
|
+
}
|
|
434
|
+
ab_vec = _mm256_add_ps(_mm256_permute2f128_ps(ab_vec, ab_vec, 0x81), ab_vec);
|
|
435
|
+
ab_vec = _mm256_hadd_ps(ab_vec, ab_vec);
|
|
436
|
+
ab_vec = _mm256_hadd_ps(ab_vec, ab_vec);
|
|
437
|
+
float result[1];
|
|
438
|
+
_mm_store_ss(result, _mm256_castps256_ps128(ab_vec));
|
|
439
|
+
return 1 - result[0];
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
__attribute__((target("avx2"))) //
|
|
443
|
+
__attribute__((target("f16c"))) //
|
|
444
|
+
__attribute__((target("fma"))) inline static simsimd_f32_t //
|
|
445
|
+
simsimd_cos_f16x8_avx2(simsimd_f16_t const* a, simsimd_f16_t const* b, size_t d) {
|
|
446
|
+
__m256 ab_vec = _mm256_set1_ps(0);
|
|
447
|
+
__m256 a2_vec = _mm256_set1_ps(0);
|
|
448
|
+
__m256 b2_vec = _mm256_set1_ps(0);
|
|
449
|
+
for (size_t i = 0; i != d; i += 8) {
|
|
450
|
+
__m256 a_vec = _mm256_cvtph_ps(_mm_loadu_si128((__m128i const*)(a + i)));
|
|
451
|
+
__m256 b_vec = _mm256_cvtph_ps(_mm_loadu_si128((__m128i const*)(b + i)));
|
|
452
|
+
ab_vec = _mm256_fmadd_ps(a_vec, b_vec, ab_vec);
|
|
453
|
+
a2_vec = _mm256_fmadd_ps(a_vec, a_vec, a2_vec);
|
|
454
|
+
b2_vec = _mm256_fmadd_ps(b_vec, b_vec, b2_vec);
|
|
455
|
+
}
|
|
456
|
+
ab_vec = _mm256_add_ps(_mm256_permute2f128_ps(ab_vec, ab_vec, 0x81), ab_vec);
|
|
457
|
+
ab_vec = _mm256_hadd_ps(ab_vec, ab_vec);
|
|
458
|
+
ab_vec = _mm256_hadd_ps(ab_vec, ab_vec);
|
|
459
|
+
a2_vec = _mm256_add_ps(_mm256_permute2f128_ps(a2_vec, a2_vec, 0x81), a2_vec);
|
|
460
|
+
a2_vec = _mm256_hadd_ps(a2_vec, a2_vec);
|
|
461
|
+
a2_vec = _mm256_hadd_ps(a2_vec, a2_vec);
|
|
462
|
+
b2_vec = _mm256_add_ps(_mm256_permute2f128_ps(b2_vec, b2_vec, 0x81), b2_vec);
|
|
463
|
+
b2_vec = _mm256_hadd_ps(b2_vec, b2_vec);
|
|
464
|
+
b2_vec = _mm256_hadd_ps(b2_vec, b2_vec);
|
|
465
|
+
float ab_result[1], a2_result[1], b2_result[1];
|
|
466
|
+
_mm_store_ss(ab_result, _mm256_castps256_ps128(ab_vec));
|
|
467
|
+
_mm_store_ss(a2_result, _mm256_castps256_ps128(a2_vec));
|
|
468
|
+
_mm_store_ss(b2_result, _mm256_castps256_ps128(b2_vec));
|
|
469
|
+
return 1 - ab_result[0] / (sqrtf(a2_result[0]) * sqrtf(b2_result[0]));
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
__attribute__((target("avx2"))) //
|
|
473
|
+
__attribute__((target("f16c"))) //
|
|
474
|
+
__attribute__((target("fma"))) inline static simsimd_f32_t //
|
|
475
|
+
simsimd_l2sq_f16x8_avx2(simsimd_f16_t const* a, simsimd_f16_t const* b, size_t d) {
|
|
476
|
+
__m256 sum_vec = _mm256_set1_ps(0);
|
|
477
|
+
for (size_t i = 0; i != d; i += 8) {
|
|
478
|
+
__m256 a_vec = _mm256_cvtph_ps(_mm_loadu_si128((__m128i const*)(a + i)));
|
|
479
|
+
__m256 b_vec = _mm256_cvtph_ps(_mm_loadu_si128((__m128i const*)(b + i)));
|
|
480
|
+
__m256 diff_vec = _mm256_sub_ps(a_vec, b_vec);
|
|
481
|
+
sum_vec = _mm256_fmadd_ps(diff_vec, diff_vec, sum_vec);
|
|
482
|
+
}
|
|
483
|
+
sum_vec = _mm256_add_ps(_mm256_permute2f128_ps(sum_vec, sum_vec, 0x81), sum_vec);
|
|
484
|
+
sum_vec = _mm256_hadd_ps(sum_vec, sum_vec);
|
|
485
|
+
sum_vec = _mm256_hadd_ps(sum_vec, sum_vec);
|
|
486
|
+
float result[1];
|
|
487
|
+
_mm_store_ss(result, _mm256_castps256_ps128(sum_vec));
|
|
488
|
+
return result[0];
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
__attribute__((target("avx2"))) //
|
|
492
|
+
inline static simsimd_f32_t
|
|
493
|
+
simsimd_cos_i8x32_avx2(int8_t const* a, int8_t const* b, size_t d) {
|
|
494
|
+
|
|
495
|
+
__m256i ab_vec = _mm256_setzero_si256();
|
|
496
|
+
__m256i a2_vec = _mm256_setzero_si256();
|
|
497
|
+
__m256i b2_vec = _mm256_setzero_si256();
|
|
498
|
+
|
|
499
|
+
for (size_t i = 0; i != d; i += 32) {
|
|
500
|
+
__m256i a_vec = _mm256_loadu_si256((__m256i const*)(a + i));
|
|
501
|
+
__m256i b_vec = _mm256_loadu_si256((__m256i const*)(b + i));
|
|
502
|
+
|
|
503
|
+
// Multiply and add packed 8-bit integers
|
|
504
|
+
__m256i ab_part_vec = _mm256_maddubs_epi16(a_vec, b_vec);
|
|
505
|
+
__m256i a2_part_vec = _mm256_maddubs_epi16(a_vec, a_vec);
|
|
506
|
+
__m256i b2_part_vec = _mm256_maddubs_epi16(b_vec, b_vec);
|
|
507
|
+
|
|
508
|
+
ab_vec = _mm256_add_epi32(ab_vec, ab_part_vec);
|
|
509
|
+
a2_vec = _mm256_add_epi32(a2_vec, a2_part_vec);
|
|
510
|
+
b2_vec = _mm256_add_epi32(b2_vec, b2_part_vec);
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// Horizontal sum across the 256-bit register
|
|
514
|
+
__m128i ab_low = _mm256_extracti128_si256(ab_vec, 0);
|
|
515
|
+
__m128i ab_high = _mm256_extracti128_si256(ab_vec, 1);
|
|
516
|
+
__m128i ab_sum = _mm_add_epi32(ab_low, ab_high);
|
|
517
|
+
|
|
518
|
+
__m128i a2_low = _mm256_extracti128_si256(a2_vec, 0);
|
|
519
|
+
__m128i a2_high = _mm256_extracti128_si256(a2_vec, 1);
|
|
520
|
+
__m128i a2_sum = _mm_add_epi32(a2_low, a2_high);
|
|
521
|
+
|
|
522
|
+
__m128i b2_low = _mm256_extracti128_si256(b2_vec, 0);
|
|
523
|
+
__m128i b2_high = _mm256_extracti128_si256(b2_vec, 1);
|
|
524
|
+
__m128i b2_sum = _mm_add_epi32(b2_low, b2_high);
|
|
525
|
+
|
|
526
|
+
// Further reduce to a single sum for each vector
|
|
527
|
+
int ab = _mm_extract_epi32(_mm_hadd_epi32(_mm_hadd_epi32(ab_sum, ab_sum), ab_sum), 0);
|
|
528
|
+
int a2 = _mm_extract_epi32(_mm_hadd_epi32(_mm_hadd_epi32(a2_sum, a2_sum), a2_sum), 0);
|
|
529
|
+
int b2 = _mm_extract_epi32(_mm_hadd_epi32(_mm_hadd_epi32(b2_sum, b2_sum), b2_sum), 0);
|
|
530
|
+
|
|
531
|
+
return 1 - ab / (sqrtf(a2) * sqrtf(b2));
|
|
389
532
|
}
|
|
390
533
|
|
|
391
534
|
#endif // SIMSIMD_TARGET_X86_AVX2
|
|
392
535
|
|
|
393
536
|
#if SIMSIMD_TARGET_X86_AVX512
|
|
394
537
|
|
|
538
|
+
__attribute__((target("avx512fp16"))) //
|
|
539
|
+
__attribute__((target("avx512f"))) inline static simsimd_f32_t //
|
|
540
|
+
simsimd_dot_f16x16_avx512(simsimd_f16_t const* a, simsimd_f16_t const* b, size_t d) {
|
|
541
|
+
__m512 ab_vec = _mm512_set1_ps(0);
|
|
542
|
+
for (size_t i = 0; i != d; i += 16) {
|
|
543
|
+
__m512 a_vec = _mm512_cvtxph_ps(_mm256_loadu_ph(a + i));
|
|
544
|
+
__m512 b_vec = _mm512_cvtxph_ps(_mm256_loadu_ph(b + i));
|
|
545
|
+
ab_vec = _mm512_fmadd_ps(a_vec, b_vec, ab_vec);
|
|
546
|
+
}
|
|
547
|
+
simsimd_f32_t ab = _mm512_reduce_add_ps(ab_vec);
|
|
548
|
+
return 1 - ab;
|
|
549
|
+
}
|
|
550
|
+
|
|
395
551
|
__attribute__((target("avx512fp16"))) //
|
|
396
552
|
__attribute__((target("avx512f"))) inline static simsimd_f32_t //
|
|
397
553
|
simsimd_cos_f16x16_avx512(simsimd_f16_t const* a, simsimd_f16_t const* b, size_t d) {
|
|
@@ -408,7 +564,21 @@ simsimd_cos_f16x16_avx512(simsimd_f16_t const* a, simsimd_f16_t const* b, size_t
|
|
|
408
564
|
simsimd_f32_t ab = _mm512_reduce_add_ps(ab_vec);
|
|
409
565
|
simsimd_f32_t a2 = _mm512_reduce_add_ps(a2_vec);
|
|
410
566
|
simsimd_f32_t b2 = _mm512_reduce_add_ps(b2_vec);
|
|
411
|
-
return 1 - ab / (
|
|
567
|
+
return 1 - ab / (sqrtf(a2) * sqrtf(b2));
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
__attribute__((target("avx512fp16"))) //
|
|
571
|
+
__attribute__((target("avx512f"))) inline static simsimd_f32_t //
|
|
572
|
+
simsimd_l2sq_f16x16_avx512(simsimd_f16_t const* a, simsimd_f16_t const* b, size_t d) {
|
|
573
|
+
__m512 sum_vec = _mm512_set1_ps(0);
|
|
574
|
+
for (size_t i = 0; i != d; i += 16) {
|
|
575
|
+
__m512 a_vec = _mm512_cvtxph_ps(_mm256_loadu_ph(a + i));
|
|
576
|
+
__m512 b_vec = _mm512_cvtxph_ps(_mm256_loadu_ph(b + i));
|
|
577
|
+
__m512 diff_vec = _mm512_sub_ps(a_vec, b_vec);
|
|
578
|
+
sum_vec = _mm512_fmadd_ps(diff_vec, diff_vec, sum_vec);
|
|
579
|
+
}
|
|
580
|
+
simsimd_f32_t sum = _mm512_reduce_add_ps(sum_vec);
|
|
581
|
+
return sum;
|
|
412
582
|
}
|
|
413
583
|
|
|
414
584
|
__attribute__((target("avx512vpopcntdq"))) //
|
package/simsimd/pyproject.toml
CHANGED
|
@@ -30,8 +30,9 @@ repair-wheel-command = "auditwheel repair --lib-sdir . -w {dest_dir} {wheel}"
|
|
|
30
30
|
[tool.cibuildwheel.macos]
|
|
31
31
|
before-build = [
|
|
32
32
|
"rm -rf {project}/build",
|
|
33
|
+
"brew install gcc@12",
|
|
33
34
|
]
|
|
34
|
-
archs = ["x86_64", "
|
|
35
|
+
archs = ["x86_64", "arm64"]
|
|
35
36
|
repair-wheel-command = "delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel}"
|
|
36
37
|
|
|
37
38
|
[tool.cibuildwheel.windows]
|
package/simsimd/python/lib.c
CHANGED
|
@@ -58,6 +58,8 @@ PyMODINIT_FUNC PyInit_simsimd(void) {
|
|
|
58
58
|
return NULL;
|
|
59
59
|
|
|
60
60
|
PyModule_AddObject(m, "tanimoto_b1x8_naive", distance(&simsimd_tanimoto_b1x8_naive));
|
|
61
|
+
|
|
62
|
+
// Specialized:
|
|
61
63
|
PyModule_AddObject(m, "tanimoto_maccs_naive", distance(&simsimd_tanimoto_maccs_naive));
|
|
62
64
|
PyModule_AddObject(m, "tanimoto_conditional_naive", distance(&simsimd_tanimoto_conditional_naive));
|
|
63
65
|
|
|
@@ -66,6 +68,8 @@ PyMODINIT_FUNC PyInit_simsimd(void) {
|
|
|
66
68
|
PyModule_AddObject(m, "cos_f16x4_neon", distance(&simsimd_cos_f16x4_neon));
|
|
67
69
|
PyModule_AddObject(m, "cos_i8x16_neon", distance(&simsimd_cos_i8x16_neon));
|
|
68
70
|
PyModule_AddObject(m, "cos_f32x4_neon", distance(&simsimd_cos_f32x4_neon));
|
|
71
|
+
|
|
72
|
+
// Specialized:
|
|
69
73
|
PyModule_AddObject(m, "tanimoto_maccs_neon", distance(&simsimd_tanimoto_maccs_neon));
|
|
70
74
|
|
|
71
75
|
#if SIMSIMD_TARGET_ARM_SVE
|
|
@@ -76,16 +80,28 @@ PyMODINIT_FUNC PyInit_simsimd(void) {
|
|
|
76
80
|
PyModule_AddObject(m, "l2sq_f16_sve", distance(&simsimd_l2sq_f16_sve));
|
|
77
81
|
PyModule_AddObject(m, "hamming_b1x8_sve", distance(&simsimd_hamming_b1x8_sve));
|
|
78
82
|
PyModule_AddObject(m, "hamming_b1x128_sve", distance(&simsimd_hamming_b1x128_sve));
|
|
83
|
+
|
|
84
|
+
// Specialized:
|
|
79
85
|
PyModule_AddObject(m, "tanimoto_maccs_sve", distance(&simsimd_tanimoto_maccs_sve));
|
|
80
86
|
#endif
|
|
81
87
|
#endif
|
|
82
88
|
|
|
83
89
|
#if SIMSIMD_TARGET_X86
|
|
90
|
+
PyModule_AddObject(m, "dot_f32x4_avx2", distance(&simsimd_dot_f32x4_avx2));
|
|
84
91
|
PyModule_AddObject(m, "cos_f32x4_avx2", distance(&simsimd_cos_f32x4_avx2));
|
|
92
|
+
PyModule_AddObject(m, "l2sq_f32x4_avx2", distance(&simsimd_l2sq_f32x4_avx2));
|
|
93
|
+
PyModule_AddObject(m, "dot_f16x8_avx2", distance(&simsimd_dot_f16x8_avx2));
|
|
94
|
+
PyModule_AddObject(m, "cos_f16x8_avx2", distance(&simsimd_cos_f16x8_avx2));
|
|
95
|
+
PyModule_AddObject(m, "l2sq_f16x8_avx2", distance(&simsimd_l2sq_f16x8_avx2));
|
|
85
96
|
|
|
86
97
|
#if SIMSIMD_TARGET_X86_AVX512
|
|
98
|
+
PyModule_AddObject(m, "dot_f16x16_avx512", distance(&simsimd_dot_f16x16_avx512));
|
|
87
99
|
PyModule_AddObject(m, "cos_f16x16_avx512", distance(&simsimd_cos_f16x16_avx512));
|
|
100
|
+
PyModule_AddObject(m, "l2sq_f16x16_avx512", distance(&simsimd_l2sq_f16x16_avx512));
|
|
101
|
+
|
|
88
102
|
PyModule_AddObject(m, "hamming_b1x128_avx512", distance(&simsimd_hamming_b1x128_avx512));
|
|
103
|
+
|
|
104
|
+
// Specialized:
|
|
89
105
|
PyModule_AddObject(m, "tanimoto_maccs_avx512", distance(&simsimd_tanimoto_maccs_avx512));
|
|
90
106
|
#endif
|
|
91
107
|
#endif
|