strobemers-rs
Rust implementation of strobemer generation (MinStrobes, RandStrobes).
Streaming iterators produce 64-bit strobemer hashes over DNA/RNA sequences.
Background
- The original strobemer concept and reference implementation live at ksahlin/strobemers.
- This crate’s design was guided by the Go port found at shenwei356/strobemers, but the code here is a complete Rust‐native rewrite (zero
unsafe).- Strobe selection is verified against that Go port value-by-value in
tests/go_conformance.rs. Hash values differ between the two, because they use different ntHash libraries; the tests therefore drive both with the same injected k-mer hasher.- One deliberate deviation: when
w_min > (n-1) * k, the search window for the last few positions starts past the end of the sequence. The Go code silently reuses the previous strobe there; this crate ends iteration instead, so every reported strobe position is a real k-mer.
Overview
Strobemers are an alternative to contiguous k-mer hashing designed to improve sensitivity in long-read alignment and genome comparison.
This crate provides:
-
MinStrobes (order 2/3)
Choose subsequent strobes by selecting the minimum hash within a sliding window. -
RandStrobes (order 2/3)
Choose subsequent strobes by a pseudo-random but reproducible rule derived from hash values.
Sequences must consist of A, C, G, T/U only. The default hasher skips
k-mer windows containing any other base, which would break the mapping from
hash index to sequence position, so such sequences are rejected with
StrobeError::IncompleteHashValues (as in the Go reference).
Installation
Add to your Cargo.toml via command line.
cargo add strobemers-rs
Quick Start
use ;
Performance notes
Both iterators precompute one 64-bit hash per k-mer up front, so scratch memory
is 8 bytes per base. MinStrobes also needs the minimum of a sliding window: it
precomputes that as a table — another 16 bytes per base — while the table stays
cache-resident, and computes it online for longer sequences, keeping only
O(w_max) entries. Scratch for a 20 Mbp sequence is therefore 152 MiB rather
than 457 MiB, and per-base throughput stops degrading as the sequence grows.
Measured with cargo bench on a Xeon Platinum 8480+ over 1 Mbp of random DNA,
k = 31, w_min = 20, w_max = 50:
| default target | -C target-cpu=native |
|
|---|---|---|
MinStrobes order 2 |
25.9 ms | 26.4 ms |
MinStrobes order 3 |
30.1 ms | 30.6 ms |
RandStrobes order 2 |
30.8 ms | 21.1 ms |
RandStrobes order 3 |
55.1 ms | 39.4 ms |
RandStrobes picks its next strobe by minimising (h1 + h2) & prime over the
window. With the default prime that reduces to a branchless 64-bit min, which
vectorises into vpminuq when the target has AVX-512 — building with
RUSTFLAGS="-C target-cpu=native" (or -C target-cpu=x86-64-v4) is worth about
1.4x there. MinStrobes is unaffected, being bound by memory traffic rather
than by that loop.
Both iterators are ExactSizeIterator, so collect() allocates exactly once.
Using a Custom Hash Function
By default, strobemers-rs uses nthash-rs for k-mer hashing.
However, you can inject your own hash function by implementing the KmerHasher trait and passing it via the with_hasher method. See the example for more details.
License
This project is MIT‑licensed (see LICENSE).