usearch 0.18.8 → 0.19.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/Cargo.toml +1 -1
- package/README.md +187 -40
- package/c/lib.cpp +71 -51
- package/c/test.c +182 -0
- package/c/usearch.h +11 -5
- package/conanfile.py +1 -1
- package/cpp/bench.cpp +6 -6
- package/cpp/test.cpp +11 -9
- package/docs/compilation.md +1 -0
- package/include/usearch/index.hpp +290 -54
- package/include/usearch/index_punned_dense.hpp +125 -108
- package/include/usearch/index_punned_helpers.hpp +2 -12
- package/objc/USearchObjective.mm +4 -0
- package/objc/include/USearchObjective.h +5 -0
- package/package.json +2 -2
- package/python/lib.cpp +234 -199
- package/python/scripts/bench.ipynb +13 -2113
- package/python/scripts/bench.py +45 -29
- package/python/scripts/index_faiss.py +19 -19
- package/python/scripts/test.py +320 -61
- package/python/usearch/eval.py +100 -49
- package/python/usearch/index.py +245 -129
- package/python/usearch/io.py +25 -25
- package/python/usearch/join.py +2 -4
- package/python/usearch/numba.py +22 -18
- package/python/usearch/server.py +38 -26
- package/setup.py +56 -59
- 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 +2 -1
- package/swift/Test.swift +13 -9
- 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);
|
|
@@ -248,6 +288,8 @@ class index_punned_dense_gt {
|
|
|
248
288
|
search_result_t search_around(label_t hint, f32_t const* vector, std::size_t wanted, search_config_t config) const { return search_around_(hint, vector, wanted, config, casts_.from_f32); }
|
|
249
289
|
search_result_t search_around(label_t hint, f64_t const* vector, std::size_t wanted, search_config_t config) const { return search_around_(hint, vector, wanted, config, casts_.from_f64); }
|
|
250
290
|
|
|
291
|
+
search_result_t empty_search_result() const { return search_result_t{*typed_}; }
|
|
292
|
+
|
|
251
293
|
bool get(label_t label, b1x8_t* vector) const { return get_(label, vector, casts_.to_b1x8); }
|
|
252
294
|
bool get(label_t label, f8_bits_t* vector) const { return get_(label, vector, casts_.to_f8); }
|
|
253
295
|
bool get(label_t label, f16_t* vector) const { return get_(label, vector, casts_.to_f16); }
|
|
@@ -278,7 +320,7 @@ class index_punned_dense_gt {
|
|
|
278
320
|
return make_( //
|
|
279
321
|
dimensions, accuracy, //
|
|
280
322
|
config, expansion_add, expansion_search, //
|
|
281
|
-
|
|
323
|
+
metric_t(metric), make_casts_(accuracy));
|
|
282
324
|
}
|
|
283
325
|
|
|
284
326
|
index_punned_dense_gt fork() const {
|
|
@@ -286,8 +328,6 @@ class index_punned_dense_gt {
|
|
|
286
328
|
|
|
287
329
|
result.dimensions_ = dimensions_;
|
|
288
330
|
result.scalar_words_ = scalar_words_;
|
|
289
|
-
result.scalar_kind_ = scalar_kind_;
|
|
290
|
-
result.isa_ = isa_;
|
|
291
331
|
result.casted_vector_bytes_ = casted_vector_bytes_;
|
|
292
332
|
result.cast_buffer_ = cast_buffer_;
|
|
293
333
|
result.casts_ = casts_;
|
|
@@ -372,6 +412,16 @@ class index_punned_dense_gt {
|
|
|
372
412
|
return typed_->search_around(static_cast<id_t>(hint), {vector_data, vector_bytes}, wanted, config);
|
|
373
413
|
}
|
|
374
414
|
|
|
415
|
+
void reindex_labels() {
|
|
416
|
+
shared_lock_t lock(lookup_table_mutex_);
|
|
417
|
+
lookup_table_.clear();
|
|
418
|
+
for (std::size_t i = 0; i != typed_->size(); ++i) {
|
|
419
|
+
member_citerator_t iterator = typed_->cbegin() + i;
|
|
420
|
+
member_cref_t member = *iterator;
|
|
421
|
+
lookup_table_[member.label] = static_cast<id_t>(i);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
375
425
|
id_t lookup_id_(label_t label) const {
|
|
376
426
|
shared_lock_t lock(lookup_table_mutex_);
|
|
377
427
|
return lookup_table_.at(label);
|
|
@@ -425,20 +475,18 @@ class index_punned_dense_gt {
|
|
|
425
475
|
static index_punned_dense_gt make_( //
|
|
426
476
|
std::size_t dimensions, scalar_kind_t scalar_kind, //
|
|
427
477
|
index_config_t config, std::size_t expansion_add, std::size_t expansion_search, //
|
|
428
|
-
|
|
478
|
+
metric_t metric, casts_t casts) {
|
|
429
479
|
|
|
430
480
|
std::size_t hardware_threads = std::thread::hardware_concurrency();
|
|
431
481
|
index_punned_dense_gt result;
|
|
432
482
|
result.dimensions_ = dimensions;
|
|
433
|
-
result.scalar_kind_ = scalar_kind;
|
|
434
483
|
result.scalar_words_ = count_scalar_words_(dimensions, scalar_kind);
|
|
435
484
|
result.expansion_add_ = expansion_add;
|
|
436
485
|
result.expansion_search_ = expansion_search;
|
|
437
486
|
result.casted_vector_bytes_ = bytes_per_scalar(scalar_kind) * result.scalar_words_;
|
|
438
487
|
result.cast_buffer_.resize(hardware_threads * result.casted_vector_bytes_);
|
|
439
488
|
result.casts_ = casts;
|
|
440
|
-
result.
|
|
441
|
-
result.root_metric_ = metric_and_meta.metric;
|
|
489
|
+
result.root_metric_ = metric;
|
|
442
490
|
|
|
443
491
|
// Fill the thread IDs.
|
|
444
492
|
result.available_threads_.resize(hardware_threads);
|
|
@@ -446,7 +494,7 @@ class index_punned_dense_gt {
|
|
|
446
494
|
|
|
447
495
|
// Available since C11, but only C++17, so we use the C version.
|
|
448
496
|
index_t* raw = index_allocator_t{}.allocate(1);
|
|
449
|
-
new (raw) index_t(config,
|
|
497
|
+
new (raw) index_t(config, metric);
|
|
450
498
|
result.typed_ = raw;
|
|
451
499
|
return result;
|
|
452
500
|
}
|
|
@@ -491,80 +539,49 @@ class index_punned_dense_gt {
|
|
|
491
539
|
}
|
|
492
540
|
}
|
|
493
541
|
|
|
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) {
|
|
542
|
+
static metric_t ip_metric_f32_(std::size_t dimensions) {
|
|
506
543
|
(void)dimensions;
|
|
507
544
|
#if USEARCH_USE_SIMSIMD
|
|
508
545
|
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
|
-
};
|
|
546
|
+
return {metric_kind_t::ip_k, isa_t::avx2_k, 0.f,
|
|
547
|
+
[=](f32_t const* a, f32_t const* b) { return 1.f - simsimd_dot_f32x4avx2(a, b, dimensions); }};
|
|
515
548
|
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
|
-
};
|
|
549
|
+
return {metric_kind_t::ip_k, isa_t::sve_k, 0.f,
|
|
550
|
+
[=](f32_t const* a, f32_t const* b) { return 1.f - simsimd_dot_f32sve(a, b, dimensions); }};
|
|
522
551
|
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
|
-
};
|
|
552
|
+
return {metric_kind_t::ip_k, isa_t::neon_k, 0.f,
|
|
553
|
+
[=](f32_t const* a, f32_t const* b) { return 1.f - simsimd_dot_f32x4neon(a, b, dimensions); }};
|
|
529
554
|
#endif
|
|
530
|
-
return
|
|
555
|
+
return ip_gt<f32_t>{};
|
|
531
556
|
}
|
|
532
557
|
|
|
533
|
-
static
|
|
558
|
+
static metric_t cos_metric_f16_(std::size_t dimensions) {
|
|
534
559
|
(void)dimensions;
|
|
535
560
|
#if USEARCH_USE_SIMSIMD
|
|
536
561
|
if (hardware_supports(isa_t::avx512_k) && dimensions % 16 == 0)
|
|
537
|
-
return {
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
isa_t::avx512_k,
|
|
542
|
-
};
|
|
562
|
+
return {metric_kind_t::cos_k, isa_t::avx512_k, simsimd_f16_t(0),
|
|
563
|
+
[=](simsimd_f16_t const* a, simsimd_f16_t const* b) {
|
|
564
|
+
return 1.f - simsimd_cos_f16x16avx512(a, b, dimensions);
|
|
565
|
+
}};
|
|
543
566
|
if (hardware_supports(isa_t::neon_k) && dimensions % 4 == 0)
|
|
544
|
-
return {
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
isa_t::neon_k,
|
|
549
|
-
};
|
|
567
|
+
return {metric_kind_t::cos_k, isa_t::neon_k, simsimd_f16_t(0),
|
|
568
|
+
[=](simsimd_f16_t const* a, simsimd_f16_t const* b) {
|
|
569
|
+
return 1.f - simsimd_cos_f16x4neon(a, b, dimensions);
|
|
570
|
+
}};
|
|
550
571
|
#endif
|
|
551
|
-
return
|
|
572
|
+
return cos_gt<f16_t, f32_t>{};
|
|
552
573
|
}
|
|
553
574
|
|
|
554
|
-
static
|
|
555
|
-
(void)dimensions;
|
|
575
|
+
static metric_t cos_metric_f8_(std::size_t dimensions) {
|
|
556
576
|
#if USEARCH_USE_SIMSIMD
|
|
557
577
|
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
|
-
};
|
|
578
|
+
return {metric_kind_t::cos_k, isa_t::neon_k, int8_t(0),
|
|
579
|
+
[=](int8_t const* a, int8_t const* b) { return 1.f - simsimd_cos_i8x16neon(a, b, dimensions); }};
|
|
563
580
|
#endif
|
|
564
|
-
return
|
|
581
|
+
return cos_f8_t{dimensions};
|
|
565
582
|
}
|
|
566
583
|
|
|
567
|
-
static
|
|
584
|
+
static metric_t ip_metric_(std::size_t dimensions, scalar_kind_t accuracy) {
|
|
568
585
|
switch (accuracy) {
|
|
569
586
|
case scalar_kind_t::f32_k:
|
|
570
587
|
// The two most common numeric types for the most common metric have optimized versions
|
|
@@ -574,62 +591,62 @@ class index_punned_dense_gt {
|
|
|
574
591
|
return cos_metric_f16_(dimensions);
|
|
575
592
|
|
|
576
593
|
case scalar_kind_t::f8_k: return cos_metric_f8_(dimensions);
|
|
577
|
-
case scalar_kind_t::f64_k: return
|
|
594
|
+
case scalar_kind_t::f64_k: return ip_gt<f64_t>{};
|
|
578
595
|
default: return {};
|
|
579
596
|
}
|
|
580
597
|
}
|
|
581
598
|
|
|
582
|
-
static
|
|
599
|
+
static metric_t l2sq_metric_(std::size_t dimensions, scalar_kind_t accuracy) {
|
|
583
600
|
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
|
|
601
|
+
case scalar_kind_t::f8_k: return l2sq_f8_t{dimensions};
|
|
602
|
+
case scalar_kind_t::f16_k: return l2sq_gt<f16_t, f32_t>{};
|
|
603
|
+
case scalar_kind_t::f32_k: return l2sq_gt<f32_t>{};
|
|
604
|
+
case scalar_kind_t::f64_k: return l2sq_gt<f64_t>{};
|
|
588
605
|
default: return {};
|
|
589
606
|
}
|
|
590
607
|
}
|
|
591
608
|
|
|
592
|
-
static
|
|
609
|
+
static metric_t cos_metric_(std::size_t dimensions, scalar_kind_t accuracy) {
|
|
593
610
|
switch (accuracy) {
|
|
594
611
|
case scalar_kind_t::f8_k: return cos_metric_f8_(dimensions);
|
|
595
612
|
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
|
|
613
|
+
case scalar_kind_t::f32_k: return cos_gt<f32_t>{};
|
|
614
|
+
case scalar_kind_t::f64_k: return cos_gt<f64_t>{};
|
|
598
615
|
default: return {};
|
|
599
616
|
}
|
|
600
617
|
}
|
|
601
618
|
|
|
602
|
-
static
|
|
619
|
+
static metric_t haversine_metric_(scalar_kind_t accuracy) {
|
|
603
620
|
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
|
|
621
|
+
case scalar_kind_t::f8_k: return haversine_gt<f8_bits_t, f32_t>{};
|
|
622
|
+
case scalar_kind_t::f16_k: return haversine_gt<f16_t, f32_t>{};
|
|
623
|
+
case scalar_kind_t::f32_k: return haversine_gt<f32_t>{};
|
|
624
|
+
case scalar_kind_t::f64_k: return haversine_gt<f64_t>{};
|
|
608
625
|
default: return {};
|
|
609
626
|
}
|
|
610
627
|
}
|
|
611
628
|
|
|
612
|
-
static
|
|
629
|
+
static metric_t pearson_metric_(scalar_kind_t accuracy) {
|
|
613
630
|
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
|
|
631
|
+
case scalar_kind_t::f8_k: return pearson_correlation_gt<f8_bits_t, f32_t>{};
|
|
632
|
+
case scalar_kind_t::f16_k: return pearson_correlation_gt<f16_t, f32_t>{};
|
|
633
|
+
case scalar_kind_t::f32_k: return pearson_correlation_gt<f32_t>{};
|
|
634
|
+
case scalar_kind_t::f64_k: return pearson_correlation_gt<f64_t>{};
|
|
618
635
|
default: return {};
|
|
619
636
|
}
|
|
620
637
|
}
|
|
621
638
|
|
|
622
|
-
static
|
|
639
|
+
static metric_t make_metric_(metric_kind_t kind, std::size_t dimensions, scalar_kind_t accuracy) {
|
|
623
640
|
switch (kind) {
|
|
624
641
|
case metric_kind_t::ip_k: return ip_metric_(dimensions, accuracy);
|
|
625
642
|
case metric_kind_t::cos_k: return cos_metric_(dimensions, accuracy);
|
|
626
643
|
case metric_kind_t::l2sq_k: return l2sq_metric_(dimensions, accuracy);
|
|
627
644
|
case metric_kind_t::pearson_k: return pearson_metric_(accuracy);
|
|
628
645
|
case metric_kind_t::haversine_k: return haversine_metric_(accuracy);
|
|
629
|
-
case metric_kind_t::hamming_k: return
|
|
646
|
+
case metric_kind_t::hamming_k: return hamming_gt<b1x8_t>{};
|
|
630
647
|
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
|
|
648
|
+
case metric_kind_t::tanimoto_k: return tanimoto_gt<b1x8_t>{};
|
|
649
|
+
case metric_kind_t::sorensen_k: return sorensen_gt<b1x8_t>{};
|
|
633
650
|
default: return {};
|
|
634
651
|
}
|
|
635
652
|
}
|
|
@@ -94,20 +94,11 @@ inline bool hardware_supports(isa_t isa) noexcept {
|
|
|
94
94
|
default: return false;
|
|
95
95
|
}
|
|
96
96
|
#endif
|
|
97
|
+
|
|
98
|
+
(void)isa;
|
|
97
99
|
return false;
|
|
98
100
|
}
|
|
99
101
|
|
|
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
102
|
inline std::size_t bytes_per_scalar(scalar_kind_t accuracy) noexcept {
|
|
112
103
|
switch (accuracy) {
|
|
113
104
|
case scalar_kind_t::f32_k: return 4;
|
|
@@ -186,7 +177,6 @@ inline expected_gt<metric_kind_t> metric_from_name(char const* name, std::size_t
|
|
|
186
177
|
|
|
187
178
|
using punned_distance_t = float;
|
|
188
179
|
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
180
|
|
|
191
181
|
class f8_bits_t;
|
|
192
182
|
class f16_bits_t;
|
package/objc/USearchObjective.mm
CHANGED
|
@@ -206,6 +206,10 @@ scalar_kind_t to_native_scalar(USearchScalar m) {
|
|
|
206
206
|
_native->clear();
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
+
- (void)reserve:(UInt32)count {
|
|
210
|
+
_native->reserve(static_cast<std::size_t>(count));
|
|
211
|
+
}
|
|
212
|
+
|
|
209
213
|
- (void)save:(NSString *)path {
|
|
210
214
|
char const *path_c = [path UTF8String];
|
|
211
215
|
|
|
@@ -51,6 +51,11 @@ API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0), watchos(6.0))
|
|
|
51
51
|
*/
|
|
52
52
|
+ (instancetype)make:(USearchMetric)metric dimensions:(UInt32)dimensions connectivity:(UInt32)connectivity quantization:(USearchScalar)quantization NS_SWIFT_NAME(make(metric:dimensions:connectivity:quantization:));
|
|
53
53
|
|
|
54
|
+
/**
|
|
55
|
+
* @brief Pre-allocates space in the index for the given number of vectors.
|
|
56
|
+
*/
|
|
57
|
+
- (void)reserve:(UInt32)count NS_SWIFT_NAME(reserve(_:));
|
|
58
|
+
|
|
54
59
|
/**
|
|
55
60
|
* @brief Adds a labeled vector to the index.
|
|
56
61
|
* @param vector Single-precision vector.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "usearch",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.1",
|
|
4
4
|
"description": "Smaller & Faster Single-File Vector Search Engine from Unum",
|
|
5
5
|
"author": "Ashot Vardanian",
|
|
6
6
|
"license": "Apache 2.0",
|
|
@@ -24,6 +24,6 @@
|
|
|
24
24
|
"@semantic-release/exec": "^6.0.3",
|
|
25
25
|
"@semantic-release/git": "^10.0.1",
|
|
26
26
|
"conventional-changelog-eslint": "^3.0.9",
|
|
27
|
-
"semantic-release": "^21.0.
|
|
27
|
+
"semantic-release": "^21.0.6"
|
|
28
28
|
}
|
|
29
29
|
}
|