Skip to main content

MWPF

Hypergraph Minimum-Weight Parity Factor Decoder for QEC

Unitary Fund

The paper is available at https://arxiv.org/abs/2508.04969.

We also provide a web page that allows people to play with some QEC codes, noise models and their decoding processes. Check it out here (https://mwpf.dev).

Hypergraph MWPF is proven to be NP-hard [1]. Our design is taking advantage of clustering technique to lower the average time complexity and reach almost-linear average time complexity at small physical error rate. Please wait for our paper for more discussion of the speed v.s. accuracy.

Color Code Example (click for YouTube video)

Installation

pip install -U mwpf_rational

MWPF now supports stim simulation. You may experience high logical error rate due to some adaptor bugs prior to sinter version 1.15, so instead of using the mw_parity_factor decoder in sinter, you may want to manually import the latest MWPF decoder from the mwpf>=0.2.8 package.

pip install -U 'mwpf_rational[stim]'
from mwpf_rational import SinterMWPFRationalDecoder

sinter.collect(
    tasks = ...,
    num_workers = 1,
    decoders = ["mwpf_rational"],
    custom_decoders = { "mwpf_rational": SinterMWPFRationalDecoder(cluster_node_limit=50) },
)

# MWPF decoder now supports heralded error decoding in stim circuit!
#   Since the sinter.Decoder interface only gives a DEM (Detector Error Model), which doesn't include heralded error
#   information, you need to manually provide the circuit when constructing the decoder, like below
custom_decoders = { "mwpf_rational": SinterMWPFRationalDecoder(cluster_node_limit=50).with_circuit(circuit) }

Background

The Most-Likely Error (MLE) decoding problem can be formulated as a MWPF problem.

Naming

We named it Minimum-Weight Parity Factor because of a concept called "parity $(g,f)$-factor" in Lovász's 1972 paper [2]. In the context of QEC, the functions $g(v)$ and $f(v)$ associates with the measured syndrome as shown above. Without ambiguity, we just call it "parity factor".

Relationship with MWPM decoder

Minimum-Weight Perfect Matching decoder is the traditional decoder for QEC. When the decoding graph is a simple graph, the MLE decoding problem can be reduced to an MWPM problem on a generated complete graph with $O(|V|^2)$ edges. Two recent works [2] and [3] improves the average time complexity to almost theoretical upper bound of $O(|V|)$ by not explicitly generating the complete graph. This motivates our idea to design an algorithm directly on the model graph, hoping to reach the same $O(|V|)$ average time complexity even if the model graph is hypergraph.

Key Idea

We try to extend the blossom algorithm that solves the MWPM problem on simple graphs. An interesting attribute of the blossom algorithm is that it deals with an exponential number of linear constraints in order to relax the integer constraints. The added linear constraints, which we refer to as "blossom constraints", are based on a very simple idea: filtering out invalid solutions. The blossom constraints simply say "any odd cluster cannot be perfectly matched internally", which is obviously true. However, this "filtering" requires an exponential number of linear constraints [5], which is impossible to generate efficiently. Thus, the algorithm must implicitly consider those exponential number of constraints without ever listing them. In fact, the blossom algorithm only keeps track of $O(|V|)$ such constraints from the exponentially many. Surprisingly, this works! Inspired by this miracle, we now have the courage to use an exponential number of linear constraints to solve MWPF.

Rigorous Math

The ILP problem above is very similar to that of the blossom algorithm, except for the more complex "blossom"definition: it's now a subgraph $S=(V_S, E_S), V_S \subseteq V, E_S \subseteq E$ instead of just a subset of vertices $S\subseteq V$ in the blossom algorithm. We have mathematically proved the equivalence between hypergraph MWPF and this ILP. In the next step, we simply relax the integer constraints.

Clearly, as a relaxation, the minimum objective value is no larger than that of the ILP. Unfortunately, we haven't been able to rigorously prove that they have the same optimal objective value, nor can we find a counter example. We leave this conjecture as is for now, and do not assume its correctness.

Conjecture: $\min\text{ILP}=\min\text{LP}$.

The dual problem is a transpose of the primal LP problem. According to the duality theorem, they have the same optimal value. The key is that each primal constraint becomes a dual variable, and each primal variable becomes a dual constraint. Clearly, for the dual problem, $y_S = 0, \forall S \in \mathcal{O}$ is a solution (despite usually not the optimal solution). In this way, we can keep track of only non-zero dual variables to implicitly considering all the exponentially many primal constraints. Since the dual LP problem becomes a maximization problem, we have the whole inequality chain as below.

If we can find a pair of feasible primal and dual solutions with the same weight, then this inequality chain collapses to an equality chain and the primal solution is proven to be optimal. Even if they are not equal, we still get a proximity bound.

In fact, MWPM decoder using the blossom algorithm fits in this framework, where the alternating tree operation guarantees that in the end the primal must be equal to the dual. Union-Find decoder and hypergraph UF decoder can also be explained by this framework, but the proximity bound is usually not singleton.

Usage

The decoding process is two steps (shown in Background)

  1. offline: construct the model graph given the QEC code and the noise model
  2. online: compute the most-likely error $\mathcal{E}\subseteq E$ given the syndrome (represented by the defect vertices $D \subseteq V$) and some dynamic weights
from mwpf_rational import HyperEdge, SolverInitializer, SolverSerialJointSingleHair, SyndromePattern

# Offline
vertex_num = 4
weighted_edges = [
    HyperEdge([0, 1], 100),  # [vertices], weight
    HyperEdge([1, 2], 100),
    HyperEdge([2, 3], 100),
    HyperEdge([0], 100),  # boundary vertex
    HyperEdge([0, 1, 2], 60),  # hyperedge
]
initializer = SolverInitializer(vertex_num, weighted_edges)
hyperion = SolverSerialJointSingleHair(initializer)

# Online
syndrome = [0, 1, 3]
hyperion.solve(SyndromePattern(syndrome))
hyperion_subgraph = hyperion.subgraph()
print(hyperion_subgraph)  # out: [3, 5], weighted 160
_, bound = hyperion.subgraph_range()
print((bound.lower, bound.upper))  # out: (Fraction(160, 1), Fraction(160, 1))

The example hyergraph is below: grey edges are weighted 100 and the purple hyperedge is weighted 60.

In constrast, if we were to solve MWPF with MWPM decoder, then we have to ignore the hyperedge $e_4$ and thus leads to suboptimal result, as shown by the following Python script using the Fusion Blossom library.

from fusion_blossom import SolverInitializer, SolverSerial, SyndromePattern

# Offline
vertex_num = 5
weighted_edges = [(0, 4, 100), (0, 1, 100), (1, 2, 100), (2, 3, 100)]
virtual_vertices = [4]
initializer = SolverInitializer(vertex_num, weighted_edges, virtual_vertices)
fusion = SolverSerial(initializer)

# Online
syndrome = [0, 1, 3]
fusion.solve(SyndromePattern(syndrome))
fusion_subgraph = fusion.subgraph()
print(fusion_subgraph)  # out: [0, 2, 3], which is weighted 300 instead of 160

Advanced Usage

When trading off accuracy and decoding time, we provide a timeout parameter for the decoder. Also, one can specify whether you want the clusters to all grow together or grow one by one. More parameters are coming as we develop the library.

config = {
    "cluster_node_limit":  50,  # how many dual variables are allowed in each cluster before falling back to UF decoder,
                                # by default infinite but setting it to 50 works for circuit-level surface code d=7
                                # for millisecond decoding. I would recommend use this option alone (without timeout) to
                                # tune between decoding speed and accuracy.
    "timeout": 3.0,  # 3 second timeout for each cluster, by default infinite (preferred)
}
hyperion = SolverSerialJointSingleHair(initializer, config)

An embedded visualization tool is coming soon.

Examples

For surface code with depolarizing noise mode $p_x =p_y=p_z = p/3$, here shows physical error rates 1%, 2% and 4% (left to right).

Surface Code Example (click for YouTube video)

For triangle color code with X errors, here shows physical error rates 1%, 2% and 4% (left to right).

Triangle Color Code Example (click for YouTube video)

For circuit-level surface code, here shows physical error rate 0.03%, 0.1% and 0.3% (left to right).

Circuit-level Surface Code Example (click for YouTube video)

Reference

[1] Berlekamp, Elwyn, Robert McEliece, and Henk Van Tilborg. "On the inherent intractability of certain coding problems (corresp.)." IEEE Transactions on Information Theory 24.3 (1978): 384-386.

[2] Lovász, László. "The factorization of graphs. II." Acta Mathematica Academiae Scientiarum Hungarica 23 (1972): 223-246.

[3] Higgott, Oscar, and Craig Gidney. "Sparse Blossom: correcting a million errors per core second with minimum-weight matching." arXiv preprint arXiv:2303.15933 (2023).

[4] Wu, Yue, and Lin Zhong. "Fusion Blossom: Fast MWPM Decoders for QEC." arXiv preprint arXiv:2305.08307 (2023).

[5] Rothvoß, Thomas. "The matching polytope has exponential extension complexity." Journal of the ACM (JACM) 64.6 (2017): 1-19.

Metadata

Release files for mwpf-rational 0.2.12

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

Source distribution (sdist)

Source distribution for mwpf-rational 0.2.12
File Size Uploaded
mwpf_rational-0.2.12.tar.gz 1.5 MB Details

Built distributions (wheels)

Table of built distributions (wheels) for mwpf-rational 0.2.12
File
mwpf_rational-0.2.12-cp38-abi3-win_amd64.whl CPython 3.8 abi3 Windows x86-64 Details
mwpf_rational-0.2.12-cp38-abi3-musllinux_1_2_x86_64.whl CPython 3.8 abi3 Linux musl 1.2+ x86-64 Details
mwpf_rational-0.2.12-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.8 abi3 Linux glibc 2.17+ x86-64 Details
mwpf_rational-0.2.12-cp38-abi3-macosx_10_12_universal2.whl CPython 3.8 abi3 macOS 10.12+ universal2 (ARM64, x86-64) Details

Total release size: 51.4 MB

Release files / mwpf_rational-0.2.12.tar.gz

Download URL mwpf_rational-0.2.12.tar.gz
Size 1.5 MB
Tags Source
SHA-256 checksum
How to use checksums
0b66f02ef0b02cd3af134ef6b17a85a2a3f6b3aeaa7b7dc8fe93e680a7bd93c4
BLAKE2b-256 checksum
How to use checksums
8b96ab04680a4e12aad82fcc4e0fe669cd92d75fea433eaa14794a3c201f525d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.12.9

Release files / mwpf_rational-0.2.12-cp38-abi3-win_amd64.whl

Download URL mwpf_rational-0.2.12-cp38-abi3-win_amd64.whl
Size 2.3 MB
Tags CPython 3.8 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
c6d447c5f075136a30c5d7e905f8942d95a06a38d16c86e719e0a9bf0bbbd318
BLAKE2b-256 checksum
How to use checksums
fc9291c9ad6000716a8b844896d296c6e81a2a9f8e0c6b5bd54b65aec1d30940
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.12.9

Release files / mwpf_rational-0.2.12-cp38-abi3-musllinux_1_2_x86_64.whl

Download URL mwpf_rational-0.2.12-cp38-abi3-musllinux_1_2_x86_64.whl
Size 21.4 MB
Tags CPython 3.8 Linux musl 1.2+ x86-64 abi3
SHA-256 checksum
How to use checksums
027c03a0975fa248bed3118eb7835fc44c0e816e1a9e1d474f01c8ce3b568ae5
BLAKE2b-256 checksum
How to use checksums
a6135add43372f1b0f94201de320fe1ce81c0041ba03f6b305222ea341917f54
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.12.9

Release files / mwpf_rational-0.2.12-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL mwpf_rational-0.2.12-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 21.3 MB
Tags CPython 3.8 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
54fdc7da77d83170757220041d8df288d7e369407d7972cce1b20b7788121ec0
BLAKE2b-256 checksum
How to use checksums
689ec0be6868b7aa0e1a28dcb29916261426fc9453a665379dad6d60713af9c2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.12.9

Release files / mwpf_rational-0.2.12-cp38-abi3-macosx_10_12_universal2.whl

Download URL mwpf_rational-0.2.12-cp38-abi3-macosx_10_12_universal2.whl
Size 5.0 MB
Tags CPython 3.8 abi3 macOS 10.12+ universal2 (ARM64, x86-64)
SHA-256 checksum
How to use checksums
56f6416fe1d5648f78f6a238530bfbf14a2abc9a357a942fe3d55a3f152bb0a6
BLAKE2b-256 checksum
How to use checksums
c22a6565b8d7e71cc59ba093af91a23b5cee348a6e53f3430535e2640c58e706
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.12.9

Release history Release notifications | RSS feed

This release

0.2.12 This release

5 release files

0.2.11

5 release files

0.2.10

5 release files

0.2.9

5 release files

0.2.8

5 release files

0.2.7

4 release files

0.2.6

4 release files

0.2.5

4 release files

0.2.4

4 release files

0.2.3

4 release files

0.2.2

4 release files

0.2.1

4 release files

0.2.0

4 release files

0.1.5

4 release files

0.1.4

4 release files

0.1.2

4 release files

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