C · Edit Distances

Edit Distances

#include <stringzilla/types.h>#include <stringzilla/capabilities.h>#include <stringzilla/levenshtein.h> 6.0.0-rc.1 · 91a27bdd

Includes core APIs with hardware-specific backends:

Myers' bit-parallel algorithm treats every query as a pattern, packed 64 symbols per machine word, and every candidate streams one symbol per step. An engine prepares the whole batch's match masks once and advances several candidates per step - one per scalar state, four per YMM, eight per ZMM, one per thread on a device - so the tables are built once per batch rather than once per pair. A byte is its own mask class, while a rune takes the class its query assigned it or class zero when the query lacks it, which sz_levenshtein_symbol_t picks between. Strings of any length are accepted on either side; device queries are bounded by their length index. Long byte pairs on a device use an internal tiled wavefront for intra-pair parallelism.

The building blocks are public as well, for callers that own the loop nest: the query preparation and the transposes on the query side, and per backend a state, a vertical, and the init, step, any-active and score verbs over them, named by candidates per step, such as sz_levenshtein_u64x4_step_haswell. Scoring itself has one entry point per backend, such as sz_levenshtein_distances_haswell, which takes the caller's order and a bound past which a distance need not be exact.

API

Types

sz_similarity_locality_tDescribes the alignment scope for string similarity algorithms.
types.h:912 ↗
enum sz_similarity_locality_t

Values

sz_similarity_global_k0
sz_similarity_local_k1

See also

sz_similarity_global_k, sz_similarity_local_k

sz_similarity_objective_tDescribes the alignment objective for string similarity algorithms.
types.h:921 ↗
enum sz_similarity_objective_t

Values

sz_minimize_distance_k0
sz_maximize_score_k1

See also

sz_minimize_distance_k, sz_maximize_score_k

sz_similarity_packing_tDescribes how a similarity kernel packs work across SIMD lanes or a GPU warp's threads.
types.h:938 ↗
enum sz_similarity_packing_t

one_pair_per_walk_k vectorizes within a single (query, candidate) pair, in anti-diagonal lanes — the intra-sequence form, used for one-off pairs and the ragged tail of a cross-product.

candidates_across_lanes_k vectorizes across many candidates of one shared query, one candidate per lane — the inter-sequence form that keeps every lane busy regardless of string length, the cross-product workhorse.

Values

sz_packing_one_pair_per_walk_k0
sz_packing_candidates_across_lanes_k1

See also

sz_packing_one_pair_per_walk_k, sz_packing_candidates_across_lanes_k

sz_similarity_gaps_tDescribes the cost model for gap opening vs extension in string similarity algorithms.
types.h:947 ↗
enum sz_similarity_gaps_t

Values

sz_gaps_linear_k1Linear costs require us to build only 1 DP matrix.
sz_gaps_affine_k3Affine costs require us to build 3 DP matrices.

See also

sz_levenshtein_symbol_tWhich symbols a batch counts, as the alphabet picks the transpose and the mask layout alike.
types.h:977 ↗
enum sz_levenshtein_symbol_t

Values

sz_levenshtein_bytes_k0Every byte is its own symbol, and a distance counts bytes.
sz_levenshtein_runes_k1Every UTF-8 rune is one symbol, each maximal ill-formed subpart decoding to one U+FFFD.
sz_kernel_levenshtein_engine_init_tSignature of every sz_levenshtein_engine_init kernel.
capabilities.h:877 ↗
typedef sz_status_t(*) sz_kernel_levenshtein_engine_init_t(struct sz_levenshtein_engine_t *, sz_strings_view_t const *, sz_levenshtein_symbol_t, sz_allocator_t *, sz_stream_t);
sz_kernel_levenshtein_distances_tSignature of every sz_levenshtein_distances kernel, at either alphabet.
capabilities.h:881 ↗
typedef sz_status_t(*) sz_kernel_levenshtein_distances_t(struct sz_levenshtein_engine_t *, sz_strings_view_t const *, sz_size_t const *, sz_size_t const *, sz_size_t, sz_size_t *, sz_size_t, sz_stream_t);

Functions

sz_levenshtein_engine_initPrepares queries into one block from allocator, for the best capability of capabilities that has an init kernel.
levenshtein.h:68 ↗
sz_status_t sz_levenshtein_engine_init(
    sz_levenshtein_engine_t *engine,
    sz_strings_view_t const *queries,
    sz_levenshtein_symbol_t symbol,
    sz_capability_t capabilities,
    sz_allocator_t *allocator,
    sz_stream_t stream);

Backends

  • sz_levenshtein_engine_initserialhaswellskylakeicelakeneoncudablackwellrocmmetal

Parameters

engineoutUntouched unless the call succeeds; sz_levenshtein_engine_free frees it.
queriesinThe patterns every candidate is scored against, in any layout over host-readable texts, whose symbols and classes size the block.
symbolinWhether a distance counts bytes or UTF-8 runes.
capabilitiesinOne device's capabilities, like sz_capabilities_enabled_cpu or sz_capabilities_enabled_cuda report; its group picks the CPU or a GPU vendor.
allocatorinSource of the engine's blocks, or STRINGZILLA_NULL for sz_allocator_init_unified_best of capabilities.
streaminNull on the CPU. On a GPU, the stream to queue on, also naming the device: a cudaStream_t, a hipStream_t, or an id<MTLCommandQueue>; null for the default.

Notes

May join stream; no scoring verb ever does.

Statuses

sz_levenshtein_engine_freeReturns both of engine 's blocks to the allocator that built them, once the work queued on stream is done with them, and leaves it empty.
levenshtein.h:75 ↗
void sz_levenshtein_engine_free(
    sz_levenshtein_engine_t *engine,
    sz_stream_t stream);
sz_levenshtein_distancesEdit distances from every prepared query to every candidate, by the kernel of the capability engine was prepared for, exact up to bound.
levenshtein.h:112 ↗
sz_status_t sz_levenshtein_distances(
    sz_levenshtein_engine_t *engine,
    sz_strings_view_t const *candidates,
    sz_size_t const *symbol_counts,
    sz_size_t const *order,
    sz_size_t bound,
    sz_size_t *distances,
    sz_size_t distances_stride,
    sz_stream_t stream);

Backends

  • sz_levenshtein_distancesserialhaswellskylakeicelakeneoncudablackwellrocmmetal

A query prepared once scores any number of candidate batches: the engine's scratch only grows, so batches no larger than an earlier one allocate nothing. A host sweep advances a few candidates together and costs as long as the longest of them, so an order grouping similar lengths keeps it short, and it stops early once every candidate it holds is past bound.

Parameters

engineinThe prepared batch; its round scratch may grow. It keeps no stream and no round state on a device, so any number of that device's streams may score it at once.
candidatesinThe texts, on the residency engine was built for: any layout on the CPU, and on a device a tape sz_strings_to_tape_best wrote into a unified allocator.
symbol_countsinEach candidate's length in the engine's symbols by candidate index, as sz_levenshtein_utf8_runes counts runes, or null to count them as the sweep goes.
orderinThe visiting order, a permutation of the candidate indices, or null for the engine's own. Neither it nor symbol_counts changes a distance, and a device engine, which orders and counts candidates itself, reads neither.
boundinThe largest distance reported exactly; a candidate past it reports bound + 1 on every backend. STRINGZILLA_SIZE_MAX keeps every distance exact.
distancesoutThe [count, candidates] distances, query q at distances[q * stride + c], device-reachable on a device.
distances_strideinEntries from one query's row to the next, at least the count.
streaminNull on the CPU. On a GPU, the stream to queue on, which also names the device the round runs on; null for the default.

Notes

Grows the engine's host scratch when a round needs more than the last one did; never joins, so the caller joins stream before reading distances.

Statuses

sz_levenshtein_engine_init_serialPrepares queries into one block from allocator, for the serial kernels.
levenshtein.h:131 ↗
sz_status_t sz_levenshtein_engine_init_serial(
    sz_levenshtein_engine_t *engine,
    sz_strings_view_t const *queries,
    sz_levenshtein_symbol_t symbol,
    sz_allocator_t *allocator,
    sz_stream_t stream);

Backends

  • sz_levenshtein_engine_initserialhaswellskylakeicelakeneoncudablackwellrocmmetal

Parameters

engineoutUntouched unless the call succeeds; sz_levenshtein_engine_free frees it.
queriesinThe patterns every candidate is scored against, in any layout over host-readable texts, whose symbols and classes size the block.
symbolinWhether a distance counts bytes or UTF-8 runes.
allocatorinSource of the engine's blocks, or STRINGZILLA_NULL for sz_allocator_init_unified_serial.
streaminNull on the CPU.

Statuses

sz_levenshtein_distances_serialEdit distances from every prepared query to every candidate, by the kernel of the capability engine was prepared for, exact up to bound.
levenshtein.h:136 ↗
sz_status_t sz_levenshtein_distances_serial(
    sz_levenshtein_engine_t *engine,
    sz_strings_view_t const *candidates,
    sz_size_t const *symbol_counts,
    sz_size_t const *order,
    sz_size_t bound,
    sz_size_t *distances,
    sz_size_t distances_stride,
    sz_stream_t stream);

Backends

  • sz_levenshtein_distancesserialhaswellskylakeicelakeneoncudablackwellrocmmetal

A query prepared once scores any number of candidate batches: the engine's scratch only grows, so batches no larger than an earlier one allocate nothing. A host sweep advances a few candidates together and costs as long as the longest of them, so an order grouping similar lengths keeps it short, and it stops early once every candidate it holds is past bound.

Parameters

engineinThe prepared batch; its round scratch may grow. It keeps no stream and no round state on a device, so any number of that device's streams may score it at once.
candidatesinThe texts, on the residency engine was built for: any layout on the CPU, and on a device a tape sz_strings_to_tape_best wrote into a unified allocator.
symbol_countsinEach candidate's length in the engine's symbols by candidate index, as sz_levenshtein_utf8_runes counts runes, or null to count them as the sweep goes.
orderinThe visiting order, a permutation of the candidate indices, or null for the engine's own. Neither it nor symbol_counts changes a distance, and a device engine, which orders and counts candidates itself, reads neither.
boundinThe largest distance reported exactly; a candidate past it reports bound + 1 on every backend. STRINGZILLA_SIZE_MAX keeps every distance exact.
distancesoutThe [count, candidates] distances, query q at distances[q * stride + c], device-reachable on a device.
distances_strideinEntries from one query's row to the next, at least the count.
streaminNull on the CPU. On a GPU, the stream to queue on, which also names the device the round runs on; null for the default.

Notes

Grows the engine's host scratch when a round needs more than the last one did; never joins, so the caller joins stream before reading distances.

Statuses

sz_levenshtein_find_kernelFinds the Levenshtein kernel of kind, from the best of capabilities.
levenshtein.h:265 ↗
sz_status_t sz_levenshtein_find_kernel(
    sz_kernel_kind_t kind,
    sz_capability_t capabilities,
    sz_kernel_punned_t *kernel,
    sz_capability_t *capability);

Parameters

kindinThe verb whose kernel to find.
capabilitiesinThe mask to pick the best capability from.
kerneloutThe kernel, or null when none of capabilities has it.
capabilityoutThe capability the kernel belongs to, or zero.

Statuses