Drop-in Rust acceleration of scVelo for single-cell RNA velocity.
Project description
scvelo-rs
Drop-in compatible. More velocity - A drop-in Rust + PyO3 port of scVelo.
Rust implementation of recover_dynamics, velocity_graph,
deterministic velocity, and pca. Lighter operations like plotting, datasets, pseudotime & terminal states still route through scVelo and scanpy to keep them bit-exact.
# Option 1 — drop-in import.
import scvelo_rs as scv
adata = scv.datasets.pancreas()
scv.pp.filter_and_normalize(adata); scv.pp.moments(adata)
scv.tl.recover_dynamics(adata) # ~35× faster than the original scvelo
scv.tl.velocity(adata, mode="dynamical")
scv.tl.velocity_graph(adata)
scv.pl.velocity_embedding_stream(adata, basis="umap")
# Option 2 — monkey-patch. Keep your existing `import scvelo as scv`;
# only the three patched hot paths get the Rust kernel.
import scvelo as scv
import scvelo_rs.patch # noqa: F401 # patches scv.tl.{recover_dynamics, velocity, velocity_graph}
scv.tl.recover_dynamics(adata) # bit-exact, no other code change needed
Highlights
- 30–40× faster than the original scVelo on representative atlases (5k–100k cells), and ~2–4× lower peak memory. See Benchmarks.
- Bit-exact equivalence to scVelo on 99.9% of genes — the residual
drift is at f64 ULP scale (per-gene Pearson r = 1.0000 across
fit_alpha,fit_beta,fit_gamma,fit_t_). - Drop-in: import
scvelo_rs.patchand every downstream call toscv.tl.{recover_dynamics, velocity, velocity_graph}routes to Rust. Orimport scvelo_rs as scvfor the full API. - Cross-platform wheels for Linux x86_64/aarch64, macOS arm64/x86_64,
Windows x86_64. Single
abi3-py310wheel covers Python 3.10–3.13. - CPU-only. Runs anywhere Python runs — laptop, HPC, Docker, ARM. No CUDA. No Numba. No JIT warmup.
Installation
pip install scvelo-rs
scVelo and scanpy are runtime dependencies (used for plotting, dataset I/O, DPT/PAGA pass-through). They are pulled in automatically.
Quick start
Three usage patterns, in order of how invasive the migration is.
1. Monkey-patch (zero code changes)
Add one line at the top of your existing scVelo script:
import scvelo as scv
import scvelo_rs.patch # noqa: F401 # swaps scv.tl.{recover_dynamics, velocity, velocity_graph}
adata = scv.datasets.pancreas()
scv.pp.filter_and_normalize(adata)
scv.pp.moments(adata)
scv.tl.recover_dynamics(adata) # now Rust-backed
scv.tl.velocity(adata, mode="dynamical")
scv.tl.velocity_graph(adata)
Originals are preserved at scv.tl.<name>_original for A/B comparison.
2. Drop-in import
Replace import scvelo as scv with import scvelo_rs as scv. The
scvelo_rs.{tl, pp, pl, datasets} namespaces expose scVelo's full public
API; the hot loops route through Rust, everything else passes through
scVelo unchanged.
import scvelo_rs as scv
adata = scv.datasets.pancreas()
scv.pp.filter_and_normalize(adata)
scv.pp.moments(adata)
scv.tl.recover_dynamics(adata)
scv.tl.velocity(adata, mode="dynamical")
scv.tl.velocity_graph(adata)
scv.pl.velocity_embedding_stream(adata, basis="umap")
3. Direct call
import scvelo_rs
scvelo_rs.recover_dynamics(adata) # same signature as scv.tl.recover_dynamics
See examples/ for runnable end-to-end scripts.
Benchmarks
Measured locally on standard datasets.
Wall time
| benchmark | cells | genes | scvelo | scvelo-rs | speedup |
|---|---|---|---|---|---|
| recover_dynamics (5k cells, 50 genes) | 5,000 | 50 | 43.24 s | 1.03 s | 42.0× |
| recover_dynamics + velocity (20k, 100) | 20,000 | 100 | 380.02 s | 10.09 s | 37.7× |
| recover_dynamics + velocity + velocity_graph (20k, 100) | 20,000 | 100 | 389.54 s | 10.79 s | 36.1× |
| full pipeline (50k, 100) | 50,000 | 100 | 1202.26 s | 34.35 s | 35.0× |
| recover_dynamics (100k, 30) | 100,000 | 30 | 671.65 s | 22.85 s | 29.4× |
Peak memory
| benchmark | cells | genes | scvelo | scvelo-rs | saved |
|---|---|---|---|---|---|
| recover_dynamics (5k, 50) | 5,000 | 50 | 108.4 MB | 35.0 MB | 73 MB |
| velocity_graph (20k, 100) | 20,000 | 100 | 1727.5 MB | 626.5 MB | 1,101 MB |
| steady-state layers (5k, 200) | 5,000 | 200 | 252.1 MB | 66.2 MB | 186 MB |
| full pipeline (50k, 100) | 50,000 | 100 | 4831.6 MB | 1879.3 MB | 2,952 MB |
| recover_dynamics + velocity_graph (100k, 30) | 100,000 | 30 | 7074.4 MB | 2794.9 MB | 4,280 MB |
Build from source
Requires Rust 1.75+ and Python 3.10+.
git clone https://github.com/ilaykav/scvelo-rs
cd scvelo-rs
python -m venv .venv && source .venv/bin/activate # or .venv\Scripts\activate on Windows
pip install -e ".[dev]"
maturin develop --release
pytest tests/unit tests/integration
The Rust crates nalgebra (SVD for PCA) and hnsw_rs (HNSW for KNN)
are pure-Rust — no OpenBLAS, no vcpkg, no system C libraries.
Cross-platform builds work out of the box.
Documentation
A full Sphinx site (Quick start, Installation, Migration from scVelo,
Architecture, Numerical parity, Benchmarks) is in the works for v0.2.
Until then, this README, the CHANGELOG, and the
runnable scripts under examples/ and
notebooks/ cover the same ground.
Contributing
Bug reports, PRs, and benchmark contributions welcome. See
CONTRIBUTING.md — the short version is:
git clone https://github.com/ilaykav/scvelo-rs
cd scvelo-rs
pip install -e ".[dev]"
maturin develop --release
pytest tests/unit tests/integration
Bit-exact equivalence to scVelo is the contract for every Rust-backed
function. PRs that move per-gene drift above 1e-9 need a documented
reason.
License
Released under BSD-3-Clause. The Rust kernels are independent reimplementations of theislab's published algorithms — credit for the underlying methods belongs to La Manno et al. 2018 (RNA velocity, Nature, doi:10.1038/s41586-018-0414-6) and Bergen et al. 2020 (scVelo, Nat Biotechnol, doi:10.1038/s41587-020-0591-3).
Citing this work
scvelo-rs is a faithful port: the method is Bergen et al. 2020,
the implementation is this repository. Always cite the original
scVelo paper as the primary reference; cite the version of
scvelo-rs you used as a software dependency (pip show scvelo-rs
or scvelo_rs.__version__).
@article{bergen2020generalizing,
title = {Generalizing RNA velocity to transient cell states through dynamical modeling},
author = {Bergen, Volker and Lange, Marius and Peidli, Stefan and
Wolf, F. Alexander and Theis, Fabian J.},
journal = {Nature Biotechnology},
year = {2020},
doi = {10.1038/s41587-020-0591-3}
}
@software{scvelo_rs,
title = {scvelo-rs: a Rust acceleration of scVelo's dynamical model},
author = {Kavitzky, Ilay},
year = {2026},
version = {0.1.0},
url = {https://github.com/ilaykav/scvelo-rs},
note = {Rust + PyO3 port of Bergen et al. 2020 (doi:10.1038/s41587-020-0591-3)}
}
Authored and maintained by Ilay Kavitzky. Contribution guidelines are
in CONTRIBUTING.md.
Reporting bugs and feature requests
Open an issue at github.com/ilaykav/scvelo-rs/issues.
Bug reports — include:
scvelo-rsversion (pip show scvelo-rs)- OS and Python version
- A minimum reproducer (a small
.h5adslice + the calls that fail is usually enough) - What you expected vs what you got
Parity issues (a fitted parameter or velocity vector differs from the original scvelo): include both runs' values for the affected gene/cell, the relative drift, and which fixture you ran on.
Feature requests — describe the workflow you can't do today, not just the API you'd like. Atlas-scale parity reports are especially welcome.
For anything else, direct mail: ilay.kavitzky@gmail.com.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file scvelo_rs-0.1.0.tar.gz.
File metadata
- Download URL: scvelo_rs-0.1.0.tar.gz
- Upload date:
- Size: 100.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: maturin/1.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ce115398a57a679b0b90deb24e7290a19aecc2d3f059d926b20b1e3aca75fab8
|
|
| MD5 |
6aaf46f4f1cfb0854476011710e1d5ca
|
|
| BLAKE2b-256 |
39537e32c0591c72dc77676df69c931de8ed1bb45e3846ec38a6f78681fef23c
|
File details
Details for the file scvelo_rs-0.1.0-cp310-abi3-win_amd64.whl.
File metadata
- Download URL: scvelo_rs-0.1.0-cp310-abi3-win_amd64.whl
- Upload date:
- Size: 1.6 MB
- Tags: CPython 3.10+, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: maturin/1.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c5e7ade0f166fc36bfe98c7d1e808f12cb29810e673c74376c25585ed8431add
|
|
| MD5 |
83ebc0d5795eb72c0a5a017ad7e4bea1
|
|
| BLAKE2b-256 |
7a1f2471a31edab2ef127b5babdfda8970a340ed5567568551ad5b98c314be5d
|
File details
Details for the file scvelo_rs-0.1.0-cp310-abi3-manylinux_2_28_x86_64.whl.
File metadata
- Download URL: scvelo_rs-0.1.0-cp310-abi3-manylinux_2_28_x86_64.whl
- Upload date:
- Size: 1.7 MB
- Tags: CPython 3.10+, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: maturin/1.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e2a6d0e91d6bc486162c3b4b8e7181d435711c7dfab3bb57ca2588af45b296ca
|
|
| MD5 |
56a32f036f23a28a958bef0bd7ea518a
|
|
| BLAKE2b-256 |
fb6a421c22f7f9c05116696097a0cb0408f2c82f38e9180fc09c82b2cda8871b
|
File details
Details for the file scvelo_rs-0.1.0-cp310-abi3-manylinux_2_28_aarch64.whl.
File metadata
- Download URL: scvelo_rs-0.1.0-cp310-abi3-manylinux_2_28_aarch64.whl
- Upload date:
- Size: 1.6 MB
- Tags: CPython 3.10+, manylinux: glibc 2.28+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: maturin/1.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
90034fe6b67a3da260ec627a5710003ef7177069196cc67aeee1574078ccd2b2
|
|
| MD5 |
f8a82e15c804d91c36b31d5b807437c9
|
|
| BLAKE2b-256 |
fc11f593e51867f235c92fc8ef7e8e892e4b052430b2cc1caf93aadaf0341c18
|
File details
Details for the file scvelo_rs-0.1.0-cp310-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: scvelo_rs-0.1.0-cp310-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 1.5 MB
- Tags: CPython 3.10+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: maturin/1.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7f541dae597d37b26e11cd5d50192644f81cb1f4fceba3c25ad5d36c99b63622
|
|
| MD5 |
70c3165fbfe277177abb7ad9e6a568a6
|
|
| BLAKE2b-256 |
bfe04cf6650c138589b88e62f7fcdae0fbedd81adb182d225efefbbd35d9480e
|