usearch 0.22.2 → 0.22.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/.releaserc +2 -1
- package/.vscode/launch.json +5 -1
- package/.vscode/settings.json +3 -1
- package/Cargo.toml +1 -1
- package/README.md +6 -7
- package/conanfile.py +1 -1
- package/cpp/bench.cpp +2 -2
- package/cpp/test.cpp +4 -1
- package/docs/compilation.md +29 -7
- package/docs/cpp/index.rst +3 -3
- package/docs/cpp/reference.rst +13 -3
- package/docs/index.rst +8 -8
- package/docs/java/reference.rst +1 -1
- package/include/usearch/index.hpp +96 -47
- package/include/usearch/index_punned_dense.hpp +258 -128
- package/include/usearch/index_punned_helpers.hpp +150 -40
- package/javascript/README.md +1 -1
- package/package.json +1 -1
- package/pyproject.toml +3 -3
- package/python/lib.cpp +4 -0
- package/wasmer.toml +5 -1
|
@@ -200,44 +200,38 @@ class index_punned_dense_gt {
|
|
|
200
200
|
using stats_t = typename index_t::stats_t;
|
|
201
201
|
using match_t = typename index_t::match_t;
|
|
202
202
|
|
|
203
|
-
struct labeling_result_t {
|
|
204
|
-
error_t error{};
|
|
205
|
-
std::size_t completed{};
|
|
206
|
-
|
|
207
|
-
explicit operator bool() const noexcept { return !error; }
|
|
208
|
-
labeling_result_t failed(error_t message) noexcept {
|
|
209
|
-
error = std::move(message);
|
|
210
|
-
return std::move(*this);
|
|
211
|
-
}
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
struct compaction_result_t {
|
|
215
|
-
error_t error{};
|
|
216
|
-
std::size_t pruned_edges{};
|
|
217
|
-
|
|
218
|
-
explicit operator bool() const noexcept { return !error; }
|
|
219
|
-
compaction_result_t failed(error_t message) noexcept {
|
|
220
|
-
error = std::move(message);
|
|
221
|
-
return std::move(*this);
|
|
222
|
-
}
|
|
223
|
-
};
|
|
224
|
-
|
|
225
203
|
index_punned_dense_gt() = default;
|
|
226
|
-
index_punned_dense_gt(index_punned_dense_gt&& other)
|
|
204
|
+
index_punned_dense_gt(index_punned_dense_gt&& other)
|
|
205
|
+
: dimensions_(std::move(other.dimensions_)), //
|
|
206
|
+
scalar_words_(std::move(other.scalar_words_)), //
|
|
207
|
+
expansion_add_(std::move(other.expansion_add_)), //
|
|
208
|
+
expansion_search_(std::move(other.expansion_search_)), //
|
|
209
|
+
typed_(exchange(other.typed_, nullptr)), //
|
|
210
|
+
casted_vector_bytes_(std::move(other.casted_vector_bytes_)), //
|
|
211
|
+
cast_buffer_(std::move(other.cast_buffer_)), //
|
|
212
|
+
casts_(std::move(other.casts_)), //
|
|
213
|
+
root_metric_(std::move(other.root_metric_)), //
|
|
214
|
+
available_threads_(std::move(other.available_threads_)), //
|
|
215
|
+
labeled_lookup_(std::move(other.labeled_lookup_)), //
|
|
216
|
+
free_ids_(std::move(other.free_ids_)), //
|
|
217
|
+
free_label_(std::move(other.free_label_)) {} //
|
|
218
|
+
|
|
227
219
|
index_punned_dense_gt& operator=(index_punned_dense_gt&& other) {
|
|
228
220
|
swap(other);
|
|
229
221
|
return *this;
|
|
230
222
|
}
|
|
231
223
|
|
|
232
|
-
|
|
233
|
-
|
|
224
|
+
/**
|
|
225
|
+
* @brief Swaps the contents of this index with another index.
|
|
226
|
+
* @param other The other index to swap with.
|
|
227
|
+
*/
|
|
234
228
|
void swap(index_punned_dense_gt& other) {
|
|
235
229
|
std::swap(dimensions_, other.dimensions_);
|
|
236
230
|
std::swap(scalar_words_, other.scalar_words_);
|
|
237
231
|
std::swap(expansion_add_, other.expansion_add_);
|
|
238
232
|
std::swap(expansion_search_, other.expansion_search_);
|
|
239
|
-
std::swap(casted_vector_bytes_, other.casted_vector_bytes_);
|
|
240
233
|
std::swap(typed_, other.typed_);
|
|
234
|
+
std::swap(casted_vector_bytes_, other.casted_vector_bytes_);
|
|
241
235
|
std::swap(cast_buffer_, other.cast_buffer_);
|
|
242
236
|
std::swap(casts_, other.casts_);
|
|
243
237
|
std::swap(root_metric_, other.root_metric_);
|
|
@@ -247,8 +241,65 @@ class index_punned_dense_gt {
|
|
|
247
241
|
std::swap(free_label_, other.free_label_);
|
|
248
242
|
}
|
|
249
243
|
|
|
244
|
+
~index_punned_dense_gt() {
|
|
245
|
+
if (typed_)
|
|
246
|
+
typed_->~index_t();
|
|
247
|
+
index_allocator_t{}.deallocate(typed_, 1);
|
|
248
|
+
typed_ = nullptr;
|
|
249
|
+
}
|
|
250
|
+
|
|
250
251
|
static index_config_t optimize(index_config_t config) { return index_t::optimize(config); }
|
|
251
252
|
|
|
253
|
+
/**
|
|
254
|
+
* @brief Constructs an instance of ::index_punned_dense_gt.
|
|
255
|
+
* @param[in] dimensions The of dimensions per vector.
|
|
256
|
+
* @param[in] metric One of the default supported metric @b kinds for distance measurements.
|
|
257
|
+
* @param[in] config The index configuration (optional).
|
|
258
|
+
* @param[in] accuracy The scalar kind used for internal representations (optional).
|
|
259
|
+
* @param[in] expansion_add The expansion factor for adding vectors (optional).
|
|
260
|
+
* @param[in] expansion_search The expansion factor for searching vectors (optional).
|
|
261
|
+
* @param[in] free_label The label used for freed vectors (optional).
|
|
262
|
+
* @return An instance of ::index_punned_dense_gt.
|
|
263
|
+
*/
|
|
264
|
+
static index_punned_dense_gt make( //
|
|
265
|
+
std::size_t dimensions, metric_kind_t metric, //
|
|
266
|
+
index_config_t config = {}, //
|
|
267
|
+
scalar_kind_t accuracy = scalar_kind_t::f32_k, //
|
|
268
|
+
std::size_t expansion_add = default_expansion_add(), //
|
|
269
|
+
std::size_t expansion_search = default_expansion_search(), //
|
|
270
|
+
label_t free_label = default_free_value<label_t>()) {
|
|
271
|
+
|
|
272
|
+
return make_( //
|
|
273
|
+
dimensions, accuracy, //
|
|
274
|
+
config, expansion_add, expansion_search, //
|
|
275
|
+
make_metric_(metric, dimensions, accuracy), make_casts_(accuracy), free_label);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* @brief Constructs an instance of ::index_punned_dense_gt.
|
|
280
|
+
* @param[in] dimensions The of dimensions per vector.
|
|
281
|
+
* @param[in] metric The @b ad-hoc metric wrapped for third-party distance measures.
|
|
282
|
+
* @param[in] config The index configuration (optional).
|
|
283
|
+
* @param[in] accuracy The scalar kind used for internal representations (optional).
|
|
284
|
+
* @param[in] expansion_add The expansion factor for adding vectors (optional).
|
|
285
|
+
* @param[in] expansion_search The expansion factor for searching vectors (optional).
|
|
286
|
+
* @param[in] free_label The label used for freed vectors (optional).
|
|
287
|
+
* @return An instance of ::index_punned_dense_gt.
|
|
288
|
+
*/
|
|
289
|
+
static index_punned_dense_gt make( //
|
|
290
|
+
std::size_t dimensions, metric_t metric, //
|
|
291
|
+
index_config_t config = {}, //
|
|
292
|
+
scalar_kind_t accuracy = scalar_kind_t::f32_k, //
|
|
293
|
+
std::size_t expansion_add = default_expansion_add(), //
|
|
294
|
+
std::size_t expansion_search = default_expansion_search(), //
|
|
295
|
+
label_t free_label = default_free_value<label_t>()) {
|
|
296
|
+
|
|
297
|
+
return make_( //
|
|
298
|
+
dimensions, accuracy, //
|
|
299
|
+
config, expansion_add, expansion_search, //
|
|
300
|
+
metric_t(metric), make_casts_(accuracy), free_label);
|
|
301
|
+
}
|
|
302
|
+
|
|
252
303
|
std::size_t dimensions() const { return dimensions_; }
|
|
253
304
|
std::size_t scalar_words() const { return scalar_words_; }
|
|
254
305
|
std::size_t connectivity() const { return typed_->connectivity(); }
|
|
@@ -274,6 +325,50 @@ class index_punned_dense_gt {
|
|
|
274
325
|
stats_t stats() const { return typed_->stats(); }
|
|
275
326
|
stats_t stats(std::size_t level) const { return typed_->stats(level); }
|
|
276
327
|
|
|
328
|
+
std::size_t memory_usage() const {
|
|
329
|
+
return typed_->memory_usage(0) + //
|
|
330
|
+
typed_->tape_allocator().total_wasted() + //
|
|
331
|
+
typed_->tape_allocator().total_reserved();
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// clang-format off
|
|
335
|
+
add_result_t add(label_t label, b1x8_t const* vector) { return add_(label, vector, casts_.from_b1x8); }
|
|
336
|
+
add_result_t add(label_t label, f8_bits_t const* vector) { return add_(label, vector, casts_.from_f8); }
|
|
337
|
+
add_result_t add(label_t label, f16_t const* vector) { return add_(label, vector, casts_.from_f16); }
|
|
338
|
+
add_result_t add(label_t label, f32_t const* vector) { return add_(label, vector, casts_.from_f32); }
|
|
339
|
+
add_result_t add(label_t label, f64_t const* vector) { return add_(label, vector, casts_.from_f64); }
|
|
340
|
+
|
|
341
|
+
add_result_t add(label_t label, b1x8_t const* vector, add_config_t config) { return add_(label, vector, config, casts_.from_b1x8); }
|
|
342
|
+
add_result_t add(label_t label, f8_bits_t const* vector, add_config_t config) { return add_(label, vector, config, casts_.from_f8); }
|
|
343
|
+
add_result_t add(label_t label, f16_t const* vector, add_config_t config) { return add_(label, vector, config, casts_.from_f16); }
|
|
344
|
+
add_result_t add(label_t label, f32_t const* vector, add_config_t config) { return add_(label, vector, config, casts_.from_f32); }
|
|
345
|
+
add_result_t add(label_t label, f64_t const* vector, add_config_t config) { return add_(label, vector, config, casts_.from_f64); }
|
|
346
|
+
|
|
347
|
+
search_result_t search(b1x8_t const* vector, std::size_t wanted) const { return search_(vector, wanted, casts_.from_b1x8); }
|
|
348
|
+
search_result_t search(f8_bits_t const* vector, std::size_t wanted) const { return search_(vector, wanted, casts_.from_f8); }
|
|
349
|
+
search_result_t search(f16_t const* vector, std::size_t wanted) const { return search_(vector, wanted, casts_.from_f16); }
|
|
350
|
+
search_result_t search(f32_t const* vector, std::size_t wanted) const { return search_(vector, wanted, casts_.from_f32); }
|
|
351
|
+
search_result_t search(f64_t const* vector, std::size_t wanted) const { return search_(vector, wanted, casts_.from_f64); }
|
|
352
|
+
|
|
353
|
+
search_result_t search(b1x8_t const* vector, std::size_t wanted, search_config_t config) const { return search_(vector, wanted, config, casts_.from_b1x8); }
|
|
354
|
+
search_result_t search(f8_bits_t const* vector, std::size_t wanted, search_config_t config) const { return search_(vector, wanted, config, casts_.from_f8); }
|
|
355
|
+
search_result_t search(f16_t const* vector, std::size_t wanted, search_config_t config) const { return search_(vector, wanted, config, casts_.from_f16); }
|
|
356
|
+
search_result_t search(f32_t const* vector, std::size_t wanted, search_config_t config) const { return search_(vector, wanted, config, casts_.from_f32); }
|
|
357
|
+
search_result_t search(f64_t const* vector, std::size_t wanted, search_config_t config) const { return search_(vector, wanted, config, casts_.from_f64); }
|
|
358
|
+
|
|
359
|
+
bool get(label_t label, b1x8_t* vector) const { return get_(label, vector, casts_.to_b1x8); }
|
|
360
|
+
bool get(label_t label, f8_bits_t* vector) const { return get_(label, vector, casts_.to_f8); }
|
|
361
|
+
bool get(label_t label, f16_t* vector) const { return get_(label, vector, casts_.to_f16); }
|
|
362
|
+
bool get(label_t label, f32_t* vector) const { return get_(label, vector, casts_.to_f32); }
|
|
363
|
+
bool get(label_t label, f64_t* vector) const { return get_(label, vector, casts_.to_f64); }
|
|
364
|
+
// clang-format on
|
|
365
|
+
|
|
366
|
+
search_result_t empty_search_result() const { return search_result_t{*typed_}; }
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* @brief Reserves memory for the index and the labeled lookup.
|
|
370
|
+
* @return `true` if the memory reservation was successful, `false` otherwise.
|
|
371
|
+
*/
|
|
277
372
|
bool reserve(index_limits_t limits) {
|
|
278
373
|
{
|
|
279
374
|
unique_lock_t lock(labeled_lookup_mutex_);
|
|
@@ -282,6 +377,9 @@ class index_punned_dense_gt {
|
|
|
282
377
|
return typed_->reserve(limits);
|
|
283
378
|
}
|
|
284
379
|
|
|
380
|
+
/**
|
|
381
|
+
* @brief Clears the whole index, reclaiming the memory.
|
|
382
|
+
*/
|
|
285
383
|
void clear() {
|
|
286
384
|
unique_lock_t lookup_lock(labeled_lookup_mutex_);
|
|
287
385
|
std::unique_lock<std::mutex> free_lock(free_ids_mutex_);
|
|
@@ -290,8 +388,18 @@ class index_punned_dense_gt {
|
|
|
290
388
|
free_ids_.clear();
|
|
291
389
|
}
|
|
292
390
|
|
|
391
|
+
/**
|
|
392
|
+
* @brief Saves the index to a file.
|
|
393
|
+
* @param[in] path The path to the file.
|
|
394
|
+
* @return Outcome descriptor explictly convertable to boolean.
|
|
395
|
+
*/
|
|
293
396
|
serialization_result_t save(char const* path) const { return typed_->save(path); }
|
|
294
397
|
|
|
398
|
+
/**
|
|
399
|
+
* @brief Parses the index from file to RAM.
|
|
400
|
+
* @param[in] path The path to the file.
|
|
401
|
+
* @return Outcome descriptor explictly convertable to boolean.
|
|
402
|
+
*/
|
|
295
403
|
serialization_result_t load(char const* path) {
|
|
296
404
|
serialization_result_t result = typed_->load(path);
|
|
297
405
|
if (result)
|
|
@@ -299,6 +407,11 @@ class index_punned_dense_gt {
|
|
|
299
407
|
return result;
|
|
300
408
|
}
|
|
301
409
|
|
|
410
|
+
/**
|
|
411
|
+
* @brief Parses the index from file, without loading it into RAM.
|
|
412
|
+
* @param[in] path The path to the file.
|
|
413
|
+
* @return Outcome descriptor explictly convertable to boolean.
|
|
414
|
+
*/
|
|
302
415
|
serialization_result_t view(char const* path) {
|
|
303
416
|
serialization_result_t result = typed_->view(path);
|
|
304
417
|
if (result)
|
|
@@ -306,58 +419,34 @@ class index_punned_dense_gt {
|
|
|
306
419
|
return result;
|
|
307
420
|
}
|
|
308
421
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
422
|
+
/**
|
|
423
|
+
* @brief Checks if a vector with specidied label is present.
|
|
424
|
+
* @return `true` if the label is present in the index, `false` otherwise.
|
|
425
|
+
*/
|
|
313
426
|
bool contains(label_t label) const {
|
|
314
427
|
shared_lock_t lock(labeled_lookup_mutex_);
|
|
315
428
|
return labeled_lookup_.contains(label);
|
|
316
429
|
}
|
|
317
430
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
offset = (std::min)(offset, labeled_lookup_.size());
|
|
322
|
-
std::advance(it, offset);
|
|
323
|
-
for (; it != labeled_lookup_.end() && limit; ++it, ++labels, --limit)
|
|
324
|
-
*labels = it->first;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// clang-format off
|
|
328
|
-
add_result_t add(label_t label, b1x8_t const* vector) { return add_(label, vector, casts_.from_b1x8); }
|
|
329
|
-
add_result_t add(label_t label, f8_bits_t const* vector) { return add_(label, vector, casts_.from_f8); }
|
|
330
|
-
add_result_t add(label_t label, f16_t const* vector) { return add_(label, vector, casts_.from_f16); }
|
|
331
|
-
add_result_t add(label_t label, f32_t const* vector) { return add_(label, vector, casts_.from_f32); }
|
|
332
|
-
add_result_t add(label_t label, f64_t const* vector) { return add_(label, vector, casts_.from_f64); }
|
|
333
|
-
|
|
334
|
-
add_result_t add(label_t label, b1x8_t const* vector, add_config_t config) { return add_(label, vector, config, casts_.from_b1x8); }
|
|
335
|
-
add_result_t add(label_t label, f8_bits_t const* vector, add_config_t config) { return add_(label, vector, config, casts_.from_f8); }
|
|
336
|
-
add_result_t add(label_t label, f16_t const* vector, add_config_t config) { return add_(label, vector, config, casts_.from_f16); }
|
|
337
|
-
add_result_t add(label_t label, f32_t const* vector, add_config_t config) { return add_(label, vector, config, casts_.from_f32); }
|
|
338
|
-
add_result_t add(label_t label, f64_t const* vector, add_config_t config) { return add_(label, vector, config, casts_.from_f64); }
|
|
339
|
-
|
|
340
|
-
search_result_t search(b1x8_t const* vector, std::size_t wanted) const { return search_(vector, wanted, casts_.from_b1x8); }
|
|
341
|
-
search_result_t search(f8_bits_t const* vector, std::size_t wanted) const { return search_(vector, wanted, casts_.from_f8); }
|
|
342
|
-
search_result_t search(f16_t const* vector, std::size_t wanted) const { return search_(vector, wanted, casts_.from_f16); }
|
|
343
|
-
search_result_t search(f32_t const* vector, std::size_t wanted) const { return search_(vector, wanted, casts_.from_f32); }
|
|
344
|
-
search_result_t search(f64_t const* vector, std::size_t wanted) const { return search_(vector, wanted, casts_.from_f64); }
|
|
345
|
-
|
|
346
|
-
search_result_t search(b1x8_t const* vector, std::size_t wanted, search_config_t config) const { return search_(vector, wanted, config, casts_.from_b1x8); }
|
|
347
|
-
search_result_t search(f8_bits_t const* vector, std::size_t wanted, search_config_t config) const { return search_(vector, wanted, config, casts_.from_f8); }
|
|
348
|
-
search_result_t search(f16_t const* vector, std::size_t wanted, search_config_t config) const { return search_(vector, wanted, config, casts_.from_f16); }
|
|
349
|
-
search_result_t search(f32_t const* vector, std::size_t wanted, search_config_t config) const { return search_(vector, wanted, config, casts_.from_f32); }
|
|
350
|
-
search_result_t search(f64_t const* vector, std::size_t wanted, search_config_t config) const { return search_(vector, wanted, config, casts_.from_f64); }
|
|
351
|
-
|
|
352
|
-
search_result_t empty_search_result() const { return search_result_t{*typed_}; }
|
|
431
|
+
struct labeling_result_t {
|
|
432
|
+
error_t error{};
|
|
433
|
+
std::size_t completed{};
|
|
353
434
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
435
|
+
explicit operator bool() const noexcept { return !error; }
|
|
436
|
+
labeling_result_t failed(error_t message) noexcept {
|
|
437
|
+
error = std::move(message);
|
|
438
|
+
return std::move(*this);
|
|
439
|
+
}
|
|
440
|
+
};
|
|
360
441
|
|
|
442
|
+
/**
|
|
443
|
+
* @brief Removes an entry with the specified label from the index.
|
|
444
|
+
* @param[in] label The label of the entry to remove.
|
|
445
|
+
* @return The ::labeling_result_t indicating the result of the removal operation.
|
|
446
|
+
* If the removal was successful, `result.completed` will be `true`.
|
|
447
|
+
* If the label was not found in the index, `result.completed` will be `false`.
|
|
448
|
+
* If an error occurred during the removal operation, `result.error` will contain an error message.
|
|
449
|
+
*/
|
|
361
450
|
labeling_result_t remove(label_t label) {
|
|
362
451
|
labeling_result_t result;
|
|
363
452
|
|
|
@@ -385,6 +474,14 @@ class index_punned_dense_gt {
|
|
|
385
474
|
return result;
|
|
386
475
|
}
|
|
387
476
|
|
|
477
|
+
/**
|
|
478
|
+
* @brief Removes multiple entries with the specified labels from the index.
|
|
479
|
+
* @param[in] labels_begin The beginning of the labels range.
|
|
480
|
+
* @param[in] labels_end The ending of the labels range.
|
|
481
|
+
* @return The ::labeling_result_t indicating the result of the removal operation.
|
|
482
|
+
* `result.completed` will contain the number of labels that were successfully removed.
|
|
483
|
+
* `result.error` will contain an error message if an error occurred during the removal operation.
|
|
484
|
+
*/
|
|
388
485
|
template <typename labels_iterator_at>
|
|
389
486
|
labeling_result_t remove(labels_iterator_at&& labels_begin, labels_iterator_at&& labels_end) {
|
|
390
487
|
|
|
@@ -418,20 +515,14 @@ class index_punned_dense_gt {
|
|
|
418
515
|
return result;
|
|
419
516
|
}
|
|
420
517
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
};
|
|
430
|
-
typed_->isolate(disallow, std::forward<executor_at>(executor), std::forward<progress_at>(progress));
|
|
431
|
-
result.pruned_edges = pruned_edges;
|
|
432
|
-
return result;
|
|
433
|
-
}
|
|
434
|
-
|
|
518
|
+
/**
|
|
519
|
+
* @brief Renames an entry with the specified label to a new label.
|
|
520
|
+
* @param[in] from The current label of the entry to rename.
|
|
521
|
+
* @param[in] to The new label to assign to the entry.
|
|
522
|
+
* @return The ::labeling_result_t indicating the result of the rename operation.
|
|
523
|
+
* If the rename was successful, `result.completed` will be `true`.
|
|
524
|
+
* If the entry with the current label was not found, `result.completed` will be `false`.
|
|
525
|
+
*/
|
|
435
526
|
labeling_result_t rename(label_t from, label_t to) {
|
|
436
527
|
labeling_result_t result;
|
|
437
528
|
unique_lock_t lookup_lock(labeled_lookup_mutex_);
|
|
@@ -447,32 +538,52 @@ class index_punned_dense_gt {
|
|
|
447
538
|
return result;
|
|
448
539
|
}
|
|
449
540
|
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
541
|
+
/**
|
|
542
|
+
* @brief Exports a range of labels for the vectors present in the index.
|
|
543
|
+
* @param[out] labels Pointer to the array where the labels will be exported.
|
|
544
|
+
* @param[in] offset The number of labels to skip. Useful for pagination.
|
|
545
|
+
* @param[in] limit The maximum number of labels to export, that can fit in ::labels.
|
|
546
|
+
*/
|
|
547
|
+
void export_labels(label_t* labels, std::size_t offset, std::size_t limit) const {
|
|
548
|
+
shared_lock_t lock(labeled_lookup_mutex_);
|
|
549
|
+
auto it = labeled_lookup_.begin();
|
|
550
|
+
offset = (std::min)(offset, labeled_lookup_.size());
|
|
551
|
+
std::advance(it, offset);
|
|
552
|
+
for (; it != labeled_lookup_.end() && limit; ++it, ++labels, --limit)
|
|
553
|
+
*labels = it->first;
|
|
462
554
|
}
|
|
463
555
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
556
|
+
/**
|
|
557
|
+
* @brief Adapts the Male-Optimal Stable Marriage algorithm for unequal sets
|
|
558
|
+
* to perform fast one-to-one matching between two large collections
|
|
559
|
+
* of vectors, using approximate nearest neighbors search.
|
|
560
|
+
*
|
|
561
|
+
* @param[inout] first_to_second Container to map ::first labels to ::second.
|
|
562
|
+
* @param[inout] second_to_first Container to map ::second labels to ::first.
|
|
563
|
+
* @param[in] executor Thread-pool to execute the job in parallel.
|
|
564
|
+
* @param[in] progress Callback to report the execution progress.
|
|
565
|
+
*/
|
|
566
|
+
template < //
|
|
567
|
+
typename first_to_second_at = dummy_label_to_label_mapping_t, //
|
|
568
|
+
typename second_to_first_at = dummy_label_to_label_mapping_t, //
|
|
569
|
+
typename executor_at = dummy_executor_t, //
|
|
570
|
+
typename progress_at = dummy_progress_t //
|
|
571
|
+
>
|
|
572
|
+
static join_result_t join( //
|
|
573
|
+
index_punned_dense_gt const& first, //
|
|
574
|
+
index_punned_dense_gt const& second, //
|
|
575
|
+
join_config_t config = {}, //
|
|
576
|
+
first_to_second_at&& first_to_second = first_to_second_at{}, //
|
|
577
|
+
second_to_first_at&& second_to_first = second_to_first_at{}, //
|
|
578
|
+
executor_at&& executor = executor_at{}, //
|
|
579
|
+
progress_at&& progress = progress_at{}) noexcept {
|
|
471
580
|
|
|
472
|
-
return
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
581
|
+
return index_t::join( //
|
|
582
|
+
*first.typed_, *second.typed_, config, //
|
|
583
|
+
std::forward<first_to_second_at>(first_to_second), //
|
|
584
|
+
std::forward<second_to_first_at>(second_to_first), //
|
|
585
|
+
std::forward<executor_at>(executor), //
|
|
586
|
+
std::forward<progress_at>(progress));
|
|
476
587
|
}
|
|
477
588
|
|
|
478
589
|
struct copy_result_t {
|
|
@@ -486,6 +597,11 @@ class index_punned_dense_gt {
|
|
|
486
597
|
}
|
|
487
598
|
};
|
|
488
599
|
|
|
600
|
+
/**
|
|
601
|
+
* @brief Copies the ::index_punned_dense_gt @b with all the data in it.
|
|
602
|
+
* @param config The copy configuration (optional).
|
|
603
|
+
* @return A copy of the ::index_punned_dense_gt instance.
|
|
604
|
+
*/
|
|
489
605
|
copy_result_t copy(copy_config_t config = {}) const {
|
|
490
606
|
copy_result_t result = fork();
|
|
491
607
|
if (!result)
|
|
@@ -503,6 +619,10 @@ class index_punned_dense_gt {
|
|
|
503
619
|
return result;
|
|
504
620
|
}
|
|
505
621
|
|
|
622
|
+
/**
|
|
623
|
+
* @brief Copies the ::index_punned_dense_gt model @b without any data.
|
|
624
|
+
* @return A similarly configured ::index_punned_dense_gt instance.
|
|
625
|
+
*/
|
|
506
626
|
copy_result_t fork() const {
|
|
507
627
|
copy_result_t result;
|
|
508
628
|
index_punned_dense_gt& other = result.index;
|
|
@@ -527,27 +647,37 @@ class index_punned_dense_gt {
|
|
|
527
647
|
return result;
|
|
528
648
|
}
|
|
529
649
|
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
typename executor_at = dummy_executor_t, //
|
|
534
|
-
typename progress_at = dummy_progress_t //
|
|
535
|
-
>
|
|
536
|
-
static join_result_t join( //
|
|
537
|
-
index_punned_dense_gt const& first, //
|
|
538
|
-
index_punned_dense_gt const& second, //
|
|
539
|
-
join_config_t config = {}, //
|
|
540
|
-
first_to_second_at&& first_to_second = first_to_second_at{}, //
|
|
541
|
-
second_to_first_at&& second_to_first = second_to_first_at{}, //
|
|
542
|
-
executor_at&& executor = executor_at{}, //
|
|
543
|
-
progress_at&& progress = progress_at{}) noexcept {
|
|
650
|
+
struct compaction_result_t {
|
|
651
|
+
error_t error{};
|
|
652
|
+
std::size_t pruned_edges{};
|
|
544
653
|
|
|
545
|
-
return
|
|
546
|
-
|
|
547
|
-
std::
|
|
548
|
-
std::
|
|
549
|
-
|
|
550
|
-
|
|
654
|
+
explicit operator bool() const noexcept { return !error; }
|
|
655
|
+
compaction_result_t failed(error_t message) noexcept {
|
|
656
|
+
error = std::move(message);
|
|
657
|
+
return std::move(*this);
|
|
658
|
+
}
|
|
659
|
+
};
|
|
660
|
+
|
|
661
|
+
/**
|
|
662
|
+
* @brief Performs compaction on the index, pruning links to removed entries.
|
|
663
|
+
* @param executor The executor parallel processing. Default ::dummy_executor_t single-threaded.
|
|
664
|
+
* @param progress The progress tracker instance to use. Default ::dummy_progress_t reports nothing.
|
|
665
|
+
* @return The ::compaction_result_t indicating the result of the compaction operation.
|
|
666
|
+
* `result.pruned_edges` will contain the number of edges that were removed.
|
|
667
|
+
* `result.error` will contain an error message if an error occurred during the compaction operation.
|
|
668
|
+
*/
|
|
669
|
+
template <typename executor_at = dummy_executor_t, typename progress_at = dummy_progress_t>
|
|
670
|
+
compaction_result_t compact(executor_at&& executor = executor_at{}, progress_at&& progress = progress_at{}) {
|
|
671
|
+
compaction_result_t result;
|
|
672
|
+
std::atomic<std::size_t> pruned_edges;
|
|
673
|
+
auto disallow = [&](member_cref_t const& member) noexcept {
|
|
674
|
+
bool freed = member.label == free_label_;
|
|
675
|
+
pruned_edges += freed;
|
|
676
|
+
return freed;
|
|
677
|
+
};
|
|
678
|
+
typed_->isolate(disallow, std::forward<executor_at>(executor), std::forward<progress_at>(progress));
|
|
679
|
+
result.pruned_edges = pruned_edges;
|
|
680
|
+
return result;
|
|
551
681
|
}
|
|
552
682
|
|
|
553
683
|
private:
|