Skip to main content

umi-collapse

CI Coverage Types Mutation Python License

Deterministic, dependency-free UMI error correction for tabular DNA counts. It provides a transparent all-pairs adjacency baseline, an indexed radius-one implementation, and directional clustering using the UMI-tools criterion high >= 2 * low - 1.

Installation

python -m pip install umi-collapse

For development and the benchmark:

python -m pip install -e '.[dev]'
pytest --cov=umi_collapse --cov-branch --cov-fail-under=100

Quickstart

Input is an exact two-column TSV. Counts must be positive integers.

umi	count
AAAA	10
AAAT	5
AATT	3
CCCC	7
umi-collapse counts.tsv --mode directional -o clusters.tsv

The stable TSV result is:

cluster	representative	total	members
1	AAAA	18	AAAA,AAAT,AATT
2	CCCC	7	CCCC

Use --json for a JSON array, --mode adjacency for undirected connected components, or --naive with adjacency mode to select the all-pairs baseline. The equivalent module command is python -m umi_collapse.

The Python API accepts a mapping and returns immutable cluster records:

from umi_collapse import collapse

clusters = collapse({"AAAA": 10, "AAAT": 5, "AATT": 3})
assert clusters[0].total == 18

Algorithm

flowchart LR; I[umi TSV counts] --> V[validate: ACGT, equal length]; V --> N[radius-1 index: masked buckets]; N --> E[candidate edges]; E --> D{mode}; D -->|adjacency| CC[connected components]; D -->|directional| DI[count-ordered collapse]; CC --> O[clusters]; DI --> O

Hamming distance counts substitutions between equal-length UMIs. Adjacency mode connects UMIs at distance one and returns connected components. Its indexed candidate generator enumerates the three possible substitutions at every position and checks membership in a hash set, requiring $3L$ lookups per UMI rather than comparing every pair. The deliberately simple naive implementation is retained as an executable correctness oracle.

Directional mode starts from UMIs ordered by descending count and then lexicographically. An edge may be traversed from a higher-count UMI to a lower one only when high >= 2 * low - 1; qualifying descendants can themselves absorb further errors. Representatives, members, and output clusters all have explicit stable ordering, so repeated runs are byte-for-byte reproducible.

Reproducible capability evidence

benchmarks/benchmark_candidates.py creates a seeded set of 12-base parent UMIs and one-substitution errors until the requested total UMI count is reached, computes the complete edge sets using both indexed and all-pairs generation, fails if those sets differ, and reports median timings:

python benchmarks/benchmark_candidates.py --seed 2026 --umis 1000 --length 12

The output includes identical_edges, both elapsed times, and their measured speedup. This is material algorithmic improvement: candidate work changes from $O(N^2 L)$ Hamming comparisons to $O(NL)$ expected hash lookups for fixed DNA alphabet size. Timings are intentionally generated locally rather than quoted as a universal number because they depend on hardware and interpreter state. The test suite also exercises a smaller seeded benchmark and requires exact edge-set equality.

Validation and failure behavior

The reader rejects malformed headers or rows, duplicate UMIs (case-insensitive), non-ACGT symbols, mixed UMI lengths, and nonpositive or non-integer counts. Errors are printed to stderr and the CLI exits with status 2. CI runs Ruff, strict mypy, and the full property-based and deterministic suite on Linux and macOS with Python 3.11–3.13, enforcing 100% statement and branch coverage over all package modules.

Mutation testing

The deterministic suite generated 425 mutants and killed 413 (97.18%). The 12 survivors were individually reviewed and are behavior-equivalent under the public contract, not missed mutants. There were zero suspicious results and zero timeouts.

Behavior-equivalent rationale Count
One-edit neighbor strict comparison 1
Indexed-versus-naive identical edge contract and default routing 5
Typing cast identity 1
UTF-8 aliases and default encodings 5
Total reviewed equivalents 12

Reproduce the run from the repository root:

source .venv/bin/activate
mutmut run
mutmut results

Limitations

The indexed implementation supports Hamming radius one only; it does not handle insertions, deletions, ambiguous IUPAC bases, quality scores, paired reads, or streaming input. All UMIs are retained in memory. Directional clustering is a count-table correction heuristic, not a model of sample-specific sequencing chemistry. The benchmark models substitution errors and is not evidence about biological accuracy.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

umi_collapse-1.0.0.tar.gz (13.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

umi_collapse-1.0.0-py3-none-any.whl (10.4 kB view details)

Uploaded Python 3

File details

Details for the file umi_collapse-1.0.0.tar.gz.

File metadata

  • Download URL: umi_collapse-1.0.0.tar.gz
  • Upload date:
  • Size: 13.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for umi_collapse-1.0.0.tar.gz
Algorithm Hash digest
SHA256 3420801ce20af195a048b543fff49faf9fa58e02ec809c365680efc1dca81055
MD5 502eb0b0c962929041f6b033b1a8eb82
BLAKE2b-256 e8d5400db3fd60dfe9173e748ee05adc3a57d201177c2aefaddb924abe133322

See more details on using hashes here.

Provenance

The following attestation bundles were made for umi_collapse-1.0.0.tar.gz:

Publisher: publish.yml on bmouler/umi-collapse

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file umi_collapse-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: umi_collapse-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 10.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for umi_collapse-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 36cae4453e649da236e422d54a3ba75b07980a5173539e3cd1331436b36cd167
MD5 87324f5464a3ed7b96a03443bf7a2393
BLAKE2b-256 10e5abfcf8bc5ac5ffa8212e2c47799f32b9f9e332229d4c75cc3e5715f68db6

See more details on using hashes here.

Provenance

The following attestation bundles were made for umi_collapse-1.0.0-py3-none-any.whl:

Publisher: publish.yml on bmouler/umi-collapse

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page