PyMatching
PyMatching: A Python/C++ library for decoding quantum error correcting codes with minimum-weight perfect matching.
Install / Use
/learn @oscarhiggott/PyMatchingREADME
PyMatching 2
PyMatching is a fast Python/C++ library for decoding quantum error correcting (QEC) codes using the Minimum Weight Perfect Matching (MWPM) decoder. Given the syndrome measurements from a quantum error correction circuit, the MWPM decoder finds the most probable set of errors, given the assumption that error mechanisms are independent, as well as graphlike (each error causes either one or two detection events). The MWPM decoder is the most popular decoder for decoding surface codes, and can also be used to decode various other code families, including subsystem codes, honeycomb codes and 2D hyperbolic codes.
Version 2 includes a new implementation of the blossom algorithm which is 100-1000x faster than previous versions of PyMatching. PyMatching can be configured using arbitrary weighted graphs, with or without a boundary, and can be combined with Craig Gidney's Stim library to simulate and decode error correction circuits in the presence of circuit-level noise. The sinter package combines Stim and PyMatching to perform fast, parallelised monte-carlo sampling of quantum error correction circuits. As of a recent update (v2.3), pymatching also supports correlated matching.
Documentation for PyMatching can be found at: pymatching.readthedocs.io
Our paper gives more background on the MWPM decoder and our implementation (sparse blossom) released in PyMatching v2.
To see how stim, sinter and pymatching can be used to estimate the threshold of an error correcting code with circuit-level noise, try out the stim getting started notebook.
The new >100x faster implementation for Version 2
Version 2 features a new implementation of the blossom algorithm, which I wrote with Craig Gidney. Our new implementation, which we refer to as the sparse blossom algorithm, can be seen as a generalisation of the blossom algorithm to handle the decoding problem relevant to QEC. We solve the problem of finding minimum-weight paths between detection events in a detector graph directly, which avoids the need to use costly all-to-all Dijkstra searches to find a MWPM in a derived graph using the original blossom algorithm. The new version is also exact - unlike previous versions of PyMatching, no approximation is made. See our paper for more details.
Our new implementation is over 100x faster than previous versions of PyMatching, and is over 100,000x faster than NetworkX (benchmarked with surface code circuits). At 0.1% circuit-noise, PyMatching can decode both X and Z basis measurements of surface code circuits up to distance 17 in under 1 microsecond per round of syndrome extraction on a single core. Furthermore, the runtime is roughly linear in the number of nodes in the graph.
The plot below compares the performance of PyMatching v2 with the previous version (v0.7) as well as with NetworkX for decoding surface code circuits with circuit-level depolarising noise. All decoders were run on a single core of an M1 processor, processing both the X and Z basis measurements. The equations T=N^x in the legend (and plotted as dashed lines) are obtained from a fit to the same dataset for distance > 10, where N is the number of detectors (nodes) per round, and T is the decoding time per round. See the benchmarks folder in the repository for the data and stim circuits, as well as additional benchmarks.

Sparse blossom is conceptually similar to the approach described in this paper by Austin Fowler, although our approach differs in many of the details (as explained in our paper). There are even more similarities with the very nice independent work by Yue Wu, who recently released the fusion-blossom library. One of the differences with our approach is that fusion-blossom grows the exploratory regions of alternating trees in a similar way to how clusters are grown in Union-Find, whereas our approach instead progresses along a timeline, and uses a global priority queue to grow alternating trees. Yue also has a paper coming soon, so stay tuned for that as well.
Correlated matching
As of PyMatching version 2.3, correlated matching is now also available in pymatching! Thank you to Sid Madhuk, who was the primary contributor for this new feature.
Correlated matching has better accuracy than standard (uncorrelated) matching for many decoding problems where hyperedge errors are present. When these hyperedge errors are decomposed into edges (graphlike errors), they amount to correlations between these edges in the matching graph. A common example of such a hyperedge error is a $Y$ error in the surface code.
The "two-pass" correlated matching decoder implemented in pymatching works by running sparse blossom twice. The first pass is a standard (uncorrelated) run of sparse blossom, to predict a set of edges in the matching graph. Correlated matching then assumes these errors (edges) occurred and reweights edges that are correlated with it based on this assumption. Matching is then run for the second time on this reweighted graph.
Installation
The latest version of PyMatching can be downloaded and installed from PyPI with the command:
pip install pymatching --upgrade
Usage
PyMatching can load matching graphs from a check matrix, a stim.DetectorErrorModel, a networkx.Graph, a
rustworkx.PyGraph or by adding edges individually with pymatching.Matching.add_edge and
pymatching.Matching.add_boundary_edge.
Decoding Stim circuits
PyMatching can be combined with Stim. Generally, the easiest and fastest way to
do this is using sinter (use v1.10.0 or later), which uses PyMatching and Stim to run
parallelised monte carlo simulations of quantum error correction circuits.
However, in this section we will use Stim and PyMatching directly, to demonstrate how their Python APIs can be used.
To install stim, run pip install stim --upgrade.
First, we generate a stim circuit. Here, we use a surface code circuit included with stim:
import numpy as np
import stim
import pymatching
circuit = stim.Circuit.generated(
"surface_code:rotated_memory_x",
distance=5,
rounds=5,
after_clifford_depolarization=0.005
)
Next, we use stim to generate a stim.DetectorErrorModel (DEM), which is effectively a
Tanner graph describing the circuit-level noise model.
By setting decompose_errors=True, stim decomposes all error mechanisms into edge-like error
mechanisms (which cause either one or two detection events).
This ensures that our DEM is graphlike, and can be loaded by pymatching:
model = circuit.detector_error_model(decompose_errors=True)
matching = pymatching.Matching.from_detector_error_model(model)
Next, we will sample 1000 shots from the circuit. Each shot (a row of shots) contains the full syndrome (detector
measurements), as well as the logical observable measurements, from simulating the noisy circuit:
sampler = circuit.compile_detector_sampler()
syndrome, actual_observables = sampler.sample(shots=1000, separate_observables=True)
Now we can decode! We compare PyMatching's predictions of the logical observables with the actual observables sampled with stim, in order to count the number of mistakes and estimate the logical error rate:
predicted_observables = matching.decode_batch(syndrome)
num_errors = np.sum(np.any(predicted_observables != actual_observables, axis=1))
print(num_errors) # prints 8
To decode instead with correlated matching, set enable_correlations=True both when configuiing the pymatching.Matching object:
matching_corr = pymatching.Matching.from_detector_error_model(model, enable_correlations=True)
as well as when decoding:
predicted_observables_corr = matching_corr.decode_batch(syndrome, enable_correlations=True)
num_errors = np.sum(np.any(predicted_observables_corr != actual_observables, axis=1))
print(num_errors) # prints 3
Loading from a parity check matrix
We can also load a pymatching.Matching object from a binary
parity check matrix, another representation of a Tanner graph.
Each row in the parity check matrix H corresponds to a parity check, and each c
Related Skills
node-connect
339.5kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
83.9kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
339.5kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
83.9kCommit, push, and open a PR
