Backend sampling - #744
Open
positr0nium wants to merge 42 commits into
Open
Conversation
positr0nium
marked this pull request as ready for review
July 16, 2026 11:08
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Introduces
@backend_sampler— a Jasp decorator that routessample()andexpectation_value()calls through a real quantum backend instead of the Jaspify simulator. The quantum circuit is extracted once, executed on the backend for all shots, and the classical post-processing is replayed via the Jaspr's own while-loop — JIT-compiled through JAX. Control-flow primitives (fori_loop,while,cond,scan,jit) are handled via a custom equation evaluator that propagates through all nesting levels. Example:Related Issues
Closes #
Related to the
sampling_upgradesbranchType of Change
Breaking Change?
What was changed?
New decorator:
@backend_sampler(backend=...)— routessample()/expectation_value()calls through a real backend. Usesmake_jaxpr(notmake_jaspr) for the outer trace — no quantum tracing context, so direct quantum operations outside sampling kernels fail cleanly at trace time.New interpreter module:
backend_sampling_interpreter.py— contains the Jaspr-level logic:_extract_to_qc_args()— mini-interpreter that runs the eval Jaspr until the firstsampling_body_funccall, capturing all arguments automatically (handles JAX-implicitly-prepended closure variables)._make_backend_sampling_fn()— factory returning abackend_sampling_fnthat extracts the circuit viaJaspr.to_qc(), runs it once on the backend, and replays the post-processing loop._body_loop_evaluator()— interceptssampling_body_funcin the eval Jaspr, replacing it withJaspr.extract_post_processing()using pre-computed measurement bits.Control-flow propagation — the outer equation evaluator handles
jit/pjit,while,cond, andscanprimitives by recursively callingeval_jaxprwith the custom evaluator, ensuringsample()/expectation_value()calls are intercepted regardless of nesting depth inside control flow.Real-time feedback detection — catches the
"Tried to convert real-time feedback into QuantumCircuit"exception fromto_qc()and re-raises asRuntimeErrorwith a clear message pointing tojaspify._backend_shots_marker— identity@jax.jitmarker inserted at the top ofsampling_eval_functionandexpectation_value_eval_functionso the backend sampler can reliably locate the shot count in the traced Jaxpr without fragile position-based extraction.Supporting changes:
sampling.py/ev.py: added_backend_shots_markercall; renamedstate_prep→sampling_kernelinexpectation_valuefor consistency.measurement_primitive.py: fixedmeasure_implementationto index into the qubit array.tracing_quantum_session.py: allow qubit reuse from templates.qaoa_problem.py: acceptQuantumVariableTemplateinqargparameter.qc_extraction_interpreter.py: supportQuantumVariableTemplateand parity handle fixes.Documentation:
backend_samplerdocstring with usage examples, parameter docs, Raises section, and architecture notes.BackendSampling.rstto Sphinx docs and updatedJasp/index.rsttoctree.Tests (57 total):
fori_loop,cond,while_loop,scan, nestedjit,switch.How was it tested?
All 57 tests pass locally:
pytest tests/jax_tests/test_backend_sampling.py \ tests/jax_tests/test_backend_sampling_ev.py \ tests/jax_tests/test_to_qc_in_tracing_context.py -q # 57 passed in ~25sChecklist
Reviewer Notes
backend_sampling.py(decorator + outer evaluator) andbackend_sampling_interpreter.py(Jaspr interpreters) keeps the architecture modular.make_jaxprvsmake_jasprchoice is deliberate:make_jaxpravoids opening a quantum tracing context for the outer orchestration function, so any accidental direct quantum operations fail at trace time with a clear error.jit/while/cond/scan) follow the same pattern as the post-processing interpreter — propagating the custom evaluator downward viaeval_jaxpr(eqn_evaluator=...).