usearch 0.9.7 → 0.10.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/VERSION +1 -1
- package/conanfile.py +1 -1
- package/include/usearch/usearch.hpp +35 -2
- package/package.json +1 -1
- package/python/lib.cpp +7 -0
- package/src/punned.hpp +6 -0
- package/src/test.cpp +3 -0
package/Cargo.toml
CHANGED
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.10.0
|
package/conanfile.py
CHANGED
|
@@ -4,7 +4,7 @@ from conans import ConanFile
|
|
|
4
4
|
class USearchConan(ConanFile):
|
|
5
5
|
|
|
6
6
|
name = 'USearch'
|
|
7
|
-
version = '0.
|
|
7
|
+
version = '0.10.0'
|
|
8
8
|
license = 'Apache 2.0'
|
|
9
9
|
url = 'https://github.com/unum-cloud/usearch'
|
|
10
10
|
description = 'Smaller & Faster Single-File Vector Search Engine from Unum'
|
|
@@ -781,6 +781,7 @@ template <typename scalar_at> class span_gt {
|
|
|
781
781
|
constexpr std::size_t default_connectivity() { return 16; }
|
|
782
782
|
constexpr std::size_t default_expansion_add() { return 128; }
|
|
783
783
|
constexpr std::size_t default_expansion_search() { return 64; }
|
|
784
|
+
constexpr std::size_t default_allocator_entry_bytes() { return 64; }
|
|
784
785
|
|
|
785
786
|
/**
|
|
786
787
|
* @brief Configuration settings for the index construction.
|
|
@@ -1416,6 +1417,7 @@ class index_gt {
|
|
|
1416
1417
|
std::size_t nodes;
|
|
1417
1418
|
std::size_t edges;
|
|
1418
1419
|
std::size_t max_edges;
|
|
1420
|
+
std::size_t allocated_bytes;
|
|
1419
1421
|
};
|
|
1420
1422
|
|
|
1421
1423
|
stats_t stats() const noexcept {
|
|
@@ -1428,6 +1430,7 @@ class index_gt {
|
|
|
1428
1430
|
for (level_t level = 0; level != node.level(); ++level)
|
|
1429
1431
|
edges += neighbors_(node, level).size();
|
|
1430
1432
|
|
|
1433
|
+
result.allocated_bytes += node_bytes_(node);
|
|
1431
1434
|
result.edges += edges;
|
|
1432
1435
|
result.max_edges += max_edges;
|
|
1433
1436
|
}
|
|
@@ -1437,16 +1440,46 @@ class index_gt {
|
|
|
1437
1440
|
stats_t stats(std::size_t level) const noexcept {
|
|
1438
1441
|
stats_t result{};
|
|
1439
1442
|
result.nodes = size();
|
|
1443
|
+
|
|
1444
|
+
std::size_t neighbors_bytes = !level ? pre_.neighbors_base_bytes : pre_.neighbors_bytes;
|
|
1440
1445
|
for (std::size_t i = 0; i != result.nodes; ++i) {
|
|
1441
1446
|
node_t node = node_with_id_(i);
|
|
1442
|
-
if (node.level()
|
|
1443
|
-
|
|
1447
|
+
if (node.level() < level)
|
|
1448
|
+
continue;
|
|
1449
|
+
|
|
1450
|
+
result.edges += neighbors_(node, level).size();
|
|
1451
|
+
result.allocated_bytes += node_head_bytes_() + node_vector_bytes_(node) + neighbors_bytes;
|
|
1444
1452
|
}
|
|
1453
|
+
|
|
1445
1454
|
std::size_t max_edges_per_node = level ? config_.connectivity : base_level_multiple_() * config_.connectivity;
|
|
1446
1455
|
result.max_edges = result.nodes * max_edges_per_node;
|
|
1447
1456
|
return result;
|
|
1448
1457
|
}
|
|
1449
1458
|
|
|
1459
|
+
/**
|
|
1460
|
+
* @brief A relatively accurate lower bound on the amount of memory consumed by the system.
|
|
1461
|
+
* In practice it's error will be below 10%.
|
|
1462
|
+
*/
|
|
1463
|
+
std::size_t memory_usage(std::size_t allocator_entry_bytes = default_allocator_entry_bytes()) const noexcept {
|
|
1464
|
+
std::size_t total = 0;
|
|
1465
|
+
if (viewed_file_descriptor_ == 0) {
|
|
1466
|
+
stats_t s = stats();
|
|
1467
|
+
total += s.allocated_bytes;
|
|
1468
|
+
total += s.nodes * allocator_entry_bytes;
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1471
|
+
// Temporary data-structures, proportional to the number of nodes:
|
|
1472
|
+
total += nodes_.capacity() * sizeof(node_t) + allocator_entry_bytes;
|
|
1473
|
+
|
|
1474
|
+
// Temporary data-structures, proportional to the number of threads:
|
|
1475
|
+
std::size_t per_thread = (std::max)(config_.expansion_search, config_.expansion_add) * sizeof(candidate_t);
|
|
1476
|
+
total += thread_contexts_.capacity() * (sizeof(thread_context_t) + per_thread) + allocator_entry_bytes * 3;
|
|
1477
|
+
return total;
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
void change_expansion_add(std::size_t n) noexcept { config_.expansion_add = n; }
|
|
1481
|
+
void change_expansion_search(std::size_t n) noexcept { config_.expansion_search = n; }
|
|
1482
|
+
|
|
1450
1483
|
#pragma endregion
|
|
1451
1484
|
|
|
1452
1485
|
#pragma region Serialization
|
package/package.json
CHANGED
package/python/lib.cpp
CHANGED
|
@@ -405,6 +405,9 @@ template <typename index_at> void save_index(index_at const& index, std::string
|
|
|
405
405
|
template <typename index_at> void load_index(index_at& index, std::string const& path) { index.load(path.c_str()); }
|
|
406
406
|
template <typename index_at> void view_index(index_at& index, std::string const& path) { index.view(path.c_str()); }
|
|
407
407
|
template <typename index_at> void clear_index(index_at& index) { index.clear(); }
|
|
408
|
+
template <typename index_at> std::size_t get_expansion_add(index_at const &index) { return index.config().expansion_add; }
|
|
409
|
+
template <typename index_at> std::size_t get_expansion_search(index_at const &index) { return index.config().expansion_search; }
|
|
410
|
+
|
|
408
411
|
// clang-format on
|
|
409
412
|
|
|
410
413
|
template <typename element_at> bool has_duplicates(element_at const* begin, element_at const* end) {
|
|
@@ -522,6 +525,10 @@ PYBIND11_MODULE(index, m) {
|
|
|
522
525
|
i.def_property_readonly("capacity", &punned_py_t::capacity);
|
|
523
526
|
i.def_property_readonly( //
|
|
524
527
|
"dtype", [](punned_py_t const& index) -> std::string { return accuracy_name(index.accuracy()); });
|
|
528
|
+
i.def_property_readonly("memory_usage", &punned_py_t::memory_usage);
|
|
529
|
+
|
|
530
|
+
i.def_property("expansion_add", &get_expansion_add<punned_py_t>, &punned_py_t::change_expansion_add);
|
|
531
|
+
i.def_property("expansion_search", &get_expansion_search<punned_py_t>, &punned_py_t::change_expansion_search);
|
|
525
532
|
|
|
526
533
|
i.def("save", &save_index<punned_py_t>, py::arg("path"));
|
|
527
534
|
i.def("load", &load_index<punned_py_t>, py::arg("path"));
|
package/src/punned.hpp
CHANGED
|
@@ -455,6 +455,8 @@ class punned_gt {
|
|
|
455
455
|
std::size_t capacity() const { return typed_->capacity(); }
|
|
456
456
|
config_t const& config() const { return typed_->config(); }
|
|
457
457
|
void clear() { return typed_->clear(); }
|
|
458
|
+
void change_expansion_add(std::size_t n) noexcept { typed_->change_expansion_add(n); }
|
|
459
|
+
void change_expansion_search(std::size_t n) noexcept { typed_->change_expansion_search(n); }
|
|
458
460
|
|
|
459
461
|
member_citerator_t cbegin() const noexcept { return typed_->cbegin(); }
|
|
460
462
|
member_citerator_t cend() const noexcept { return typed_->cend(); }
|
|
@@ -474,6 +476,10 @@ class punned_gt {
|
|
|
474
476
|
void view(char const* path) { typed_->view(path); }
|
|
475
477
|
void reserve(std::size_t capacity) { typed_->reserve(capacity); }
|
|
476
478
|
|
|
479
|
+
std::size_t memory_usage(std::size_t allocator_entry_bytes = default_allocator_entry_bytes()) const noexcept {
|
|
480
|
+
return typed_->memory_usage(allocator_entry_bytes);
|
|
481
|
+
}
|
|
482
|
+
|
|
477
483
|
// clang-format off
|
|
478
484
|
add_result_t add(label_t label, f8_bits_t const* vector) { return add_(label, vector, casts_.from_f8); }
|
|
479
485
|
add_result_t add(label_t label, f16_bits_t const* vector) { return add_(label, vector, casts_.from_f16); }
|
package/src/test.cpp
CHANGED
|
@@ -65,6 +65,9 @@ template <typename scalar_at, typename index_at> void test3d(index_at&& index) {
|
|
|
65
65
|
assert(matched_count == 3);
|
|
66
66
|
assert(matched_labels[0] == 42);
|
|
67
67
|
assert(std::abs(matched_distances[0]) < 0.01);
|
|
68
|
+
|
|
69
|
+
assert(index.memory_usage() > 0);
|
|
70
|
+
assert(index.stats().max_edges > 0);
|
|
68
71
|
}
|
|
69
72
|
|
|
70
73
|
int main(int, char**) {
|