Skip to content

Fast deterministic detector sampling#78

Merged
rafaelha merged 19 commits into
mainfrom
rafaelha/fast_deterministic_detector_sampling
May 19, 2026
Merged

Fast deterministic detector sampling#78
rafaelha merged 19 commits into
mainfrom
rafaelha/fast_deterministic_detector_sampling

Conversation

@rafaelha
Copy link
Copy Markdown
Collaborator

@rafaelha rafaelha commented Mar 25, 2026

This PR contains the Clifford detector sampling fast path used in https://arxiv.org/pdf/2604.01059

Instead of compiling graphs into parametric expressions, one can read of the Tanner graph directly for deterministic detectors.

image

This significantly speeds up Clifford-only circuits (non-Clifford circuits are only slightly sped up). For example, for the circuits from the Clifft paper I got the following updated numbers:

image

Note that r=1 coherent noise circuits from Clifft become Clifford-only circuits after ZX reduction in the Tsim compilation step.

import tsim
import time


def benchmark_detector_sampler(path: str, n: int) -> None:
    c = tsim.Circuit.from_file(path)
    sampler = c.compile_detector_sampler()

    batch_size = n
    sampler.sample(n, batch_size=batch_size)

    start = time.perf_counter()
    samples = 0
    duration = 0.0
    while duration < 5:
        sampler.sample(n, batch_size=batch_size)
        samples += n
        duration = time.perf_counter() - start

    samples_per_second = samples / duration
    print(f"{samples_per_second / 1e6:.1f} M samples/s")


benchmark_detector_sampler("surface7.stim", 10_000_000)
benchmark_detector_sampler("surface3_coherent.stim", 100_000_000)
benchmark_detector_sampler("surface5_coherent.stim", 1_000_000)

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 25, 2026

☂️ Python Coverage

current status: ✅

Overall Coverage

Lines Covered Coverage Threshold Status
2296 2201 96% 0% 🟢

New Files

No new covered files...

Modified Files

File Coverage Status
src/tsim/circuit.py 94% 🟢
src/tsim/compile/pipeline.py 100% 🟢
src/tsim/core/graph.py 91% 🟢
src/tsim/core/types.py 100% 🟢
src/tsim/sampler.py 90% 🟢
TOTAL 95% 🟢

updated for commit: acbece1 by action🐍

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 25, 2026

PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-05-19 17:58 UTC

@rafaelha rafaelha marked this pull request as draft March 25, 2026 21:45
@Roger-luo
Copy link
Copy Markdown
Collaborator

Hi! Could you add a bit more context to this issue? A description of the expected behavior, use case, or any relevant details would help us prioritize and implement it. Thanks!

@rafaelha rafaelha force-pushed the rafaelha/fast_deterministic_detector_sampling branch from 6197df5 to 400766b Compare April 29, 2026 15:05
…faelha/fast_deterministic_detector_sampling
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 19, 2026

☂️ Code Coverage

current status: ✅

Overall Coverage

Statements Covered Coverage Threshold Status
2577 2495 97% 0% 🟢

New Files

No new covered files...

Modified Files

File Coverage Status
src/tsim/circuit.py 97% 🟢
src/tsim/compile/pipeline.py 100% 🟢
src/tsim/core/graph.py 91% 🟢
src/tsim/core/types.py 100% 🟢
src/tsim/sampler.py 94% 🟢
TOTAL 96% 🟢

updated for commit: 6c72a81 by action🐍

rafaelha added 3 commits May 19, 2026 11:08
- Introduced a zero-copy fast path in `_CompiledSamplerBase` to optimize sampling when direct f-indices are contiguous, without flips or reindexing.
- Updated `compile_program` to consolidate direct entries into a single list, enhancing clarity and efficiency in handling direct components.
- Simplified the logic for sorting direct entries and adjusted the output order to align with the original layout, reducing potential reindexing at sample time.
- Enhanced the `transform_error_basis` function to streamline the detection of phase variables, improving overall graph processing efficiency.
@rafaelha rafaelha marked this pull request as ready for review May 19, 2026 15:14
- Added a new test for the detector sampler that verifies it returns empty arrays when no detectors are present, both with and without a reference sample.
- Removed outdated test cases that were previously causing crashes due to empty concatenation.
@rafaelha rafaelha requested a review from Copilot May 19, 2026 15:19
@rafaelha
Copy link
Copy Markdown
Collaborator Author

@codex review again

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a fast path for detector sampling when connected components are deterministically given by a single error-basis variable (f_i), avoiding the JAX compilation + autoregressive sampling pipeline for those components. This targets faster detector sampling on low-noise surface-code-like circuits (per the linked paper).

Changes:

  • Detect “direct” connected components (single output equal to one f variable, optionally flipped) and represent them explicitly in CompiledProgram.
  • Add a pure-NumPy sampling fast path for programs consisting only of direct components, plus precomputed output reindexing to avoid per-sample argsort.
  • Add a unit test for reference sampling with zero detectors, a benchmark-style test, and documentation/changelog updates.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/tsim/core/graph.py Adds direct-component classification and prioritizes output-adjacent parameter vertices during error-basis transform.
src/tsim/compile/pipeline.py Splits compilation into direct vs compiled components; precomputes output permutation (output_reindex).
src/tsim/core/types.py Extends CompiledProgram to carry direct_f_indices, direct_flips, and output_reindex.
src/tsim/sampler.py Uses direct bits in sample_program; adds NumPy-only _sample_direct fast path; updates probability_of.
src/tsim/circuit.py Documents the new detector-sampler fast path behavior.
test/unit/test_sampler.py Adds regression test for use_detector_reference_sample=True with no detectors.
test/integration/test_sampler.py Updates CompiledProgram construction to include new required fields.
test/unit/benchmarks/test_classical_detector_sampling.py Adds a performance threshold test (currently problematic for CI).
CHANGELOG.md Documents the new detector-sampler fast path under Unreleased.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread test/unit/benchmarks/test_classical_detector_sampling.py Outdated
@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Another round soon, please!

ℹ️ 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".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@rafaelha
Copy link
Copy Markdown
Collaborator Author

Code review

Found 1 issue:

  1. The new benchmark file lives under test/unit/benchmarks/ and will be picked up by the default pytest collection (testpaths = "test/" in pyproject.toml), so CI will run a shots = 10_000_000 sample on every PR. The assertion uses an absolute 5e-8 s/shot threshold that is hardware-dependent and will be flaky across runners. Consider gating with a marker (e.g. @pytest.mark.benchmark excluded by default), reducing shot count, or removing the hard threshold. Note: Copilot already flagged this inline on the same PR.

def test_classical_detector_sampling_time_per_shot():
"""At p=1e-6 the detector sampler should produce shots faster than 5e-8 s/shot."""
d = 7
p = 1e-6
shots = 10_000_000
stim_circuit = stim.Circuit.generated(
"surface_code:rotated_memory_z",
distance=d,
rounds=d,
before_round_data_depolarization=p,
before_measure_flip_probability=p,
after_clifford_depolarization=p,
after_reset_flip_probability=p,
)
tc = tsim.Circuit(str(stim_circuit))
sampler = tc.compile_detector_sampler()
# Warm up JIT compilation
sampler.sample(shots=shots)
t0 = time.perf_counter()
sampler.sample(shots=shots)
sample_time_s = time.perf_counter() - t0
time_per_shot = sample_time_s / shots
assert (
time_per_shot < 5e-8
), f"Time per shot {time_per_shot * 1e6:.4f} us exceeds 5e-8 s budget"

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

@rafaelha rafaelha merged commit b25cb6e into main May 19, 2026
10 checks passed
@rafaelha rafaelha deleted the rafaelha/fast_deterministic_detector_sampling branch May 19, 2026 17:51
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.

3 participants