usearch 0.18.8 → 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.
@@ -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 = punned_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, byte_t, aligned_allocator_t, memory_mapping_allocator_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
- metric_and_meta_t(metric), make_casts_(accuracy));
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
- metric_and_meta_t metric_and_meta, casts_t casts) {
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.isa_ = metric_and_meta.isa;
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, metric_and_meta.metric);
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
- template <typename scalar_at, typename typed_at> static metric_t pun_metric_(typed_at metric) {
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
- pun_metric_<simsimd_f32_t>([=](simsimd_f32_t const* a, simsimd_f32_t const* b) {
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
- pun_metric_<simsimd_f32_t>([=](simsimd_f32_t const* a, simsimd_f32_t const* b) {
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
- pun_metric_<simsimd_f32_t>([=](simsimd_f32_t const* a, simsimd_f32_t const* b) {
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 pun_metric_<f32_t>(ip_gt<f32_t>{});
553
+ return ip_gt<f32_t>{};
531
554
  }
532
555
 
533
- static metric_and_meta_t cos_metric_f16_(std::size_t dimensions) {
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
- pun_metric_<simsimd_f16_t>([=](simsimd_f16_t const* a, simsimd_f16_t const* b) {
539
- return 1.f - simsimd_cos_f16x16avx512(a, b, dimensions);
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
- pun_metric_<simsimd_f16_t>([=](simsimd_f16_t const* a, simsimd_f16_t const* b) {
546
- return 1.f - simsimd_cos_f16x4neon(a, b, dimensions);
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 pun_metric_<f16_t>(cos_gt<f16_t, f32_t>{});
570
+ return cos_gt<f16_t, f32_t>{};
552
571
  }
553
572
 
554
- static metric_and_meta_t cos_metric_f8_(std::size_t dimensions) {
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
- pun_metric_<int8_t>(
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 pun_metric_<f8_bits_t>(cos_f8_t{dimensions});
579
+ return cos_f8_t{dimensions};
565
580
  }
566
581
 
567
- static metric_and_meta_t ip_metric_(std::size_t dimensions, scalar_kind_t accuracy) {
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 pun_metric_<f64_t>(ip_gt<f64_t>{});
592
+ case scalar_kind_t::f64_k: return ip_gt<f64_t>{};
578
593
  default: return {};
579
594
  }
580
595
  }
581
596
 
582
- static metric_and_meta_t l2sq_metric_(std::size_t dimensions, scalar_kind_t accuracy) {
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 pun_metric_<f8_bits_t>(l2sq_f8_t{dimensions});
585
- case scalar_kind_t::f16_k: return pun_metric_<f16_t>(l2sq_gt<f16_t, f32_t>{});
586
- case scalar_kind_t::f32_k: return pun_metric_<f32_t>(l2sq_gt<f32_t>{});
587
- case scalar_kind_t::f64_k: return pun_metric_<f64_t>(l2sq_gt<f64_t>{});
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 metric_and_meta_t cos_metric_(std::size_t dimensions, scalar_kind_t accuracy) {
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 pun_metric_<f32_t>(cos_gt<f32_t>{});
597
- case scalar_kind_t::f64_k: return pun_metric_<f64_t>(cos_gt<f64_t>{});
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 metric_and_meta_t haversine_metric_(scalar_kind_t accuracy) {
617
+ static metric_t haversine_metric_(scalar_kind_t accuracy) {
603
618
  switch (accuracy) {
604
- case scalar_kind_t::f8_k: return pun_metric_<f8_bits_t>(haversine_gt<f8_bits_t, f32_t>{});
605
- case scalar_kind_t::f16_k: return pun_metric_<f16_t>(haversine_gt<f16_t, f32_t>{});
606
- case scalar_kind_t::f32_k: return pun_metric_<f32_t>(haversine_gt<f32_t>{});
607
- case scalar_kind_t::f64_k: return pun_metric_<f64_t>(haversine_gt<f64_t>{});
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 metric_and_meta_t pearson_metric_(scalar_kind_t accuracy) {
627
+ static metric_t pearson_metric_(scalar_kind_t accuracy) {
613
628
  switch (accuracy) {
614
- case scalar_kind_t::f8_k: return pun_metric_<f8_bits_t>(pearson_correlation_gt<f8_bits_t, f32_t>{});
615
- case scalar_kind_t::f16_k: return pun_metric_<f16_t>(pearson_correlation_gt<f16_t, f32_t>{});
616
- case scalar_kind_t::f32_k: return pun_metric_<f32_t>(pearson_correlation_gt<f32_t>{});
617
- case scalar_kind_t::f64_k: return pun_metric_<f64_t>(pearson_correlation_gt<f64_t>{});
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 metric_and_meta_t make_metric_(metric_kind_t kind, std::size_t dimensions, scalar_kind_t accuracy) {
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 pun_metric_<unsigned char>(hamming_gt<unsigned char>{});
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 pun_metric_<unsigned char>(tanimoto_gt<unsigned char>{});
632
- case metric_kind_t::sorensen_k: return pun_metric_<unsigned char>(sorensen_gt<unsigned char>{});
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
  }
@@ -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,7 +175,6 @@ 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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "usearch",
3
- "version": "0.18.8",
3
+ "version": "0.19.0",
4
4
  "description": "Smaller & Faster Single-File Vector Search Engine from Unum",
5
5
  "author": "Ashot Vardanian",
6
6
  "license": "Apache 2.0",