usearch 0.18.6 → 0.19.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/README.md +184 -11
- package/conanfile.py +1 -1
- package/cpp/bench.cpp +2 -2
- package/cpp/test.cpp +11 -9
- package/docs/compilation.md +4 -2
- package/include/usearch/index.hpp +269 -50
- package/include/usearch/index_punned_dense.hpp +123 -108
- package/include/usearch/index_punned_helpers.hpp +5 -13
- package/package.json +1 -1
- package/python/lib.cpp +116 -40
- package/python/scripts/bench.ipynb +4 -4
- package/python/scripts/bench.py +51 -28
- package/python/scripts/index_faiss.py +19 -19
- package/python/scripts/test.py +275 -56
- package/python/usearch/eval.py +100 -49
- package/python/usearch/index.py +118 -88
- package/python/usearch/io.py +23 -23
- package/python/usearch/join.py +2 -4
- package/python/usearch/numba.py +44 -30
- package/python/usearch/server.py +38 -26
- package/simsimd/.vscode/settings.json +2 -1
- package/simsimd/CMakeLists.txt +1 -1
- package/simsimd/README.md +14 -2
- package/simsimd/bench.cxx +44 -27
- package/simsimd/include/simsimd/simsimd.h +22 -7
- package/simsimd/include/simsimd/simsimd.hpp +0 -443
|
@@ -20,6 +20,7 @@ struct cos_f8_t {
|
|
|
20
20
|
std::size_t dimensions;
|
|
21
21
|
|
|
22
22
|
inline cos_f8_t(std::size_t dims) noexcept : dimensions(dims) {}
|
|
23
|
+
inline metric_kind_t kind() const noexcept { return metric_kind_t::cos_k; }
|
|
23
24
|
inline punned_distance_t operator()(f8_bits_t const* a, f8_bits_t const* b) const noexcept {
|
|
24
25
|
std::int32_t ab{}, a2{}, b2{};
|
|
25
26
|
#if USEARCH_USE_OPENMP
|
|
@@ -45,6 +46,8 @@ struct l2sq_f8_t {
|
|
|
45
46
|
std::size_t dimensions;
|
|
46
47
|
|
|
47
48
|
inline l2sq_f8_t(std::size_t dims) noexcept : dimensions(dims) {}
|
|
49
|
+
inline metric_kind_t kind() const noexcept { return metric_kind_t::l2sq_k; }
|
|
50
|
+
inline scalar_kind_t scalar_kind() const noexcept { return scalar_kind_t::f8_k; }
|
|
48
51
|
inline punned_distance_t operator()(f8_bits_t const* a, f8_bits_t const* b) const noexcept {
|
|
49
52
|
std::int32_t ab_deltas_sq{};
|
|
50
53
|
#if USEARCH_USE_OPENMP
|
|
@@ -60,6 +63,48 @@ struct l2sq_f8_t {
|
|
|
60
63
|
}
|
|
61
64
|
};
|
|
62
65
|
|
|
66
|
+
struct index_punned_dense_metric_t {
|
|
67
|
+
using scalar_t = byte_t;
|
|
68
|
+
using result_t = punned_distance_t;
|
|
69
|
+
using view_t = punned_vector_view_t;
|
|
70
|
+
using stl_func_t = std::function<punned_distance_t(punned_vector_view_t, punned_vector_view_t)>;
|
|
71
|
+
|
|
72
|
+
stl_func_t func_;
|
|
73
|
+
metric_kind_t kind_ = metric_kind_t::unknown_k;
|
|
74
|
+
scalar_kind_t scalar_kind_ = scalar_kind_t::unknown_k;
|
|
75
|
+
isa_t isa_ = isa_t::auto_k;
|
|
76
|
+
|
|
77
|
+
index_punned_dense_metric_t() = default;
|
|
78
|
+
|
|
79
|
+
template <typename typed_at, typename scalar_at = typename typed_at::scalar_t>
|
|
80
|
+
index_punned_dense_metric_t(typed_at typed)
|
|
81
|
+
: index_punned_dense_metric_t(typed.kind(), isa_t::auto_k, scalar_at{}, typed) {}
|
|
82
|
+
|
|
83
|
+
template <typename typed_at, typename scalar_at>
|
|
84
|
+
index_punned_dense_metric_t(metric_kind_t kind, isa_t isa, scalar_at, typed_at metric) {
|
|
85
|
+
using scalar_t = scalar_at;
|
|
86
|
+
using typed_view_t = span_gt<scalar_t const>;
|
|
87
|
+
func_ = [=](view_t a, view_t b) -> result_t {
|
|
88
|
+
std::size_t dims = a.size() / sizeof(scalar_t);
|
|
89
|
+
typed_view_t a_typed{(scalar_t const*)a.data(), dims};
|
|
90
|
+
typed_view_t b_typed{(scalar_t const*)b.data(), dims};
|
|
91
|
+
return metric(a_typed, b_typed);
|
|
92
|
+
};
|
|
93
|
+
if (std::is_same<scalar_at, f8_bits_t>())
|
|
94
|
+
scalar_kind_ = scalar_kind_t::f8_k;
|
|
95
|
+
else if (std::is_same<scalar_at, f16_bits_t>())
|
|
96
|
+
scalar_kind_ = scalar_kind_t::f16_k;
|
|
97
|
+
else
|
|
98
|
+
scalar_kind_ = common_scalar_kind<scalar_at>();
|
|
99
|
+
kind_ = kind;
|
|
100
|
+
isa_ = isa;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
inline metric_kind_t kind() const noexcept { return kind_; }
|
|
104
|
+
inline scalar_kind_t scalar_kind() const noexcept { return scalar_kind_; }
|
|
105
|
+
inline result_t operator()(view_t a, view_t b) const { return func_(a, b); }
|
|
106
|
+
};
|
|
107
|
+
|
|
63
108
|
/**
|
|
64
109
|
* @brief Oversimplified type-punned index for equidimensional vectors
|
|
65
110
|
* with automatic down-casting and hardware isa.
|
|
@@ -71,25 +116,15 @@ class index_punned_dense_gt {
|
|
|
71
116
|
using id_t = id_at;
|
|
72
117
|
using distance_t = punned_distance_t;
|
|
73
118
|
/// @brief Punned metric object.
|
|
74
|
-
using metric_t =
|
|
119
|
+
using metric_t = index_punned_dense_metric_t;
|
|
75
120
|
|
|
76
121
|
private:
|
|
77
122
|
/// @brief Schema: input buffer, bytes in input buffer, output buffer.
|
|
78
123
|
using cast_t = std::function<bool(byte_t const*, std::size_t, byte_t*)>;
|
|
79
124
|
/// @brief Punned index.
|
|
80
|
-
using index_t = index_gt<metric_t, label_t, id_t,
|
|
125
|
+
using index_t = index_gt<metric_t, label_t, id_t, aligned_allocator_t, memory_mapping_allocator_t>;
|
|
81
126
|
using index_allocator_t = aligned_allocator_gt<index_t, 64>;
|
|
82
127
|
|
|
83
|
-
/// @brief A type-punned metric and metadata about present isa support.
|
|
84
|
-
struct metric_and_meta_t {
|
|
85
|
-
metric_t metric;
|
|
86
|
-
isa_t isa;
|
|
87
|
-
|
|
88
|
-
metric_and_meta_t(metric_t m = {}, isa_t i = isa_t::auto_k) : metric(m), isa(i) {}
|
|
89
|
-
metric_and_meta_t(metric_and_meta_t const&) = default;
|
|
90
|
-
metric_and_meta_t& operator=(metric_and_meta_t const&) = default;
|
|
91
|
-
};
|
|
92
|
-
|
|
93
128
|
using member_iterator_t = typename index_t::member_iterator_t;
|
|
94
129
|
using member_citerator_t = typename index_t::member_citerator_t;
|
|
95
130
|
using member_ref_t = typename index_t::member_ref_t;
|
|
@@ -104,9 +139,6 @@ class index_punned_dense_gt {
|
|
|
104
139
|
index_t* typed_ = nullptr;
|
|
105
140
|
|
|
106
141
|
std::size_t casted_vector_bytes_ = 0;
|
|
107
|
-
scalar_kind_t scalar_kind_ = scalar_kind_t::f32_k;
|
|
108
|
-
isa_t isa_ = isa_t::auto_k;
|
|
109
|
-
|
|
110
142
|
mutable std::vector<byte_t> cast_buffer_;
|
|
111
143
|
struct casts_t {
|
|
112
144
|
cast_t from_b1x8;
|
|
@@ -153,8 +185,6 @@ class index_punned_dense_gt {
|
|
|
153
185
|
std::swap(dimensions_, other.dimensions_);
|
|
154
186
|
std::swap(scalar_words_, other.scalar_words_);
|
|
155
187
|
std::swap(casted_vector_bytes_, other.casted_vector_bytes_);
|
|
156
|
-
std::swap(scalar_kind_, other.scalar_kind_);
|
|
157
|
-
std::swap(isa_, other.isa_);
|
|
158
188
|
std::swap(typed_, other.typed_);
|
|
159
189
|
std::swap(cast_buffer_, other.cast_buffer_);
|
|
160
190
|
std::swap(casts_, other.casts_);
|
|
@@ -173,6 +203,7 @@ class index_punned_dense_gt {
|
|
|
173
203
|
index_limits_t const& limits() const { return typed_->limits(); }
|
|
174
204
|
void clear() { return typed_->clear(); }
|
|
175
205
|
|
|
206
|
+
metric_t const& metric() const { return root_metric_; }
|
|
176
207
|
std::size_t expansion_add() const { return expansion_add_; }
|
|
177
208
|
std::size_t expansion_search() const { return expansion_search_; }
|
|
178
209
|
void change_expansion_add(std::size_t n) { expansion_add_ = n; }
|
|
@@ -188,13 +219,22 @@ class index_punned_dense_gt {
|
|
|
188
219
|
stats_t stats() const { return typed_->stats(); }
|
|
189
220
|
stats_t stats(std::size_t level) const { return typed_->stats(level); }
|
|
190
221
|
|
|
191
|
-
scalar_kind_t scalar_kind() const { return scalar_kind_; }
|
|
192
|
-
isa_t isa() const { return isa_; }
|
|
193
|
-
|
|
194
|
-
serialization_result_t save(char const* path) const { return typed_->save(path); }
|
|
195
|
-
serialization_result_t load(char const* path) { return typed_->load(path); }
|
|
196
|
-
serialization_result_t view(char const* path) { return typed_->view(path); }
|
|
197
222
|
bool reserve(index_limits_t limits) { return typed_->reserve(limits); }
|
|
223
|
+
serialization_result_t save(char const* path) const { return typed_->save(path); }
|
|
224
|
+
|
|
225
|
+
serialization_result_t load(char const* path) {
|
|
226
|
+
serialization_result_t result = typed_->load(path);
|
|
227
|
+
if (result)
|
|
228
|
+
reindex_labels();
|
|
229
|
+
return result;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
serialization_result_t view(char const* path) {
|
|
233
|
+
serialization_result_t result = typed_->view(path);
|
|
234
|
+
if (result)
|
|
235
|
+
reindex_labels();
|
|
236
|
+
return result;
|
|
237
|
+
}
|
|
198
238
|
|
|
199
239
|
std::size_t memory_usage(std::size_t allocator_entry_bytes = default_allocator_entry_bytes()) const {
|
|
200
240
|
return typed_->memory_usage(allocator_entry_bytes);
|
|
@@ -278,7 +318,7 @@ class index_punned_dense_gt {
|
|
|
278
318
|
return make_( //
|
|
279
319
|
dimensions, accuracy, //
|
|
280
320
|
config, expansion_add, expansion_search, //
|
|
281
|
-
|
|
321
|
+
metric_t(metric), make_casts_(accuracy));
|
|
282
322
|
}
|
|
283
323
|
|
|
284
324
|
index_punned_dense_gt fork() const {
|
|
@@ -286,8 +326,6 @@ class index_punned_dense_gt {
|
|
|
286
326
|
|
|
287
327
|
result.dimensions_ = dimensions_;
|
|
288
328
|
result.scalar_words_ = scalar_words_;
|
|
289
|
-
result.scalar_kind_ = scalar_kind_;
|
|
290
|
-
result.isa_ = isa_;
|
|
291
329
|
result.casted_vector_bytes_ = casted_vector_bytes_;
|
|
292
330
|
result.cast_buffer_ = cast_buffer_;
|
|
293
331
|
result.casts_ = casts_;
|
|
@@ -372,6 +410,16 @@ class index_punned_dense_gt {
|
|
|
372
410
|
return typed_->search_around(static_cast<id_t>(hint), {vector_data, vector_bytes}, wanted, config);
|
|
373
411
|
}
|
|
374
412
|
|
|
413
|
+
void reindex_labels() {
|
|
414
|
+
shared_lock_t lock(lookup_table_mutex_);
|
|
415
|
+
lookup_table_.clear();
|
|
416
|
+
for (std::size_t i = 0; i != typed_->size(); ++i) {
|
|
417
|
+
member_citerator_t iterator = typed_->cbegin() + i;
|
|
418
|
+
member_cref_t member = *iterator;
|
|
419
|
+
lookup_table_[member.label] = static_cast<id_t>(i);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
375
423
|
id_t lookup_id_(label_t label) const {
|
|
376
424
|
shared_lock_t lock(lookup_table_mutex_);
|
|
377
425
|
return lookup_table_.at(label);
|
|
@@ -425,20 +473,18 @@ class index_punned_dense_gt {
|
|
|
425
473
|
static index_punned_dense_gt make_( //
|
|
426
474
|
std::size_t dimensions, scalar_kind_t scalar_kind, //
|
|
427
475
|
index_config_t config, std::size_t expansion_add, std::size_t expansion_search, //
|
|
428
|
-
|
|
476
|
+
metric_t metric, casts_t casts) {
|
|
429
477
|
|
|
430
478
|
std::size_t hardware_threads = std::thread::hardware_concurrency();
|
|
431
479
|
index_punned_dense_gt result;
|
|
432
480
|
result.dimensions_ = dimensions;
|
|
433
|
-
result.scalar_kind_ = scalar_kind;
|
|
434
481
|
result.scalar_words_ = count_scalar_words_(dimensions, scalar_kind);
|
|
435
482
|
result.expansion_add_ = expansion_add;
|
|
436
483
|
result.expansion_search_ = expansion_search;
|
|
437
484
|
result.casted_vector_bytes_ = bytes_per_scalar(scalar_kind) * result.scalar_words_;
|
|
438
485
|
result.cast_buffer_.resize(hardware_threads * result.casted_vector_bytes_);
|
|
439
486
|
result.casts_ = casts;
|
|
440
|
-
result.
|
|
441
|
-
result.root_metric_ = metric_and_meta.metric;
|
|
487
|
+
result.root_metric_ = metric;
|
|
442
488
|
|
|
443
489
|
// Fill the thread IDs.
|
|
444
490
|
result.available_threads_.resize(hardware_threads);
|
|
@@ -446,7 +492,7 @@ class index_punned_dense_gt {
|
|
|
446
492
|
|
|
447
493
|
// Available since C11, but only C++17, so we use the C version.
|
|
448
494
|
index_t* raw = index_allocator_t{}.allocate(1);
|
|
449
|
-
new (raw) index_t(config,
|
|
495
|
+
new (raw) index_t(config, metric);
|
|
450
496
|
result.typed_ = raw;
|
|
451
497
|
return result;
|
|
452
498
|
}
|
|
@@ -491,80 +537,49 @@ class index_punned_dense_gt {
|
|
|
491
537
|
}
|
|
492
538
|
}
|
|
493
539
|
|
|
494
|
-
|
|
495
|
-
using scalar_t = scalar_at;
|
|
496
|
-
using vector_view_t = span_gt<scalar_t const>;
|
|
497
|
-
return [=](punned_vector_view_t a, punned_vector_view_t b) -> punned_distance_t {
|
|
498
|
-
std::size_t dims = a.size() / sizeof(scalar_t);
|
|
499
|
-
vector_view_t a_typed{(scalar_t const*)a.data(), dims};
|
|
500
|
-
vector_view_t b_typed{(scalar_t const*)b.data(), dims};
|
|
501
|
-
return metric(a_typed, b_typed);
|
|
502
|
-
};
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
static metric_and_meta_t ip_metric_f32_(std::size_t dimensions) {
|
|
540
|
+
static metric_t ip_metric_f32_(std::size_t dimensions) {
|
|
506
541
|
(void)dimensions;
|
|
507
542
|
#if USEARCH_USE_SIMSIMD
|
|
508
543
|
if (hardware_supports(isa_t::avx2_k) && dimensions % 4 == 0)
|
|
509
|
-
return {
|
|
510
|
-
|
|
511
|
-
return 1.f - simsimd_dot_f32x4avx2(a, b, dimensions);
|
|
512
|
-
}),
|
|
513
|
-
isa_t::avx2_k,
|
|
514
|
-
};
|
|
544
|
+
return {metric_kind_t::ip_k, isa_t::avx2_k, 0.f,
|
|
545
|
+
[=](f32_t const* a, f32_t const* b) { return 1.f - simsimd_dot_f32x4avx2(a, b, dimensions); }};
|
|
515
546
|
if (hardware_supports(isa_t::sve_k))
|
|
516
|
-
return {
|
|
517
|
-
|
|
518
|
-
return 1.f - simsimd_dot_f32sve(a, b, dimensions);
|
|
519
|
-
}),
|
|
520
|
-
isa_t::sve_k,
|
|
521
|
-
};
|
|
547
|
+
return {metric_kind_t::ip_k, isa_t::sve_k, 0.f,
|
|
548
|
+
[=](f32_t const* a, f32_t const* b) { return 1.f - simsimd_dot_f32sve(a, b, dimensions); }};
|
|
522
549
|
if (hardware_supports(isa_t::neon_k) && dimensions % 4 == 0)
|
|
523
|
-
return {
|
|
524
|
-
|
|
525
|
-
return 1.f - simsimd_dot_f32x4neon(a, b, dimensions);
|
|
526
|
-
}),
|
|
527
|
-
isa_t::neon_k,
|
|
528
|
-
};
|
|
550
|
+
return {metric_kind_t::ip_k, isa_t::neon_k, 0.f,
|
|
551
|
+
[=](f32_t const* a, f32_t const* b) { return 1.f - simsimd_dot_f32x4neon(a, b, dimensions); }};
|
|
529
552
|
#endif
|
|
530
|
-
return
|
|
553
|
+
return ip_gt<f32_t>{};
|
|
531
554
|
}
|
|
532
555
|
|
|
533
|
-
static
|
|
556
|
+
static metric_t cos_metric_f16_(std::size_t dimensions) {
|
|
534
557
|
(void)dimensions;
|
|
535
558
|
#if USEARCH_USE_SIMSIMD
|
|
536
559
|
if (hardware_supports(isa_t::avx512_k) && dimensions % 16 == 0)
|
|
537
|
-
return {
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
isa_t::avx512_k,
|
|
542
|
-
};
|
|
560
|
+
return {metric_kind_t::cos_k, isa_t::avx512_k, simsimd_f16_t(0),
|
|
561
|
+
[=](simsimd_f16_t const* a, simsimd_f16_t const* b) {
|
|
562
|
+
return 1.f - simsimd_cos_f16x16avx512(a, b, dimensions);
|
|
563
|
+
}};
|
|
543
564
|
if (hardware_supports(isa_t::neon_k) && dimensions % 4 == 0)
|
|
544
|
-
return {
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
isa_t::neon_k,
|
|
549
|
-
};
|
|
565
|
+
return {metric_kind_t::cos_k, isa_t::neon_k, simsimd_f16_t(0),
|
|
566
|
+
[=](simsimd_f16_t const* a, simsimd_f16_t const* b) {
|
|
567
|
+
return 1.f - simsimd_cos_f16x4neon(a, b, dimensions);
|
|
568
|
+
}};
|
|
550
569
|
#endif
|
|
551
|
-
return
|
|
570
|
+
return cos_gt<f16_t, f32_t>{};
|
|
552
571
|
}
|
|
553
572
|
|
|
554
|
-
static
|
|
555
|
-
(void)dimensions;
|
|
573
|
+
static metric_t cos_metric_f8_(std::size_t dimensions) {
|
|
556
574
|
#if USEARCH_USE_SIMSIMD
|
|
557
575
|
if (hardware_supports(isa_t::neon_k) && dimensions % 16 == 0)
|
|
558
|
-
return {
|
|
559
|
-
|
|
560
|
-
[=](int8_t const* a, int8_t const* b) { return 1.f - simsimd_cos_i8x16neon(a, b, dimensions); }),
|
|
561
|
-
isa_t::neon_k,
|
|
562
|
-
};
|
|
576
|
+
return {metric_kind_t::cos_k, isa_t::neon_k, int8_t(0),
|
|
577
|
+
[=](int8_t const* a, int8_t const* b) { return 1.f - simsimd_cos_i8x16neon(a, b, dimensions); }};
|
|
563
578
|
#endif
|
|
564
|
-
return
|
|
579
|
+
return cos_f8_t{dimensions};
|
|
565
580
|
}
|
|
566
581
|
|
|
567
|
-
static
|
|
582
|
+
static metric_t ip_metric_(std::size_t dimensions, scalar_kind_t accuracy) {
|
|
568
583
|
switch (accuracy) {
|
|
569
584
|
case scalar_kind_t::f32_k:
|
|
570
585
|
// The two most common numeric types for the most common metric have optimized versions
|
|
@@ -574,62 +589,62 @@ class index_punned_dense_gt {
|
|
|
574
589
|
return cos_metric_f16_(dimensions);
|
|
575
590
|
|
|
576
591
|
case scalar_kind_t::f8_k: return cos_metric_f8_(dimensions);
|
|
577
|
-
case scalar_kind_t::f64_k: return
|
|
592
|
+
case scalar_kind_t::f64_k: return ip_gt<f64_t>{};
|
|
578
593
|
default: return {};
|
|
579
594
|
}
|
|
580
595
|
}
|
|
581
596
|
|
|
582
|
-
static
|
|
597
|
+
static metric_t l2sq_metric_(std::size_t dimensions, scalar_kind_t accuracy) {
|
|
583
598
|
switch (accuracy) {
|
|
584
|
-
case scalar_kind_t::f8_k: return
|
|
585
|
-
case scalar_kind_t::f16_k: return
|
|
586
|
-
case scalar_kind_t::f32_k: return
|
|
587
|
-
case scalar_kind_t::f64_k: return
|
|
599
|
+
case scalar_kind_t::f8_k: return l2sq_f8_t{dimensions};
|
|
600
|
+
case scalar_kind_t::f16_k: return l2sq_gt<f16_t, f32_t>{};
|
|
601
|
+
case scalar_kind_t::f32_k: return l2sq_gt<f32_t>{};
|
|
602
|
+
case scalar_kind_t::f64_k: return l2sq_gt<f64_t>{};
|
|
588
603
|
default: return {};
|
|
589
604
|
}
|
|
590
605
|
}
|
|
591
606
|
|
|
592
|
-
static
|
|
607
|
+
static metric_t cos_metric_(std::size_t dimensions, scalar_kind_t accuracy) {
|
|
593
608
|
switch (accuracy) {
|
|
594
609
|
case scalar_kind_t::f8_k: return cos_metric_f8_(dimensions);
|
|
595
610
|
case scalar_kind_t::f16_k: return cos_metric_f16_(dimensions);
|
|
596
|
-
case scalar_kind_t::f32_k: return
|
|
597
|
-
case scalar_kind_t::f64_k: return
|
|
611
|
+
case scalar_kind_t::f32_k: return cos_gt<f32_t>{};
|
|
612
|
+
case scalar_kind_t::f64_k: return cos_gt<f64_t>{};
|
|
598
613
|
default: return {};
|
|
599
614
|
}
|
|
600
615
|
}
|
|
601
616
|
|
|
602
|
-
static
|
|
617
|
+
static metric_t haversine_metric_(scalar_kind_t accuracy) {
|
|
603
618
|
switch (accuracy) {
|
|
604
|
-
case scalar_kind_t::f8_k: return
|
|
605
|
-
case scalar_kind_t::f16_k: return
|
|
606
|
-
case scalar_kind_t::f32_k: return
|
|
607
|
-
case scalar_kind_t::f64_k: return
|
|
619
|
+
case scalar_kind_t::f8_k: return haversine_gt<f8_bits_t, f32_t>{};
|
|
620
|
+
case scalar_kind_t::f16_k: return haversine_gt<f16_t, f32_t>{};
|
|
621
|
+
case scalar_kind_t::f32_k: return haversine_gt<f32_t>{};
|
|
622
|
+
case scalar_kind_t::f64_k: return haversine_gt<f64_t>{};
|
|
608
623
|
default: return {};
|
|
609
624
|
}
|
|
610
625
|
}
|
|
611
626
|
|
|
612
|
-
static
|
|
627
|
+
static metric_t pearson_metric_(scalar_kind_t accuracy) {
|
|
613
628
|
switch (accuracy) {
|
|
614
|
-
case scalar_kind_t::f8_k: return
|
|
615
|
-
case scalar_kind_t::f16_k: return
|
|
616
|
-
case scalar_kind_t::f32_k: return
|
|
617
|
-
case scalar_kind_t::f64_k: return
|
|
629
|
+
case scalar_kind_t::f8_k: return pearson_correlation_gt<f8_bits_t, f32_t>{};
|
|
630
|
+
case scalar_kind_t::f16_k: return pearson_correlation_gt<f16_t, f32_t>{};
|
|
631
|
+
case scalar_kind_t::f32_k: return pearson_correlation_gt<f32_t>{};
|
|
632
|
+
case scalar_kind_t::f64_k: return pearson_correlation_gt<f64_t>{};
|
|
618
633
|
default: return {};
|
|
619
634
|
}
|
|
620
635
|
}
|
|
621
636
|
|
|
622
|
-
static
|
|
637
|
+
static metric_t make_metric_(metric_kind_t kind, std::size_t dimensions, scalar_kind_t accuracy) {
|
|
623
638
|
switch (kind) {
|
|
624
639
|
case metric_kind_t::ip_k: return ip_metric_(dimensions, accuracy);
|
|
625
640
|
case metric_kind_t::cos_k: return cos_metric_(dimensions, accuracy);
|
|
626
641
|
case metric_kind_t::l2sq_k: return l2sq_metric_(dimensions, accuracy);
|
|
627
642
|
case metric_kind_t::pearson_k: return pearson_metric_(accuracy);
|
|
628
643
|
case metric_kind_t::haversine_k: return haversine_metric_(accuracy);
|
|
629
|
-
case metric_kind_t::hamming_k: return
|
|
644
|
+
case metric_kind_t::hamming_k: return hamming_gt<uint8_t>{};
|
|
630
645
|
case metric_kind_t::jaccard_k: // Equivalent to Tanimoto
|
|
631
|
-
case metric_kind_t::tanimoto_k: return
|
|
632
|
-
case metric_kind_t::sorensen_k: return
|
|
646
|
+
case metric_kind_t::tanimoto_k: return tanimoto_gt<uint8_t>{};
|
|
647
|
+
case metric_kind_t::sorensen_k: return sorensen_gt<uint8_t>{};
|
|
633
648
|
default: return {};
|
|
634
649
|
}
|
|
635
650
|
}
|
|
@@ -80,7 +80,7 @@ inline bool hardware_supports(isa_t isa) noexcept {
|
|
|
80
80
|
#if defined(USEARCH_DEFINED_ARM) && defined(USEARCH_DEFINED_LINUX)
|
|
81
81
|
unsigned long capabilities = getauxval(AT_HWCAP);
|
|
82
82
|
switch (isa) {
|
|
83
|
-
case isa_t::neon_k: return
|
|
83
|
+
case isa_t::neon_k: return true; // Must be supported on 64-bit Arm
|
|
84
84
|
case isa_t::sve_k: return capabilities & HWCAP_SVE;
|
|
85
85
|
default: return false;
|
|
86
86
|
}
|
|
@@ -97,17 +97,6 @@ inline bool hardware_supports(isa_t isa) noexcept {
|
|
|
97
97
|
return false;
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
enum class b1x8_t : unsigned char {};
|
|
101
|
-
|
|
102
|
-
enum class scalar_kind_t {
|
|
103
|
-
unknown_k = 0,
|
|
104
|
-
f64_k,
|
|
105
|
-
f32_k,
|
|
106
|
-
f16_k,
|
|
107
|
-
f8_k,
|
|
108
|
-
b1x8_k,
|
|
109
|
-
};
|
|
110
|
-
|
|
111
100
|
inline std::size_t bytes_per_scalar(scalar_kind_t accuracy) noexcept {
|
|
112
101
|
switch (accuracy) {
|
|
113
102
|
case scalar_kind_t::f32_k: return 4;
|
|
@@ -186,13 +175,16 @@ inline expected_gt<metric_kind_t> metric_from_name(char const* name, std::size_t
|
|
|
186
175
|
|
|
187
176
|
using punned_distance_t = float;
|
|
188
177
|
using punned_vector_view_t = span_gt<byte_t const>;
|
|
189
|
-
using punned_metric_t = std::function<punned_distance_t(punned_vector_view_t, punned_vector_view_t)>;
|
|
190
178
|
|
|
191
179
|
class f8_bits_t;
|
|
192
180
|
class f16_bits_t;
|
|
193
181
|
|
|
194
182
|
#if USEARCH_USE_NATIVE_F16
|
|
183
|
+
#if defined(USEARCH_DEFINED_ARM)
|
|
184
|
+
using f16_native_t = __fp16;
|
|
185
|
+
#else
|
|
195
186
|
using f16_native_t = _Float16;
|
|
187
|
+
#endif
|
|
196
188
|
using f16_t = f16_native_t;
|
|
197
189
|
#else
|
|
198
190
|
using f16_native_t = void;
|