Skip to content

Fix: DetectorErrorModelArrays ignores stim's ^ decomposition separator#462

Draft
HaoTy wants to merge 4 commits into
mainfrom
fix/non-graphlike-error
Draft

Fix: DetectorErrorModelArrays ignores stim's ^ decomposition separator#462
HaoTy wants to merge 4 commits into
mainfrom
fix/non-graphlike-error

Conversation

@HaoTy
Copy link
Copy Markdown
Collaborator

@HaoTy HaoTy commented Apr 24, 2026

The non-matchable circuit issue mentioned in #445 and tqec/tqec#913 can be reproduced with even Stim-generated surface code circuits, as long as there is DEPOLARIZE2 noise:

    sinter.collect(
        tasks=[
            sinter.Task(
                circuit=stim.Circuit.generated(
                    "surface_code:rotated_memory_z",
                    distance=3,
                    after_clifford_depolarization=0.01,
                    rounds=3,
                )
            )
        ],
        num_workers=32,
        max_shots=100_000,
        max_errors=500,
        print_progress=True,
        decoders=["custom_decoder"],
        custom_decoders={"custom_decoder": decoders.SinterDecoder(with_MWPM=True)},
    )

Below analysis and fix are AI-generated, but makes sense to me.

Stim decomposes every non-graphlike error into graphlike pieces separated by ^. Sinter uses this by default, so pymatching's from_detector_error_model works fine. qldpc's DetectorErrorModelArrays.get_circuit_errors ignores ^ separators (src/qldpc/decoders/dems.py:128), merging all targets of a decomposed error back into one multi-detector column — which is what breaks from_check_matrix.

…rs, breaking matching decoders on DEMs with non-graphlike errors
@HaoTy HaoTy marked this pull request as ready for review April 24, 2026 17:45
@HaoTy HaoTy requested a review from perlinm as a code owner April 24, 2026 17:46
@perlinm
Copy link
Copy Markdown
Collaborator

perlinm commented Apr 24, 2026

Thanks for investigating! I think what we've discovered is that the qldpc.decoders.DetectorErrorModelArrays "forgets" data that it should keep in a stim.DetectorErrorModel.

From the stim documentation:

A separator target (^) is not an actual thing to target, but rather a marker used to split up the targets of an error mechanism into a suggested decomposition.

A bit more discussion here.

If my interpretation here is correct, the key word here is "suggested". The true error mechanism is the full list of targets, ignoring the separator. For Y errors in the surface code the full list of targets corresponds to a non-graphlike error. One possible fix is to simply ignore the error when building a matching decoder. Another possible fix is to decompose such an error into two correlated graph-like errors, and delegate the treatment of correlations to the decoder. I am pretty sure that matching decoders simply ignore the correlations. Worth noting: in the case of the surface code, these two fixes should be equivalent up to slight changes to the probability of each X or Z error.

The fix in this PR amounts to throwing out the information about correlations. In other words, it upgrades the ^ separator from a "suggestion" to an imperative: "decompose this error and forget about the correlation". Perhaps that makes sense more sense than the current fix in #445 for the surface code, but I am not sure that this fix makes sense more generally for other codes. I need to give this a bit more thought.

@HaoTy
Copy link
Copy Markdown
Collaborator Author

HaoTy commented Apr 24, 2026

Thanks for the clear explanation! I think it makes sense to preserve the correlation information and let the decoder decide. "pymatching-correlated" has been merged into Sinter (quantumlib/Stim#1012, quantumlib/Stim#1046), which can serve as a reference. Feel free to close or edit this PR.

@perlinm
Copy link
Copy Markdown
Collaborator

perlinm commented Apr 24, 2026

Tentative plan:

  1. Save suggestions in qldpc.decoders.DetectorErrorModelArrays (how exactly TBD). This information should be preserved when converting to/from a stim.DetectorErrorModel.
  2. Add a decompose_errors: bool = True option to the matching decoder constructor (here).

This branch and PR are a suitable place for these changes.

@perlinm perlinm marked this pull request as draft April 24, 2026 22:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants