# Platform Notes

> USearch for C

### Sequence Indexes

A sequence index searches byte strings, UTF-8 text, DNA, RNA and proteins under edit distances and alignments, in RAM only.
Variable-length entries travel as Apache Arrow tapes, `usearch_tape_view_t`: the elements end to end, and `count + 1` offsets around them, 32-bit or 64-bit as its `layout` says, so sequences are bytes with byte offsets:

```c
usearch_sequence_index_t sequences = NULL;
usearch_sequence_init_ram(&(usearch_sequence_init_ram_t) {
    .index = &sequences, .outcome = &outcome, .metric = usearch_sequence_metric_levenshtein_utf8_k});

char const tape[] = "kittensittingmitten";
uint64_t const offsets[4] = {0, 6, 13, 19};
usearch_key_t words[3] = {{.bytes[15] = 1}, {.bytes[15] = 2}, {.bytes[15] = 3}};
usearch_sequence_insert(&(usearch_sequence_insert_t) {.index = sequences,
                                                      .executor = executor,
                                                      .outcome = &outcome,
                                                      .count = 3,
                                                      .keys = {words, sizeof(usearch_key_t)},
                                                      .sequences = {.data = tape,
                                                                    .layout = usearch_tape_u64_k,
                                                                    .offsets = {.u64 = offsets},
                                                                    .scalar = usearch_scalar_u8_k}});

uint64_t const query_offsets[2] = {0, 6};
usearch_sequence_search(&(usearch_sequence_search_t) {.index = sequences,
                                                      .executor = executor,
                                                      .outcome = &outcome,
                                                      .count = 1,
                                                      .queries = {.data = "sitten",
                                                                  .layout = usearch_tape_u64_k,
                                                                  .offsets = {.u64 = query_offsets},
                                                                  .scalar = usearch_scalar_u8_k},
                                                      .matches = &matches,
                                                      .arena = arena,
                                                      .wanted = 3});
```

The kinds are Levenshtein over bytes or UTF-8 code points, Needleman-Wunsch with a linear gap, and overlap, the share of fixed-width windows one side misses of the other.
Needleman-Wunsch takes `usearch_sequence_weights_t`, a 256×256 substitution matrix with a gap cost, and the overlap kind takes `window_widths` in bytes, each refused by every other kind with `usearch_status_config_mismatch_k`.
The verbs mirror the dense ones: `init_ram`, `init_vram`, `load_ram`, `load_vram`, `view_ram`, `reserve`, `clear`, `insert`, `refine`, `search` with a predicate, `get` writing tapes into an arena, `cursor_next` writing keys and their links, `absorb`, `split`, `save`, `metadata_read`, the `_buffer` forms of `load_ram`, `save` and `metadata_read`, and `describe`, while `count` also reports a key's total and largest byte lengths.
A key already holding `values_per_key` entries rejects the whole insertion with `usearch_status_overflow_k`.
The engine serves every kind, and answers `view_ram` with `usearch_status_unsupported_k`; `refine`, `absorb` and `split` serve RAM indexes, while `sample`, `health` and cursors with `starts` and `links` serve RAM indexes and NVMe views.
The stand-in serves every kind by textbook dynamic programming, quadratic and unbanded, and reports alignment similarities negated.

### Shape Indexes

A shape index searches 3D point clouds of any size, like molecules, conformers and protein backbones, in RAM or VRAM.
Its tape is points end to end, `x`, `y` and `z` interleaved, with offsets that count points rather than scalars:

```c
usearch_shapes_index_t conformers = NULL;
usearch_shapes_init_ram(&(usearch_shapes_init_ram_t) {.index = &conformers,
                                                      .outcome = &outcome,
                                                      .metric = usearch_shapes_metric_wasserstein_procrustes_k,
                                                      .quantization = usearch_scalar_f16_k});

float const atoms[5][3] = {{0, 0, 0}, {1.1f, 0, 0}, {0, 0, 0}, {1.5f, 0, 0}, {0, 1.5f, 0}};
uint64_t const point_offsets[3] = {0, 2, 5}; // a 2-atom and a 3-atom entry
usearch_shapes_insert(&(usearch_shapes_insert_t) {.index = conformers,
                                                  .executor = executor,
                                                  .outcome = &outcome,
                                                  .count = 2,
                                                  .keys = {molecules, sizeof(usearch_key_t)},
                                                  .shapes = {.data = atoms,
                                                             .layout = usearch_tape_u64_k,
                                                             .offsets = {.u64 = point_offsets},
                                                             .scalar = usearch_scalar_f32_k}});
```

Chamfer and Hausdorff pair every point with its nearest partner after aligning the principal axes under all eight sign flips, keeping the best.
Wasserstein-Procrustes pairs points by an exact transport plan, alternated with the best rotation or reflection.
Gromov-Wasserstein compares each side's internal distances.
All four are invariant to rotation, reflection, translation and point order.
A non-zero `points` freezes the count, rejecting insertions of any other with `usearch_status_shape_mismatch_k`.
The verbs are the sequence ones, where `get` converts to an `outputs_scalar` and returns each shape in its inserted pose, and `count` reports a key's total and largest point counts.
The engine serves all four kinds in RAM and on NVMe over `f16` or `f32` points, refusing other quantizations and `view_ram` with `usearch_status_unsupported_k`, and Chamfer and Hausdorff on NVIDIA GPUs; `sample`, `health` and cursors with `starts` and `links` serve RAM indexes and NVMe views.
The stand-in scores Chamfer and Hausdorff in the frame the points arrive in, refuses the two transport kinds with `usearch_status_unknown_kind_k`, refuses quantizations other than `f16` and `f32` with `usearch_status_unsupported_k`, and refuses every VRAM verb with `usearch_status_device_k`.

### Geospatial Indexes

A geospatial index searches observations on and above the Earth, like photos, video frames, drone footage and sensor fixes, in RAM, on NVMe or on NVIDIA GPUs.
Each entry is one `usearch_geospatial_observation_t` of eleven doubles in natural units: latitude and longitude in WGS-84 degrees, altitude in metres above the ellipsoid, the horizontal accuracy, the heading, pitch, heading accuracy and field of view of the device's view cone, how far it saw, and the first and last Unix second it covers.
A device that recorded nothing for a field leaves it NaN, never zero, and each NaN only widens the tests that read it: an unknown accuracy counts as exact, an unknown view as looking everywhere, an unknown time as always.
A key may hold several observations, up to the `values_per_key` its creation froze, like a camera's frames or a vehicle's fixes:

```c
#include <math.h> // `NAN` - a field no device recorded

usearch_geospatial_index_t places = NULL;
usearch_geospatial_init_ram(&(usearch_geospatial_init_ram_t) {.index = &places, .outcome = &outcome});

usearch_geospatial_observation_t const stops[3] = {
    // latitude, longitude, altitude, accuracy, heading, pitch, heading accuracy, field, range, begin, end
    {51.5308, -0.1238, NAN, 5, NAN, NAN, NAN, NAN, NAN, NAN, NAN},
    {51.5320, -0.1233, NAN, 5, NAN, NAN, NAN, NAN, NAN, NAN, NAN},
    {51.5033, -0.1196, NAN, 5, NAN, NAN, NAN, NAN, NAN, NAN, NAN},
};
usearch_geospatial_insert(&(usearch_geospatial_insert_t) {.index = places,
                                                          .executor = executor,
                                                          .outcome = &outcome,
                                                          .count = 3,
                                                          .keys = {stop_keys, sizeof(usearch_key_t)},
                                                          .observations = stops});
```

`usearch_geospatial_within` reports every entry a `relation` admits inside the `tolerance`, however many there turn out to be, as one tape per query in the arena:

```c
usearch_geospatial_observation_t const station = {51.5308, -0.1238, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN};
usearch_matches_tape_view_t nearby = {0}; // `nearby.offsets[1]` entries, their chords in metres
usearch_geospatial_within(&(usearch_geospatial_within_t) {.index = places,
                                                          .executor = executor,
                                                          .outcome = &outcome,
                                                          .count = 1,
                                                          .queries = &station,
                                                          .relation = usearch_geospatial_relation_near_k,
                                                          .tolerance = {.metres = 500},
                                                          .matches = &nearby,
                                                          .arena = arena});
```

`usearch_geospatial_search` ranks the `wanted` nearest entries of each query the relation admits instead, where a zero radius ranks by distance alone.
Every score is the chord between the two positions in metres, altitude included, which ranks as the great-circle arc does.
`near_k` admits entries within the radius widened by three standard deviations of both positions' accuracies combined.
`visible_k` also needs a clear line of sight over the handle's `terrain`, and a handle without one refuses it.
`sees_k` needs the entry's view cone to hold the query, which cameras see this place, and `seen_k` the query's cone to hold the entry, what this camera sees; both clear the terrain too when the handle has one.
The tolerance's `seconds` widen the query's interval on both ends, and a query without a time matches entries of any time.
The terrain is a north-up grid of heights above the ellipsoid, borrowed in place or filled on demand by a callback; a checkpoint never carries it, so every load and view names it again, and a GPU index takes borrowed heights alone.
The remaining verbs are the shapes ones, where `get` returns observations within the stored rounding, centimetres and milliseconds among them, `count` reports a key's entries, and `sample` places its draws at their Earth-fixed positions.
The engine serves every relation in RAM, on NVMe and on NVIDIA GPUs, answering `view_ram` with `usearch_status_unsupported_k`; `sample`, `health` and cursors with `starts` and `links` serve RAM indexes and NVMe views.
The stand-in scans every entry exactly, keeps the doubles inserted, refuses every terrain and so `visible_k`, and refuses every VRAM verb with `usearch_status_device_k`.

### What This Binding Does Not Expose

- __Batched admission.__
  The predicate is one call per key; the span-admission form exists only in the C++ layer, since a C callback per candidate batch would cost more than it amortizes.
- __Custom metrics.__
  A metric of your own, over payloads of your own, belongs to the C++ baseline tier, whose index takes any batched metric you write; see [`include/usearch/basic/README.md`](https://github.com/unum-cloud/USearch/blob/main/include/usearch/basic/README.md).

### Design

- __This is the C ABI itself.__
  Every name is the one `c/usearch/` declares: a verb `usearch_dense_<verb>` takes a `usearch_dense_<verb>_t`, and closed sets are C enums with name tables, never strings.
- __The completion chooses, the verb stays.__
  A `NULL` executor runs a verb on the calling thread, an executor with the default completion blocks on it, and `usearch_completion_deferred_k` submits it, all with the same argument struct.
- __Deferred calls report through the same outcome.__
  `usearch_outcome_status` polls and `usearch_outcome_wait` blocks, both with the acquire ordering the final store pairs with.
- __No life of its own.__
  Threads live only in executors, and a deferred call only on its executor's thread 0; every `*_free` waits for the calls naming its handle first.
- __Arenas are lent and reused, never shared.__
  Every output whose length scales with the call lands in an arena the caller passes; each call rewinds it, so the previous call's views go stale the moment the next one starts.
- __Nothing costs anything until it is used.__
  Submitting a call allocates nothing, and an arena allocates only when a call writes into it.
- __One shape for every call.__
  Each verb takes one struct set by designator, so a call names only what it changes and the struct grows without breaking source.
- __Failures are statuses.__
  The library never logs or aborts, and a dense verb a residency lacks answers `usearch_status_unsupported_k` rather than missing from the build.

`#include <usearch/geospatial_index.h>`

## usearch_geospatial_observation_t

One observation as devices record it: every field in its natural unit, and NaN wherever nothing was recorded.

```c
struct usearch_geospatial_observation_t
```

An unknown accuracy counts as exact, an unknown view as looking everywhere without limit, and an unknown time as always, so a missing field only ever widens the tests that read it. The index stores a quantized copy that rounds every field outward, and reads it back through [`usearch_geospatial_get`](https://www.unum.cloud/docs/usearch/c/retrieval-and-streaming.md#usearch_geospatial_get) within that rounding: centimetres, a 2⁻¹⁶ turn of heading, a 2⁻⁸ turn of pitch and field, whole metres of accuracy and range, and milliseconds.

- `latitude_degrees` `double`: Degrees north on WGS-84, south negative.
- `longitude_degrees` `double`: Degrees east on WGS-84, west negative.
- `altitude_metres` `double`: Metres above the WGS-84 ellipsoid.
- `accuracy_metres` `double`: One standard deviation of the horizontal position, in metres.
- `heading_degrees` `double`: Where the device looked: degrees clockwise from true north.
- `pitch_degrees` `double`: Degrees above the horizon.
- `heading_accuracy_degrees` `double`: One standard deviation of the heading, in degrees, which widens the field of view by three on each side: ROS `orientation_covariance`, or a compass's own.
- `field_of_view_degrees` `double`: The full field of view in degrees: 2·atan(18 mm / EXIF `FocalLengthIn35mmFilm`) for a landscape frame; MISB tag 16; the ROS `CameraInfo` matrix.
- `range_metres` `double`: How far the device saw, in metres along the slant.
- `begin_seconds` `double`: The first instant the observation covers, in Unix seconds, UTC.
- `end_seconds` `double`: The last instant the observation covers, in Unix seconds, UTC: a clip's creation date plus its duration, or the sources of `begin_seconds`.

## usearch_geospatial_relation_t

Which entries count as matches of a query; the radius and time window of `[usearch_geospatial_tolerance_t](#usearch_geospatial_tolerance_t)` narrow every relation alike.

```c
enum usearch_geospatial_relation_t
```

- `usearch_geospatial_relation_unknown_k` = `0`
- `usearch_geospatial_relation_near_k` = `1`: Within the radius of each other, widened by three standard deviations of both positions combined.
- `usearch_geospatial_relation_visible_k` = `2`: Near, with a clear line of sight over the handle's terrain; refused by a handle without one.
- `usearch_geospatial_relation_sees_k` = `3`: Near, and the entry's view cone holds the query: "which cameras see this place".
- `usearch_geospatial_relation_seen_k` = `4`: Near, and the query's view cone holds the entry: "what does this camera see".

## usearch_geospatial_terrain_callback_t

Fills `rows` × `columns` heights of a terrain, in metres above the WGS-84 ellipsoid, starting at row `first_row` and column `first_column`, with `heights_stride` bytes between rows; a cell the source does not have stays NaN, which never blocks a sight line.

```c
typedef void(*) usearch_geospatial_terrain_callback_t(size_t first_row, size_t first_column, size_t rows, size_t columns, float *heights, size_t heights_stride, void *state);
```

Called concurrently from the executor's threads.

## usearch_geospatial_terrain_t

The elevation every line of sight is tested over: a north-up geographic grid of heights, given by exactly one of a borrowed buffer, a fill callback or a dataset path.

```c
struct usearch_geospatial_terrain_t
```

A zeroed terrain means none. Heights are metres above the WGS-84 ellipsoid, like observation altitudes, so orthometric grids such as the Copernicus DEM's need the geoid's height added first. The grid is treated as locally flat at the latitude of its middle row, which keeps distances within 1 % across a one-degree tile.

- `rows` `size_t`: The grid's row count; rows run south from the north edge.
- `columns` `size_t`: The grid's column count; columns run east from the west edge.
- `north_latitude_degrees` `double`: The latitude of the centre of cell [0,0], in degrees.
- `west_longitude_degrees` `double`: The longitude of the centre of cell [0,0], in degrees.
- `row_step_degrees` `double`: The step between rows, in degrees, positive.
- `column_step_degrees` `double`: The step between columns, in degrees, positive.
- `heights` `float const *`: The whole grid, row-major, borrowed for the handle's lifetime.
- `heights_stride` `size_t`: The bytes between consecutive rows of `heights`; zero means packed.
- `callback` `usearch_geospatial_terrain_callback_t`: Or a handler filling windows of the grid on demand, called with `state`; VRAM handles refuse it with [`usearch_status_unsupported_k`](https://www.unum.cloud/docs/usearch/c/errors.md#usearch_status_unsupported_k), as no device calls the host.
- `state` `void *`: The opaque pointer passed back to every `callback` call.
- `path` `usearch_bytes_view_t`: Or a dataset on disk, which only an NVMe residency will read; RAM and VRAM handles refuse it with [`usearch_status_unsupported_k`](https://www.unum.cloud/docs/usearch/c/errors.md#usearch_status_unsupported_k).

## usearch_geospatial_tolerance_t

What "close" means numerically for one search: the radius around each query position, and the slack its time interval allows.

```c
struct usearch_geospatial_tolerance_t
```

Zero `metres` means no radius: the search ranks by distance alone. Position uncertainty widens the radius by three standard deviations of the query's and the entry's accuracy combined, so a pair whose true positions lie within it matches at 98.9 % confidence. An entry matches in time when its interval and the query's, widened by `seconds` on each side, overlap; a query without a time matches every entry.

- `metres` `double`: Radius in metres; zero means none.
- `seconds` `double`: Slack added to both ends of the query's time interval, in seconds.

