PyMatching


NamePyMatching JSON
Version 2.3.0 PyPI version JSON
download
home_pagehttps://github.com/oscarhiggott/PyMatching
SummaryA package for decoding quantum error correcting codes using minimum-weight perfect matching.
upload_time2025-08-10 06:13:19
maintainerNone
docs_urlNone
authorOscar Higgott and Craig Gidney
requires_python>=3.7
licenseNone
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # PyMatching 2

![Continuous Integration](https://github.com/oscarhiggott/PyMatching/workflows/ci/badge.svg)
[![codecov](https://codecov.io/gh/oscarhiggott/PyMatching/branch/master/graph/badge.svg)](https://codecov.io/gh/oscarhiggott/PyMatching)
[![docs](https://readthedocs.org/projects/pymatching/badge/?version=latest&style=plastic)](https://readthedocs.org/projects/pymatching/builds/)
[![PyPI version](https://badge.fury.io/py/PyMatching.svg)](https://badge.fury.io/py/PyMatching)
[![Unitary Fund](https://img.shields.io/badge/Supported%20By-UNITARY%20FUND-brightgreen.svg?style=for-the-badge)](http://unitary.fund)

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](https://arxiv.org/abs/quant-ph/0110143), 
and can also be used to decode various other code families, including 
[subsystem codes](https://arxiv.org/abs/1207.1443), 
[honeycomb codes](https://quantum-journal.org/papers/q-2021-10-19-564/) and 
[2D hyperbolic codes](https://arxiv.org/abs/1506.04029).

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](https://github.com/quantumlib/Stim) library to simulate and decode error correction circuits 
in the presence of circuit-level noise. The [sinter](https://pypi.org/project/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](https://arxiv.org/abs/1310.0863).

Documentation for PyMatching can be found at: [pymatching.readthedocs.io](https://pymatching.readthedocs.io/en/stable/)

Our [paper](https://arxiv.org/abs/2303.15933) 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](https://github.com/quantumlib/Stim/blob/main/doc/getting_started.ipynb).

## 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](https://arxiv.org/abs/2303.15933) 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](https://github.com/oscarhiggott/PyMatching/raw/master/benchmarks) folder in the repository 
for the data and stim circuits, as well as additional benchmarks.


![PyMatching new vs old vs NetworkX](https://github.com/oscarhiggott/PyMatching/raw/master/benchmarks/surface_codes/surface_code_rotated_memory_x_p_0.001_d_5_7_9_13_17_23_29_39_50_both_bases/pymatching_v0.7_vs_pymatching_v2_vs_networkx_timing_p=0.001_per_round_both_bases_decoded.png)


Sparse blossom is conceptually similar to the approach described in [this paper](https://arxiv.org/abs/1307.1740) 
by Austin Fowler, although our approach differs in many of the details (as explained in our [paper](https://arxiv.org/abs/2303.15933)).
There are even more similarities with the very nice independent work by Yue Wu, who recently released the 
[fusion-blossom](https://pypi.org/project/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](https://arxiv.org/abs/1310.0863) 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](https://pypi.org/project/PyMatching/) 
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](https://github.com/quantumlib/Stim). Generally, the easiest and fastest way to 
do this is using [sinter](https://pypi.org/project/stim/) (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:

```python
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](https://en.wikipedia.org/wiki/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:

```python
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:

```python
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:

```python
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:
```python
matching_corr = pymatching.Matching.from_detector_error_model(dem, enable_correlations=True)
```

as well as when decoding:
```python
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](https://en.wikipedia.org/wiki/Parity-check_matrix), another representation of a Tanner graph.
Each row in the parity check matrix `H` corresponds to a parity check, and each column corresponds to an 
error mechanism.
The element `H[i,j]` of `H` is 1 if parity check `i` is flipped by error mechanism `j`, and 0 otherwise.
To be used by PyMatching, the error mechanisms in `H` must be _graphlike_.
This means that each column must contain either one or two 1s (if a column has a single 1, it represents a half-edge 
connected to the boundary).

We can give each edge in the graph a weight, by providing PyMatching with a `weights` numpy array.
Element `weights[j]` of the `weights` array sets the edge weight for the edge corresponding to column `j` of `H`.
If the error mechanisms are treated as independent, then we typically want to set the weight of edge `j` to 
the log-likelihood ratio `log((1-p_j)/p_j)`, where `p_j` is the error probability associated with edge `j`.
With this setting, PyMatching will find the most probable set of error mechanisms, given the syndrome.

With PyMatching configured using `H` and `weights`, decoding a binary syndrome vector `syndrome` (a numpy array 
of length `H.shape[0]`) corresponds to finding a set of errors defined in a binary `predictions` vector 
satisfying `H@predictions % 2 == syndrome` while minimising the total solution weight `predictions@weights`.

In quantum error correction, rather than predicting which exact set of error mechanisms occurred, we typically want to 
predict the outcome of _logical observable_ measurements, which are the parities of error mechanisms.
These can be represented by a binary matrix `observables`. Similar to the check matrix, `observables[i,j]` is 1 if 
logical observable `i` is flipped by error mechanism `j`.
For example, suppose our syndrome `syndrome`, was the result of a set of errors `noise` (a binary array of 
length `H.shape[1]`), such that `syndrome = H@noise % 2`.
Our decoding is successful if `observables@noise % 2 == observables@predictions % 2`.

Putting this together, we can decode a distance 5 repetition code as follows:

```python
import numpy as np
from scipy.sparse import csc_matrix
import pymatching
H = csc_matrix([[1, 1, 0, 0, 0],
                 [0, 1, 1, 0, 0],
                 [0, 0, 1, 1, 0],
                 [0, 0, 0, 1, 1]])
weights = np.array([4, 3, 2, 3, 4])   # Set arbitrary weights for illustration
matching = pymatching.Matching(H, weights=weights)
prediction = matching.decode(np.array([0, 1, 0, 1]))
print(prediction)  # prints: [0 0 1 1 0]
# Optionally, we can return the weight as well:
prediction, solution_weight = matching.decode(np.array([0, 1, 0, 1]), return_weight=True)
print(prediction)  # prints: [0 0 1 1 0]
print(solution_weight)  # prints: 5.0
```

And in order to estimate the logical error rate for a physical error rate of 10%, we can sample 
as follows:

```python
import numpy as np
from scipy.sparse import csc_matrix
import pymatching
H = csc_matrix([[1, 1, 0, 0, 0],
                [0, 1, 1, 0, 0],
                [0, 0, 1, 1, 0],
                [0, 0, 0, 1, 1]])
observables = csc_matrix([[1, 0, 0, 0, 0]])
error_probability = 0.1
weights = np.ones(H.shape[1]) * np.log((1-error_probability)/error_probability)
matching = pymatching.Matching.from_check_matrix(H, weights=weights)
num_shots = 1000
num_errors = 0
for i in range(num_shots):
    noise = (np.random.random(H.shape[1]) < error_probability).astype(np.uint8)
    syndrome = H@noise % 2
    prediction = matching.decode(syndrome)
    predicted_observables = observables@prediction % 2
    actual_observables = observables@noise % 2
    num_errors += not np.array_equal(predicted_observables, actual_observables)
print(num_errors)  # prints 4
```

Note that we can also ask PyMatching to predict the logical observables directly, by supplying them 
to the `faults_matrix` argument when constructing the `pymatching.Matching` object. This allows the decoder to make 
some additional optimisations, that speed up the decoding procedure a bit. The following example uses this approach, 
and is equivalent to the example above:

```python
import numpy as np
from scipy.sparse import csc_matrix
import pymatching

H = csc_matrix([[1, 1, 0, 0, 0],
                [0, 1, 1, 0, 0],
                [0, 0, 1, 1, 0],
                [0, 0, 0, 1, 1]])
observables = csc_matrix([[1, 0, 0, 0, 0]])
error_probability = 0.1
weights = np.ones(H.shape[1]) * np.log((1-error_probability)/error_probability)
matching = pymatching.Matching.from_check_matrix(H, weights=weights, faults_matrix=observables)
num_shots = 1000
num_errors = 0
for i in range(num_shots):
    noise = (np.random.random(H.shape[1]) < error_probability).astype(np.uint8)
    syndrome = H@noise % 2
    predicted_observables = matching.decode(syndrome)
    actual_observables = observables@noise % 2
    num_errors += not np.array_equal(predicted_observables, actual_observables)

print(num_errors)  # prints 6
```

We'll make one more optimisation, which is to use `matching.decode_batch` to decode the batch of shots, rather than
iterating over calls to `matching.decode` in Python:

```python
import numpy as np
from scipy.sparse import csc_matrix
import pymatching

H = csc_matrix([[1, 1, 0, 0, 0],
                [0, 1, 1, 0, 0],
                [0, 0, 1, 1, 0],
                [0, 0, 0, 1, 1]])
observables = csc_matrix([[1, 0, 0, 0, 0]])
error_probability = 0.1
num_shots = 1000
weights = np.ones(H.shape[1]) * np.log((1-error_probability)/error_probability)
matching = pymatching.Matching.from_check_matrix(H, weights=weights, faults_matrix=observables)
noise = (np.random.random((num_shots, H.shape[1])) < error_probability).astype(np.uint8)
shots = (noise @ H.T) % 2
actual_observables = (noise @ observables.T) % 2
predicted_observables = matching.decode_batch(shots)
num_errors = np.sum(np.any(predicted_observables != actual_observables, axis=1))
print(num_errors)  # prints 6

```



Instead of using a check matrix, the Matching object can also be constructed using
the [`Matching.add_edge`](https://pymatching.readthedocs.io/en/stable/api.html#pymatching.matching.Matching.add_edge)
and 
[`Matching.add_boundary_edge`](https://pymatching.readthedocs.io/en/stable/api.html#pymatching.matching.Matching.add_boundary_edge) 
methods, or by loading from a NetworkX or rustworkx graph. 

For more details on how to use PyMatching,
see [the documentation](https://pymatching.readthedocs.io).

## Attribution

When using PyMatching please cite our [paper](https://arxiv.org/abs/2303.15933) on the sparse blossom algorithm (implemented in version 2):

```
@article{Higgott2025sparseblossom,
  doi = {10.22331/q-2025-01-20-1600},
  url = {https://doi.org/10.22331/q-2025-01-20-1600},
  title = {Sparse {B}lossom: correcting a million errors per core second with minimum-weight matching},
  author = {Higgott, Oscar and Gidney, Craig},
  journal = {{Quantum}},
  issn = {2521-327X},
  publisher = {{Verein zur F{\"{o}}rderung des Open Access Publizierens in den Quantenwissenschaften}},
  volume = {9},
  pages = {1600},
  month = jan,
  year = {2025}
}
```

Note: the previous PyMatching [paper](https://arxiv.org/abs/2105.13082) descibes the implementation in version 0.7 and 
earlier of PyMatching (not v2).

## Acknowledgements

We are grateful to the Google Quantum AI team for supporting the development of PyMatching v2. Earlier versions of 
PyMatching were supported by Unitary Fund and EPSRC.

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/oscarhiggott/PyMatching",
    "name": "PyMatching",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.7",
    "maintainer_email": null,
    "keywords": null,
    "author": "Oscar Higgott and Craig Gidney",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/a3/04/64028ae55692a85327cc3bd7cbc377248b39a7b1f341c8841822085bd40d/pymatching-2.3.0.tar.gz",
    "platform": null,
    "description": "# PyMatching 2\n\n![Continuous Integration](https://github.com/oscarhiggott/PyMatching/workflows/ci/badge.svg)\n[![codecov](https://codecov.io/gh/oscarhiggott/PyMatching/branch/master/graph/badge.svg)](https://codecov.io/gh/oscarhiggott/PyMatching)\n[![docs](https://readthedocs.org/projects/pymatching/badge/?version=latest&style=plastic)](https://readthedocs.org/projects/pymatching/builds/)\n[![PyPI version](https://badge.fury.io/py/PyMatching.svg)](https://badge.fury.io/py/PyMatching)\n[![Unitary Fund](https://img.shields.io/badge/Supported%20By-UNITARY%20FUND-brightgreen.svg?style=for-the-badge)](http://unitary.fund)\n\nPyMatching is a fast Python/C++ library for decoding quantum error correcting (QEC) codes using the Minimum Weight\nPerfect Matching (MWPM) decoder.\nGiven the syndrome measurements from a quantum error correction circuit, the MWPM decoder finds the most probable set \nof errors, given the assumption that error mechanisms are _independent_, as well as _graphlike_ (each error causes \neither one or two detection events).\nThe MWPM decoder is the most popular decoder for decoding [surface codes](https://arxiv.org/abs/quant-ph/0110143), \nand can also be used to decode various other code families, including \n[subsystem codes](https://arxiv.org/abs/1207.1443), \n[honeycomb codes](https://quantum-journal.org/papers/q-2021-10-19-564/) and \n[2D hyperbolic codes](https://arxiv.org/abs/1506.04029).\n\nVersion 2 includes a new implementation of the blossom algorithm which is **100-1000x faster** than previous versions\nof PyMatching.\nPyMatching can be configured using arbitrary weighted graphs, with or without a boundary, and can be combined with \nCraig Gidney's [Stim](https://github.com/quantumlib/Stim) library to simulate and decode error correction circuits \nin the presence of circuit-level noise. The [sinter](https://pypi.org/project/sinter/) package combines Stim and \nPyMatching to perform fast, parallelised monte-carlo sampling of quantum error correction circuits.\nAs of a recent update (v2.3), pymatching also supports [correlated matching](https://arxiv.org/abs/1310.0863).\n\nDocumentation for PyMatching can be found at: [pymatching.readthedocs.io](https://pymatching.readthedocs.io/en/stable/)\n\nOur [paper](https://arxiv.org/abs/2303.15933) gives more background on the MWPM decoder and our implementation (sparse blossom) released in PyMatching v2.\n\nTo see how stim, sinter and pymatching can be used to estimate the threshold of an error correcting code with \ncircuit-level noise, try out the [stim getting started notebook](https://github.com/quantumlib/Stim/blob/main/doc/getting_started.ipynb).\n\n## The new >100x faster implementation for Version 2\n\nVersion 2 features a new implementation of the blossom algorithm, which I wrote with Craig Gidney.\nOur new implementation, which we refer to as the _sparse blossom_ algorithm, can be seen as a generalisation of the \nblossom algorithm to handle the decoding problem relevant to QEC. \nWe solve the problem of finding minimum-weight paths between detection events in a detector graph \n_directly_, which avoids the need to use costly all-to-all Dijkstra searches to find a MWPM in a derived \ngraph using the original blossom algorithm.\nThe new version is also exact - unlike previous versions of PyMatching, no approximation is made.\nSee our [paper](https://arxiv.org/abs/2303.15933) for more details.\n\nOur new implementation is **over 100x faster** than previous versions of PyMatching, and is \n**over 100,000x faster** than NetworkX (benchmarked with surface code circuits). At 0.1% circuit-noise, PyMatching can \ndecode both X and Z basis measurements of surface code circuits up to distance 17 in under 1 microsecond per round \nof syndrome extraction on a single core. Furthermore, the runtime is roughly linear in the number \nof nodes in the graph.\n\nThe plot below compares the performance of PyMatching v2 with the previous \nversion (v0.7) as well as with NetworkX for decoding surface code circuits with circuit-level depolarising noise. \nAll decoders were run on a single core of an M1 processor, processing both the X and Z basis measurements.\nThe equations T=N^x in the legend (and plotted as dashed lines) are \nobtained from a fit to the same dataset for \ndistance > 10, where N is the number of detectors (nodes) per round, and T is the decoding time per round.\nSee the [benchmarks](https://github.com/oscarhiggott/PyMatching/raw/master/benchmarks) folder in the repository \nfor the data and stim circuits, as well as additional benchmarks.\n\n\n![PyMatching new vs old vs NetworkX](https://github.com/oscarhiggott/PyMatching/raw/master/benchmarks/surface_codes/surface_code_rotated_memory_x_p_0.001_d_5_7_9_13_17_23_29_39_50_both_bases/pymatching_v0.7_vs_pymatching_v2_vs_networkx_timing_p=0.001_per_round_both_bases_decoded.png)\n\n\nSparse blossom is conceptually similar to the approach described in [this paper](https://arxiv.org/abs/1307.1740) \nby Austin Fowler, although our approach differs in many of the details (as explained in our [paper](https://arxiv.org/abs/2303.15933)).\nThere are even more similarities with the very nice independent work by Yue Wu, who recently released the \n[fusion-blossom](https://pypi.org/project/fusion-blossom/) library.\nOne of the differences with our approach is that fusion-blossom grows the exploratory regions of alternating trees \nin a similar way to how clusters are grown in Union-Find, whereas our approach instead progresses along a timeline, \nand uses a global priority queue to grow alternating trees.\nYue also has a paper coming soon, so stay tuned for that as well.\n\n## Correlated matching\n\nAs of PyMatching version 2.3, [correlated matching](https://arxiv.org/abs/1310.0863) is now also available in pymatching! Thank you to Sid Madhuk, who was the primary contributor for this new feature.\n\nCorrelated 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.\n\nThe \"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.\n\n## Installation\n\nThe latest version of PyMatching can be downloaded and installed from [PyPI](https://pypi.org/project/PyMatching/) \nwith the command:\n\n```\npip install pymatching --upgrade\n```\n\n\n## Usage\n\nPyMatching can load matching graphs from a check matrix, a `stim.DetectorErrorModel`, a `networkx.Graph`, a \n`rustworkx.PyGraph` or by adding edges individually with `pymatching.Matching.add_edge` and \n`pymatching.Matching.add_boundary_edge`.\n\n### Decoding Stim circuits\n\nPyMatching can be combined with [Stim](https://github.com/quantumlib/Stim). Generally, the easiest and fastest way to \ndo this is using [sinter](https://pypi.org/project/stim/) (use v1.10.0 or later), which uses PyMatching and Stim to run \nparallelised monte carlo simulations of quantum error correction circuits.\nHowever, in this section we will use Stim and PyMatching directly, to demonstrate how their Python APIs can be used.\nTo install stim, run `pip install stim --upgrade`.\n\nFirst, we generate a stim circuit. Here, we use a surface code circuit included with stim:\n\n```python\nimport numpy as np\nimport stim\nimport pymatching\ncircuit = stim.Circuit.generated(\n    \"surface_code:rotated_memory_x\", \n    distance=5, \n    rounds=5, \n    after_clifford_depolarization=0.005\n)\n```\n\nNext, we use stim to generate a `stim.DetectorErrorModel` (DEM), which is effectively a \n[Tanner graph](https://en.wikipedia.org/wiki/Tanner_graph) describing the circuit-level noise model.\nBy setting `decompose_errors=True`, stim decomposes all error mechanisms into _edge-like_ error \nmechanisms (which cause either one or two detection events).\nThis ensures that our DEM is graphlike, and can be loaded by pymatching:\n\n```python\nmodel = circuit.detector_error_model(decompose_errors=True)\nmatching = pymatching.Matching.from_detector_error_model(model)\n```\n\nNext, we will sample 1000 shots from the circuit. Each shot (a row of `shots`) contains the full syndrome (detector \nmeasurements), as well as the logical observable measurements, from simulating the noisy circuit:\n\n```python\nsampler = circuit.compile_detector_sampler()\nsyndrome, actual_observables = sampler.sample(shots=1000, separate_observables=True)\n```\n\nNow 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:\n\n```python\npredicted_observables = matching.decode_batch(syndrome)\nnum_errors = np.sum(np.any(predicted_observables != actual_observables, axis=1))\n\nprint(num_errors)  # prints 8\n```\n\nTo decode instead with correlated matching, set `enable_correlations=True` both when configuiing the `pymatching.Matching` object:\n```python\nmatching_corr = pymatching.Matching.from_detector_error_model(dem, enable_correlations=True)\n```\n\nas well as when decoding:\n```python\npredicted_observables_corr = matching_corr.decode_batch(syndrome, enable_correlations=True)\nnum_errors = np.sum(np.any(predicted_observables_corr != actual_observables, axis=1))\n\nprint(num_errors)  # prints 3\n```\n\n### Loading from a parity check matrix\n\nWe can also load a `pymatching.Matching` object from a binary\n[parity check matrix](https://en.wikipedia.org/wiki/Parity-check_matrix), another representation of a Tanner graph.\nEach row in the parity check matrix `H` corresponds to a parity check, and each column corresponds to an \nerror mechanism.\nThe element `H[i,j]` of `H` is 1 if parity check `i` is flipped by error mechanism `j`, and 0 otherwise.\nTo be used by PyMatching, the error mechanisms in `H` must be _graphlike_.\nThis means that each column must contain either one or two 1s (if a column has a single 1, it represents a half-edge \nconnected to the boundary).\n\nWe can give each edge in the graph a weight, by providing PyMatching with a `weights` numpy array.\nElement `weights[j]` of the `weights` array sets the edge weight for the edge corresponding to column `j` of `H`.\nIf the error mechanisms are treated as independent, then we typically want to set the weight of edge `j` to \nthe log-likelihood ratio `log((1-p_j)/p_j)`, where `p_j` is the error probability associated with edge `j`.\nWith this setting, PyMatching will find the most probable set of error mechanisms, given the syndrome.\n\nWith PyMatching configured using `H` and `weights`, decoding a binary syndrome vector `syndrome` (a numpy array \nof length `H.shape[0]`) corresponds to finding a set of errors defined in a binary `predictions` vector \nsatisfying `H@predictions % 2 == syndrome` while minimising the total solution weight `predictions@weights`.\n\nIn quantum error correction, rather than predicting which exact set of error mechanisms occurred, we typically want to \npredict the outcome of _logical observable_ measurements, which are the parities of error mechanisms.\nThese can be represented by a binary matrix `observables`. Similar to the check matrix, `observables[i,j]` is 1 if \nlogical observable `i` is flipped by error mechanism `j`.\nFor example, suppose our syndrome `syndrome`, was the result of a set of errors `noise` (a binary array of \nlength `H.shape[1]`), such that `syndrome = H@noise % 2`.\nOur decoding is successful if `observables@noise % 2 == observables@predictions % 2`.\n\nPutting this together, we can decode a distance 5 repetition code as follows:\n\n```python\nimport numpy as np\nfrom scipy.sparse import csc_matrix\nimport pymatching\nH = csc_matrix([[1, 1, 0, 0, 0],\n                 [0, 1, 1, 0, 0],\n                 [0, 0, 1, 1, 0],\n                 [0, 0, 0, 1, 1]])\nweights = np.array([4, 3, 2, 3, 4])   # Set arbitrary weights for illustration\nmatching = pymatching.Matching(H, weights=weights)\nprediction = matching.decode(np.array([0, 1, 0, 1]))\nprint(prediction)  # prints: [0 0 1 1 0]\n# Optionally, we can return the weight as well:\nprediction, solution_weight = matching.decode(np.array([0, 1, 0, 1]), return_weight=True)\nprint(prediction)  # prints: [0 0 1 1 0]\nprint(solution_weight)  # prints: 5.0\n```\n\nAnd in order to estimate the logical error rate for a physical error rate of 10%, we can sample \nas follows:\n\n```python\nimport numpy as np\nfrom scipy.sparse import csc_matrix\nimport pymatching\nH = csc_matrix([[1, 1, 0, 0, 0],\n                [0, 1, 1, 0, 0],\n                [0, 0, 1, 1, 0],\n                [0, 0, 0, 1, 1]])\nobservables = csc_matrix([[1, 0, 0, 0, 0]])\nerror_probability = 0.1\nweights = np.ones(H.shape[1]) * np.log((1-error_probability)/error_probability)\nmatching = pymatching.Matching.from_check_matrix(H, weights=weights)\nnum_shots = 1000\nnum_errors = 0\nfor i in range(num_shots):\n    noise = (np.random.random(H.shape[1]) < error_probability).astype(np.uint8)\n    syndrome = H@noise % 2\n    prediction = matching.decode(syndrome)\n    predicted_observables = observables@prediction % 2\n    actual_observables = observables@noise % 2\n    num_errors += not np.array_equal(predicted_observables, actual_observables)\nprint(num_errors)  # prints 4\n```\n\nNote that we can also ask PyMatching to predict the logical observables directly, by supplying them \nto the `faults_matrix` argument when constructing the `pymatching.Matching` object. This allows the decoder to make \nsome additional optimisations, that speed up the decoding procedure a bit. The following example uses this approach, \nand is equivalent to the example above:\n\n```python\nimport numpy as np\nfrom scipy.sparse import csc_matrix\nimport pymatching\n\nH = csc_matrix([[1, 1, 0, 0, 0],\n                [0, 1, 1, 0, 0],\n                [0, 0, 1, 1, 0],\n                [0, 0, 0, 1, 1]])\nobservables = csc_matrix([[1, 0, 0, 0, 0]])\nerror_probability = 0.1\nweights = np.ones(H.shape[1]) * np.log((1-error_probability)/error_probability)\nmatching = pymatching.Matching.from_check_matrix(H, weights=weights, faults_matrix=observables)\nnum_shots = 1000\nnum_errors = 0\nfor i in range(num_shots):\n    noise = (np.random.random(H.shape[1]) < error_probability).astype(np.uint8)\n    syndrome = H@noise % 2\n    predicted_observables = matching.decode(syndrome)\n    actual_observables = observables@noise % 2\n    num_errors += not np.array_equal(predicted_observables, actual_observables)\n\nprint(num_errors)  # prints 6\n```\n\nWe'll make one more optimisation, which is to use `matching.decode_batch` to decode the batch of shots, rather than\niterating over calls to `matching.decode` in Python:\n\n```python\nimport numpy as np\nfrom scipy.sparse import csc_matrix\nimport pymatching\n\nH = csc_matrix([[1, 1, 0, 0, 0],\n                [0, 1, 1, 0, 0],\n                [0, 0, 1, 1, 0],\n                [0, 0, 0, 1, 1]])\nobservables = csc_matrix([[1, 0, 0, 0, 0]])\nerror_probability = 0.1\nnum_shots = 1000\nweights = np.ones(H.shape[1]) * np.log((1-error_probability)/error_probability)\nmatching = pymatching.Matching.from_check_matrix(H, weights=weights, faults_matrix=observables)\nnoise = (np.random.random((num_shots, H.shape[1])) < error_probability).astype(np.uint8)\nshots = (noise @ H.T) % 2\nactual_observables = (noise @ observables.T) % 2\npredicted_observables = matching.decode_batch(shots)\nnum_errors = np.sum(np.any(predicted_observables != actual_observables, axis=1))\nprint(num_errors)  # prints 6\n\n```\n\n\n\nInstead of using a check matrix, the Matching object can also be constructed using\nthe [`Matching.add_edge`](https://pymatching.readthedocs.io/en/stable/api.html#pymatching.matching.Matching.add_edge)\nand \n[`Matching.add_boundary_edge`](https://pymatching.readthedocs.io/en/stable/api.html#pymatching.matching.Matching.add_boundary_edge) \nmethods, or by loading from a NetworkX or rustworkx graph. \n\nFor more details on how to use PyMatching,\nsee [the documentation](https://pymatching.readthedocs.io).\n\n## Attribution\n\nWhen using PyMatching please cite our [paper](https://arxiv.org/abs/2303.15933) on the sparse blossom algorithm (implemented in version 2):\n\n```\n@article{Higgott2025sparseblossom,\n  doi = {10.22331/q-2025-01-20-1600},\n  url = {https://doi.org/10.22331/q-2025-01-20-1600},\n  title = {Sparse {B}lossom: correcting a million errors per core second with minimum-weight matching},\n  author = {Higgott, Oscar and Gidney, Craig},\n  journal = {{Quantum}},\n  issn = {2521-327X},\n  publisher = {{Verein zur F{\\\"{o}}rderung des Open Access Publizierens in den Quantenwissenschaften}},\n  volume = {9},\n  pages = {1600},\n  month = jan,\n  year = {2025}\n}\n```\n\nNote: the previous PyMatching [paper](https://arxiv.org/abs/2105.13082) descibes the implementation in version 0.7 and \nearlier of PyMatching (not v2).\n\n## Acknowledgements\n\nWe are grateful to the Google Quantum AI team for supporting the development of PyMatching v2. Earlier versions of \nPyMatching were supported by Unitary Fund and EPSRC.\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "A package for decoding quantum error correcting codes using minimum-weight perfect matching.",
    "version": "2.3.0",
    "project_urls": {
        "Homepage": "https://github.com/oscarhiggott/PyMatching"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "28c2ca0ab6b14543d99ea39b1789339f4d6f8f8cbd20d8b6d6a4f66c98568a67",
                "md5": "8d33b2858997d82db061f2ce116f7416",
                "sha256": "af1fa546bcea11fd4ce19c9442ffd6028e0ef5477b1b1de250dcb43b1935710d"
            },
            "downloads": -1,
            "filename": "pymatching-2.3.0-cp310-cp310-macosx_11_0_arm64.whl",
            "has_sig": false,
            "md5_digest": "8d33b2858997d82db061f2ce116f7416",
            "packagetype": "bdist_wheel",
            "python_version": "cp310",
            "requires_python": ">=3.7",
            "size": 405607,
            "upload_time": "2025-08-10T06:12:49",
            "upload_time_iso_8601": "2025-08-10T06:12:49.098878Z",
            "url": "https://files.pythonhosted.org/packages/28/c2/ca0ab6b14543d99ea39b1789339f4d6f8f8cbd20d8b6d6a4f66c98568a67/pymatching-2.3.0-cp310-cp310-macosx_11_0_arm64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "3d62ad68d9d918d8bf2f881e49134b28f358118cc21e82ce9954eb7c7a5c1a05",
                "md5": "689aa8d49dfa8fb04e21869d01fc8252",
                "sha256": "d7c7d62be3e669d0b63921cc6a785668019da9aa3ca47d88eb79823c0675b59d"
            },
            "downloads": -1,
            "filename": "pymatching-2.3.0-cp310-cp310-macosx_11_0_x86_64.whl",
            "has_sig": false,
            "md5_digest": "689aa8d49dfa8fb04e21869d01fc8252",
            "packagetype": "bdist_wheel",
            "python_version": "cp310",
            "requires_python": ">=3.7",
            "size": 445735,
            "upload_time": "2025-08-10T06:12:50",
            "upload_time_iso_8601": "2025-08-10T06:12:50.708164Z",
            "url": "https://files.pythonhosted.org/packages/3d/62/ad68d9d918d8bf2f881e49134b28f358118cc21e82ce9954eb7c7a5c1a05/pymatching-2.3.0-cp310-cp310-macosx_11_0_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "a26a95182fe1af2d65935af0e67ed29d7f16fd412b519fbcbb8d098b97edd18f",
                "md5": "81e7089fa353346b61ee6c4a1be58089",
                "sha256": "9d9d74ae591f251721697b79b53d815853825651b87a7e3978e1c59819c5aa02"
            },
            "downloads": -1,
            "filename": "pymatching-2.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl",
            "has_sig": false,
            "md5_digest": "81e7089fa353346b61ee6c4a1be58089",
            "packagetype": "bdist_wheel",
            "python_version": "cp310",
            "requires_python": ">=3.7",
            "size": 624789,
            "upload_time": "2025-08-10T06:12:51",
            "upload_time_iso_8601": "2025-08-10T06:12:51.886296Z",
            "url": "https://files.pythonhosted.org/packages/a2/6a/95182fe1af2d65935af0e67ed29d7f16fd412b519fbcbb8d098b97edd18f/pymatching-2.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "b04d9345fb064a7d34c7f2281ee0774ee1eb745a784076732909b658503530e7",
                "md5": "705d82b864f92167a94a76f53d515e61",
                "sha256": "caabe481581ff47c94a3a0751f60231a5d1bc1dd7241e4b31e7b6a71a6742b9b"
            },
            "downloads": -1,
            "filename": "pymatching-2.3.0-cp310-cp310-win_amd64.whl",
            "has_sig": false,
            "md5_digest": "705d82b864f92167a94a76f53d515e61",
            "packagetype": "bdist_wheel",
            "python_version": "cp310",
            "requires_python": ">=3.7",
            "size": 345822,
            "upload_time": "2025-08-10T06:12:53",
            "upload_time_iso_8601": "2025-08-10T06:12:53.093676Z",
            "url": "https://files.pythonhosted.org/packages/b0/4d/9345fb064a7d34c7f2281ee0774ee1eb745a784076732909b658503530e7/pymatching-2.3.0-cp310-cp310-win_amd64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "3155657af095acfbd3eb22b59012bec07f3571ab6ad906f66513e16b61053c7c",
                "md5": "13b8c81f8fe7bf610b041d13382d52e8",
                "sha256": "849f6492785b013e825cfccf168d57ef18b63466f587608daaf327757807880d"
            },
            "downloads": -1,
            "filename": "pymatching-2.3.0-cp311-cp311-macosx_11_0_arm64.whl",
            "has_sig": false,
            "md5_digest": "13b8c81f8fe7bf610b041d13382d52e8",
            "packagetype": "bdist_wheel",
            "python_version": "cp311",
            "requires_python": ">=3.7",
            "size": 406851,
            "upload_time": "2025-08-10T06:12:54",
            "upload_time_iso_8601": "2025-08-10T06:12:54.317849Z",
            "url": "https://files.pythonhosted.org/packages/31/55/657af095acfbd3eb22b59012bec07f3571ab6ad906f66513e16b61053c7c/pymatching-2.3.0-cp311-cp311-macosx_11_0_arm64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "7bdc41a14f49ea451689ffaf3271aedf94f5f11772f7b820ef1bcce7f74eade9",
                "md5": "8fd3cf2c30bb1968de0534b20e97fec8",
                "sha256": "b29c8e21a30eba855e01cc53a68e3db9b386c3f7e00a5e7f0eef9e74ed7adf97"
            },
            "downloads": -1,
            "filename": "pymatching-2.3.0-cp311-cp311-macosx_11_0_x86_64.whl",
            "has_sig": false,
            "md5_digest": "8fd3cf2c30bb1968de0534b20e97fec8",
            "packagetype": "bdist_wheel",
            "python_version": "cp311",
            "requires_python": ">=3.7",
            "size": 447226,
            "upload_time": "2025-08-10T06:12:55",
            "upload_time_iso_8601": "2025-08-10T06:12:55.596595Z",
            "url": "https://files.pythonhosted.org/packages/7b/dc/41a14f49ea451689ffaf3271aedf94f5f11772f7b820ef1bcce7f74eade9/pymatching-2.3.0-cp311-cp311-macosx_11_0_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "64801dfdf83e3b6db173ad2e0a0b6fd96161b8c3f241c82bbcb89f74ead8cc61",
                "md5": "18de97d84330a0b66081def7f988ed58",
                "sha256": "d885229418d31748040528d50523e06c627fab0f89d2c0cedcf4b863dd1e584d"
            },
            "downloads": -1,
            "filename": "pymatching-2.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl",
            "has_sig": false,
            "md5_digest": "18de97d84330a0b66081def7f988ed58",
            "packagetype": "bdist_wheel",
            "python_version": "cp311",
            "requires_python": ">=3.7",
            "size": 625752,
            "upload_time": "2025-08-10T06:12:56",
            "upload_time_iso_8601": "2025-08-10T06:12:56.666508Z",
            "url": "https://files.pythonhosted.org/packages/64/80/1dfdf83e3b6db173ad2e0a0b6fd96161b8c3f241c82bbcb89f74ead8cc61/pymatching-2.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "1937be803c4da5b9360d8142236f1b60afc0fd2b2c91a8f6a91b3eea4f96ce10",
                "md5": "edd88b41ca456c4f0ccf1cf0b786fa9f",
                "sha256": "7eb1ab15c11de8d3619e6b1715199f14a7c64f3d26eb11a40de4624f0ab40a57"
            },
            "downloads": -1,
            "filename": "pymatching-2.3.0-cp311-cp311-win_amd64.whl",
            "has_sig": false,
            "md5_digest": "edd88b41ca456c4f0ccf1cf0b786fa9f",
            "packagetype": "bdist_wheel",
            "python_version": "cp311",
            "requires_python": ">=3.7",
            "size": 346533,
            "upload_time": "2025-08-10T06:12:58",
            "upload_time_iso_8601": "2025-08-10T06:12:58.032079Z",
            "url": "https://files.pythonhosted.org/packages/19/37/be803c4da5b9360d8142236f1b60afc0fd2b2c91a8f6a91b3eea4f96ce10/pymatching-2.3.0-cp311-cp311-win_amd64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "01a6ff8947b1b9390fd4bd0a3fdfd33ffe42e4c67fbe00502e2bb4a49a06ef8f",
                "md5": "e3c0a910f4769cc6da99ce2d73a4cd58",
                "sha256": "d736574e4853873fda4fc954d7272c471d1c1907ab7091bb88992fef8667ebb3"
            },
            "downloads": -1,
            "filename": "pymatching-2.3.0-cp312-cp312-macosx_11_0_arm64.whl",
            "has_sig": false,
            "md5_digest": "e3c0a910f4769cc6da99ce2d73a4cd58",
            "packagetype": "bdist_wheel",
            "python_version": "cp312",
            "requires_python": ">=3.7",
            "size": 406337,
            "upload_time": "2025-08-10T06:12:59",
            "upload_time_iso_8601": "2025-08-10T06:12:59.013592Z",
            "url": "https://files.pythonhosted.org/packages/01/a6/ff8947b1b9390fd4bd0a3fdfd33ffe42e4c67fbe00502e2bb4a49a06ef8f/pymatching-2.3.0-cp312-cp312-macosx_11_0_arm64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "b0f4cfc0954e33b0e20171b7ed91a0db229f6ad3122b96f465245aead5a70317",
                "md5": "58d59b1eb7234b9f0273778c0a562c1b",
                "sha256": "ac0f7f7053499e1470b5afd2969f9cb2598a3b4878bed2151e27f6a0cece41d5"
            },
            "downloads": -1,
            "filename": "pymatching-2.3.0-cp312-cp312-macosx_11_0_x86_64.whl",
            "has_sig": false,
            "md5_digest": "58d59b1eb7234b9f0273778c0a562c1b",
            "packagetype": "bdist_wheel",
            "python_version": "cp312",
            "requires_python": ">=3.7",
            "size": 447191,
            "upload_time": "2025-08-10T06:13:00",
            "upload_time_iso_8601": "2025-08-10T06:13:00.090331Z",
            "url": "https://files.pythonhosted.org/packages/b0/f4/cfc0954e33b0e20171b7ed91a0db229f6ad3122b96f465245aead5a70317/pymatching-2.3.0-cp312-cp312-macosx_11_0_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "33072da14305c67fa32e2a1e154e66532f3aca41540f6e31d08047078459f249",
                "md5": "dfe0f0e9a60a6e68b31eacf717579b74",
                "sha256": "28a7e08dba89d6b81ecc0cd850ae247aab8124ba70e00b5d9a41485b1ce452ba"
            },
            "downloads": -1,
            "filename": "pymatching-2.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl",
            "has_sig": false,
            "md5_digest": "dfe0f0e9a60a6e68b31eacf717579b74",
            "packagetype": "bdist_wheel",
            "python_version": "cp312",
            "requires_python": ">=3.7",
            "size": 627058,
            "upload_time": "2025-08-10T06:13:01",
            "upload_time_iso_8601": "2025-08-10T06:13:01.431126Z",
            "url": "https://files.pythonhosted.org/packages/33/07/2da14305c67fa32e2a1e154e66532f3aca41540f6e31d08047078459f249/pymatching-2.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "75f30620f6f2ae44f67c5eef218f00dbfbc30ea73d5010cccc2acc2510f906e7",
                "md5": "85eca0bfc951f2bffa95a122c991c40d",
                "sha256": "db25873ac1a1b690a2c75edc8807d8f29d9e382bed1d6944ce148394e7df5170"
            },
            "downloads": -1,
            "filename": "pymatching-2.3.0-cp312-cp312-win_amd64.whl",
            "has_sig": false,
            "md5_digest": "85eca0bfc951f2bffa95a122c991c40d",
            "packagetype": "bdist_wheel",
            "python_version": "cp312",
            "requires_python": ">=3.7",
            "size": 348274,
            "upload_time": "2025-08-10T06:13:02",
            "upload_time_iso_8601": "2025-08-10T06:13:02.697906Z",
            "url": "https://files.pythonhosted.org/packages/75/f3/0620f6f2ae44f67c5eef218f00dbfbc30ea73d5010cccc2acc2510f906e7/pymatching-2.3.0-cp312-cp312-win_amd64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "488e3d49a02f7e3dc9702c37424f26743020041ef738d95b5fbb6f8f83ae099f",
                "md5": "e8284eca2fb7d8cd0efcf112130ef46c",
                "sha256": "db04273a7e0b6dec07f9f8a271b72bf7bd47f37c4be29824903fb404fb488f2c"
            },
            "downloads": -1,
            "filename": "pymatching-2.3.0-cp313-cp313-macosx_11_0_arm64.whl",
            "has_sig": false,
            "md5_digest": "e8284eca2fb7d8cd0efcf112130ef46c",
            "packagetype": "bdist_wheel",
            "python_version": "cp313",
            "requires_python": ">=3.7",
            "size": 406414,
            "upload_time": "2025-08-10T06:13:03",
            "upload_time_iso_8601": "2025-08-10T06:13:03.924388Z",
            "url": "https://files.pythonhosted.org/packages/48/8e/3d49a02f7e3dc9702c37424f26743020041ef738d95b5fbb6f8f83ae099f/pymatching-2.3.0-cp313-cp313-macosx_11_0_arm64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "7c76e3df4ff9ed1d6b7dc85559b2a73939d0237dec72304f62a274cc1a33e754",
                "md5": "f25d00b84330dd2c54391dcae49c0066",
                "sha256": "9fd0be40a0460e1aef18772155a3a64903aef965bb731dbe857ae0290225f730"
            },
            "downloads": -1,
            "filename": "pymatching-2.3.0-cp313-cp313-macosx_11_0_x86_64.whl",
            "has_sig": false,
            "md5_digest": "f25d00b84330dd2c54391dcae49c0066",
            "packagetype": "bdist_wheel",
            "python_version": "cp313",
            "requires_python": ">=3.7",
            "size": 447311,
            "upload_time": "2025-08-10T06:13:04",
            "upload_time_iso_8601": "2025-08-10T06:13:04.973552Z",
            "url": "https://files.pythonhosted.org/packages/7c/76/e3df4ff9ed1d6b7dc85559b2a73939d0237dec72304f62a274cc1a33e754/pymatching-2.3.0-cp313-cp313-macosx_11_0_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "1ff1b7bcb02a9ec9d014dec68b6569911875e56e94e5fa4799547929dbebe12e",
                "md5": "75d4639519159065c440bde3da911e45",
                "sha256": "ace71104a55ab87bf375b5e9348519a84a0ab2902ae0308d0cb674c163fec4a2"
            },
            "downloads": -1,
            "filename": "pymatching-2.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl",
            "has_sig": false,
            "md5_digest": "75d4639519159065c440bde3da911e45",
            "packagetype": "bdist_wheel",
            "python_version": "cp313",
            "requires_python": ">=3.7",
            "size": 627037,
            "upload_time": "2025-08-10T06:13:06",
            "upload_time_iso_8601": "2025-08-10T06:13:06.285061Z",
            "url": "https://files.pythonhosted.org/packages/1f/f1/b7bcb02a9ec9d014dec68b6569911875e56e94e5fa4799547929dbebe12e/pymatching-2.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "64efec7cce907a3f97e376f3ca4602cceea0e215c268e31c94cb0f04dcd2a019",
                "md5": "214d2de3cec35f1735c58cd1dfd2944a",
                "sha256": "f6d79e756f11c4fca17c278a23c01209f0d972ef082af8def2ce83ba63b2567e"
            },
            "downloads": -1,
            "filename": "pymatching-2.3.0-cp313-cp313-win_amd64.whl",
            "has_sig": false,
            "md5_digest": "214d2de3cec35f1735c58cd1dfd2944a",
            "packagetype": "bdist_wheel",
            "python_version": "cp313",
            "requires_python": ">=3.7",
            "size": 348279,
            "upload_time": "2025-08-10T06:13:08",
            "upload_time_iso_8601": "2025-08-10T06:13:08.312850Z",
            "url": "https://files.pythonhosted.org/packages/64/ef/ec7cce907a3f97e376f3ca4602cceea0e215c268e31c94cb0f04dcd2a019/pymatching-2.3.0-cp313-cp313-win_amd64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "bdb7eb125f1a1d39ad39cff9d2f260479123850f55b2dc4acce4ff6aff715bf8",
                "md5": "f26aedb66214a66febaa64e6ca02f356",
                "sha256": "ae5e85a363c20eed31c8779f3147252ca8f83c182787994ea48e0c5bdcdb534f"
            },
            "downloads": -1,
            "filename": "pymatching-2.3.0-cp38-cp38-macosx_11_0_arm64.whl",
            "has_sig": false,
            "md5_digest": "f26aedb66214a66febaa64e6ca02f356",
            "packagetype": "bdist_wheel",
            "python_version": "cp38",
            "requires_python": ">=3.7",
            "size": 405229,
            "upload_time": "2025-08-10T06:13:09",
            "upload_time_iso_8601": "2025-08-10T06:13:09.571524Z",
            "url": "https://files.pythonhosted.org/packages/bd/b7/eb125f1a1d39ad39cff9d2f260479123850f55b2dc4acce4ff6aff715bf8/pymatching-2.3.0-cp38-cp38-macosx_11_0_arm64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "27604cec98e3f9360275f507f4935e02e4095262d25c6a26fe5a9adebbce4dd9",
                "md5": "f3ce1750d59ab1a8a79939d2e7e541d7",
                "sha256": "33d1496de2cf8a2638b9f591268f7f3ec30d17edfebbc1fd7433f60ebb9f0dd9"
            },
            "downloads": -1,
            "filename": "pymatching-2.3.0-cp38-cp38-macosx_11_0_x86_64.whl",
            "has_sig": false,
            "md5_digest": "f3ce1750d59ab1a8a79939d2e7e541d7",
            "packagetype": "bdist_wheel",
            "python_version": "cp38",
            "requires_python": ">=3.7",
            "size": 445367,
            "upload_time": "2025-08-10T06:13:10",
            "upload_time_iso_8601": "2025-08-10T06:13:10.845331Z",
            "url": "https://files.pythonhosted.org/packages/27/60/4cec98e3f9360275f507f4935e02e4095262d25c6a26fe5a9adebbce4dd9/pymatching-2.3.0-cp38-cp38-macosx_11_0_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "1d2913be0a7523857184ebd59c72edbd175a14de2be29a90581b2bc8c1e0aa16",
                "md5": "306aa082729a15d4a0a46b21813ef433",
                "sha256": "eeb6c76fe2468c912075242fe246b2a5feb3be000ebd9c09817f89fcb5125863"
            },
            "downloads": -1,
            "filename": "pymatching-2.3.0-cp38-cp38-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl",
            "has_sig": false,
            "md5_digest": "306aa082729a15d4a0a46b21813ef433",
            "packagetype": "bdist_wheel",
            "python_version": "cp38",
            "requires_python": ">=3.7",
            "size": 624579,
            "upload_time": "2025-08-10T06:13:12",
            "upload_time_iso_8601": "2025-08-10T06:13:12.327486Z",
            "url": "https://files.pythonhosted.org/packages/1d/29/13be0a7523857184ebd59c72edbd175a14de2be29a90581b2bc8c1e0aa16/pymatching-2.3.0-cp38-cp38-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "c42a9e5dab65ce1dcb462694582650ae7d80034a01e8d5711e70b199db5be141",
                "md5": "e97deee404f1c312b23fec9c4486d641",
                "sha256": "08267359059d6c8786c22ff5b9ffdf4de195d002adfb5c20de67ed8dbee23450"
            },
            "downloads": -1,
            "filename": "pymatching-2.3.0-cp38-cp38-win_amd64.whl",
            "has_sig": false,
            "md5_digest": "e97deee404f1c312b23fec9c4486d641",
            "packagetype": "bdist_wheel",
            "python_version": "cp38",
            "requires_python": ">=3.7",
            "size": 345526,
            "upload_time": "2025-08-10T06:13:13",
            "upload_time_iso_8601": "2025-08-10T06:13:13.608866Z",
            "url": "https://files.pythonhosted.org/packages/c4/2a/9e5dab65ce1dcb462694582650ae7d80034a01e8d5711e70b199db5be141/pymatching-2.3.0-cp38-cp38-win_amd64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "dec51e4a1a01b391bbd0a1d74de7b4c6d44e87909e37958ca726e8cf8a9084a7",
                "md5": "90b1ef11a6208cca125085c156e9980f",
                "sha256": "393964f5b19a4e1bb5670cdaab88d999168a33d7b14dc91815a80f2694fda017"
            },
            "downloads": -1,
            "filename": "pymatching-2.3.0-cp39-cp39-macosx_11_0_arm64.whl",
            "has_sig": false,
            "md5_digest": "90b1ef11a6208cca125085c156e9980f",
            "packagetype": "bdist_wheel",
            "python_version": "cp39",
            "requires_python": ">=3.7",
            "size": 405712,
            "upload_time": "2025-08-10T06:13:14",
            "upload_time_iso_8601": "2025-08-10T06:13:14.842521Z",
            "url": "https://files.pythonhosted.org/packages/de/c5/1e4a1a01b391bbd0a1d74de7b4c6d44e87909e37958ca726e8cf8a9084a7/pymatching-2.3.0-cp39-cp39-macosx_11_0_arm64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "eca327cbdcd4118314547846bf1130168f481b2a48d6895fbe80d2c54c228340",
                "md5": "2d3592f5fe5041d8a354f480379ea774",
                "sha256": "8544889db2b5e68f1190ed1413e9985f73d156ef3c6dae9eeda7ff8896a53bcc"
            },
            "downloads": -1,
            "filename": "pymatching-2.3.0-cp39-cp39-macosx_11_0_x86_64.whl",
            "has_sig": false,
            "md5_digest": "2d3592f5fe5041d8a354f480379ea774",
            "packagetype": "bdist_wheel",
            "python_version": "cp39",
            "requires_python": ">=3.7",
            "size": 445762,
            "upload_time": "2025-08-10T06:13:16",
            "upload_time_iso_8601": "2025-08-10T06:13:16.009792Z",
            "url": "https://files.pythonhosted.org/packages/ec/a3/27cbdcd4118314547846bf1130168f481b2a48d6895fbe80d2c54c228340/pymatching-2.3.0-cp39-cp39-macosx_11_0_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "edbef866ad3818d1c6e329f2bb1d939d993bf373b8274ba687abe9af6ae7146d",
                "md5": "506d6679a0994d8e68041dbfd4fbbdc8",
                "sha256": "7e88fb4ea84f7bea95d3831a9dcee7fd0c32d1d4b49969a4574094cc86eeb076"
            },
            "downloads": -1,
            "filename": "pymatching-2.3.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl",
            "has_sig": false,
            "md5_digest": "506d6679a0994d8e68041dbfd4fbbdc8",
            "packagetype": "bdist_wheel",
            "python_version": "cp39",
            "requires_python": ">=3.7",
            "size": 625109,
            "upload_time": "2025-08-10T06:13:17",
            "upload_time_iso_8601": "2025-08-10T06:13:17.163897Z",
            "url": "https://files.pythonhosted.org/packages/ed/be/f866ad3818d1c6e329f2bb1d939d993bf373b8274ba687abe9af6ae7146d/pymatching-2.3.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "2b0314088b84409c11a88064fd4aa1235a61ec573f4035d35ad03794a5e65904",
                "md5": "65b390b77070b337f71accb5cb2ceec0",
                "sha256": "c8a3d1df76679fd4cd9a00e65b1a95334e0c1a6fd494bc6de12f5620f138dde2"
            },
            "downloads": -1,
            "filename": "pymatching-2.3.0-cp39-cp39-win_amd64.whl",
            "has_sig": false,
            "md5_digest": "65b390b77070b337f71accb5cb2ceec0",
            "packagetype": "bdist_wheel",
            "python_version": "cp39",
            "requires_python": ">=3.7",
            "size": 348792,
            "upload_time": "2025-08-10T06:13:18",
            "upload_time_iso_8601": "2025-08-10T06:13:18.389186Z",
            "url": "https://files.pythonhosted.org/packages/2b/03/14088b84409c11a88064fd4aa1235a61ec573f4035d35ad03794a5e65904/pymatching-2.3.0-cp39-cp39-win_amd64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "a30464028ae55692a85327cc3bd7cbc377248b39a7b1f341c8841822085bd40d",
                "md5": "878966fee81e814488ff01d3ad853a44",
                "sha256": "1d59186e1a867e4c9f2388e972e8fe4b5df8fdd99c05ac551532acec4a1258c6"
            },
            "downloads": -1,
            "filename": "pymatching-2.3.0.tar.gz",
            "has_sig": false,
            "md5_digest": "878966fee81e814488ff01d3ad853a44",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7",
            "size": 344971,
            "upload_time": "2025-08-10T06:13:19",
            "upload_time_iso_8601": "2025-08-10T06:13:19.677725Z",
            "url": "https://files.pythonhosted.org/packages/a3/04/64028ae55692a85327cc3bd7cbc377248b39a7b1f341c8841822085bd40d/pymatching-2.3.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-08-10 06:13:19",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "oscarhiggott",
    "github_project": "PyMatching",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "pymatching"
}
        
Elapsed time: 0.79894s