because your operators deserve to propagate at escape velocity
monoprop is a high-performance C++ library with Python bindings for Majorana and
Pauli propagation — a backend for classically simulating and variationally
optimising quantum circuits. Rather than storing the full quantum state, it
expands an operator in the Majorana basis and propagates it through a circuit,
truncating terms that contribute little. It scales to large systems by partitioning
the operator across cores and across nodes with MPI.
Warning
This package is under active development. This project follows Semantic Versioning. While in 0.x.y, breaking changes may occur in minor releases.
Pin your version if you depend on it. If you have feedback, please open an issue.
monoprop is compared with other open-source Pauli and Majorana propagation engines:
Head to our benchmarks page for more details.
Every commit on main also runs the internal benchmark suite, tracked over time
with Bencher to catch performance regressions.
📖 Full documentation: https://docs.monoprop.algorithmiq.tech
pip install monoprop # or: uv add monopropThe prebuilt PyPI wheels are single-process (built without MPI). For multi-rank runs, or to build the C++ library and executables, build from source (see below).
Back-propagate a Majorana observable through a one-gate circuit:
from monoprop import MajoranaPropagator, ExpGate, Circuit, MajoranaOperator
# Observable m_0 m_1 m_2 m_4, evolved under one Majorana rotation exp(+i θ · M_γ),
# generated by M_γ = i*m_4 m_5.
observable = MajoranaOperator({(0, 1, 2, 4): 1.0}, num_modes=8)
gate = ExpGate(
MajoranaOperator({(4, 5): 1j}, num_modes=8)
) # Hermitian generator: weight-2 => imaginary coeff
circuit = Circuit(gates=[gate], system_size=8, parameters=[0.5]) # one angle per gate
mp = MajoranaPropagator.from_circuit(circuit, observable, cutoff=16)
print(mp.evolved_operator()) # the gate splits the monomial into two termsQubit (Pauli) operators are simulated with PauliPropagator. Here we back-propagate
Z ⊗ Z through one exp(-i θ/2 · X_0) rotation:
from monoprop import PauliPropagator, ExpGate, Circuit, PauliOperator, Pauli
observable = PauliOperator(
{"ZZ": 1.0}, num_qubits=2
) # num_qubits lives on the observable
gate = ExpGate(PauliOperator({Pauli("X", 0): 1.0}, num_qubits=2)) # exp(+i θ · X_0)
circuit = Circuit(gates=[gate], system_size=2, parameters=[0.5]) # one angle per gate
mp = PauliPropagator.from_circuit(circuit, observable, cutoff=16) # construct + evolve
print(mp.evolved_operator()) # the gate splits Z ⊗ Z into two termsSee the getting-started guide for fermionic operators and more.
A from-source build gives you the editable Python bindings and the C++ build tree used for the library and unit tests. MPI is off by default in every build path; enable it explicitly.
Python bindings (via uv):
uv sync --all-extras -v
# with MPI:
monoprop_ENABLE_MPI=ON uv sync --all-extras -vC++ unit-test build:
uv sync --all-extras -v
ctest --test-dir build/editable/ReleaseThe platform packages are listed in tools/packages/ (apt.txt / brew.txt,
plus the -mpi lists), which is what CI and the devcontainer install.
just build [uv sync args…] performs the build CI performs — the same recipe
GitHub Actions calls, so a lane can be reproduced locally.
Full instructions — prerequisites, MPI options, and running the example
executable — are in the building guide.
In particular, from-source builds require hwloc and pkg-config so CMake can
locate hwloc.
uv sync --all-groups --all-extras -v # installs the workspace, incl. the bench tooling
just test # build, then the Python and C++ suites
just test-py / just test-cpp # one leg, against whatever is installed
just test-mpi # Python + C++ tests under MPISee the testing guide
for the with/without-MPI details and the rank matrix. CI has explicit MPI-enabled
lanes on Linux x86-64, Linux ARM64, and macOS; installing the mpi extra alone
does not enable the C++ MPI build. CI requires a registered MPI CTest variant,
and each whole-suite MPI run has a 600-second deadlock timeout. Source builds
select the MPI variant with monoprop_ENABLE_MPI=ON in the environment.
Standalone MPI-enabled C++ programs must initialize MPI before constructing a
propagator and finalize it only after all propagators have been destroyed. The
exported CMake target preserves the package's MPI setting independently of any
MPI::MPI_CXX target already present in the consuming project. QA coverage
merges separate serial and MPI-instrumented builds, including two-rank Python
and C++ MPI runs, so both compatibility paths contribute to the reports. Run
just code-coverage for the same combined report locally; it builds both
variants and renders monoprop-coverage/index.html.
The repository is a uv workspace:
- the root is
monopropitself (src/monoprop,cpp/); packages/monoprop-bench-toolsis the reusable benchmark harness — peak-memory measurement, the benchmarked model builders, and the result renderers — published separately so scripts and notebooks can depend on it without the repository;packages/bench-third-partyholds the cross-engine comparison scripts. It has CUDA-specific pins, so it is a standalone uv project with its own lockfile;benches/is monoprop's own benchmark suite, which uses the tooling above.
The repository ships a DevContainer that installs every
dependency (including the MPI toolchain and pre-commit hooks) and configures the
editor. To use it you need:
- A working Docker installation (Docker Desktop on macOS/Windows, Docker Engine on Linux).
- Visual Studio Code with the Dev Containers extension.
Clone the repository and open the folder in VS Code; it will build the container and run the setup automatically (this takes a few minutes the first time):
git clone https://github.com/Algorithmiq/monoprop.gitWithout a DevContainer, install the prerequisites from the building guide by hand.
The repository is a Nix flake, so on Nix or NixOS none of the prerequisites have to be installed by hand:
nix develop # dev shell: C++ toolchain, hwloc, MPI, uv, just, node
nix build .#monoprop # build the package (`.#monoprop-mpi` for the MPI build)
nix run # Python interpreter with monoprop importableInside nix develop the usual uv sync and just workflows apply unchanged.
Downstream flakes can follow their own nixpkgs, import monoprop.overlays.default,
and consume pkgs.monoprop or pkgs.monoprop-mpi; see the
building guide.
The Nix entrypoints are distributed from the repository flake, not in the PyPI
source distribution. Nix sandbox builds read the latest stable release from the
root VERSION file; setuptools-scm remains authoritative for normal Git-based
Python builds.
Please read CONTRIBUTING.md before opening a pull request. All contributions require accepting the Individual CLA through CLA Assistant. If you are contributing on behalf of your employer, contact cla@algorithmiq.fi to arrange a Corporate CLA.
The documentation is built with Fumadocs and hosted at
https://docs.monoprop.algorithmiq.tech. The Python API reference is generated from
docstrings (griffe) and the tutorials are
executed from the notebooks in docs/notebooks/. Building the documentation locally requires npm, the Node.js package manager. Once that is available, you can run:
just build-docs # output: docs/out/
just serve-docs # live-reloading dev server
just check-doc-links # checks exported HTML links (including external URLs)The link checker's options live in .lychee.postbuild.toml, so the recipe and the
docs workflow (which runs lychee through its own action) check the same thing.
Any PR that changes behavior, public APIs, build/test commands, or repository paths must update the relevant docs in the same change:
AGENTS.mdfor agent/developer workflow instructions.README.mdfor top-level usage and contributor guidance.docs/pages for user-facing and in-depth technical documentation.
If you use monoprop in your research, please cite:
@ARTICLE{Miller2025-aj,
title = "{Simulation of Fermionic circuits using Majorana Propagation}",
author = "Miller, Aaron and Holmes, Zoë and Salehi, Özlem and
Chakraborty, Rahul and Nykänen, Anton and Zimborás, Zoltán
and Glos, Adam and García-Pérez, Guillermo",
journal = "arXiv [quant-ph]",
year = 2025,
eprint = "2503.18939",
archivePrefix = "arXiv",
primaryClass = "quant-ph",
url = "https://arxiv.org/abs/2503.18939"
}monoprop is released under the Apache License 2.0.


