Skip to content

Sample constant components without compiling them - #201

Open
rafaelha wants to merge 1 commit into
mainfrom
claude/focused-carson-da204b
Open

rafaelha wants to merge 1 commit into
mainfrom
claude/focused-carson-da204b

Conversation

@rafaelha

Copy link
Copy Markdown
Collaborator

Summary

classify_direct only accepted a single-output component whose classical Z spider has exactly one error-basis parameter (len(phase.parameters) != 1 returned None). Deterministic detectors of noiseless circuits reduce to the same two-vertex shape with no parameters, so each one went through decompose/compile_scalars and was sampled as its own JAX component.

This PR adds a constant path next to the direct path:

  • compile/pipeline.py: classify_constant(component) returns the output bit (phase.value == 1, the same convention as the direct flip). It shares the structural check (classical output, Hadamard edge, classical Z spider, phase 0/π) with classify_direct through the new _output_bit_phase.
  • core/types.py: new CompiledProgram.constant_bits field. output_order is now [direct..., constant..., compiled...], and output_reindex is computed from it as before.
  • sampler.py:
    • sample_program broadcasts the constants into the concatenated result.
    • _compute_direct_outputs scatters them, so programs with only direct and constant outputs still skip JAX via _sample_direct. The all-direct gather path is unchanged, because scattering benchmarked 1.6–2.4× slower.
    • Postselection treats constant detectors as direct.
    • CompiledStateProbs.probability_of multiplies by an indicator that the state matches the constants.
    • repr reports the constant count.
  • Docs, docstrings and CHANGELOG are updated.

Effect

Noiseless distillation.stim (from clifft-bench), detector sampler:

before after
compiled components 41 1
direct / constant 0 / 0 0 / 40
graphs 534 454
sample(10_000) 2.73 s 1.31 s

Behaviour changes

  • A fixed seed can give different compiled-component samples, because constants no longer consume PRNG splits.
  • Masking a constant-1 detector in postselection_mask now discards every shot without running JAX (unless use_detector_reference_sample cancels it). Before, it fell back to full sampling.

Tests

  • New tests in test/unit/compile/test_pipeline.py:
    • A noiseless circuit with deterministic detectors (one random detector plus constants 0, 1 and 1, one of them through T · T_DAG). It checks the number of compiled components, constant_bits, output_order with a non-identity reindex, and that sampled detectors equal the constants.
    • An all-constant circuit never calls sample_program, with and without reference samples.
    • Direct and constant outputs interleaved, on both the numpy and the JAX path.
    • probability_of with constants.
    • classify_constant accept and reject cases.
  • test/unit/test_postselection.py: postselection on a constant detector, with and without a reference sample.
  • uv run pytest test/unit (1052 passed), uv run pytest test/integration (311 passed), uv run pyright src test (0 errors).
  • An independent review compared the new code with main on 300 random noisy Clifford+T circuits. Probabilities matched to 7.5e-9, and every sampler option (including postselection) gave the same constant and direct columns as main. It also checked marginals against stim on 147 Clifford circuits.

🤖 Generated with Claude Code

classify_direct only accepted a single-output component whose classical Z
spider carries exactly one error-basis parameter. Deterministic detectors of
noiseless circuits reduce to the same two-vertex shape with no parameters, so
each went through extract/decompose/compile and was sampled as its own JAX
component (40 of them for the noiseless distillation circuit).

Add classify_constant (sharing the structural check with classify_direct via
_output_bit_phase) and a CompiledProgram.constant_bits field. Constants sit
between the direct and the compiled outputs in output_order; the sampler
broadcasts them in sample_program, scatters them in _compute_direct_outputs
(so all-direct-or-constant programs still skip JAX), counts them as direct
for postselection, and checks them in CompiledStateProbs.probability_of.

Noiseless distillation.stim detector sampler: 41 -> 1 compiled components,
10k shots 2.7 s -> 1.3 s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-15T22:33:39.810018Z e63f6b3 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://queracomputing.github.io/tsim/pr-preview/pr-201/

Built to branch gh-pages at 2026-10-15 22:32 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@github-actions

Copy link
Copy Markdown
Contributor

☂️ Code Coverage

current status: ✅

Overall Coverage

Statements Covered Coverage Threshold Status
2722 2593 95% 0% 🟢

New Files

No new covered files...

Modified Files

File Coverage Status
src/tsim/circuit.py 92% 🟢
src/tsim/compile/pipeline.py 100% 🟢
src/tsim/core/types.py 100% 🟢
src/tsim/sampler.py 93% 🟢
TOTAL 96% 🟢

updated for commit: e63f6b3 by action🐍

This branch has not been deployed

No deployments
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.

1 participant