gpmap-v2
Live interactive tour: gpmap-v2.streamlit.app (source under examples/streamlit/).
A typed, Rust-accelerated container and simulator toolkit for genotype-phenotype maps.
gpmap-v2 is a clean-break rewrite of harmslab/gpmap. It exposes the same conceptual model (a GenotypePhenotypeMap backed by a pandas DataFrame) with a locked schema, vectorized hot paths, and a PyO3 Rust core for the operations that used to be inner Python loops.
Why
- Fast. String-encoded genotypes are replaced with packed
uint8matrices. The encoding step (genotypes_to_binary) runs rayon-parallel in Rust. Construction is 5x faster than v1 at L=16 (65k genotypes), andbinary_packedis a free cached lookup afterward -- no repeated re-encoding on each access. - Typed. Full type hints, mypy-checked, strict mode.
- Safe. Cartesian-product enumeration is size-guarded out of the box (
SpaceTooLargeError). No more silent 10^26 allocations. - Stable surface. The container and
encoding_tableschema are locked inSCHEMA.mdfor downstream consumers. - Modern tooling.
uv+maturin+pyproject.toml. Automated releases viapython-semantic-release. OIDC-based PyPI publishing.
Install
pip install gpmap-v2
Or with uv:
uv add gpmap-v2
Python 3.10+. Prebuilt wheels ship for Linux (x86_64, aarch64), macOS (x86_64, aarch64), and Windows (x64).
Quick start
from gpmap import GenotypePhenotypeMap
gpm = GenotypePhenotypeMap(
wildtype="AAA",
genotypes=["AAA", "AAT", "ATA", "TAA", "ATT", "TAT", "TTA", "TTT"],
phenotypes=[0.1, 0.2, 0.2, 0.6, 0.4, 0.6, 1.0, 1.1],
stdeviations=[0.05] * 8,
)
gpm.genotypes # np.ndarray of strings, shape (8,)
gpm.phenotypes # np.ndarray[float64], shape (8,)
gpm.binary_packed # np.ndarray[uint8], shape (8, 3) - the fast path
gpm.binary # np.ndarray of '0'/'1' strings - back-compat accessor
gpm.n_mutations # per-genotype Hamming weight
gpm.encoding_table # pandas DataFrame per SCHEMA.md
gpm.data # pandas DataFrame view for Jupyter
Simulating landscapes
from gpmap.simulate import NKSimulation, MountFujiSimulation
import numpy as np
sim = NKSimulation(
wildtype="AAAA",
mutations={i: ["A", "T"] for i in range(4)},
K=2,
rng=np.random.default_rng(0),
)
sim.phenotypes.shape # (16,)
I/O round-trips
from gpmap import to_json, read_json, to_csv, read_csv
to_json(gpm, "map.json")
gpm2 = read_json("map.json")
to_csv(gpm, "map.csv") # writes map.csv + map.csv.meta.json
gpm3 = read_csv("map.csv")
Public API surface
The full list of stable exports lives in gpmap.__all__. The ones downstream consumers depend on (notably epistasis-v2) are:
GenotypePhenotypeMap,GenotypePhenotypeMap.from_dataframeget_encoding_table,genotypes_to_binary,genotypes_to_binary_packedupper_transform,lower_transformStandardDeviationMap,StandardErrorMapSpaceTooLargeError,SchemaError,UnknownLetterErrorread_csv,read_json,read_pickle,read_excel(andto_*counterparts)- All simulators under
gpmap.simulate
The load-bearing schema contract (column names, dtypes, invariants) is in SCHEMA.md. Breaking changes to that document bump the major version.
Benchmarks vs v1
Measured on Windows 11 against gpmap==0.7.0. Full biallelic space (AT alphabet),
timeit best-of-5. See benchmarks/vs_v1.py for scripts and setup.
v2 encodes eagerly at construction (Rust, parallel). v1 encodes lazily, so construction is cheaper but binary access costs extra on every call. The table below times construction including encoding for v2 and just object setup for v1.
| L | genotypes | v1 construct (ms) | v2 construct (ms) | speedup |
|---|---|---|---|---|
| 8 | 256 | 2.14 | 6.23 | 0.3x |
| 10 | 1,024 | 4.48 | 7.99 | 0.6x |
| 12 | 4,096 | 14.57 | 10.53 | 1.4x |
| 14 | 16,384 | 59.30 | 18.68 | 3.2x |
| 16 | 65,536 | 258.18 | 51.19 | 5.0x |
binary_packed access after construction: v2 ~0 ms (cached); v1 binary access at L=16
costs ~11 ms per call (re-encoded each time from the underlying pandas column).
Development
git clone https://github.com/lperezmo/gpmap-v2
cd gpmap-v2
uv sync
uv run maturin develop --release
uv run pytest
uv run ruff check python/gpmap tests
A typical dev inner loop after editing Rust:
uv run maturin develop --release && uv run pytest
Consuming from another local project
gpmap-v2 is designed to be consumed as an editable dependency during co-development with sister packages (e.g. epistasis-v2). In the consumer's pyproject.toml:
[tool.uv.sources]
gpmap-v2 = { path = "/absolute/path/to/gpmap-v2", editable = true }
[project]
dependencies = ["gpmap-v2"]
Then uv sync or uv add gpmap-v2 in the consumer. Imports remain import gpmap.
Migration from v1 (harmslab/gpmap)
gpmap-v2 is not wire-compatible with v1. Key differences:
- Distribution name is
gpmap-v2on PyPI; import path is stillgpmap. - The
encoding_tablecolumngenotype_indexhas been renamed tosite_indexto match its actual meaning. The old name is still readable via a deprecated alias. read_dataframeis nowfrom_dataframe.binary_packed(uint8 2D) is exposed alongside the string-formbinary. Prefer the packed form for any hot-path consumer.- JSON files must carry
"schema_version": "1". Legacy files are readable with a warning. upper_transformandlower_transformare now genuinely distinct (v1 had a copy-paste bug where they were identical).stats.unbiased_varhonors theaxiskwarg (v1 ignored it and hardcodedaxis=1).simulate.random_mutation_setno longer mutates the module-level amino-acid list.simulate.MultiPeakMountFujiSimulationpeak search has a retry cap; it raises instead of spinning forever on infeasible constraints.
See CHANGELOG.md for the full list.
Releases
Releases are driven by python-semantic-release on merge to main. Commit messages follow Conventional Commits:
fix: ...-> patchfeat: ...-> minorfeat!: ...orBREAKING CHANGE:footer -> major
CHANGELOG.md, version bumps, Git tags, GitHub Releases, wheel builds, and PyPI uploads all happen automatically.
License
MIT. See LICENSE.
Metadata
Release files for gpmap-v2 1.0.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| gpmap_v2-1.0.2.tar.gz | 25.6 kB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| gpmap_v2-1.0.2-cp310-abi3-win_amd64.whl | CPython 3.10 | abi3 | Windows x86-64 | Details |
| gpmap_v2-1.0.2-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.10 | abi3 | Linux glibc 2.17+ x86-64 | Details |
| gpmap_v2-1.0.2-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl | CPython 3.10 | abi3 | Linux glibc 2.17+ ARM64 | Details |
| gpmap_v2-1.0.2-cp310-abi3-macosx_11_0_arm64.whl | CPython 3.10 | abi3 | macOS 11.0+ ARM64 | Details |
| gpmap_v2-1.0.2-cp310-abi3-macosx_10_12_x86_64.whl | CPython 3.10 | abi3 | macOS 10.12+ x86-64 | Details |
Total release size: 1.8 MB
Release files / gpmap_v2-1.0.2.tar.gz
| Download URL | gpmap_v2-1.0.2.tar.gz |
|---|---|
| Size | 25.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6e56ce890a431bcfaacb4313b7b1869a09b34376bae5909685ed829e4641816e
|
|
BLAKE2b-256 checksum How to use checksums |
10e5c7156608d3136b5954676e702d76ba75e894f7994d21a8ed0e856ace398e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / gpmap_v2-1.0.2-cp310-abi3-win_amd64.whl
| Download URL | gpmap_v2-1.0.2-cp310-abi3-win_amd64.whl |
|---|---|
| Size | 232.4 kB |
| Tags | CPython 3.10 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
2e4cb6c153fa69ba25d094fa4d607098f32c37c92655b541a67cfffdbf724c9d
|
|
BLAKE2b-256 checksum How to use checksums |
c08553a6154ceedd93c523a3493e0784431c623b75b7a6053387787d21895454
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / gpmap_v2-1.0.2-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | gpmap_v2-1.0.2-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 408.0 kB |
| Tags | CPython 3.10 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
33584c4deeea18a4294be051d1bc4a69a68b8ce7069ae68d28657917aae8469f
|
|
BLAKE2b-256 checksum How to use checksums |
22c6e3589245a176241a5c5d5408dcde8c234d4754cc328d5220c83aa611b573
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / gpmap_v2-1.0.2-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | gpmap_v2-1.0.2-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 400.7 kB |
| Tags | CPython 3.10 Linux glibc 2.17+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
b2776aaaf33153c3ed604b9b93c1b5a4783bb5fa0e07d37cc920ad6e5aec7f9d
|
|
BLAKE2b-256 checksum How to use checksums |
e468f80c11da58f846271a24fbf22baa1cf3ff77d3f58c5cf19428159bc20ffc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / gpmap_v2-1.0.2-cp310-abi3-macosx_11_0_arm64.whl
| Download URL | gpmap_v2-1.0.2-cp310-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 356.7 kB |
| Tags | CPython 3.10 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
5bc2ba03a530171ca67392b513f28d652d5e92e2ffe3af806d29e01b1adba3ca
|
|
BLAKE2b-256 checksum How to use checksums |
ece1fe4def3bd98bb03c02622ba0e5842e41c3f4774ce6adf4e29ae1e023b90d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / gpmap_v2-1.0.2-cp310-abi3-macosx_10_12_x86_64.whl
| Download URL | gpmap_v2-1.0.2-cp310-abi3-macosx_10_12_x86_64.whl |
|---|---|
| Size | 354.5 kB |
| Tags | CPython 3.10 abi3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
5e9417afe22c0df4ebe37b28239eafd5e92c082336ced36dcd9dc484a4efa955
|
|
BLAKE2b-256 checksum How to use checksums |
e2d3f45b20c7fa407c4099e8e80e510c0273f1de1d9c23cae80650a60b732b0f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|