usearch 0.18.2 → 0.18.3
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.hpp +43 -39
- package/include/usearch/index_punned_dense.hpp +24 -15
- package/include/usearch/index_punned_helpers.hpp +35 -25
- package/package.json +1 -1
- package/python/lib.cpp +3 -11
- package/python/usearch/index.py +2 -0
- package/setup.py +5 -2
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 = '0.18.
|
|
7
|
+
version = '0.18.3'
|
|
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'
|
|
@@ -15,34 +15,38 @@
|
|
|
15
15
|
|
|
16
16
|
// Inferring C++ version
|
|
17
17
|
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L)
|
|
18
|
-
#define
|
|
18
|
+
#define USEARCH_DEFINED_CPP17
|
|
19
19
|
#endif
|
|
20
20
|
|
|
21
21
|
// Inferring target OS
|
|
22
22
|
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
|
|
23
|
-
#define
|
|
23
|
+
#define USEARCH_DEFINED_WINDOWS
|
|
24
24
|
#elif defined(__APPLE__) && defined(__MACH__)
|
|
25
|
-
#define
|
|
25
|
+
#define USEARCH_DEFINED_APPLE
|
|
26
26
|
#elif defined(__linux__)
|
|
27
|
-
#define
|
|
27
|
+
#define USEARCH_DEFINED_LINUX
|
|
28
28
|
#endif
|
|
29
29
|
|
|
30
30
|
// Inferring the compiler
|
|
31
31
|
#if defined(__clang__)
|
|
32
|
-
#define
|
|
32
|
+
#define USEARCH_DEFINED_CLANG
|
|
33
33
|
#elif defined(__GNUC__)
|
|
34
|
-
#define
|
|
34
|
+
#define USEARCH_DEFINED_GCC
|
|
35
35
|
#endif
|
|
36
36
|
|
|
37
37
|
// Inferring hardware architecture: x86 vs Arm
|
|
38
38
|
#if defined(__x86_64__)
|
|
39
|
-
#define
|
|
39
|
+
#define USEARCH_DEFINED_X86
|
|
40
40
|
#elif defined(__aarch64__)
|
|
41
|
-
#define
|
|
41
|
+
#define USEARCH_DEFINED_ARM
|
|
42
|
+
#endif
|
|
43
|
+
|
|
44
|
+
#if !defined(USEARCH_USE_OPENMP)
|
|
45
|
+
#define USEARCH_USE_OPENMP 0
|
|
42
46
|
#endif
|
|
43
47
|
|
|
44
48
|
// OS-specific includes
|
|
45
|
-
#if defined(
|
|
49
|
+
#if defined(USEARCH_DEFINED_WINDOWS)
|
|
46
50
|
#define _USE_MATH_DEFINES
|
|
47
51
|
#include <Windows.h>
|
|
48
52
|
#include <sys/stat.h> // `fstat` for file size
|
|
@@ -69,20 +73,20 @@
|
|
|
69
73
|
#include <utility> // `std::pair`
|
|
70
74
|
|
|
71
75
|
// Prefetching
|
|
72
|
-
#if defined(
|
|
76
|
+
#if defined(USEARCH_DEFINED_GCC)
|
|
73
77
|
// https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html
|
|
74
78
|
// Zero means we are only going to read from that memory.
|
|
75
79
|
// Three means high temporal locality and suggests to keep
|
|
76
80
|
// the data in all layers of cache.
|
|
77
81
|
#define prefetch_m(ptr) __builtin_prefetch((void*)(ptr), 0, 3)
|
|
78
|
-
#elif defined(
|
|
82
|
+
#elif defined(USEARCH_DEFINED_X86)
|
|
79
83
|
#define prefetch_m(ptr) _mm_prefetch((void*)(ptr), _MM_HINT_T0)
|
|
80
84
|
#else
|
|
81
85
|
#define prefetch_m(ptr)
|
|
82
86
|
#endif
|
|
83
87
|
|
|
84
88
|
// Alignment
|
|
85
|
-
#if defined(
|
|
89
|
+
#if defined(USEARCH_DEFINED_WINDOWS)
|
|
86
90
|
#define usearch_pack_m
|
|
87
91
|
#define usearch_align_m __declspec(align(64))
|
|
88
92
|
#else
|
|
@@ -225,11 +229,11 @@ template <typename scalar_at = float, typename result_at = scalar_at> struct ip_
|
|
|
225
229
|
|
|
226
230
|
inline result_t operator()(scalar_t const* a, scalar_t const* b, std::size_t dim) const noexcept {
|
|
227
231
|
result_type ab{};
|
|
228
|
-
#if
|
|
232
|
+
#if USEARCH_USE_OPENMP
|
|
229
233
|
#pragma omp simd reduction(+ : ab)
|
|
230
|
-
#elif defined(
|
|
234
|
+
#elif defined(USEARCH_DEFINED_CLANG)
|
|
231
235
|
#pragma clang loop vectorize(enable)
|
|
232
|
-
#elif defined(
|
|
236
|
+
#elif defined(USEARCH_DEFINED_GCC)
|
|
233
237
|
#pragma GCC ivdep
|
|
234
238
|
#endif
|
|
235
239
|
for (std::size_t i = 0; i != dim; ++i)
|
|
@@ -254,11 +258,11 @@ template <typename scalar_at = float, typename result_at = scalar_at> struct cos
|
|
|
254
258
|
|
|
255
259
|
inline result_t operator()(scalar_t const* a, scalar_t const* b, std::size_t dim) const noexcept {
|
|
256
260
|
result_t ab{}, a2{}, b2{};
|
|
257
|
-
#if
|
|
261
|
+
#if USEARCH_USE_OPENMP
|
|
258
262
|
#pragma omp simd reduction(+ : ab, a2, b2)
|
|
259
|
-
#elif defined(
|
|
263
|
+
#elif defined(USEARCH_DEFINED_CLANG)
|
|
260
264
|
#pragma clang loop vectorize(enable)
|
|
261
|
-
#elif defined(
|
|
265
|
+
#elif defined(USEARCH_DEFINED_GCC)
|
|
262
266
|
#pragma GCC ivdep
|
|
263
267
|
#endif
|
|
264
268
|
for (std::size_t i = 0; i != dim; ++i)
|
|
@@ -283,11 +287,11 @@ template <typename scalar_at = float, typename result_at = scalar_at> struct l2s
|
|
|
283
287
|
|
|
284
288
|
inline result_t operator()(scalar_t const* a, scalar_t const* b, std::size_t dim) const noexcept {
|
|
285
289
|
result_t ab_deltas_sq{};
|
|
286
|
-
#if
|
|
290
|
+
#if USEARCH_USE_OPENMP
|
|
287
291
|
#pragma omp simd reduction(+ : ab_deltas_sq)
|
|
288
|
-
#elif defined(
|
|
292
|
+
#elif defined(USEARCH_DEFINED_CLANG)
|
|
289
293
|
#pragma clang loop vectorize(enable)
|
|
290
|
-
#elif defined(
|
|
294
|
+
#elif defined(USEARCH_DEFINED_GCC)
|
|
291
295
|
#pragma GCC ivdep
|
|
292
296
|
#endif
|
|
293
297
|
for (std::size_t i = 0; i != dim; ++i)
|
|
@@ -313,11 +317,11 @@ template <typename scalar_at = std::uint64_t, typename result_at = std::size_t>
|
|
|
313
317
|
inline result_t operator()(scalar_t const* a, scalar_t const* b, std::size_t words) const noexcept {
|
|
314
318
|
constexpr std::size_t bits_per_word_k = sizeof(scalar_t) * CHAR_BIT;
|
|
315
319
|
result_t matches{};
|
|
316
|
-
#if
|
|
320
|
+
#if USEARCH_USE_OPENMP
|
|
317
321
|
#pragma omp simd reduction(+ : matches)
|
|
318
|
-
#elif defined(
|
|
322
|
+
#elif defined(USEARCH_DEFINED_CLANG)
|
|
319
323
|
#pragma clang loop vectorize(enable)
|
|
320
|
-
#elif defined(
|
|
324
|
+
#elif defined(USEARCH_DEFINED_GCC)
|
|
321
325
|
#pragma GCC ivdep
|
|
322
326
|
#endif
|
|
323
327
|
for (std::size_t i = 0; i != words; ++i)
|
|
@@ -344,11 +348,11 @@ template <typename scalar_at = std::uint64_t, typename result_at = float> struct
|
|
|
344
348
|
constexpr std::size_t bits_per_word_k = sizeof(scalar_t) * CHAR_BIT;
|
|
345
349
|
result_t and_count{};
|
|
346
350
|
result_t or_count{};
|
|
347
|
-
#if
|
|
351
|
+
#if USEARCH_USE_OPENMP
|
|
348
352
|
#pragma omp simd reduction(+ : and_count, or_count)
|
|
349
|
-
#elif defined(
|
|
353
|
+
#elif defined(USEARCH_DEFINED_CLANG)
|
|
350
354
|
#pragma clang loop vectorize(enable)
|
|
351
|
-
#elif defined(
|
|
355
|
+
#elif defined(USEARCH_DEFINED_GCC)
|
|
352
356
|
#pragma GCC ivdep
|
|
353
357
|
#endif
|
|
354
358
|
for (std::size_t i = 0; i != words; ++i)
|
|
@@ -376,11 +380,11 @@ template <typename scalar_at = std::uint64_t, typename result_at = float> struct
|
|
|
376
380
|
constexpr std::size_t bits_per_word_k = sizeof(scalar_t) * CHAR_BIT;
|
|
377
381
|
result_t and_count{};
|
|
378
382
|
result_t any_count{};
|
|
379
|
-
#if
|
|
383
|
+
#if USEARCH_USE_OPENMP
|
|
380
384
|
#pragma omp simd reduction(+ : and_count, any_count)
|
|
381
|
-
#elif defined(
|
|
385
|
+
#elif defined(USEARCH_DEFINED_CLANG)
|
|
382
386
|
#pragma clang loop vectorize(enable)
|
|
383
|
-
#elif defined(
|
|
387
|
+
#elif defined(USEARCH_DEFINED_GCC)
|
|
384
388
|
#pragma GCC ivdep
|
|
385
389
|
#endif
|
|
386
390
|
for (std::size_t i = 0; i != words; ++i)
|
|
@@ -437,11 +441,11 @@ template <typename scalar_at = float, typename result_at = float> struct pearson
|
|
|
437
441
|
inline result_t operator()(scalar_t const* a, scalar_t const* b, std::size_t dim) const noexcept {
|
|
438
442
|
result_t a_sum{}, b_sum{}, ab_sum{};
|
|
439
443
|
result_t a_sq_sum{}, b_sq_sum{};
|
|
440
|
-
#if
|
|
444
|
+
#if USEARCH_USE_OPENMP
|
|
441
445
|
#pragma omp simd reduction(+ : a_sum, b_sum, ab_sum, a_sq_sum, b_sq_sum)
|
|
442
|
-
#elif defined(
|
|
446
|
+
#elif defined(USEARCH_DEFINED_CLANG)
|
|
443
447
|
#pragma clang loop vectorize(enable)
|
|
444
|
-
#elif defined(
|
|
448
|
+
#elif defined(USEARCH_DEFINED_GCC)
|
|
445
449
|
#pragma GCC ivdep
|
|
446
450
|
#endif
|
|
447
451
|
for (std::size_t i = 0; i != dim; ++i) {
|
|
@@ -603,7 +607,7 @@ template <typename allocator_at = std::allocator<char>> class visits_bitset_gt {
|
|
|
603
607
|
inline bool test(std::size_t i) const noexcept { return slots_[i / bits_per_slot()] & (1ul << (i & bits_mask())); }
|
|
604
608
|
inline void set(std::size_t i) noexcept { slots_[i / bits_per_slot()] |= (1ul << (i & bits_mask())); }
|
|
605
609
|
|
|
606
|
-
#if defined(
|
|
610
|
+
#if defined(USEARCH_DEFINED_WINDOWS)
|
|
607
611
|
|
|
608
612
|
inline bool atomic_set(std::size_t i) noexcept {
|
|
609
613
|
slot_t mask{1ul << (i & bits_mask())};
|
|
@@ -890,7 +894,7 @@ class sorted_buffer_gt {
|
|
|
890
894
|
static bool less(element_t const& a, element_t const& b) noexcept { return comparator_t{}(a, b); }
|
|
891
895
|
};
|
|
892
896
|
|
|
893
|
-
#if defined(
|
|
897
|
+
#if defined(USEARCH_DEFINED_WINDOWS)
|
|
894
898
|
#pragma pack(push, 1) // Pack struct elements on 1-byte alignment
|
|
895
899
|
#endif
|
|
896
900
|
|
|
@@ -904,7 +908,7 @@ class usearch_pack_m uint40_t {
|
|
|
904
908
|
inline uint40_t() noexcept { std::memset(octets, 0, 5); }
|
|
905
909
|
inline uint40_t(std::uint32_t n) noexcept { std::memcpy(octets + 1, (char*)&n, 4), octets[0] = 0; }
|
|
906
910
|
inline uint40_t(std::uint64_t n) noexcept { std::memcpy(octets, (char*)&n + 3, 5); }
|
|
907
|
-
#if defined(
|
|
911
|
+
#if defined(USEARCH_DEFINED_CLANG) && defined(USEARCH_DEFINED_APPLE)
|
|
908
912
|
inline uint40_t(std::size_t n) noexcept { std::memcpy(octets, (char*)&n + 3, 5); }
|
|
909
913
|
#endif
|
|
910
914
|
|
|
@@ -935,7 +939,7 @@ class usearch_pack_m uint40_t {
|
|
|
935
939
|
}
|
|
936
940
|
};
|
|
937
941
|
|
|
938
|
-
#if defined(
|
|
942
|
+
#if defined(USEARCH_DEFINED_WINDOWS)
|
|
939
943
|
#pragma pack(pop) // Reset alignment to default
|
|
940
944
|
#endif
|
|
941
945
|
|
|
@@ -1093,7 +1097,7 @@ static_assert(sizeof(file_header_t) == 64, "File header should be exactly 64 byt
|
|
|
1093
1097
|
/// @brief C++17 and newer version deprecate the `std::result_of`
|
|
1094
1098
|
template <typename metric_at, typename... args_at>
|
|
1095
1099
|
using return_type_gt =
|
|
1096
|
-
#if defined(
|
|
1100
|
+
#if defined(USEARCH_DEFINED_CPP17)
|
|
1097
1101
|
typename std::invoke_result<metric_at, args_at...>::type;
|
|
1098
1102
|
#else
|
|
1099
1103
|
typename std::result_of<metric_at(args_at...)>::type;
|
|
@@ -2034,7 +2038,7 @@ class index_gt {
|
|
|
2034
2038
|
*/
|
|
2035
2039
|
serialization_result_t view(char const* file_path) noexcept {
|
|
2036
2040
|
serialization_result_t result;
|
|
2037
|
-
#if defined(
|
|
2041
|
+
#if defined(USEARCH_DEFINED_WINDOWS)
|
|
2038
2042
|
return result.failed("Memory-mapping is not yet available for Windows");
|
|
2039
2043
|
#else
|
|
2040
2044
|
int open_flags = O_RDONLY;
|
|
@@ -7,16 +7,11 @@
|
|
|
7
7
|
#include <thread> // `std::thread`
|
|
8
8
|
#include <vector> // `std::vector`
|
|
9
9
|
|
|
10
|
-
#include <fp16/fp16.h>
|
|
11
|
-
#include <tsl/robin_map.h>
|
|
12
|
-
|
|
13
|
-
#if defined(USEARCH_USE_SIMSIMD)
|
|
14
|
-
#include <simsimd/simsimd.h>
|
|
15
|
-
#endif
|
|
16
|
-
|
|
17
10
|
#include <usearch/index.hpp>
|
|
18
11
|
#include <usearch/index_punned_helpers.hpp>
|
|
19
12
|
|
|
13
|
+
#include <tsl/robin_map.h>
|
|
14
|
+
|
|
20
15
|
namespace unum {
|
|
21
16
|
namespace usearch {
|
|
22
17
|
|
|
@@ -27,6 +22,13 @@ struct cos_f8_t {
|
|
|
27
22
|
inline cos_f8_t(std::size_t dims) noexcept : dimensions(dims) {}
|
|
28
23
|
inline punned_distance_t operator()(f8_bits_t const* a, f8_bits_t const* b) const noexcept {
|
|
29
24
|
std::int32_t ab{}, a2{}, b2{};
|
|
25
|
+
#if USEARCH_USE_OPENMP
|
|
26
|
+
#pragma omp simd reduction(+ : ab, a2, b2)
|
|
27
|
+
#elif defined(USEARCH_DEFINED_CLANG)
|
|
28
|
+
#pragma clang loop vectorize(enable)
|
|
29
|
+
#elif defined(USEARCH_DEFINED_GCC)
|
|
30
|
+
#pragma GCC ivdep
|
|
31
|
+
#endif
|
|
30
32
|
for (std::size_t i = 0; i != dimensions; i++) {
|
|
31
33
|
std::int16_t ai{a[i]};
|
|
32
34
|
std::int16_t bi{b[i]};
|
|
@@ -45,6 +47,13 @@ struct l2sq_f8_t {
|
|
|
45
47
|
inline l2sq_f8_t(std::size_t dims) noexcept : dimensions(dims) {}
|
|
46
48
|
inline punned_distance_t operator()(f8_bits_t const* a, f8_bits_t const* b) const noexcept {
|
|
47
49
|
std::int32_t ab_deltas_sq{};
|
|
50
|
+
#if USEARCH_USE_OPENMP
|
|
51
|
+
#pragma omp simd reduction(+ : ab_deltas_sq)
|
|
52
|
+
#elif defined(USEARCH_DEFINED_CLANG)
|
|
53
|
+
#pragma clang loop vectorize(enable)
|
|
54
|
+
#elif defined(USEARCH_DEFINED_GCC)
|
|
55
|
+
#pragma GCC ivdep
|
|
56
|
+
#endif
|
|
48
57
|
for (std::size_t i = 0; i != dimensions; i++)
|
|
49
58
|
ab_deltas_sq += square(std::int16_t(a[i]) - std::int16_t(b[i]));
|
|
50
59
|
return ab_deltas_sq;
|
|
@@ -495,8 +504,8 @@ class index_punned_dense_gt {
|
|
|
495
504
|
|
|
496
505
|
static metric_and_meta_t ip_metric_f32_(std::size_t dimensions) {
|
|
497
506
|
(void)dimensions;
|
|
498
|
-
#if
|
|
499
|
-
#if defined(
|
|
507
|
+
#if USEARCH_USE_SIMSIMD
|
|
508
|
+
#if defined(USEARCH_DEFINED_X86)
|
|
500
509
|
if (dimensions % 4 == 0)
|
|
501
510
|
return {
|
|
502
511
|
pun_metric_<simsimd_f32_t>([=](simsimd_f32_t const* a, simsimd_f32_t const* b) {
|
|
@@ -504,7 +513,7 @@ class index_punned_dense_gt {
|
|
|
504
513
|
}),
|
|
505
514
|
isa_t::avx2_k,
|
|
506
515
|
};
|
|
507
|
-
#elif defined(
|
|
516
|
+
#elif defined(USEARCH_DEFINED_ARM)
|
|
508
517
|
if (supports_arm_sve())
|
|
509
518
|
return {
|
|
510
519
|
pun_metric_<simsimd_f32_t>([=](simsimd_f32_t const* a, simsimd_f32_t const* b) {
|
|
@@ -526,8 +535,8 @@ class index_punned_dense_gt {
|
|
|
526
535
|
|
|
527
536
|
static metric_and_meta_t cos_metric_f16_(std::size_t dimensions) {
|
|
528
537
|
(void)dimensions;
|
|
529
|
-
#if
|
|
530
|
-
#if defined(
|
|
538
|
+
#if USEARCH_USE_SIMSIMD
|
|
539
|
+
#if defined(USEARCH_DEFINED_X86)
|
|
531
540
|
if (dimensions % 16 == 0)
|
|
532
541
|
return {
|
|
533
542
|
pun_metric_<simsimd_f16_t>([=](simsimd_f16_t const* a, simsimd_f16_t const* b) {
|
|
@@ -535,7 +544,7 @@ class index_punned_dense_gt {
|
|
|
535
544
|
}),
|
|
536
545
|
isa_t::avx512_k,
|
|
537
546
|
};
|
|
538
|
-
#elif defined(
|
|
547
|
+
#elif defined(USEARCH_DEFINED_ARM)
|
|
539
548
|
if (dimensions % 4 == 0)
|
|
540
549
|
return {
|
|
541
550
|
pun_metric_<simsimd_f16_t>([=](simsimd_f16_t const* a, simsimd_f16_t const* b) {
|
|
@@ -550,8 +559,8 @@ class index_punned_dense_gt {
|
|
|
550
559
|
|
|
551
560
|
static metric_and_meta_t cos_metric_f8_(std::size_t dimensions) {
|
|
552
561
|
(void)dimensions;
|
|
553
|
-
#if
|
|
554
|
-
#if defined(
|
|
562
|
+
#if USEARCH_USE_SIMSIMD
|
|
563
|
+
#if defined(USEARCH_DEFINED_ARM)
|
|
555
564
|
if (dimensions % 16 == 0)
|
|
556
565
|
return {
|
|
557
566
|
pun_metric_<int8_t>(
|
|
@@ -6,21 +6,41 @@
|
|
|
6
6
|
#include <thread> // `std::thread`
|
|
7
7
|
#include <vector> // `std::vector`
|
|
8
8
|
|
|
9
|
-
#include <
|
|
9
|
+
#include <usearch/index.hpp> // `expected_gt` and macros
|
|
10
10
|
|
|
11
|
-
#if
|
|
11
|
+
#if USEARCH_USE_OPENMP
|
|
12
12
|
#include <omp.h> // `omp_get_num_threads()`
|
|
13
13
|
#endif
|
|
14
14
|
|
|
15
|
-
#if defined(
|
|
15
|
+
#if defined(USEARCH_DEFINED_LINUX)
|
|
16
16
|
#include <sys/auxv.h> // `getauxval()`
|
|
17
17
|
#endif
|
|
18
18
|
|
|
19
|
-
#if defined(
|
|
19
|
+
#if defined(USEARCH_DEFINED_ARM)
|
|
20
20
|
#include <arm_fp16.h> // `__fp16`
|
|
21
21
|
#endif
|
|
22
22
|
|
|
23
|
-
#
|
|
23
|
+
#if !defined(USEARCH_USE_NATIVE_F16)
|
|
24
|
+
#if defined(__AVX512F__)
|
|
25
|
+
#define USEARCH_USE_NATIVE_F16 1
|
|
26
|
+
#elif defined(USEARCH_DEFINED_ARM)
|
|
27
|
+
#define USEARCH_USE_NATIVE_F16 1
|
|
28
|
+
#else
|
|
29
|
+
#define USEARCH_USE_NATIVE_F16 0
|
|
30
|
+
#include <fp16/fp16.h>
|
|
31
|
+
#endif
|
|
32
|
+
#else
|
|
33
|
+
#define USEARCH_USE_NATIVE_F16 0
|
|
34
|
+
#include <fp16/fp16.h>
|
|
35
|
+
#endif
|
|
36
|
+
|
|
37
|
+
#if !defined(USEARCH_USE_SIMSIMD)
|
|
38
|
+
#define USEARCH_USE_SIMSIMD 0
|
|
39
|
+
#endif
|
|
40
|
+
|
|
41
|
+
#if USEARCH_USE_SIMSIMD
|
|
42
|
+
#include <simsimd/simsimd.h>
|
|
43
|
+
#endif
|
|
24
44
|
|
|
25
45
|
namespace unum {
|
|
26
46
|
namespace usearch {
|
|
@@ -57,8 +77,8 @@ inline char const* isa_name(isa_t isa) noexcept {
|
|
|
57
77
|
}
|
|
58
78
|
|
|
59
79
|
inline bool supports_arm_sve() noexcept {
|
|
60
|
-
#if defined(
|
|
61
|
-
#if defined(
|
|
80
|
+
#if defined(USEARCH_DEFINED_ARM)
|
|
81
|
+
#if defined(USEARCH_DEFINED_LINUX)
|
|
62
82
|
unsigned long capabilities = getauxval(AT_HWCAP);
|
|
63
83
|
if (capabilities & HWCAP_SVE)
|
|
64
84
|
return true;
|
|
@@ -161,26 +181,16 @@ using punned_metric_t = std::function<punned_distance_t(punned_vector_view_t, pu
|
|
|
161
181
|
class f8_bits_t;
|
|
162
182
|
class f16_bits_t;
|
|
163
183
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
#if defined(__AVX512F__)
|
|
167
|
-
#define USEARCH_F16_NATIVE_SUPPORT 1
|
|
184
|
+
#if USEARCH_USE_NATIVE_F16
|
|
168
185
|
using f16_native_t = _Float16;
|
|
169
|
-
#elif defined(USEARCH_IS_ARM)
|
|
170
|
-
#define USEARCH_F16_NATIVE_SUPPORT 1
|
|
171
|
-
using f16_native_t = __fp16;
|
|
172
|
-
#else
|
|
173
|
-
using f16_native_t = void;
|
|
174
|
-
#endif
|
|
175
|
-
|
|
176
|
-
#if defined(USEARCH_F16_NATIVE_SUPPORT)
|
|
177
186
|
using f16_t = f16_native_t;
|
|
178
187
|
#else
|
|
188
|
+
using f16_native_t = void;
|
|
179
189
|
using f16_t = f16_bits_t;
|
|
180
190
|
#endif
|
|
181
191
|
|
|
182
192
|
inline float f16_to_f32(std::uint16_t u16) noexcept {
|
|
183
|
-
#if
|
|
193
|
+
#if USEARCH_USE_NATIVE_F16
|
|
184
194
|
f16_native_t f16;
|
|
185
195
|
std::memcpy(&f16, &u16, sizeof(std::uint16_t));
|
|
186
196
|
return float(f16);
|
|
@@ -190,7 +200,7 @@ inline float f16_to_f32(std::uint16_t u16) noexcept {
|
|
|
190
200
|
}
|
|
191
201
|
|
|
192
202
|
inline std::uint16_t f32_to_f16(float f32) noexcept {
|
|
193
|
-
#if
|
|
203
|
+
#if USEARCH_USE_NATIVE_F16
|
|
194
204
|
f16_native_t f16 = f16_native_t(f32);
|
|
195
205
|
std::uint16_t u16;
|
|
196
206
|
std::memcpy(&u16, &f16, sizeof(std::uint16_t));
|
|
@@ -316,7 +326,7 @@ class executor_stl_t {
|
|
|
316
326
|
}
|
|
317
327
|
};
|
|
318
328
|
|
|
319
|
-
#if
|
|
329
|
+
#if USEARCH_USE_OPENMP
|
|
320
330
|
|
|
321
331
|
class executor_openmp_t {
|
|
322
332
|
public:
|
|
@@ -362,7 +372,7 @@ class aligned_allocator_gt {
|
|
|
362
372
|
// void* result = nullptr;
|
|
363
373
|
// int status = posix_memalign(&result, alignment, length_bytes);
|
|
364
374
|
// return status == 0 ? (pointer)result : nullptr;
|
|
365
|
-
#if defined(
|
|
375
|
+
#if defined(USEARCH_DEFINED_WINDOWS)
|
|
366
376
|
return (pointer)_aligned_malloc(length_bytes, alignment);
|
|
367
377
|
#else
|
|
368
378
|
return (pointer)aligned_alloc(alignment, length_bytes);
|
|
@@ -370,7 +380,7 @@ class aligned_allocator_gt {
|
|
|
370
380
|
}
|
|
371
381
|
|
|
372
382
|
void deallocate(pointer begin, size_type) const {
|
|
373
|
-
#if defined(
|
|
383
|
+
#if defined(USEARCH_DEFINED_WINDOWS)
|
|
374
384
|
_aligned_free(begin);
|
|
375
385
|
#else
|
|
376
386
|
free(begin);
|
|
@@ -380,7 +390,7 @@ class aligned_allocator_gt {
|
|
|
380
390
|
|
|
381
391
|
using aligned_allocator_t = aligned_allocator_gt<>;
|
|
382
392
|
|
|
383
|
-
#if !defined(
|
|
393
|
+
#if !defined(USEARCH_DEFINED_WINDOWS)
|
|
384
394
|
|
|
385
395
|
/**
|
|
386
396
|
* @brief Memory-mapping allocator designed for "alloc many, free at once" usage patterns.
|
package/package.json
CHANGED
package/python/lib.cpp
CHANGED
|
@@ -533,17 +533,9 @@ PYBIND11_MODULE(compiled, m) {
|
|
|
533
533
|
m.attr("DEFAULT_EXPANSION_ADD") = py::int_(default_expansion_add());
|
|
534
534
|
m.attr("DEFAULT_EXPANSION_SEARCH") = py::int_(default_expansion_search());
|
|
535
535
|
|
|
536
|
-
|
|
537
|
-
m.attr("
|
|
538
|
-
|
|
539
|
-
m.attr("USES_OPENMP") = py::int_(0);
|
|
540
|
-
#endif
|
|
541
|
-
|
|
542
|
-
#if defined(USEARCH_USE_SIMSIMD)
|
|
543
|
-
m.attr("USES_SIMSIMD") = py::int_(1);
|
|
544
|
-
#else
|
|
545
|
-
m.attr("USES_SIMSIMD") = py::int_(0);
|
|
546
|
-
#endif
|
|
536
|
+
m.attr("USES_OPENMP") = py::int_(USEARCH_USE_OPENMP);
|
|
537
|
+
m.attr("USES_SIMSIMD") = py::int_(USEARCH_USE_SIMSIMD);
|
|
538
|
+
m.attr("USES_NATIVE_F16") = py::int_(USEARCH_USE_NATIVE_F16);
|
|
547
539
|
|
|
548
540
|
py::enum_<metric_kind_t>(m, "MetricKind")
|
|
549
541
|
.value("Unknown", metric_kind_t::unknown_k)
|
package/python/usearch/index.py
CHANGED
|
@@ -19,6 +19,7 @@ from usearch.compiled import (
|
|
|
19
19
|
|
|
20
20
|
USES_OPENMP,
|
|
21
21
|
USES_SIMSIMD,
|
|
22
|
+
USES_NATIVE_F16,
|
|
22
23
|
)
|
|
23
24
|
|
|
24
25
|
MetricKindBitwise = (
|
|
@@ -337,6 +338,7 @@ class Index:
|
|
|
337
338
|
'Expansion@Search': self.expansion_search,
|
|
338
339
|
'OpenMP': USES_OPENMP,
|
|
339
340
|
'SimSIMD': USES_SIMSIMD,
|
|
341
|
+
'NativeF16': USES_NATIVE_F16,
|
|
340
342
|
'JIT': self.jit,
|
|
341
343
|
'DType': self.dtype,
|
|
342
344
|
'Path': self.path,
|
package/setup.py
CHANGED
|
@@ -7,13 +7,16 @@ from pybind11.setup_helpers import Pybind11Extension
|
|
|
7
7
|
|
|
8
8
|
compile_args = ['-std=c++11', '-O3']
|
|
9
9
|
link_args = []
|
|
10
|
-
macros_args = [
|
|
10
|
+
macros_args = [
|
|
11
|
+
('USEARCH_USE_NATIVE_F16', '0'),
|
|
12
|
+
('USEARCH_USE_SIMSIMD', '1'),
|
|
13
|
+
]
|
|
11
14
|
|
|
12
15
|
if sys.platform == 'linux':
|
|
13
16
|
compile_args.append('-fopenmp')
|
|
14
17
|
link_args.append('-lgomp')
|
|
15
|
-
macros_args.append(('USEARCH_USE_OPENMP', '1'))
|
|
16
18
|
compile_args.append('-Wno-unknown-pragmas')
|
|
19
|
+
macros_args.append(('USEARCH_USE_OPENMP', '1'))
|
|
17
20
|
|
|
18
21
|
if sys.platform == 'darwin':
|
|
19
22
|
# MacOS 10.15 or higher is needed for `aligned_alloc` support.
|