Wolfram · Inputs and Outputs

Inputs and Outputs

Needs["USearch`"] 3.0.0-rc.1 · 4c3e5023

§ Arenas

Every output whose length only the call knows, such as matches, rows, products and monoliths, lands in an arena you pass. ArenaInit["Executor"->executor] places it where that executor computes, decided once, and ArenaInit[] makes host pages for the kernel’s own thread. Each call rewinds its arena and copies its outputs into Wolfram arrays, so a steady loop allocates once and every result outlives the next call. An arena serves one call at a time, so a second concurrent call fails as contended. LibraryLink cannot alias memory it did not allocate, so the results stay valid after the arena is released too. An arena from a VRAM executor holds device memory, which these functions refuse with device.

arena = ArenaInit["Executor"->executor];
total = 0;
Do[
    matches = DenseSearch[DenseIndexOn[index, executor], batch, 10, arena];    (* rewinds, allocates once *)
    total += Total[Flatten[matches["Scores"]]],
    {batch, batches}];
found = DenseSearch[index, {query}, 10, arena];
vectors = DenseGet[index, #, arena] & /@ First[found["Keys"]];               (* found is a copy, so one arena serves both *)

The arena is the last required argument, options follow it, and a call without one stays unevaluated. Fixed-size reports such as descriptions, audits and counts stay plain values and take no arena.

§ Rows & Scalars

Packed real lists cross as f64; NumericArray inputs keep their Real32 or Real64 storage. LibraryLink borrows both as read-only "Constant" arguments for the blocking call, so an existing packed list or typed array needs no input copy at this boundary. The engine still converts the input into the index’s quantization.

vectors = NumericArray[{{1., 2., 3.}, {3., 2., 1.}}, "Real32"];
DenseInsert[index, {41, 42}, vectors];
DenseSearch[index, vectors, 2, arena]

A matrix is a batch of rows, so a whole batch crosses in one call rather than one crossing per vector, and DenseInsert and DenseMultiply also take a single vector as a batch of one. The input’s own width crosses with the rows, and the engine refuses one that differs from the frozen geometry as shape-mismatch. Metrics are inner, angular, euclidean, hamming, and jaccard; quantizations are bf16, f16, e5m2, e4m3, e3m2, e2m3, i8, i4x2, u8, u4x2, and u1x8.

  • DenseReserve[receiver, capacity] reserves the total capacity, including the current size, and DenseClear[receiver] erases every entry, keeping it.
  • DenseInsert[receiver, keys, vectors] admits one row per key and fails as shape-mismatch when the counts differ.

No NumericArray holds zero keys, so DenseInsert[receiver, {}, {}] answers Null in the package without reaching the library, as the C call would.

DenseSearch[receiver, queries, wanted, arena] answers <|"Keys"->…, "Scores"->…|>, one list per query, holding the matches it found, nearest first. A query that finds fewer than wanted matches is not an error, and its lists are just shorter. No tensor holds zero rows either, so a search with no queries answers <|"Keys"->{}, "Scores"->{}|> in the package.

The breadth of the candidates rides each call in the C interface rather than the handle, so it is an "ExpansionFactor" option on every verb that walks the graph, zero deriving it. "Traversal"->"scan" skips the walk and scores every entry exactly, on RAM and NVMe handles:

DenseSearch[index, queries, 10, arena, "ExpansionFactor"->64]
DenseSearch[index, queries, 10, arena, "Traversal"->"scan"]

API

Functions

ArenaArena[id] holds the outputs a verb writes, rewound by every call writing into it and freed once nothing references it.
USearch.wl:16 ↗
Arena[id]
ArenaInitArenaInit[] makes an arena for verb outputs, placed where its "Executor" computes; None, the default, holds host memory for calls on the calling thread.
USearch.wl:23 ↗
ArenaInit[OptionsPattern[]]

Parameters

"Executor"Default: None
DenseInsertDenseInsert[receiver, keys, vectors] adds vectors, one row per key, under keys, each an integer below 2^128.
USearch.wl:38 ↗
DenseInsert[receiver, keys, vectors, OptionsPattern[]]

"ExpansionFactor" sets the breadth of the candidates the walk explores, 0 deriving it.

Parameters

"ExpansionFactor"Default: 0
DenseSearchDenseSearch[receiver, queries, wanted, arena] finds up to wanted nearest entries for each query row, answering their "Keys" and "Scores" per query.
USearch.wl:41 ↗
DenseSearch[receiver, queries, wanted, arena, OptionsPattern[]]

"ExpansionFactor" sets the breadth of the candidates the walk explores, 0 deriving it, and "Traversal" is "walk", the default, or "scan", an exact pass over every entry.

Parameters

"ExpansionFactor"Default: 0
"Traversal"Default: "walk"
DenseValuesDenseValues[receiver, keys, values] prepares immutable value rows, one per key, in the index's quantization, for DenseAttend.
USearch.wl:49 ↗
DenseValues[receiver, keys, values]