Skip to main content

bgen

C library and Python bindings for reading BGEN files (format specifications 1.2 and 1.3).

This repository is a maintained fork of the original limix/bgen and limix/cbgen projects, merged into a single codebase with a modern build system, nanobind-based Python bindings, and S3 support.

Features

  • Fast C library for parsing BGEN genotype files
  • Python bindings via nanobind
  • Supports BGEN 1.2 and 1.3 format specifications
  • zlib and zstd decompression support
  • Metafile indexing for efficient random access

Quick start (pixi)

pixi install
pixi run test

Building the C library

cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
cmake --build build
ctest --test-dir build --output-on-failure

System dependencies: zlib, zstd (installed via your system package manager or conda).

Installing the Python package

pip install .

Or in development mode:

pip install -e ".[test]"
pytest python/tests

Python usage

from cbgen import BgenFile, BgenMetafile

# Open a BGEN file
with BgenFile("example.bgen") as bgen:
    print(f"Variants: {bgen.nvariants}, Samples: {bgen.nsamples}")

    if bgen.contain_samples:
        samples = bgen.read_samples()

    # Create a metafile index for efficient access
    bgen.create_metafile("example.bgen.metafile")

# Read variant data via metafile
with BgenFile("example.bgen") as bgen:
    with BgenMetafile("example.bgen.metafile") as mf:
        partition = mf.read_partition(0)
        for variant in partition.variants:
            gt = bgen.read_genotype(variant.offset)
            print(f"{variant.rsid}: {gt.probability.shape}")

bgen.layout reports the native header's layout version (1 or 2), also available on the legacy bgen_file API. Sample and variant counts are unsigned 32-bit values exposed as Python integers. Unsupported header flags and truncated headers are rejected by the native reader.

Layout 1 supports raw and zlib-compressed, biallelic, diploid, unphased records, including metafile indexing. Its three independently rounded probabilities are decoded as q / 32768 without renormalization; all-zero triplets are marked missing and returned as NaNs. Layout 2 supports raw, zlib and zstd blocks with 1--32-bit probabilities, variable ploidy, and multiple alleles. Phased records whose samples all have zero ploidy return shape (nsamples, 0), retaining their ploidy and missingness arrays. Both layouts support precision=32 and precision=64; returned Python arrays remain valid after subsequent reads and after closing the file.

Structured batch reads

The modern BgenFile supports native batches for both layouts and every supported compression method, including mixed phase, allele counts and ploidy. One batch can supply multiple conversion fields without rereading each variant:

with BgenFile("example.bgen") as bgen:
    with BgenMetafile("example.bgen.metafile") as mf:
        offsets = [v.offset for v in mf.read_partition(0).variants]
    # Use bounded chunks, not the entire file, for large datasets.
    metadata = bgen.read_genotype_metadata(offsets)
    width = int(metadata.ncombs.max()) if len(offsets) else 0
    batch = bgen.read_genotypes_batch(offsets, max_ncomb=width, precision=64)
    probabilities = batch.probability  # (variants, samples, padded width)
    ploidy, missing = batch.ploidy, batch.missing
    for v in range(len(offsets)):
        row = probabilities[v, :, :batch.ncombs[v]]
        if batch.phased[v]:
            haplotypes = row.reshape(bgen.nsamples, -1, int(batch.nalleles[v]))

GenotypeBatchResult exposes columnar, C-contiguous, NumPy-owned arrays:

Field Shape Dtype
probability (V, S, W) float64 (default), or float32
phased (V,) bool
ploidy, missing (V, S) uint8, bool
ncombs (V,) uint32
probability_count (V, S) uint32
nalleles, nbits (V,) uint16, uint8

ncombs is each variant's single-reader width, based on its declared maximum ploidy, not the caller's padded width. probability_count is each sample's structural width even when missing: ploidy * nalleles if phased, otherwise choose(ploidy + nalleles - 1, nalleles - 1). Zero-ploidy unphased samples have one state; zero-ploidy phased samples have no probabilities. All-missing variants retain their structural widths. Missing samples and unused columns are NaN; distinguish them using missing and probability_count, not NaNs. Phased probabilities are haplotype-major; unphased probabilities retain BGEN's colex order. Layout-1 nbits is 16 and its exact independent rounding is preserved.

Offsets preserve order and duplicates. max_ncomb is capacity, never truncation: too-small or invalid widths raise an exception. An explicit width reads/decompresses and decodes each selected block once, returning metadata from that same read. None first scans widths, then rereads blocks to decode; compressed layout-2 blocks therefore decompress twice, but probability values are decoded only once. read_genotype_metadata returns GenotypeBatchMetadata without allocating or decoding probabilities. It still decompresses compressed layout-2 blocks and reads layout-1 triplets for missingness, and validates framing/header/payload lengths, not numerical probability sums. get_ncombs provides a narrower width-only scan.

Empty batches return (0, S, W), with W=0 for automatic sizing. Explicit W=0 is valid for wholly zero-ploidy phased batches. All arrays survive later reads and reader closure. Compute dosage from float64 probability views before casting output to float32 if rounding accuracy matters.

Output storage is V*S*W*itemsize + 6*V*S + 8*V bytes, including probability padding and metadata, plus offsets and native reusable one-variant encoded/ decoded scratch. There is no second full probability tensor or Python object per sample/variant. Choose V from a byte budget when S or W is large; sample slicing is not supported. File handles are not thread-safe. Legacy bgen_file.read_genotypes_batch remains probability-only float64 and does not allocate the new metadata arrays.

Performance checks

scripts/benchmark_decode.py compares two Release shared-library builds through their exported native public APIs. It generates deterministic, compressed, biallelic diploid fixtures and measures single reads, batch reads, combination scans and indexing, including float32 single reads and wider padded batches. Timings exclude fixture generation, initial native output-buffer allocation and warm-up; old/new process order alternates across repetitions. For example, on macOS:

pixi run python scripts/benchmark_decode.py --generate build-benchmark/fixtures \
  --zstd .pixi/envs/default/lib/libzstd.dylib
pixi run python scripts/benchmark_decode.py \
  --manifest build-benchmark/fixtures/fixtures.json \
  --old /path/to/before/libbgen.dylib --new /path/to/after/libbgen.dylib \
  --repeats 11 --loops 10 --output build-benchmark/results.json

Use matching compilers, optimization flags and compression libraries, and run without competing builds/tests. Results are local, warm-cache measurements, not a guarantee for other hardware, remote storage or arbitrary datasets. To compare actual installed Python wheels with the same interpreter and dependencies, use --python-old /path/to/old-install --python-new /path/to/new-install --modes single single32 batch padded scan instead of --old/--new. These measurements include NumPy output allocation and bypass editable-install hooks.

C API

Link against the bgen library:

find_package(bgen REQUIRED)
target_link_libraries(mytarget PRIVATE BGEN::bgen)

See include/bgen/bgen.h for the full C API.

Acknowledgments

  • Marc Jan Bonder for bug-reporting and improvement suggestions.
  • Yan Wong for bug-reporting and improvement suggestions.
  • Carl Kadie for bug-reporting and improvement suggestions.

Authors

License

This project is licensed under the MIT License.

Metadata

Release files for bgen-limix 4.13.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for bgen-limix 4.13.0
File Size Uploaded Provenance Actions
bgen_limix-4.13.0.tar.gz 4.9 MB With provenance Details for bgen_limix-4.13.0.tar.gz

Built distributions (wheels)

Table of built distributions (wheels) for bgen-limix 4.13.0
File Actions
bgen_limix-4.13.0-cp311-abi3-win_amd64.whl CPython 3.11 abi3 Windows x86-64 Details for bgen_limix-4.13.0-cp311-abi3-win_amd64.whl
bgen_limix-4.13.0-cp311-abi3-manylinux_2_28_x86_64.whl CPython 3.11 abi3 Linux glibc 2.28+ x86-64 Details for bgen_limix-4.13.0-cp311-abi3-manylinux_2_28_x86_64.whl
bgen_limix-4.13.0-cp311-abi3-manylinux_2_28_aarch64.whl CPython 3.11 abi3 Linux glibc 2.28+ ARM64 Details for bgen_limix-4.13.0-cp311-abi3-manylinux_2_28_aarch64.whl
bgen_limix-4.13.0-cp311-abi3-macosx_11_0_arm64.whl CPython 3.11 abi3 macOS 11.0+ ARM64 Details for bgen_limix-4.13.0-cp311-abi3-macosx_11_0_arm64.whl

Total release size: 18.5 MB

Release files / bgen_limix-4.13.0.tar.gz

Download URL bgen_limix-4.13.0.tar.gz
Size 4.9 MB
Tags Source
SHA-256 checksum
How to use checksums
845cf079e79f1a557634b6ee5a707df8e5dee631c5d9d7dfbf42a0c04fb8de88
BLAKE2b-256 checksum
How to use checksums
8f103e7f58d0fdee35cf08728d30a941cdcd3093e049da6b5746f3107656b155
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.

Transparency log

Release files / bgen_limix-4.13.0-cp311-abi3-win_amd64.whl

Download URL bgen_limix-4.13.0-cp311-abi3-win_amd64.whl
Size 3.3 MB
Tags CPython 3.11 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
f2dafd0953096d23715a57aaf3fed3c2b8ec6b9afb596dd96444ba0ab71590a5
BLAKE2b-256 checksum
How to use checksums
80b809fe6493fc9024578ad9e9d6d69e021ac1b4bd07a52c1f90cba5a05ae3d5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.

Transparency log

Release files / bgen_limix-4.13.0-cp311-abi3-manylinux_2_28_x86_64.whl

Download URL bgen_limix-4.13.0-cp311-abi3-manylinux_2_28_x86_64.whl
Size 4.2 MB
Tags CPython 3.11 Linux glibc 2.28+ x86-64 abi3
SHA-256 checksum
How to use checksums
419057cf03d62effaec6a5bf6ad05d67f75be2c5cb05b63a4c27aa600703844b
BLAKE2b-256 checksum
How to use checksums
b30b22bbcb90314af1d89d1fd0e87cb5d4c56c476fcec05efda71b7b9d6623d0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.

Transparency log

Release files / bgen_limix-4.13.0-cp311-abi3-manylinux_2_28_aarch64.whl

Download URL bgen_limix-4.13.0-cp311-abi3-manylinux_2_28_aarch64.whl
Size 4.0 MB
Tags CPython 3.11 Linux glibc 2.28+ ARM64 abi3
SHA-256 checksum
How to use checksums
cf65e29c9279744dea4421b03d23ba59755ce1a49ea8e7c50aafa759d18d24af
BLAKE2b-256 checksum
How to use checksums
34e17f428b7b9e8a32684b2669911da91a95b8a44c78b207f2416c97de2c7e71
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.

Transparency log

Release files / bgen_limix-4.13.0-cp311-abi3-macosx_11_0_arm64.whl

Download URL bgen_limix-4.13.0-cp311-abi3-macosx_11_0_arm64.whl
Size 2.1 MB
Tags CPython 3.11 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
0698465f69dacbb0eff24854a86da0ed4d9359cd0707bd0013142453a28d5e44
BLAKE2b-256 checksum
How to use checksums
dea182174664b46e158c7b90f1714cf2c40b7c6f83c836a427e20ef3737d5458
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.

Transparency log

Security for bgen-limix 4.13.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 5 files in this release have been uploaded with provenance metadata.

Select from 5 files

Attestation for bgen_limix-4.13.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page