# Metrics

> USearch for Rust

### Dense Indexes

A `DenseIndex` holds equidimensional dense vectors, built from `DenseOptions`: `dimensions`, `metric`, the stored `quantization`, and the `connectivity` and `values_per_key` bounds, where zero derives.
Every metric derives from a single inner-product kernel with pre-computed magnitudes; arbitrary metrics belong to the C++ baseline tier, forfeiting the SIMD kernel chains and the magnitude cache both.

- `DenseMetric::Inner` - inner product.
- `DenseMetric::Angular` - cosine distance, over pre-computed magnitudes.
- `DenseMetric::Euclidean` - L2 distance.
- `DenseMetric::Hamming` - bit-level, over `u1x8` vectors alone.
- `DenseMetric::Jaccard` - bit-level, over `u1x8` vectors alone.

`use usearch::DenseIndex;`

`use usearch::DenseMetric;`

`use usearch::DenseOptions;`

`use usearch::*;`

## Distance

Distance or similarity score in the metric of the index that produced it.

```rust
pub type Distance = f64;
```

## DenseIndex

Vector Search Index over equidimensional dense representations, whose verbs come from [`DenseVerbs`](https://www.unum.cloud/docs/usearch/rust/executors.md#DenseVerbs).

```rust
pub struct DenseIndex
```

[`DenseIndex::clear`](#clear) alone takes `&mut self`, since no other call may overlap it.

```
use usearch::*;

let options = DenseOptions {
    dimensions: 4,
    metric: DenseMetric::Angular,
    quantization: Scalar::I8,
    ..DenseOptions::default()
};
let index = DenseIndex::init_ram(&#x26;options, &#x26;[])?;
index.reserve(1_000)?;

let keys = [Key::from(0u64), Key::from(1u64)];
let slab: [f32; 8] = [0.2, 0.1, 0.2, 0.1, 0.1, 0.2, 0.1, 0.2];
index.insert(&#x26;keys, &#x26;rows(&#x26;slab, 4)?)?;

let query: [f32; 4] = [0.2, 0.1, 0.2, 0.1];
let executor = Executor::for_ram(&#x26;[], None, 0, 0)?;
let mut arena = Arena::new_in(&#x26;executor)?;
let matches = index.on(&#x26;executor).search(&#x26;rows(&#x26;query, 4)?, 10, &#x26;mut arena)?;
for query in matches.iter()? {
    println!("{} matches", query.keys.len());
}
```

Dropping it waits for every deferred call naming the index, then frees it.

Implements: `Debug`, `Send`, `Sync`, `Drop`, `[DenseVerbs](https://www.unum.cloud/docs/usearch/rust/executors.md#DenseVerbs)<'index>`

## on

The receiver whose verbs block on `executor`, after the calls submitted there before them.

```rust
pub fn on<'index>(&'index self, executor: &'index Executor) -> On<'index, DenseIndex>
```

Rust-only.

## deferred

The receiver whose verbs submit their calls to `executor`, answering a [`Deferred`](https://www.unum.cloud/docs/usearch/rust/errors.md#Deferred) from the same verbs given owned arguments.

```rust
pub fn deferred<'index>(
    &'index self,
    executor: &'index Executor,
) -> On<'index, DenseIndex, Deferring>
```

The library reads a deferred call's inputs after the verb returns, so lending a borrowed
query does not compile:

```
use usearch::*;

let index = DenseIndex::init_ram(&#x26;DenseOptions { dimensions: 4, ..DenseOptions::default() }, &#x26;[])?;
let executor = Executor::for_ram(&#x26;[], None, 0, 0)?;
let mut arena = Arena::new_in(&#x26;executor)?;
let query = [0.0f32; 4];
let call = index.deferred(&#x26;executor).search(&#x26;rows(&#x26;query, 4)?, 10, &#x26;mut arena)?;
```

The arena is borrowed as a blocking call borrows it, and so is the waited result:

```
use usearch::*;

let index = DenseIndex::init_ram(&#x26;DenseOptions { dimensions: 4, ..DenseOptions::default() }, &#x26;[])?;
let executor = Executor::for_ram(&#x26;[], None, 0, 0)?;
let mut arena = Arena::new_in(&#x26;executor)?;
let call = index.deferred(&#x26;executor).get::&#x3C;f32>(Key::from(1u64), &#x26;mut arena)?;
let vectors = call.wait()?;
```

Rust-only.

## clear

Erases all entries on the calling thread, keeping the reserved capacity and frozen geometry; `&mut self` keeps every other call on the handle from overlapping it.

```rust
pub fn clear(&mut self) -> Result<()>
```

## init_ram

Creates an empty, mutable index in host memory, one shard per NUMA node `memory_domains` names; empty derives every node the process may use.

```rust
pub fn init_ram(options: &DenseOptions, memory_domains: &[i32]) -> Result<Self>
```

## init_vram

Creates an empty, mutable index in device memory, sharded across `devices` and never replicated; empty derives one free device.

```rust
pub fn init_vram(options: &DenseOptions, devices: &[i32]) -> Result<Self>
```

## load_ram

Copies a checkpoint into a new, mutable index in host memory; a bare path reads on the calling thread.

```rust
pub fn load_ram<'config>(config: impl Into<DenseLoadRamConfig<'config>>) -> Result<Self>
```

## load_vram

Uploads a checkpoint into a new, mutable index in device memory, placing its parts as [`DenseIndex::load_ram`](#load_ram) does.

```rust
pub fn load_vram<'config>(config: impl Into<DenseLoadVramConfig<'config>>) -> Result<Self>
```

## load_ram_buffer

Copies a monolith from a buffer into a new, mutable index in host memory.

```rust
pub fn load_ram_buffer<'config>(
    config: impl Into<DenseLoadRamBufferConfig<'config>>,
) -> Result<Self>
```

## load_vram_buffer

Uploads a monolith from a buffer into a new, mutable index in device memory.

```rust
pub fn load_vram_buffer<'config>(
    config: impl Into<DenseLoadVramBufferConfig<'config>>,
) -> Result<Self>
```

## view_ram

Serves a checkpoint in place through a memory mapping, as a read-only index whose mutating verbs report [`Status::ReadOnly`](https://www.unum.cloud/docs/usearch/rust/errors.md#ReadOnly); the files must stay unmodified while it lives.

```rust
pub fn view_ram(path: impl AsRef<Path>) -> Result<Self>
```

## view_nvme

Serves a checkpoint in place from NVMe drives, as a read-only index whose mutating verbs report [`Status::ReadOnly`](https://www.unum.cloud/docs/usearch/rust/errors.md#ReadOnly).

```rust
pub fn view_nvme<'config>(config: impl Into<DenseViewNvmeConfig<'config>>) -> Result<Self>
```

Answers [`Status::Unsupported`](https://www.unum.cloud/docs/usearch/rust/errors.md#Unsupported) until NVMe checkpoints carry keys.

## metadata

Reads a checkpoint's geometry and metric without loading it; a manifest answers from its summary and its first part's header, so the cost does not grow with the index.

```rust
pub fn metadata(path: impl AsRef<Path>) -> Result<DenseMetadata>
```

## metadata_buffer

Reads geometry and metric out of a serialized monolith buffer.

```rust
pub fn metadata_buffer(buffer: &[u8]) -> Result<DenseMetadata>
```

## handles

The index this receiver reaches and the executor its calls run on.

```rust
fn handles(&self) -> Handles
```

## reserve

Reserves capacity for a number of incoming vectors ahead of insertion, a hint, since insertions grow the index on demand.

```rust
fn reserve(
    self,
    capacity: usize,
) -> <<Self as DenseVerbs<'index>>::Completion as Completion>::Answer<'index, DenseReserve>
```

## describe

Reports the frozen metadata and the current counters in one call.

```rust
fn describe(
    self,
) -> <<Self as DenseVerbs<'index>>::Completion as Completion>::Answer<'index, DenseDescribe>
```

## count

The number of entries stored under `key`.

```rust
fn count(
    self,
    key: Key,
) -> <<Self as DenseVerbs<'index>>::Completion as Completion>::Answer<'index, DenseCount>
```

## contains

Whether the index holds at least one entry under `key`.

```rust
fn contains(self, key: Key) -> Result<bool>
where
    Self: DenseVerbs<'index, Completion = Blocking>,
```

Rust-only.

## get

Retrieves every vector stored under `key` into `arena`, which the result borrows; an absent key yields no rows.

```rust
fn get<'arena, Value: Element>(
    self,
    key: Key,
    arena: &'arena mut Arena,
) -> <<Self as DenseVerbs<'index>>::Completion as Completion>::Answer<'index, DenseGet<'arena, Value>>
```

## insert

Adds a matrix of vectors under their keys - the native batch operation.

```rust
fn insert<'config, Keys: AsRef<[Key]>, Rows: RowsView>(
    self,
    keys: Keys,
    config: impl Into<DenseInsertConfig<'config, Rows>>,
) -> <<Self as DenseVerbs<'index>>::Completion as Completion>::Answer<'index, DenseInsert<'config, Keys, Rows>>
where
    Self::Completion: Accepts<Keys> + Accepts<DenseInsertConfig<'config, Rows>>,
```

A batch is all-or-nothing and becomes visible at once. Every entry is claimed before the first
progress report, so a `Break` is ignored. Overlaps safely with concurrent searches on the
same handle, and the input scalar type is independent of the stored quantization - the
library converts on ingest.

## refine

Re-selects the neighbors of every stored entry against the finished graph, answering a [`RefineReport`](https://www.unum.cloud/docs/usearch/rust/refinement.md#RefineReport) of the nodes re-selected and changed and the islands it re-linked.

```rust
fn refine<'config>(
    self,
    config: DenseRefineConfig<'config>,
) -> <<Self as DenseVerbs<'index>>::Completion as Completion>::Answer<'index, DenseRefine<'config>>
where
    Self::Completion: Accepts<DenseRefineConfig<'config>>,
```

A cheap insertion pass followed by refinement beats one expensive pass, so a wide expansion
factor belongs here rather than in [`DenseVerbs::insert`](#insert). On a RAM handle searches may run
throughout, on a VRAM one they may not, and insertions never may. A stop is a time budget:
the call still re-links its islands, leaving the graph correct, and answers
[`Status::Cancelled`](https://www.unum.cloud/docs/usearch/rust/errors.md#Cancelled).

## health

Audits how much of the graph a search reaches: forward reachability from as many landmarks as one search draws, swept level by level.

```rust
fn health(
    self,
) -> <<Self as DenseVerbs<'index>>::Completion as Completion>::Answer<'index, DenseHealth>
```

Read-only, so concurrent insertions merely leave fresh entries unaudited.

## search

Resolves a matrix of queries into up to `wanted` nearest matches apiece, writing them into `arena` as [`Matches`](https://www.unum.cloud/docs/usearch/rust/inputs-and-outputs.md#Matches).

```rust
fn search<'config, 'arena, Queries: RowsView>(
    self,
    queries: Queries,
    config: impl Into<DenseSearchConfig<'config>>,
    arena: &'arena mut Arena,
) -> <<Self as DenseVerbs<'index>>::Completion as Completion>::Answer<'index, DenseSearch<'config, 'arena, Queries>>
where
    Self::Completion: Accepts<Queries> + Accepts<DenseSearchConfig<'config>>,
```

Never writes to the graph, so any number of these may overlap with concurrent insertions.

## maxsim

Late-interaction scoring of multi-row queries against multi-row entries, writing up to `wanted` keys per query, largest score first, in `arena` as one ragged run; zero keeps every key a query scored.

```rust
fn maxsim<'config, 'arena, Queries: RowsView>(
    self,
    queries: Queries,
    rows_per_query: usize,
    config: impl Into<DenseMaxsimConfig<'config>>,
    arena: &'arena mut Arena,
) -> <<Self as DenseVerbs<'index>>::Completion as Completion>::Answer<'index, DenseMaxsim<'config, 'arena, Queries>>
where
    Self::Completion: Accepts<Queries> + Accepts<DenseMaxsimConfig<'config>>,
```

Every query row takes its best match within a key, and those maxima sum to that key's
score - so `rows_per_query` is the token count each query occupies, [`queries`](https://www.unum.cloud/docs/usearch/rust/linear-algebra.md#queries) holds them
end to end, and `wanted` counts documents rather than rows. This is what `values_per_key`
above one exists for. Runs on an inner-product index alone.

See [https://arxiv.org/abs/2004.12832](https://arxiv.org/abs/2004.12832) - ColBERT, which introduced this scoring.

## multiply

Approximate sparse product of a matrix against the indexed vectors, writing its keys, products and offsets in `arena` as one ragged run.

```rust
fn multiply<'config, 'arena, Left: RowsView>(
    self,
    left: Left,
    config: impl Into<DenseMultiplyConfig<'config>>,
    arena: &'arena mut Arena,
) -> <<Self as DenseVerbs<'index>>::Completion as Completion>::Answer<'index, DenseMultiply<'config, 'arena, Left>>
where
    Self::Completion: Accepts<Left> + Accepts<DenseMultiplyConfig<'config>>,
```

The linear-algebra sibling of [`DenseVerbs::search`](#search), reporting every pair the traversal
scored rather than only the nearest. Pairs arrive in traversal order rather than sorted.
Runs on an inner-product index alone, since a product is a logit.

## attend

Softmax attention of every query row over every indexed key its walk scores, folded as Flash Attention folds key tiles, with no top-k cut, writing into `arena` as rows of the queries' own scalar type.

```rust
fn attend<'config, 'lookup, 'arena, Queries: RowsView, Value: Element>(
    self,
    queries: Queries,
    value_lookup: &'lookup ValueLookup<'lookup, Value>,
    config: impl Into<DenseAttendConfig<'config>>,
    arena: &'arena mut Arena,
) -> <<Self as DenseVerbs<'index>>::Completion as Completion>::Answer<'index, DenseAttend<'config, 'lookup, 'arena, Queries, Value>>
where
    Self::Completion: Accepts<Queries> + Accepts<&'lookup ValueLookup<'lookup, Value>> + Accepts<DenseAttendConfig<'config>>,
```

The index holds one layer's keys for one key-value head and no values: `value_lookup`
resolves every scored key to its value row, as wide as the keys and stored in the index's
own quantization. A key left without a row, or given one of another type or width, refuses the
call with [`Status::ShapeMismatch`](https://www.unum.cloud/docs/usearch/rust/errors.md#ShapeMismatch), since a missing row is a wrong softmax rather than a
smaller one. A VRAM walk resolves values on the device, where no Rust closure runs, so an
arena from a VRAM executor is refused with [`Status::Device`](https://www.unum.cloud/docs/usearch/rust/errors.md#Device). The outputs come back
already divided by the partition. Runs on an inner-product index alone, since a softmax
needs logits.

See [https://arxiv.org/abs/2205.14135](https://arxiv.org/abs/2205.14135) - Flash Attention, whose recurrence this reuses.

## absorb

Absorbs every donor into this index, one after another, keeping their graphs rather than re-inserting their vectors and linking each in by walks across the appended part.

```rust
fn absorb<'config, Donors: IntoIterator<Item = DenseIndex>>(
    self,
    config: impl Into<DenseAbsorbConfig<'config, Donors>>,
) -> <<Self as DenseVerbs<'index>>::Completion as Completion>::Answer<'index, DenseAbsorb<'config>>
where
    Self::Completion: Accepts<DenseAbsorbConfig<'config, Donors>>,
```

Readers of a RAM index may keep searching throughout, while a VRAM one admits no
overlapping search. The donors are consumed whether or not the absorb succeeds: a stop cuts
only the closing refinement, every donor already moved, and answers [`Status::Cancelled`](https://www.unum.cloud/docs/usearch/rust/errors.md#Cancelled),
while a failure frees the donors it never reached and may leave the failing donor's entries
behind.

## split

Splits this index into the empty receivers, the inverse of [[`DenseVerbs::absorb`](#absorb)]: the entries are partitioned along the graph, each part lands in one receiver with its edges kept, and a closing refinement re-links every receiver, leaving this index empty and live.

```rust
fn split<'config>(
    self,
    config: impl Into<DenseSplitConfig<'config>>,
) -> <<Self as DenseVerbs<'index>>::Completion as Completion>::Answer<'index, DenseSplit<'config>>
where
    Self::Completion: Accepts<DenseSplitConfig<'config>>,
```

## sample

Draws keys around the focus, or across the whole index, each hanging from a shown or earlier draw and placed in three dimensions beside the shown ones, writing up to `wanted` of them into `arena` as a [`Sample`](https://www.unum.cloud/docs/usearch/rust/retrieval-and-streaming.md#Sample).

```rust
fn sample<'config, 'arena>(
    self,
    wanted: usize,
    arena: &'arena mut Arena,
    config: DenseSampleConfig<'config>,
) -> <<Self as DenseVerbs<'index>>::Completion as Completion>::Answer<'index, DenseSample<'config, 'arena>>
where
    Self::Completion: Accepts<DenseSampleConfig<'config>>,
```

A larger `wanted` under the same seed draws a
superset; only a RAM index samples yet.

## save

Saves the index in the layout the path extension picks - one `.safegraphs` monolith, or a `.safegraphs.json` manifest beside its shards.

```rust
fn save<'config, Location: AsRef<Path>>(
    self,
    config: impl Into<DenseSaveConfig<'config, Location>>,
) -> <<Self as DenseVerbs<'index>>::Completion as Completion>::Answer<'index, DenseSave<'config, Location>>
where
    Self::Completion: Accepts<DenseSaveConfig<'config, Location>>,
```

Demands a mutation-free window; concurrent readers keep searching throughout. A stopped save
leaves leftovers every reader rejects and the caller is left to remove.

## save_buffer

Saves the index as one monolith into the arena its config carries.

```rust
fn save_buffer<'config, 'arena>(
    self,
    config: impl Into<DenseSaveBufferConfig<'config, 'arena>>,
) -> <<Self as DenseVerbs<'index>>::Completion as Completion>::Answer<'index, DenseSaveBuffer<'config, 'arena>>
where
    Self::Completion: Accepts<DenseSaveBufferConfig<'config, 'arena>>,
```

## cursor

Opens a walk over the current contents, pulled blocking on this receiver's executor; each shard's publication watermark is read as the walk enters it, so an entry once passed is never revisited.

```rust
fn cursor(self, starts: &[Key]) -> Result<DenseCursor<'index>>
where
    Self: DenseVerbs<'index, Completion = Blocking>,
```

Without `starts` the walk yields every entry as stored. With them it yields the start keys'
own entries first, in order, then the entries those link to breadth-first, each entry once.

## search_stream

Opens a resumable nearest-neighbor stream for a one-row query, pulled blocking on this receiver's executor.

```rust
fn search_stream<Query: RowsView>(
    self,
    config: impl Into<DenseSearchStreamInitConfig<Query>>,
) -> Result<DenseSearchStream<'index>>
where
    Self: DenseVerbs<'index, Completion = Blocking>,
```

Best-first traversal is naturally pausable, so callers that post-filter aggressively pull
until satisfied instead of guessing "k" upfront. The stream keeps walk state rather than a
thread.

No residency implements the stream yet, so the engine answers [`Status::Unsupported`](https://www.unum.cloud/docs/usearch/rust/errors.md#Unsupported).

## DenseMetric

The dense metric kinds supported out of the box, all derived from a single inner-product kernel with pre-computed magnitudes.

```rust
pub enum DenseMetric
```

Hamming and Jaccard are bit-level over [`Scalar::U1x8`](https://www.unum.cloud/docs/usearch/rust/inputs-and-outputs.md#U1x8)
alone, a kind the other three refuse.

Arbitrary metrics belong to the C++ baseline tier, which forfeits the SIMD kernel chains and
the magnitude cache both.

- `Inner` = `1`: Sum of elementwise products, unnormalized and scale-sensitive; the only kind the linear-algebra verbs
accept, since a product and a softmax both need logits rather than distances.
- `Angular` = `2`: Cosine distance in [0, 2], zero for identical directions and blind to magnitude, which is precomputed once
per vector at insertion rather than per comparison.
- `Euclidean` = `3`: L2 distance, non-negative and zero only for identical vectors - the scale-sensitive counterpart to angular,
where a doubled vector is far from its original rather than identical to it.
- `Hamming` = `4`: Count of differing bits, so its range is the dimensionality and every bit weighs the same.
- `Jaccard` = `5`: Differing bits over union bits in [0, 1], ignoring the zeros both vectors share - the kind for sparse sets,
where Hamming would call two nearly-empty vectors identical.

Implements: `Clone`, `Copy`, `StructuralPartialEq`, `PartialEq`, `Eq`, `Debug`, `Default`, `Hash`, `Display`, `FromStr`

## DenseOptions

Construction options of a dense index, whose stored vectors round up to the SIMD step quantum so every kernel runs tail-free.

```rust
pub struct DenseOptions
```

[`DenseIndex::init_ram`](#init_ram) and [`DenseIndex::init_vram`](#init_vram) both take it.

- `dimensions` `usize`: The number of indexed dimensions, which init freezes; zero is refused with
[`Status::ConfigMismatch`](https://www.unum.cloud/docs/usearch/rust/errors.md#ConfigMismatch).
- `metric` `DenseMetric`: The metric kind used for distance calculations.
- `quantization` `Scalar`: The scalar type vectors are stored and quantized into.
- `connectivity` `usize`: The connections-per-node bound of the graph; zero derives.
- `values_per_key` `usize`: Upper bound on entries sharing one key; zero is unbounded.
- `cpu_class` `Option<CPUClass>`: The class a host index dispatches as; `None` dispatches as the machine.
- `gpu_class` `Option<GPUClass>`: The class a device index dispatches as; `None` dispatches as the devices.

Implements: `Clone`, `StructuralPartialEq`, `PartialEq`, `Eq`, `Debug`, `Hash`, `Default`

