Sitelet https://github.com/PECOS-packages/PECOS/pull/991
Skip to content

Lower measurement-conditioned Pauli If to Stim record controls and reject other conditionals - #991

Open
ciaranra wants to merge 2 commits into
devfrom
fix-stim-if-conditional
Open

ciaranra wants to merge 2 commits into
devfrom
fix-stim-if-conditional

Conversation

@ciaranra

@ciaranra ciaranra commented Oct 2, 2026 •

Copy link
Copy Markdown
Member

Fixes #978.

Problem

The SLR Stim backend compiled If by emitting the then-body (and the else-body) unconditionally, discarding the condition. A measurement-conditioned correction was applied on every shot. The deprecated StimGenerator had the same behavior.

Fix

Stim applies Pauli gates classically controlled by a measurement record (CX rec[-k] q applies X to q exactly when that measurement was 1), so the dominant case compiles faithfully:

  • A then-body of X/Y/Z gates (optionally inside Parallel, with comments) conditioned on one measured bit -- c[i], c[i] == 0/1, or c[i] != 0/1 -- lowers to CX/CY/CZ rec[-k] q. A condition that selects bit value 0 applies the Pauli unconditionally and then again under the record control, which cancels it when the bit is 1.
  • To find k, the backend tracks which measurement record each classical bit holds. A REPEAT body is its own record frame: a condition inside it can only read a bit measured earlier in the same iteration (an outer record's offset changes every iteration), and after the block a bit written in the body refers to the last iteration's measurement.
  • Everything else raises NotImplementedError: an else-body, a non-Pauli body, a register-level or compound condition, a bit with no measurement in scope, and a bit whose value no longer comes from a measurement (classical assignment, or any register named by a Permute, since Permute refs carry no qubit/classical kind and SLR allows a qubit and a classical register to share a name).

Qubit Permute handling is unchanged. The deprecated StimGenerator now raises on If and points to pecos.slr.generate(prog, "stim").

Tests

TestAstToStimConditionals uses Stim's own sampler as the oracle: each program measures a random bit and conditionally corrects another qubit, and the test checks the correction fires on exactly the selected shots. Coverage includes every supported condition form for X and Y, Z observed in the X basis, re-measured bits, lookbacks past rec[-1] at top level and inside REPEAT, conditions after a REPEAT, and each rejection path including invalidation carried out of a REPEAT body. A regression test checks that a qubit Permute still applies when a classical register shares its name.

Every new test fails against the previous implementation, and targeted mutations of the lookback arithmetic, last-iteration offset, frame reset, and each invalidation path are each caught.

  • tests/pecos/slr, tests/slr_tests, tests/selene/test_hugr_to_ast.py: 1241 passed, 4 skipped
  • pre-commit on the changed files: clean

Out of scope

A qubit Permute inside a Repeat body is compiled for a single iteration (pre-existing on dev, independent of If); tracked in #992.

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.

SLR Stim backend compiles If by emitting the body unconditionally, discarding the condition

1 participant