C · Refinement

Refinement

#include <usearch/dense_index.h>#include <usearch/geospatial_index.h>#include <usearch/sequence_index.h>#include <usearch/shapes_index.h>#include <usearch/types.h> 3.0.0-rc.1 · 4c3e5023

usearch_dense_refine re-selects the neighbors of every stored entry against the finished graph, improving those chosen while the graph around them was incomplete. A cheap insertion pass followed by one refinement reaches a better graph in less total time than one expensive pass, so a wide expansion_factor belongs here rather than in usearch_dense_insert. Re-selection is idempotent and claims no identity, so a cancelled pass leaves the graph correct and merely less improved, still re-links any entry no search would reach, and answers usearch_status_cancelled_k. The index keeps nothing of a stopped pass, so a caller looping until the graph settles calls again:

size_t changed = 0;
do {
    usearch_dense_refine(&(usearch_dense_refine_t) {.index = index,
                                                    .executor = executor,
                                                    .outcome = &outcome,
                                                    .changed = &changed,
                                                    .expansion_factor = 256});
} while (outcome.status == usearch_status_success_k && changed > 100);

Searches may run throughout on a RAM handle, while a VRAM handle rewrites neighbors in place and admits no overlapping search. Insertions never overlap a refinement: one running refuses it with usearch_status_contended_k, one arriving meanwhile is refused the same way and lands nothing, and so on VRAM is a save, which holds the handle the same way for its own duration. Nothing waits, so a service schedules refinements between its insertion bursts and retries a refused call.

A refinement that must continue where a cancel stopped is a handle the caller holds instead. usearch_dense_refinement_init opens it, optionally absorbing donors first, and the index refuses insertions and saves until it is finished. Each usearch_dense_refinement_next continues it on the executor it was opened with, holding that executor only for the call, and answers usearch_status_cancelled_k while more is left. It reports the running totals, the nodes re-selected so far, those whose neighbors changed, and the telemetry, so a caller stops calling once the changed share stops paying for another call. usearch_dense_refinement_finish re-links what a stopped pass leaves, reports, reopens the index and frees the handle.

§ Absorbing & Splitting

usearch_dense_absorb moves an array of donor handles into one index, one donor after another, keeping their graphs rather than re-inserting their vectors. Donors are consumed and nulled as they go, so the array itself says which handles the caller still owns and must free, and a cancel stops only the closing refinement, answering usearch_status_cancelled_k. Each donor’s shards append to the index’s as appended parts with their edges rebased, then a refinement of every shard that took one walks each of its nodes across into the other part from landmarks drawn there and re-selects it, so a group costs one such refinement per donor, and its heal re-selects from the landmarks every node no earlier one links to. A donor must share the index’s residency, scalar, class, metric and geometry, else the call answers usearch_status_config_mismatch_k, and an NVMe view answers usearch_status_read_only_k. An insertion running on the index or on the next donor refuses the call with usearch_status_contended_k, leaving that donor and the rest live, and an insertion into the index arriving meanwhile is refused the same way, while nothing may search a donor or start an insertion into it. A VRAM-built donor joins a RAM index through a save and a load.

usearch_dense_split is the inverse, emptying one index into count receivers, empty handles of its residency, scalar, class, metric, geometry and shard count. It grows one graph-local part per receiver from roots drawn from seed, breadth-first over the links and capped at an equal share, lands part p of shard s in shard s of receiver p with edges rebased and edges across parts dropped, and refines the nodes that lost an edge. usearch_dense_refinement_init takes receivers in place of donors for the resumable form, never both, refusing the pair with usearch_status_invalid_argument_k. RAM and NVIDIA and AMD VRAM indexes split, Apple and NVMe ones answer usearch_status_unsupported_k and usearch_status_read_only_k, and the stand-in partitions by brute force.

API

Types

usearch_dense_refinement_tOne refinement in flight, optionally absorbing donors or splitting into receivers first.
dense_index.h:219 ↗
typedef struct usearch_dense_refinement_handle_t * usearch_dense_refinement_t;

It holds everything the pass needs between calls, so a cancelled usearch_dense_refinement_next continues where it stopped, and nothing about it stays in the index once it finishes. The index admits no insertion and no save while the handle lives; searches proceed as during usearch_dense_refine. Each call names the index and the executor it was opened with.

usearch_geospatial_refinement_tOne refinement in flight, optionally absorbing donors or splitting into receivers first.
geospatial_index.h:106 ↗
typedef struct usearch_geospatial_refinement_handle_t * usearch_geospatial_refinement_t;

It holds everything the pass needs between calls, so a cancelled usearch_geospatial_refinement_next continues where it stopped, and nothing about it stays in the index once it finishes. The index admits no insertion and no save while the handle lives; searches proceed as during usearch_geospatial_refine. Each call names the index and the executor it was opened with.

usearch_sequence_refinement_tOne refinement in flight, optionally absorbing donors or splitting into receivers first.
sequence_index.h:87 ↗
typedef struct usearch_sequence_refinement_handle_t * usearch_sequence_refinement_t;

It holds everything the pass needs between calls, so a cancelled usearch_sequence_refinement_next continues where it stopped, and nothing about it stays in the index once it finishes. The index admits no insertion and no save while the handle lives; searches proceed as during usearch_sequence_refine. Each call names the index and the executor it was opened with.

usearch_shapes_refinement_tOne refinement in flight, optionally absorbing donors or splitting into receivers first.
shapes_index.h:134 ↗
typedef struct usearch_shapes_refinement_handle_t * usearch_shapes_refinement_t;

It holds everything the pass needs between calls, so a cancelled usearch_shapes_refinement_next continues where it stopped, and nothing about it stays in the index once it finishes. The index admits no insertion and no save while the handle lives; searches proceed as during usearch_shapes_refine. Each call names the index and the executor it was opened with.

usearch_refine_report_tWhat one refinement-family call did to the graph, counted alike in every modality and residency: refine, absorb, compact, split and refinement_finish land it.
types.h:749 ↗
struct usearch_refine_report_t

changed never exceeds reselected, and a pass over a settled graph changes nothing. A call that fails before its closing audit reports zeros; one its progress handler stopped still heals, so its report stands beside the usearch_status_cancelled_k it answers.

Fields

reselectedsize_tEntries whose neighbors were selected again: the planned entries, then the fresh entries of every later round, then the islands of every heal round.
changedsize_tOf those, the entries whose neighbor set gained a member it lacked; order never counts, nor does a back-link re-selecting an entry the pass did not.
islands_foundsize_tEntries the first audit found not reached both ways, counted once.
islands_reconnectedsize_tLinks written between an island and an entry the audit reached both ways, summed across the heal's audits.
reachabilityusearch_reachability_tThe audit closing the heal, as a fresh health call right after would take it.
usearch_refine_options_tHow a pass over the graph may spend, shared by every verb that refines.
types.h:771 ↗
struct usearch_refine_options_t

Fields

expansion_factorsize_tThe optional breadth of the candidates a re-selection walk explores; zero derives.
memory_limitsize_tThe optional bytes the pass may hold beyond the index; its tiles of rows are sized from them, and zero takes one storage chunk per tile, or on VRAM half of the free device bytes.

Functions

usearch_*_refine× 4Re-selects the neighbors of every stored entry against the finished graph, improving neighbors chosen when the graph around them was still incomplete.
dense_index.h:874 ↗
void usearch_dense_refine(usearch_dense_refine_t *arguments);
Symbolindex
usearch_dense_refineusearch_dense_index_t
usearch_geospatial_refineusearch_geospatial_index_t
usearch_sequence_refineusearch_sequence_index_t
usearch_shapes_refineusearch_shapes_index_t

This is a build step rather than a repair. A cheap insertion pass followed by one refinement reaches a better graph, in less total time, than a single expensive insertion pass - so a wide refine.expansion_factor belongs here rather than in usearch_dense_insert.

Cancelling is safe, which is what makes a whole-graph sweep affordable. Re-selecting a node's neighbors is idempotent and claims no identity, so a stopped pass leaves the graph correct and merely less improved: nothing unwinds, and the call answers usearch_status_cancelled_k. The index keeps nothing of a stopped pass, so the next call starts at the first entry again; a caller wanting to continue where a cancel stopped holds a usearch_dense_refinement_t instead. A caller loops until the report's changed falls below whatever change rate they consider settled.

Re-selection alone can leave an island, an entry no search reaches, so every call closes by re-linking them: unreachable entries re-select from scratch, and whatever the diversity judgment still drops is reconnected to a reachable one. A cancelled call skips the rest of the re-selection but still re-links, so it never leaves entries unreachable.

On a RAM handle searches may run throughout: re-selection publishes one node at a time and never removes a node, so a concurrent walk sees either the old neighbors or the new ones. On a VRAM handle the merge writes neighbors in place, so searches may not overlap. Insertions never overlap: one in flight refuses the call with usearch_status_contended_k, and one arriving meanwhile is refused the same way, as is a VRAM save. A viewed handle refuses with usearch_status_read_only_k, like every other mutating verb.

This is a build step rather than a repair. A cheap insertion pass followed by one refinement reaches a better graph, in less total time, than a single expensive insertion pass - so a wide refine.expansion_factor belongs here rather than in usearch_geospatial_insert. A refined entry keeps its cone winners and the longest of its other candidates, then has its long links drawn again by the insertion's rule, so a refine never leaves an entry without them.

Cancelling is safe, which is what makes a whole-graph sweep affordable. Re-selecting an entry's neighbors is idempotent and claims no identity, so a stopped pass leaves the graph correct and merely less improved: nothing unwinds, and the call answers usearch_status_cancelled_k. The index keeps nothing of a stopped pass, so the next call starts at the first entry again; a caller wanting to continue where a cancel stopped holds a usearch_geospatial_refinement_t instead.

Re-selection alone can leave an island, an entry no search reaches, so every call closes by re-linking them: unreachable entries re-select from scratch, and whatever the selection still drops is reconnected to a reachable one. A cancelled call skips the rest of the re-selection but still re-links, so it never leaves entries unreachable.

Searches may run throughout: re-selection rewrites one entry at a time and never removes one, so a concurrent walk sees either the old neighbors or the new ones. Insertions never overlap: one in flight refuses the call with usearch_status_contended_k, and one arriving meanwhile is refused the same way, as is a save.

This is a build step rather than a repair. A cheap insertion pass followed by one refinement reaches a better graph, in less total time, than a single expensive insertion pass - so a wide refine.expansion_factor belongs here rather than in usearch_sequence_insert. It pays most in this modality, where a single alignment is quadratic and a stingy insertion pass is tempting.

Cancelling is safe, which is what makes a whole-graph sweep affordable. Re-selecting an entry's neighbors is idempotent and claims no identity, so a stopped pass leaves the graph correct and merely less improved: nothing unwinds, and the call answers usearch_status_cancelled_k. The index keeps nothing of a stopped pass, so the next call starts at the first entry again; a caller wanting to continue where a cancel stopped holds a usearch_sequence_refinement_t instead.

Re-selection alone can leave an island, an entry no search reaches, so every call closes by re-linking them: unreachable entries re-select from scratch, and whatever the selection still drops is reconnected to a reachable one. A cancelled call skips the rest of the re-selection but still re-links, so it never leaves entries unreachable.

Searches may run throughout: re-selection rewrites one entry at a time and never removes one, so a concurrent walk sees either the old neighbors or the new ones. Insertions never overlap: one in flight refuses the call with usearch_status_contended_k, and one arriving meanwhile is refused the same way, as is a save.

This is a build step rather than a repair. A cheap insertion pass followed by one refinement reaches a better graph, in less total time, than a single expensive insertion pass - so a wide refine.expansion_factor belongs here rather than in usearch_shapes_insert. It pays most in this modality, where one comparison scores a whole shape against another.

Cancelling is safe, which is what makes a whole-graph sweep affordable. Re-selecting an entry's neighbors is idempotent and claims no identity, so a stopped pass leaves the graph correct and merely less improved: nothing unwinds, and the call answers usearch_status_cancelled_k. The index keeps nothing of a stopped pass, so the next call starts at the first entry again; a caller wanting to continue where a cancel stopped holds a usearch_shapes_refinement_t instead.

Re-selection alone can leave an island, an entry no search reaches, so every call closes by re-linking them: unreachable entries re-select from scratch, and whatever the selection still drops is reconnected to a reachable one. A cancelled call skips the rest of the re-selection but still re-links, so it never leaves entries unreachable.

Searches may run throughout: re-selection rewrites one entry at a time and never removes one, so a concurrent walk sees either the old neighbors or the new ones. Insertions never overlap: one in flight refuses the call with usearch_status_contended_k, and one arriving meanwhile is refused the same way, as is a save.

Parameters

indexusearch_dense_index_tThe handle to be refined.
executorusearch_executor_tThe executor to fan out over; its kind must match the residency.
outcomeusearch_outcome_t *Output for the outcome, final once its status leaves usearch_status_deferred_k.
completionusearch_completion_tBlocking, the default, or deferred.
reportusearch_refine_report_t *The optional output for what the call did to the graph, as usearch_refine_report_t counts it; NULL skips reporting.
refineusearch_refine_options_tThe optional breadth and bytes of the re-selection pass.
progressusearch_progress_tThe optional handler, called with nodes re-selected; a cancel stops the re-selection, still heals, and answers usearch_status_cancelled_k.
statsusearch_traversal_stats_t *The optional traversal telemetry; NULL skips reporting.

Statuses

usearch_dense_absorbAbsorbs every handle in donors into index, one after another, keeping their graphs rather than re-inserting their vectors and linking each in by walks across.
dense_index.h:1199 ↗
void usearch_dense_absorb(usearch_dense_absorb_t *arguments);

Donor handles are consumed and must not be used afterwards, not even for usearch_dense_free.

The donors land one after another, each all-or-nothing: its entries append to index shard by shard with their edges rebased, publish at once, and the donor is consumed, so at most one donor's entries are ever held twice. One refinement then walks every shard across the parts the donors appended, round by round, so a group of donors costs one refinement rather than one per donor. Readers of a RAM index may keep searching throughout, since unpublished entries hide behind the watermark, while a VRAM one rewrites neighbors in place and admits no overlapping search, as refinement does. Insertions into index or into a donor arriving meanwhile are refused with usearch_status_contended_k, while searches of a donor run throughout.

A failure leaves the donor it struck and every later one as live handles the caller still owns and must free, and index holding the donors before it; every consumed slot is nulled, so the array itself says which handles survived. The handler reports and cancels the closing refinement alone, exactly as in usearch_dense_refine: a cancel skips the rest of the walks across, still re-links, and answers usearch_status_cancelled_k with every donor consumed. A caller wanting to continue those walks later holds a usearch_dense_refinement_t instead.

usearch_dense_index_t shards[4] = {built_on_socket_0, built_on_socket_1, built_on_socket_2, built_on_socket_3};
usearch_outcome_t outcome = {0};
usearch_dense_absorb(&(usearch_dense_absorb_t){
    .index = index, .executor = executor, .outcome = &outcome, .count = 4, .donors = shards,
    .progress = {report_to_terminal, &ui, 4}});
// Every entry of `shards` is consumed here; none of them may be freed afterwards.

Parameters

indexusearch_dense_index_tThe handle absorbing the donors.
executorusearch_executor_tThe executor each donor's move and the closing refinement fan out over.
outcomeusearch_outcome_t *Output for the outcome, final once its status leaves usearch_status_deferred_k.
completionusearch_completion_tBlocking, the default, or deferred.
countsize_tDonor handles to absorb.
donorsusearch_dense_index_t *Array of count handles, each consumed and nulled once its entries are published here.
reportusearch_refine_report_t *The optional output for what the call did to the graph, as usearch_refine_report_t counts it; NULL skips reporting.
refineusearch_refine_options_tThe optional breadth and bytes of the closing refine.
progressusearch_progress_tThe optional handler, called with the donor rows stitched so far out of every donor's; a cancel stops the stitching walks as it stops usearch_dense_refine, never a move.
statsusearch_traversal_stats_t *The optional traversal telemetry; NULL skips reporting.

Statuses

usearch_dense_compactCompacts every shard of the handles in sources into target under shard_capacity entries per shard, largest first, each into the first shard with room, so it ends with as few shards as fit; in place when target is among sources.
dense_index.h:1267 ↗
void usearch_dense_compact(usearch_dense_compact_t *arguments);

The shard a bin keeps stays resident with its IDs, every other source shard follows it with its edges rebased and its keys beside it, and only the appended entries walk the target across the parts and link in, then each target shard re-links the islands that leaves, as usearch_dense_refine does. In place, a moved entry's key moves with one atomic store, so lookups and searches of target run throughout and emptied shards stay as idle slots for its next generation. Once the call moved every source, each one but target is freed and nulled, as usearch_dense_absorb frees its donors; a failure frees none, those it consumed left empty and refusing insertions, so every handle in sources stays the caller's to free.

Parameters

targetusearch_dense_index_tThe handle the sources compact into, possibly one of them.
executorusearch_executor_tThe executor every move and the closing refinement fan out over.
outcomeusearch_outcome_t *Output for the outcome, final once its status leaves usearch_status_deferred_k.
completionusearch_completion_tBlocking, the default, or deferred.
countsize_tSource handles to compact.
sourcesusearch_dense_index_t *Array of count distinct handles; each but target is freed and nulled once every source moved.
shard_capacitysize_tThe optional most entries one target shard holds; zero, or more than the target's own bound, means that bound.
refineusearch_refine_options_tThe optional breadth and bytes of the closing refine.
reportusearch_refine_report_t *The optional output for what the call did to the graph, as usearch_refine_report_t counts it; NULL skips reporting.
progressusearch_progress_tThe optional handler, called with nodes the closing refine re-selected; a cancel stops it as it stops usearch_dense_refine, never a move.
statsusearch_traversal_stats_t *The optional traversal telemetry; NULL skips reporting.

Statuses

usearch_dense_splitSplits index into the handles in receivers, the inverse of usearch_dense_absorb: graph-local parts keeping their edges rather than re-inserting their vectors, one part per receiver, and index left empty but live.
dense_index.h:1341 ↗
void usearch_dense_split(usearch_dense_split_t *arguments);

Every receiver is checked and held before the first part moves, so a refusal moves nothing. The part roots are drawn from seed without a scan, and each part grows breadth-first over the links from its root, capped at an equal share of the entries, while entries no root reaches enter the smallest part. A sharded handle splits shard by shard, part p of shard s moving into shard s of receiver p. Each part then enters its receiver all-or-nothing, its edges rebased, its edges into other parts dropped, and the entries that lost one placed first; index clears once every part moved. Each receiver closes by re-selecting the entries that lost an edge and re-linking the islands that leaves, as usearch_dense_refine does. Meanwhile, insertions into index or a receiver are refused with usearch_status_contended_k, while searches of either run throughout.

The handler reports and cancels the closing refinements alone, exactly as in usearch_dense_refine: a cancel skips the rest of the re-selection, still re-links, and answers usearch_status_cancelled_k with every part moved. A caller wanting to continue that re-selection later holds a usearch_dense_refinement_t opened with receivers instead.

Parameters

indexusearch_dense_index_tThe handle split into the receivers, left empty and live.
executorusearch_executor_tThe executor the partition, each part's move and the closing refinements fan out over.
outcomeusearch_outcome_t *Output for the outcome, final once its status leaves usearch_status_deferred_k.
completionusearch_completion_tBlocking, the default, or deferred.
countsize_tReceiver handles to split into, at least two.
receiversusearch_dense_index_t const *Array of count empty handles of the source's residency, scalar, class, metric, geometry and shard count, each receiving one part.
reportusearch_refine_report_t *The optional output for what the call did to the graph, as usearch_refine_report_t counts it; NULL skips reporting.
refineusearch_refine_options_tThe optional breadth and bytes of the closing refines.
seeduint64_tPicks the part roots: equal seeds over an unchanged index split equally.
progressusearch_progress_tThe optional handler, called with nodes the closing refines re-selected; a cancel stops them as it stops usearch_dense_refine, never a move.
statsusearch_traversal_stats_t *The optional traversal telemetry; NULL skips reporting.

Statuses

usearch_dense_refinement_initOpens a refinement of index, absorbing donors first when any are named, as usearch_dense_absorb moves them, or splitting it into receivers, as usearch_dense_split fills them.
dense_index.h:1400 ↗
void usearch_dense_refinement_init(
    usearch_dense_refinement_init_t *arguments);

Every allocation the refinement needs happens here or in a move, never in a step.

Parameters

indexusearch_dense_index_tThe handle to be refined.
executorusearch_executor_tThe executor every call on the refinement runs on; its kind must match the residency.
outcomeusearch_outcome_t *Output for the outcome, final once its status leaves usearch_status_deferred_k.
completionusearch_completion_tBlocking, the default, or deferred.
donorsusearch_dense_index_t *The optional donors to absorb first, each consumed and nulled once its entries land; the array must outlive the refinement.
countsize_tDonor handles in donors.
receiversusearch_dense_index_t const *The optional receivers to split index into first, as usearch_dense_split fills them, each refined in turn; the array must outlive the refinement.
receivers_countsize_tReceiver handles in receivers, zero or at least two.
refinementusearch_dense_refinement_t *Output for the new handle; NULL on failure.
refineusearch_refine_options_tThe optional breadth and bytes of every pass the refinement steps.
seeduint64_tPicks the part roots when receivers are named, as in usearch_dense_split.

Statuses

usearch_*_refinement_next× 4Continues the refinement until it ends or progress cancels, moving any donors still pending first.
dense_index.h:1448 ↗
void usearch_dense_refinement_next(
    usearch_dense_refinement_next_t *arguments);
Symbolindexrefinement
usearch_dense_refinement_nextusearch_dense_index_tusearch_dense_refinement_t
usearch_geospatial_refinement_nextusearch_geospatial_index_tusearch_geospatial_refinement_t
usearch_sequence_refinement_nextusearch_sequence_index_tusearch_sequence_refinement_t
usearch_shapes_refinement_nextusearch_shapes_index_tusearch_shapes_refinement_t

Answers usearch_status_cancelled_k when a later call has more to do; that call continues exactly where this one stopped. The executor is held only for the call.

Every call reaching the refinement writes the running totals, a cancelled or failed one too, so they only grow from one call to the next and changed never exceeds reselected; all stay zero while donors are pending.

Parameters

indexusearch_dense_index_tThe handle the refinement was opened on.
executorusearch_executor_tThe executor the refinement was opened with.
outcomeusearch_outcome_t *Output for the outcome, final once its status leaves usearch_status_deferred_k.
completionusearch_completion_tBlocking, the default, or deferred.
refinementusearch_dense_refinement_tThe refinement to continue.
progressusearch_progress_tThe optional handler, called with nodes re-selected across every call so far.
reselectedsize_t *The optional outputs for the nodes re-selected so far and, of those, the ones whose neighbors changed; their ratio falling is what says another call buys little.
statsusearch_traversal_stats_t *The optional traversal telemetry of every call on the refinement so far; NULL skips reporting.

Statuses

usearch_dense_refinement_finishSkips whatever re-selection a stopped refinement left, re-links the islands it leaves as usearch_dense_refine does, reports, reopens the index, and frees the handle.
dense_index.h:1486 ↗
void usearch_dense_refinement_finish(
    usearch_dense_refinement_finish_t *arguments);

A refinement whose donors have not all moved re-links nothing and reports zeros.

Parameters

indexusearch_dense_index_tThe handle the refinement was opened on.
executorusearch_executor_tThe executor the refinement was opened with.
outcomeusearch_outcome_t *Output for the outcome, final once its status leaves usearch_status_deferred_k.
completionusearch_completion_tBlocking, the default, or deferred.
refinementusearch_dense_refinement_tThe refinement to finish; freed by the call, whatever it answers.
reportusearch_refine_report_t *The optional output for what the call did to the graph, as usearch_refine_report_t counts it; NULL skips reporting.
statsusearch_traversal_stats_t *The optional traversal telemetry of every call on the refinement; NULL skips reporting.

Statuses

usearch_geospatial_absorbAbsorbs every handle in donors into index, one after another, keeping their graphs rather than re-inserting their observations, and links each in by walks across.
geospatial_index.h:1171 ↗
void usearch_geospatial_absorb(usearch_geospatial_absorb_t *arguments);

A consumed donor handle must not be used afterwards, not even for usearch_geospatial_free.

Every donor is checked and held before the first one enters, so a refusal consumes none. The donors then enter one after another, each all-or-nothing: its entries append to index with their edges rebased, publish at once, and the donor is consumed, so at most one donor's entries are ever held twice. One refinement then walks every entry across the parts the donors appended, round by round, so a group of donors costs one refinement rather than one per donor. Readers of index may keep searching throughout, since unpublished entries hide behind the watermark, while nothing may search a donor. Insertions into index arriving meanwhile are refused with usearch_status_contended_k. A donor's terrain stays with it: the observations already carry the ground they were inserted over.

The handler reports and cancels the closing refinement alone, exactly as in usearch_geospatial_refine: a cancel skips the rest of the walks across, still re-links, and answers usearch_status_cancelled_k with every donor consumed. A caller wanting to continue those walks later holds a usearch_geospatial_refinement_t instead.

Parameters

indexusearch_geospatial_index_tThe handle absorbing the donors.
executorusearch_executor_tThe executor each donor's move and the closing refinement fan out over.
outcomeusearch_outcome_t *Output for the outcome, final once its status leaves usearch_status_deferred_k.
completionusearch_completion_tBlocking, the default, or deferred.
countsize_tDonor handles to absorb.
donorsusearch_geospatial_index_t *Array of count handles, each consumed and nulled once its entries are published here.
reportusearch_refine_report_t *The optional output for what the call did to the graph, as usearch_refine_report_t counts it; NULL skips reporting.
refineusearch_refine_options_tThe optional breadth and bytes of the closing refine.
progressusearch_progress_tThe optional handler, called with the donor rows stitched so far out of every donor's; a cancel stops the stitching walks as it stops usearch_geospatial_refine, never a move.
statsusearch_traversal_stats_t *The optional traversal telemetry; NULL skips reporting.

Statuses

usearch_geospatial_splitSplits index into the handles in receivers, the inverse of usearch_geospatial_absorb: graph-local parts keeping their edges rather than re-inserting their observations, one part per receiver, and index left empty but live.
geospatial_index.h:1246 ↗
void usearch_geospatial_split(usearch_geospatial_split_t *arguments);

Every receiver is checked and held before the first part moves, so a refusal moves nothing. The part roots are drawn from seed without a scan, and each part grows breadth-first over the links from its root, capped at an equal share of the entries, while entries no root reaches enter the smallest part. Each part then enters its receiver all-or-nothing, its edges rebased, its edges into other parts dropped, and the entries that lost one placed first; index clears once every part moved. Each receiver closes by re-selecting the entries that lost an edge and re-linking the islands that leaves, as usearch_geospatial_refine does. Insertions into index or a receiver arriving meanwhile are refused with usearch_status_contended_k, and nothing may search either until the call is final. A receiver keeps its own terrain: the observations already carry the ground they were inserted over.

The handler reports and cancels the closing refinements alone, exactly as in usearch_geospatial_refine: a cancel skips the rest of the re-selection, still re-links, and answers usearch_status_cancelled_k with every part moved. A caller wanting to continue that re-selection later holds a usearch_geospatial_refinement_t opened with receivers instead.

Parameters

indexusearch_geospatial_index_tThe handle split into the receivers, left empty and live.
executorusearch_executor_tThe executor the partition, each part's move and the closing refinements fan out over.
outcomeusearch_outcome_t *Output for the outcome, final once its status leaves usearch_status_deferred_k.
completionusearch_completion_tBlocking, the default, or deferred.
countsize_tReceiver handles to split into, at least two.
receiversusearch_geospatial_index_t const *Array of count empty handles of the source's residency, class and connectivity, each receiving one part.
reportusearch_refine_report_t *The optional output for what the call did to the graph, as usearch_refine_report_t counts it; NULL skips reporting.
refineusearch_refine_options_tThe optional breadth and bytes of the closing refines.
seeduint64_tPicks the part roots: equal seeds over an unchanged index split equally.
progressusearch_progress_tThe optional handler, called with entries the closing refines re-selected; a cancel stops them as it stops usearch_geospatial_refine, never a move.
statsusearch_traversal_stats_t *The optional traversal telemetry; NULL skips reporting.

Statuses

usearch_geospatial_refinement_initOpens a refinement of index, absorbing donors first when any are named, as usearch_geospatial_absorb moves them, or splitting it into receivers, as usearch_geospatial_split fills them.
geospatial_index.h:1305 ↗
void usearch_geospatial_refinement_init(
    usearch_geospatial_refinement_init_t *arguments);

Every allocation the refinement needs in the index happens here, never in a step.

Parameters

indexusearch_geospatial_index_tThe handle to be refined.
executorusearch_executor_tThe executor every call on the refinement runs on; its kind must match the residency.
outcomeusearch_outcome_t *Output for the outcome, final once its status leaves usearch_status_deferred_k.
completionusearch_completion_tBlocking, the default, or deferred.
donorsusearch_geospatial_index_t *The optional donors to absorb first, each consumed and nulled once its entries land; the array must outlive the refinement.
countsize_tDonor handles in donors.
receiversusearch_geospatial_index_t const *The optional receivers to split index into first, as usearch_geospatial_split fills them, each refined in turn; the array must outlive the refinement.
receivers_countsize_tReceiver handles in receivers, zero or at least two.
refinementusearch_geospatial_refinement_t *Output for the new handle; NULL on failure.
refineusearch_refine_options_tThe optional breadth and bytes of every pass the refinement steps.
seeduint64_tPicks the part roots when receivers are named, as in usearch_geospatial_split.

Statuses

usearch_geospatial_refinement_finishSkips whatever re-selection a stopped refinement left, re-links the islands it leaves as usearch_geospatial_refine does, reports, reopens the index, and frees the handle.
geospatial_index.h:1389 ↗
void usearch_geospatial_refinement_finish(
    usearch_geospatial_refinement_finish_t *arguments);

A refinement whose donors have not all moved re-links nothing and reports zeros.

Parameters

indexusearch_geospatial_index_tThe handle the refinement was opened on.
executorusearch_executor_tThe executor the refinement was opened with.
outcomeusearch_outcome_t *Output for the outcome, final once its status leaves usearch_status_deferred_k.
completionusearch_completion_tBlocking, the default, or deferred.
refinementusearch_geospatial_refinement_tThe refinement to finish; freed by the call, whatever it answers.
reportusearch_refine_report_t *The optional output for what the call did to the graph, as usearch_refine_report_t counts it; NULL skips reporting.
statsusearch_traversal_stats_t *The optional traversal telemetry of every call on the refinement; NULL skips reporting.

Statuses

usearch_sequence_absorbAbsorbs every handle in donors into index, one after another, keeping their graphs rather than re-inserting their sequences, and links each in by walks across.
sequence_index.h:1061 ↗
void usearch_sequence_absorb(usearch_sequence_absorb_t *arguments);

Donor handles are consumed and must not be used afterwards, not even for usearch_sequence_free.

Every donor is checked and held before the first one enters, so a refusal consumes none. The donors then enter one after another, each all-or-nothing: its entries append to index with their edges rebased, publish at once, and the donor is consumed, so at most one donor's entries are ever held twice. One refinement then walks every entry across the parts the donors appended, round by round, so a group of donors costs one refinement rather than one per donor. Readers of index may keep searching throughout, since unpublished entries hide behind the watermark, while nothing may search a donor. Insertions into index arriving meanwhile are refused with usearch_status_contended_k.

The handler reports and cancels the closing refinement alone, exactly as in usearch_sequence_refine: a cancel skips the rest of the walks across, still re-links, and answers usearch_status_cancelled_k with every donor consumed. A caller wanting to continue those walks later holds a usearch_sequence_refinement_t instead.

Parameters

indexusearch_sequence_index_tThe handle absorbing the donors.
executorusearch_executor_tThe executor each donor's move and the closing refinement fan out over.
outcomeusearch_outcome_t *Output for the outcome, final once its status leaves usearch_status_deferred_k.
completionusearch_completion_tBlocking, the default, or deferred.
countsize_tDonor handles to absorb.
donorsusearch_sequence_index_t *Array of count handles, each consumed and nulled once its entries are published here.
reportusearch_refine_report_t *The optional output for what the call did to the graph, as usearch_refine_report_t counts it; NULL skips reporting.
refineusearch_refine_options_tThe optional breadth and bytes of the closing refine.
progressusearch_progress_tThe optional handler, called with the donor rows stitched so far out of every donor's; a cancel stops the stitching walks as it stops usearch_sequence_refine, never a move.
statsusearch_traversal_stats_t *The optional traversal telemetry; NULL skips reporting.

Statuses

usearch_sequence_splitSplits index into the handles in receivers, the inverse of usearch_sequence_absorb: graph-local parts keeping their edges rather than re-inserting their sequences, one part per receiver, and index left empty but live.
sequence_index.h:1135 ↗
void usearch_sequence_split(usearch_sequence_split_t *arguments);

Every receiver is checked and held before the first part moves, so a refusal moves nothing. The part roots are drawn from seed without a scan, and each part grows breadth-first over the links from its root, capped at an equal share of the entries, while entries no root reaches enter the smallest part. Each part then enters its receiver all-or-nothing, its edges rebased, its edges into other parts dropped, and the entries that lost one placed first; index clears once every part moved. Each receiver closes by re-selecting the entries that lost an edge and re-linking the islands that leaves, as usearch_sequence_refine does. Insertions into index or a receiver arriving meanwhile are refused with usearch_status_contended_k, and nothing may search either until the call is final.

The handler reports and cancels the closing refinements alone, exactly as in usearch_sequence_refine: a cancel skips the rest of the re-selection, still re-links, and answers usearch_status_cancelled_k with every part moved. A caller wanting to continue that re-selection later holds a usearch_sequence_refinement_t opened with receivers instead.

Parameters

indexusearch_sequence_index_tThe handle split into the receivers, left empty and live.
executorusearch_executor_tThe executor the partition, each part's move and the closing refinements fan out over.
outcomeusearch_outcome_t *Output for the outcome, final once its status leaves usearch_status_deferred_k.
completionusearch_completion_tBlocking, the default, or deferred.
countsize_tReceiver handles to split into, at least two.
receiversusearch_sequence_index_t const *Array of count empty handles of the source's residency, class, kind and geometry, each receiving one part.
reportusearch_refine_report_t *The optional output for what the call did to the graph, as usearch_refine_report_t counts it; NULL skips reporting.
refineusearch_refine_options_tThe optional breadth and bytes of the closing refines.
seeduint64_tPicks the part roots: equal seeds over an unchanged index split equally.
progressusearch_progress_tThe optional handler, called with entries the closing refines re-selected; a cancel stops them as it stops usearch_sequence_refine, never a move.
statsusearch_traversal_stats_t *The optional traversal telemetry; NULL skips reporting.

Statuses

usearch_sequence_refinement_initOpens a refinement of index, absorbing donors first when any are named, as usearch_sequence_absorb moves them, or splitting it into receivers, as usearch_sequence_split fills them.
sequence_index.h:1194 ↗
void usearch_sequence_refinement_init(
    usearch_sequence_refinement_init_t *arguments);

Every allocation the refinement needs in the index happens here, never in a step.

Parameters

indexusearch_sequence_index_tThe handle to be refined.
executorusearch_executor_tThe executor every call on the refinement runs on; its kind must match the residency.
outcomeusearch_outcome_t *Output for the outcome, final once its status leaves usearch_status_deferred_k.
completionusearch_completion_tBlocking, the default, or deferred.
donorsusearch_sequence_index_t *The optional donors to absorb first, each consumed and nulled once its entries land; the array must outlive the refinement.
countsize_tDonor handles in donors.
receiversusearch_sequence_index_t const *The optional receivers to split index into first, as usearch_sequence_split fills them, each refined in turn; the array must outlive the refinement.
receivers_countsize_tReceiver handles in receivers, zero or at least two.
refinementusearch_sequence_refinement_t *Output for the new handle; NULL on failure.
refineusearch_refine_options_tThe optional breadth and bytes of every pass the refinement steps.
seeduint64_tPicks the part roots when receivers are named, as in usearch_sequence_split.

Statuses

usearch_sequence_refinement_finishSkips whatever re-selection a stopped refinement left, re-links the islands it leaves as usearch_sequence_refine does, reports, reopens the index, and frees the handle.
sequence_index.h:1278 ↗
void usearch_sequence_refinement_finish(
    usearch_sequence_refinement_finish_t *arguments);

A refinement whose donors have not all moved re-links nothing and reports zeros.

Parameters

indexusearch_sequence_index_tThe handle the refinement was opened on.
executorusearch_executor_tThe executor the refinement was opened with.
outcomeusearch_outcome_t *Output for the outcome, final once its status leaves usearch_status_deferred_k.
completionusearch_completion_tBlocking, the default, or deferred.
refinementusearch_sequence_refinement_tThe refinement to finish; freed by the call, whatever it answers.
reportusearch_refine_report_t *The optional output for what the call did to the graph, as usearch_refine_report_t counts it; NULL skips reporting.
statsusearch_traversal_stats_t *The optional traversal telemetry of every call on the refinement; NULL skips reporting.

Statuses

usearch_shapes_absorbAbsorbs every handle in donors into index, one after another, keeping their graphs rather than re-inserting their shapes, and links each in by walks across.
shapes_index.h:1064 ↗
void usearch_shapes_absorb(usearch_shapes_absorb_t *arguments);

Donor handles are consumed and must not be used afterwards, not even for usearch_shapes_free.

Every donor is checked and held before the first one enters, so a refusal consumes none. The donors then enter one after another, each all-or-nothing: its entries append to index with their edges rebased, publish at once, and the donor is consumed, so at most one donor's entries are ever held twice. One refinement then walks every entry across the parts the donors appended, round by round, so a group of donors costs one refinement rather than one per donor. Readers of index may keep searching throughout, since unpublished entries hide behind the watermark, while nothing may search a donor. Insertions into index arriving meanwhile are refused with usearch_status_contended_k.

The handler reports and cancels the closing refinement alone, exactly as in usearch_shapes_refine: a cancel skips the rest of the walks across, still re-links, and answers usearch_status_cancelled_k with every donor consumed. A caller wanting to continue those walks later holds a usearch_shapes_refinement_t instead.

Parameters

indexusearch_shapes_index_tThe handle absorbing the donors.
executorusearch_executor_tThe executor each donor's move and the closing refinement fan out over.
outcomeusearch_outcome_t *Output for the outcome, final once its status leaves usearch_status_deferred_k.
completionusearch_completion_tBlocking, the default, or deferred.
countsize_tDonor handles to absorb.
donorsusearch_shapes_index_t *Array of count handles, each consumed and nulled once its entries are published here.
reportusearch_refine_report_t *The optional output for what the call did to the graph, as usearch_refine_report_t counts it; NULL skips reporting.
refineusearch_refine_options_tThe optional breadth and bytes of the closing refine.
progressusearch_progress_tThe optional handler, called with the donor rows stitched so far out of every donor's; a cancel stops the stitching walks as it stops usearch_shapes_refine, never a move.
statsusearch_traversal_stats_t *The optional traversal telemetry; NULL skips reporting.

Statuses

usearch_shapes_splitSplits index into the handles in receivers, the inverse of usearch_shapes_absorb: graph-local parts keeping their edges rather than re-inserting their shapes, one part per receiver, and index left empty but live.
shapes_index.h:1137 ↗
void usearch_shapes_split(usearch_shapes_split_t *arguments);

Every receiver is checked and held before the first part moves, so a refusal moves nothing. The part roots are drawn from seed without a scan, and each part grows breadth-first over the links from its root, capped at an equal share of the entries, while entries no root reaches enter the smallest part. Each part then enters its receiver all-or-nothing, its edges rebased, its edges into other parts dropped, and the entries that lost one placed first; index clears once every part moved. Each receiver closes by re-selecting the entries that lost an edge and re-linking the islands that leaves, as usearch_shapes_refine does. Insertions into index or a receiver arriving meanwhile are refused with usearch_status_contended_k, and nothing may search either until the call is final.

The handler reports and cancels the closing refinements alone, exactly as in usearch_shapes_refine: a cancel skips the rest of the re-selection, still re-links, and answers usearch_status_cancelled_k with every part moved. A caller wanting to continue that re-selection later holds a usearch_shapes_refinement_t opened with receivers instead.

Parameters

indexusearch_shapes_index_tThe handle split into the receivers, left empty and live.
executorusearch_executor_tThe executor the partition, each part's move and the closing refinements fan out over.
outcomeusearch_outcome_t *Output for the outcome, final once its status leaves usearch_status_deferred_k.
completionusearch_completion_tBlocking, the default, or deferred.
countsize_tReceiver handles to split into, at least two.
receiversusearch_shapes_index_t const *Array of count empty handles of the source's residency, class, scalar, kind and geometry, each receiving one part.
reportusearch_refine_report_t *The optional output for what the call did to the graph, as usearch_refine_report_t counts it; NULL skips reporting.
refineusearch_refine_options_tThe optional breadth and bytes of the closing refines.
seeduint64_tPicks the part roots: equal seeds over an unchanged index split equally.
progressusearch_progress_tThe optional handler, called with entries the closing refines re-selected; a cancel stops them as it stops usearch_shapes_refine, never a move.
statsusearch_traversal_stats_t *The optional traversal telemetry; NULL skips reporting.

Statuses

usearch_shapes_refinement_initOpens a refinement of index, absorbing donors first when any are named, as usearch_shapes_absorb moves them, or splitting it into receivers, as usearch_shapes_split fills them.
shapes_index.h:1196 ↗
void usearch_shapes_refinement_init(
    usearch_shapes_refinement_init_t *arguments);

Every allocation the refinement needs in the index happens here, never in a step.

Parameters

indexusearch_shapes_index_tThe handle to be refined.
executorusearch_executor_tThe executor every call on the refinement runs on; its kind must match the residency.
outcomeusearch_outcome_t *Output for the outcome, final once its status leaves usearch_status_deferred_k.
completionusearch_completion_tBlocking, the default, or deferred.
donorsusearch_shapes_index_t *The optional donors to absorb first, each consumed and nulled once its entries land; the array must outlive the refinement.
countsize_tDonor handles in donors.
receiversusearch_shapes_index_t const *The optional receivers to split index into first, as usearch_shapes_split fills them, each refined in turn; the array must outlive the refinement.
receivers_countsize_tReceiver handles in receivers, zero or at least two.
refinementusearch_shapes_refinement_t *Output for the new handle; NULL on failure.
refineusearch_refine_options_tThe optional breadth and bytes of every pass the refinement steps.
seeduint64_tPicks the part roots when receivers are named, as in usearch_shapes_split.

Statuses

usearch_shapes_refinement_finishSkips whatever re-selection a stopped refinement left, re-links the islands it leaves as usearch_shapes_refine does, reports, reopens the index, and frees the handle.
shapes_index.h:1280 ↗
void usearch_shapes_refinement_finish(
    usearch_shapes_refinement_finish_t *arguments);

A refinement whose donors have not all moved re-links nothing and reports zeros.

Parameters

indexusearch_shapes_index_tThe handle the refinement was opened on.
executorusearch_executor_tThe executor the refinement was opened with.
outcomeusearch_outcome_t *Output for the outcome, final once its status leaves usearch_status_deferred_k.
completionusearch_completion_tBlocking, the default, or deferred.
refinementusearch_shapes_refinement_tThe refinement to finish; freed by the call, whatever it answers.
reportusearch_refine_report_t *The optional output for what the call did to the graph, as usearch_refine_report_t counts it; NULL skips reporting.
statsusearch_traversal_stats_t *The optional traversal telemetry of every call on the refinement; NULL skips reporting.

Statuses