usearch 2.1.3 → 2.2.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/Cargo.toml +1 -1
- package/conanfile.py +1 -1
- package/include/usearch/index_plugins.hpp +35 -7
- 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 +108 -4
- package/simsimd/pyproject.toml +2 -1
- package/simsimd/python/lib.c +16 -0
- package/wasmer.toml +1 -1
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.
|
|
7
|
+
version = '2.2.0'
|
|
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
|
}
|
|
@@ -221,6 +221,13 @@ inline bool hardware_supports(isa_kind_t isa_kind) noexcept {
|
|
|
221
221
|
#if defined(USEARCH_DEFINED_X86) && defined(USEARCH_DEFINED_GCC)
|
|
222
222
|
__builtin_cpu_init();
|
|
223
223
|
switch (isa_kind) {
|
|
224
|
+
// Half-precision is only supported in newer versions of GCC
|
|
225
|
+
#if __GNUC__ > 11 || (__GNUC__ == 11 && __GNUC_MINOR__ >= 0)
|
|
226
|
+
case isa_kind_t::avx2f16_k: return __builtin_cpu_supports("avx2") && __builtin_cpu_supports("f16c");
|
|
227
|
+
#endif
|
|
228
|
+
#if __GNUC__ > 12 || (__GNUC__ == 12 && __GNUC_MINOR__ >= 0)
|
|
229
|
+
case isa_kind_t::avx512f16_k: return __builtin_cpu_supports("avx512f") && __builtin_cpu_supports("avx512fp16");
|
|
230
|
+
#endif
|
|
224
231
|
case isa_kind_t::avx2_k: return __builtin_cpu_supports("avx2");
|
|
225
232
|
case isa_kind_t::avx512_k: return __builtin_cpu_supports("avx512f");
|
|
226
233
|
default: return false;
|
|
@@ -1404,15 +1411,36 @@ class metric_punned_t {
|
|
|
1404
1411
|
static metric_punned_t cos_metric_f16_(std::size_t bytes_per_vector) {
|
|
1405
1412
|
#if USEARCH_USE_SIMSIMD
|
|
1406
1413
|
#if SIMSIMD_TARGET_X86_AVX512
|
|
1407
|
-
if (hardware_supports(isa_kind_t::
|
|
1414
|
+
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};
|
|
1415
|
+
#endif
|
|
1416
|
+
#if SIMSIMD_TARGET_X86_AVX2
|
|
1417
|
+
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
1418
|
#endif
|
|
1409
1419
|
#if SIMSIMD_TARGET_ARM_NEON
|
|
1410
1420
|
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
1421
|
#endif
|
|
1422
|
+
#if SIMSIMD_TARGET_ARM_SVE
|
|
1423
|
+
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};
|
|
1424
|
+
#endif
|
|
1412
1425
|
#endif
|
|
1413
1426
|
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
1427
|
}
|
|
1415
1428
|
|
|
1429
|
+
static metric_punned_t l2sq_metric_f16_(std::size_t bytes_per_vector) {
|
|
1430
|
+
#if USEARCH_USE_SIMSIMD
|
|
1431
|
+
#if SIMSIMD_TARGET_X86_AVX512
|
|
1432
|
+
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};
|
|
1433
|
+
#endif
|
|
1434
|
+
#if SIMSIMD_TARGET_X86_AVX2
|
|
1435
|
+
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};
|
|
1436
|
+
#endif
|
|
1437
|
+
#if SIMSIMD_TARGET_ARM_SVE
|
|
1438
|
+
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};
|
|
1439
|
+
#endif
|
|
1440
|
+
#endif
|
|
1441
|
+
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};
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1416
1444
|
static metric_punned_t cos_metric_i8_(std::size_t bytes_per_vector) {
|
|
1417
1445
|
#if USEARCH_USE_SIMSIMD
|
|
1418
1446
|
#if SIMSIMD_TARGET_ARM_NEON
|
|
@@ -1435,7 +1463,7 @@ class metric_punned_t {
|
|
|
1435
1463
|
static metric_punned_t l2sq_metric_(std::size_t bytes_per_vector, scalar_kind_t scalar_kind) {
|
|
1436
1464
|
switch (scalar_kind) {
|
|
1437
1465
|
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
|
|
1466
|
+
case scalar_kind_t::f16_k: return l2sq_metric_f16_(bytes_per_vector);
|
|
1439
1467
|
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
1468
|
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
1469
|
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:
|
|
@@ -160,7 +160,7 @@ simsimd_l2sq_f32_sve(simsimd_f32_t const* a, simsimd_f32_t const* b, size_t d) {
|
|
|
160
160
|
pg_vec = svwhilelt_b32(i, d);
|
|
161
161
|
} while (svptest_any(svptrue_b32(), pg_vec));
|
|
162
162
|
simsimd_f32_t d2 = svaddv_f32(svptrue_b32(), d2_vec);
|
|
163
|
-
return
|
|
163
|
+
return d2;
|
|
164
164
|
}
|
|
165
165
|
|
|
166
166
|
__attribute__((target("+sve+fp16"))) inline static simsimd_f32_t //
|
|
@@ -308,7 +308,7 @@ simsimd_l2sq_i8x16_neon(int8_t const* a, int8_t const* b, size_t d) {
|
|
|
308
308
|
|
|
309
309
|
int32x2_t d2_part = vadd_s32(vget_high_s32(d2_vec), vget_low_s32(d2_vec));
|
|
310
310
|
int32_t d2 = vget_lane_s32(vpadd_s32(d2_part, d2_part), 0);
|
|
311
|
-
return
|
|
311
|
+
return d2;
|
|
312
312
|
}
|
|
313
313
|
|
|
314
314
|
__attribute__((target("+simd"))) inline static simsimd_f32_t //
|
|
@@ -349,7 +349,7 @@ simsimd_hamming_b1x128_sve(uint8_t const* a, uint8_t const* b, size_t d) {
|
|
|
349
349
|
#if SIMSIMD_TARGET_X86
|
|
350
350
|
#if SIMSIMD_TARGET_X86_AVX2
|
|
351
351
|
|
|
352
|
-
__attribute__((target("avx2")))
|
|
352
|
+
__attribute__((target("avx2"))) //
|
|
353
353
|
__attribute__((target("fma"))) inline static simsimd_f32_t //
|
|
354
354
|
simsimd_dot_f32x4_avx2(simsimd_f32_t const* a, simsimd_f32_t const* b, size_t d) {
|
|
355
355
|
__m128 ab_vec = _mm_set1_ps(0);
|
|
@@ -362,7 +362,7 @@ simsimd_dot_f32x4_avx2(simsimd_f32_t const* a, simsimd_f32_t const* b, size_t d)
|
|
|
362
362
|
return 1 - ab_union.f;
|
|
363
363
|
}
|
|
364
364
|
|
|
365
|
-
__attribute__((target("avx2")))
|
|
365
|
+
__attribute__((target("avx2"))) //
|
|
366
366
|
__attribute__((target("fma"))) inline static simsimd_f32_t //
|
|
367
367
|
simsimd_cos_f32x4_avx2(simsimd_f32_t const* a, simsimd_f32_t const* b, size_t d) {
|
|
368
368
|
|
|
@@ -388,10 +388,100 @@ simsimd_cos_f32x4_avx2(simsimd_f32_t const* a, simsimd_f32_t const* b, size_t d)
|
|
|
388
388
|
return 1 - ab_union.f / (sqrt(a2_union.f) * sqrt(b2_union.f));
|
|
389
389
|
}
|
|
390
390
|
|
|
391
|
+
__attribute__((target("avx2"))) //
|
|
392
|
+
__attribute__((target("fma"))) inline static simsimd_f32_t //
|
|
393
|
+
simsimd_l2sq_f32x4_avx2(simsimd_f32_t const* a, simsimd_f32_t const* b, size_t d) {
|
|
394
|
+
__m128 sum_vec = _mm_set1_ps(0);
|
|
395
|
+
for (size_t i = 0; i != d; i += 4) {
|
|
396
|
+
__m128 diff_vec = _mm_sub_ps(_mm_loadu_ps(a + i), _mm_loadu_ps(b + i));
|
|
397
|
+
sum_vec = _mm_fmadd_ps(diff_vec, diff_vec, sum_vec);
|
|
398
|
+
}
|
|
399
|
+
sum_vec = _mm_hadd_ps(sum_vec, sum_vec);
|
|
400
|
+
sum_vec = _mm_hadd_ps(sum_vec, sum_vec);
|
|
401
|
+
float result[1];
|
|
402
|
+
_mm_store_ss(result, sum_vec);
|
|
403
|
+
return result[0];
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
__attribute__((target("avx2"))) //
|
|
407
|
+
__attribute__((target("f16c"))) //
|
|
408
|
+
__attribute__((target("fma"))) inline static simsimd_f32_t //
|
|
409
|
+
simsimd_dot_f16x8_avx2(simsimd_f16_t const* a, simsimd_f16_t const* b, size_t d) {
|
|
410
|
+
__m128 ab_vec = _mm_set1_ps(0);
|
|
411
|
+
for (size_t i = 0; i != d; i += 8) {
|
|
412
|
+
__m128 a_vec = _mm_cvtph_ps(_mm_loadu_si128((__m128i const*)(a + i)));
|
|
413
|
+
__m128 b_vec = _mm_cvtph_ps(_mm_loadu_si128((__m128i const*)(b + i)));
|
|
414
|
+
ab_vec = _mm_fmadd_ps(a_vec, b_vec, ab_vec);
|
|
415
|
+
}
|
|
416
|
+
ab_vec = _mm_hadd_ps(ab_vec, ab_vec);
|
|
417
|
+
ab_vec = _mm_hadd_ps(ab_vec, ab_vec);
|
|
418
|
+
float result[1];
|
|
419
|
+
_mm_store_ss(result, ab_vec);
|
|
420
|
+
return 1 - result[0];
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
__attribute__((target("avx2"))) //
|
|
424
|
+
__attribute__((target("f16c"))) //
|
|
425
|
+
__attribute__((target("fma"))) inline static simsimd_f32_t //
|
|
426
|
+
simsimd_cos_f16x8_avx2(simsimd_f16_t const* a, simsimd_f16_t const* b, size_t d) {
|
|
427
|
+
__m128 ab_vec = _mm_set1_ps(0);
|
|
428
|
+
__m128 a2_vec = _mm_set1_ps(0);
|
|
429
|
+
__m128 b2_vec = _mm_set1_ps(0);
|
|
430
|
+
for (size_t i = 0; i != d; i += 8) {
|
|
431
|
+
__m128 a_vec = _mm_cvtph_ps(_mm_loadu_si128((__m128i const*)(a + i)));
|
|
432
|
+
__m128 b_vec = _mm_cvtph_ps(_mm_loadu_si128((__m128i const*)(b + i)));
|
|
433
|
+
ab_vec = _mm_fmadd_ps(a_vec, b_vec, ab_vec);
|
|
434
|
+
a2_vec = _mm_fmadd_ps(a_vec, a_vec, a2_vec);
|
|
435
|
+
b2_vec = _mm_fmadd_ps(b_vec, b_vec, b2_vec);
|
|
436
|
+
}
|
|
437
|
+
ab_vec = _mm_hadd_ps(ab_vec, ab_vec);
|
|
438
|
+
ab_vec = _mm_hadd_ps(ab_vec, ab_vec);
|
|
439
|
+
a2_vec = _mm_hadd_ps(a2_vec, a2_vec);
|
|
440
|
+
a2_vec = _mm_hadd_ps(a2_vec, a2_vec);
|
|
441
|
+
b2_vec = _mm_hadd_ps(b2_vec, b2_vec);
|
|
442
|
+
b2_vec = _mm_hadd_ps(b2_vec, b2_vec);
|
|
443
|
+
float ab_result[1], a2_result[1], b2_result[1];
|
|
444
|
+
_mm_store_ss(ab_result, ab_vec);
|
|
445
|
+
_mm_store_ss(a2_result, a2_vec);
|
|
446
|
+
_mm_store_ss(b2_result, b2_vec);
|
|
447
|
+
return 1 - ab_result[0] / (sqrt(a2_result[0]) * sqrt(b2_result[0]));
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
__attribute__((target("avx2"))) //
|
|
451
|
+
__attribute__((target("f16c"))) //
|
|
452
|
+
__attribute__((target("fma"))) inline static simsimd_f32_t //
|
|
453
|
+
simsimd_l2sq_f16x8_avx2(simsimd_f16_t const* a, simsimd_f16_t const* b, size_t d) {
|
|
454
|
+
__m128 sum_vec = _mm_set1_ps(0);
|
|
455
|
+
for (size_t i = 0; i != d; i += 8) {
|
|
456
|
+
__m128 a_vec = _mm_cvtph_ps(_mm_loadu_si128((__m128i const*)(a + i)));
|
|
457
|
+
__m128 b_vec = _mm_cvtph_ps(_mm_loadu_si128((__m128i const*)(b + i)));
|
|
458
|
+
__m128 diff_vec = _mm_sub_ps(a_vec, b_vec);
|
|
459
|
+
sum_vec = _mm_fmadd_ps(diff_vec, diff_vec, sum_vec);
|
|
460
|
+
}
|
|
461
|
+
sum_vec = _mm_hadd_ps(sum_vec, sum_vec);
|
|
462
|
+
sum_vec = _mm_hadd_ps(sum_vec, sum_vec);
|
|
463
|
+
float result[1];
|
|
464
|
+
_mm_store_ss(result, sum_vec);
|
|
465
|
+
return result[0];
|
|
466
|
+
}
|
|
467
|
+
|
|
391
468
|
#endif // SIMSIMD_TARGET_X86_AVX2
|
|
392
469
|
|
|
393
470
|
#if SIMSIMD_TARGET_X86_AVX512
|
|
394
471
|
|
|
472
|
+
__attribute__((target("avx512fp16"))) //
|
|
473
|
+
__attribute__((target("avx512f"))) inline static simsimd_f32_t //
|
|
474
|
+
simsimd_dot_f16x16_avx512(simsimd_f16_t const* a, simsimd_f16_t const* b, size_t d) {
|
|
475
|
+
__m512 ab_vec = _mm512_set1_ps(0);
|
|
476
|
+
for (size_t i = 0; i != d; i += 16) {
|
|
477
|
+
__m512 a_vec = _mm512_cvtxph_ps(_mm256_loadu_ph(a + i));
|
|
478
|
+
__m512 b_vec = _mm512_cvtxph_ps(_mm256_loadu_ph(b + i));
|
|
479
|
+
ab_vec = _mm512_fmadd_ps(a_vec, b_vec, ab_vec);
|
|
480
|
+
}
|
|
481
|
+
simsimd_f32_t ab = _mm512_reduce_add_ps(ab_vec);
|
|
482
|
+
return 1 - ab;
|
|
483
|
+
}
|
|
484
|
+
|
|
395
485
|
__attribute__((target("avx512fp16"))) //
|
|
396
486
|
__attribute__((target("avx512f"))) inline static simsimd_f32_t //
|
|
397
487
|
simsimd_cos_f16x16_avx512(simsimd_f16_t const* a, simsimd_f16_t const* b, size_t d) {
|
|
@@ -411,6 +501,20 @@ simsimd_cos_f16x16_avx512(simsimd_f16_t const* a, simsimd_f16_t const* b, size_t
|
|
|
411
501
|
return 1 - ab / (sqrt(a2) * sqrt(b2));
|
|
412
502
|
}
|
|
413
503
|
|
|
504
|
+
__attribute__((target("avx512fp16"))) //
|
|
505
|
+
__attribute__((target("avx512f"))) inline static simsimd_f32_t //
|
|
506
|
+
simsimd_l2sq_f16x16_avx512(simsimd_f16_t const* a, simsimd_f16_t const* b, size_t d) {
|
|
507
|
+
__m512 sum_vec = _mm512_set1_ps(0);
|
|
508
|
+
for (size_t i = 0; i != d; i += 16) {
|
|
509
|
+
__m512 a_vec = _mm512_cvtxph_ps(_mm256_loadu_ph(a + i));
|
|
510
|
+
__m512 b_vec = _mm512_cvtxph_ps(_mm256_loadu_ph(b + i));
|
|
511
|
+
__m512 diff_vec = _mm512_sub_ps(a_vec, b_vec);
|
|
512
|
+
sum_vec = _mm512_fmadd_ps(diff_vec, diff_vec, sum_vec);
|
|
513
|
+
}
|
|
514
|
+
simsimd_f32_t sum = _mm512_reduce_add_ps(sum_vec);
|
|
515
|
+
return sum;
|
|
516
|
+
}
|
|
517
|
+
|
|
414
518
|
__attribute__((target("avx512vpopcntdq"))) //
|
|
415
519
|
__attribute__((target("avx512vl"))) //
|
|
416
520
|
__attribute__((target("avx512f"))) inline static simsimd_f32_t //
|
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
|