From 0a733a1ea81167df8ed31d946bd8b7b432e89086 Mon Sep 17 00:00:00 2001 From: cpegeric Date: Wed, 29 Oct 2025 13:21:07 +0000 Subject: [PATCH 1/9] acorn-1 --- include/usearch/index.hpp | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/include/usearch/index.hpp b/include/usearch/index.hpp index 73c70755b..d5399ef76 100644 --- a/include/usearch/index.hpp +++ b/include/usearch/index.hpp @@ -4239,6 +4239,34 @@ class index_gt { radius = top.top().distance; } } + } + + // predicate exists and explore 2-hop neighbors (ACORN-1) + if (!is_dummy()) { + for (compressed_slot_t successor_slot : candidate_neighbors) { + neighbors_ref_t hop2_candidate_neighbors = neighbors_base_(node_at_(successor_slot)); + + // Assume the worst-case when reserving memory + if (!visits.reserve(visits.size() + hop2_candidate_neighbors.size())) + return false; + + for (compressed_slot_t hop2_successor_slot : hop2_candidate_neighbors) { + + if (visits.set(hop2_successor_slot)) + continue; + + distance_t hop2_successor_dist = context.measure(query, citerator_at(hop2_successor_slot), metric); + if (top.size() < top_limit || hop2_successor_dist < radius) { + // This can substantially grow our priority queue: + next.insert({-hop2_successor_dist, hop2_successor_slot}); + if (is_dummy() || + predicate(member_cref_t{node_at_(hop2_successor_slot).ckey(), hop2_successor_slot})) { + top.insert({hop2_successor_dist, hop2_successor_slot}, top_limit); + radius = top.top().distance; + } + } + } + } } } From 27e8554e8ffe8961dbed12e6978063b98f68e48e Mon Sep 17 00:00:00 2001 From: cpegeric Date: Wed, 29 Oct 2025 13:23:41 +0000 Subject: [PATCH 2/9] update --- include/usearch/index.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/usearch/index.hpp b/include/usearch/index.hpp index d5399ef76..2b57535b9 100644 --- a/include/usearch/index.hpp +++ b/include/usearch/index.hpp @@ -4239,7 +4239,7 @@ class index_gt { radius = top.top().distance; } } - } + } // predicate exists and explore 2-hop neighbors (ACORN-1) if (!is_dummy()) { @@ -4266,7 +4266,7 @@ class index_gt { } } } - } + } } } From 9b317d947bde68992401079ea2ec5c63425fd1da Mon Sep 17 00:00:00 2001 From: cpegeric Date: Wed, 29 Oct 2025 13:24:33 +0000 Subject: [PATCH 3/9] update --- include/usearch/index.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/usearch/index.hpp b/include/usearch/index.hpp index 2b57535b9..31ca0a643 100644 --- a/include/usearch/index.hpp +++ b/include/usearch/index.hpp @@ -4265,7 +4265,7 @@ class index_gt { radius = top.top().distance; } } - } + } } } } From 92d5e78e3e2ccec14667847f82ede640b413e340 Mon Sep 17 00:00:00 2001 From: cpegeric Date: Wed, 29 Oct 2025 13:40:02 +0000 Subject: [PATCH 4/9] fmt --- include/usearch/index.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/usearch/index.hpp b/include/usearch/index.hpp index 31ca0a643..274187496 100644 --- a/include/usearch/index.hpp +++ b/include/usearch/index.hpp @@ -4253,7 +4253,7 @@ class index_gt { for (compressed_slot_t hop2_successor_slot : hop2_candidate_neighbors) { if (visits.set(hop2_successor_slot)) - continue; + continue; distance_t hop2_successor_dist = context.measure(query, citerator_at(hop2_successor_slot), metric); if (top.size() < top_limit || hop2_successor_dist < radius) { From 4226ecb12bd8bc73a201617eccb0cc2b2c4619fb Mon Sep 17 00:00:00 2001 From: cpegeric Date: Wed, 29 Oct 2025 13:54:26 +0000 Subject: [PATCH 5/9] prefetch --- include/usearch/index.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/usearch/index.hpp b/include/usearch/index.hpp index 274187496..0c75e9296 100644 --- a/include/usearch/index.hpp +++ b/include/usearch/index.hpp @@ -4246,6 +4246,12 @@ class index_gt { for (compressed_slot_t successor_slot : candidate_neighbors) { neighbors_ref_t hop2_candidate_neighbors = neighbors_base_(node_at_(successor_slot)); + // Optional prefetching + if (!is_dummy()) { + candidates_range_t missing_candidates{*this, hop2_candidate_neighbors, visits}; + prefetch(missing_candidates.begin(), missing_candidates.end()); + } + // Assume the worst-case when reserving memory if (!visits.reserve(visits.size() + hop2_candidate_neighbors.size())) return false; From 5afdae1b64b2d8b170a93b3ab8ccfd38685e46c8 Mon Sep 17 00:00:00 2001 From: eric Date: Wed, 29 Oct 2025 16:35:57 +0000 Subject: [PATCH 6/9] update --- include/usearch/index.hpp | 100 ++++++++++++++++++++++++++------------ 1 file changed, 68 insertions(+), 32 deletions(-) diff --git a/include/usearch/index.hpp b/include/usearch/index.hpp index 0c75e9296..74568a585 100644 --- a/include/usearch/index.hpp +++ b/include/usearch/index.hpp @@ -4213,36 +4213,70 @@ class index_gt { next.pop(); context.iteration_cycles++; - neighbors_ref_t candidate_neighbors = neighbors_base_(node_at_(candidate.slot)); + if (is_dummy()) { - // Optional prefetching - if (!is_dummy()) { - candidates_range_t missing_candidates{*this, candidate_neighbors, visits}; - prefetch(missing_candidates.begin(), missing_candidates.end()); - } + neighbors_ref_t candidate_neighbors = neighbors_base_(node_at_(candidate.slot)); - // Assume the worst-case when reserving memory - if (!visits.reserve(visits.size() + candidate_neighbors.size())) - return false; + // Optional prefetching + if (!is_dummy()) { + candidates_range_t missing_candidates{*this, candidate_neighbors, visits}; + prefetch(missing_candidates.begin(), missing_candidates.end()); + } - for (compressed_slot_t successor_slot : candidate_neighbors) { - if (visits.set(successor_slot)) - continue; + // Assume the worst-case when reserving memory + if (!visits.reserve(visits.size() + candidate_neighbors.size())) + return false; - distance_t successor_dist = context.measure(query, citerator_at(successor_slot), metric); - if (top.size() < top_limit || successor_dist < radius) { - // This can substantially grow our priority queue: - next.insert({-successor_dist, successor_slot}); - if (is_dummy() || - predicate(member_cref_t{node_at_(successor_slot).ckey(), successor_slot})) { - top.insert({successor_dist, successor_slot}, top_limit); - radius = top.top().distance; + for (compressed_slot_t successor_slot : candidate_neighbors) { + if (visits.set(successor_slot)) + continue; + + distance_t successor_dist = context.measure(query, citerator_at(successor_slot), metric); + if (top.size() < top_limit || successor_dist < radius) { + // This can substantially grow our priority queue: + next.insert({-successor_dist, successor_slot}); + if (is_dummy() || + predicate(member_cref_t{node_at_(successor_slot).ckey(), successor_slot})) { + top.insert({successor_dist, successor_slot}, top_limit); + radius = top.top().distance; + } } } - } - // predicate exists and explore 2-hop neighbors (ACORN-1) - if (!is_dummy()) { + } else { + // ACORN-1 + + // explore 1-hop neighbors + neighbors_ref_t candidate_neighbors = neighbors_base_(node_at_(candidate.slot)); + + // Optional prefetching + if (!is_dummy()) { + candidates_range_t missing_candidates{*this, candidate_neighbors, visits}; + prefetch(missing_candidates.begin(), missing_candidates.end()); + } + + // Assume the worst-case when reserving memory + if (!visits.reserve(visits.size() + candidate_neighbors.size())) + return false; + + for (compressed_slot_t successor_slot : candidate_neighbors) { + if (visits.set(successor_slot)) + continue; + + if (predicate(member_cref_t{node_at_(successor_slot).ckey(), successor_slot})) { + distance_t successor_dist = context.measure(query, citerator_at(successor_slot), metric); + if (top.size() < top_limit || successor_dist < radius) { + // This can substantially grow our priority queue: + next.insert({-successor_dist, successor_slot}); + + top.insert({successor_dist, successor_slot}, top_limit); + radius = top.top().distance; + } + } + } + + + // explore 2-hop neighbors for (compressed_slot_t successor_slot : candidate_neighbors) { neighbors_ref_t hop2_candidate_neighbors = neighbors_base_(node_at_(successor_slot)); @@ -4261,19 +4295,21 @@ class index_gt { if (visits.set(hop2_successor_slot)) continue; - distance_t hop2_successor_dist = context.measure(query, citerator_at(hop2_successor_slot), metric); - if (top.size() < top_limit || hop2_successor_dist < radius) { - // This can substantially grow our priority queue: - next.insert({-hop2_successor_dist, hop2_successor_slot}); - if (is_dummy() || - predicate(member_cref_t{node_at_(hop2_successor_slot).ckey(), hop2_successor_slot})) { - top.insert({hop2_successor_dist, hop2_successor_slot}, top_limit); - radius = top.top().distance; + if (predicate(member_cref_t{node_at_(hop2_successor_slot).ckey(), hop2_successor_slot})) { + distance_t hop2_successor_dist = + context.measure(query, citerator_at(hop2_successor_slot), metric); + if (top.size() < top_limit || hop2_successor_dist < radius) { + // This can substantially grow our priority queue: + next.insert({-hop2_successor_dist, hop2_successor_slot}); + + top.insert({hop2_successor_dist, hop2_successor_slot}, top_limit); + radius = top.top().distance; } } } } - } + } + } return true; From 1eaff9056b97acdc2341d8227a25f91ad7862ba3 Mon Sep 17 00:00:00 2001 From: cpegeric Date: Wed, 29 Oct 2025 16:44:57 +0000 Subject: [PATCH 7/9] fmt --- include/usearch/index.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/usearch/index.hpp b/include/usearch/index.hpp index 74568a585..ffd3c6c0b 100644 --- a/include/usearch/index.hpp +++ b/include/usearch/index.hpp @@ -4308,8 +4308,7 @@ class index_gt { } } } - } - + } } return true; From 55c7961eccfb8724f6e37fe4da7c2e092679acee Mon Sep 17 00:00:00 2001 From: cpegeric Date: Wed, 29 Oct 2025 23:36:26 +0000 Subject: [PATCH 8/9] Fix: remove 2-hop-neighbour visit --- include/usearch/index.hpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/usearch/index.hpp b/include/usearch/index.hpp index ffd3c6c0b..f15a53970 100644 --- a/include/usearch/index.hpp +++ b/include/usearch/index.hpp @@ -4292,9 +4292,6 @@ class index_gt { for (compressed_slot_t hop2_successor_slot : hop2_candidate_neighbors) { - if (visits.set(hop2_successor_slot)) - continue; - if (predicate(member_cref_t{node_at_(hop2_successor_slot).ckey(), hop2_successor_slot})) { distance_t hop2_successor_dist = context.measure(query, citerator_at(hop2_successor_slot), metric); From 12cde8b2dfa4b57471631db4b5c3c8babcab04a1 Mon Sep 17 00:00:00 2001 From: cpegeric Date: Wed, 29 Oct 2025 23:43:58 +0000 Subject: [PATCH 9/9] Revert "Fix: remove 2-hop-neighbour visit" This reverts commit 55c7961eccfb8724f6e37fe4da7c2e092679acee. --- include/usearch/index.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/usearch/index.hpp b/include/usearch/index.hpp index f15a53970..ffd3c6c0b 100644 --- a/include/usearch/index.hpp +++ b/include/usearch/index.hpp @@ -4292,6 +4292,9 @@ class index_gt { for (compressed_slot_t hop2_successor_slot : hop2_candidate_neighbors) { + if (visits.set(hop2_successor_slot)) + continue; + if (predicate(member_cref_t{node_at_(hop2_successor_slot).ckey(), hop2_successor_slot})) { distance_t hop2_successor_dist = context.measure(query, citerator_at(hop2_successor_slot), metric);