Skip to content

Add PNA tutorial#5209

Open
henryzou50 wants to merge 32 commits into
mainfrom
pna-tutorial
Open

Add PNA tutorial#5209
henryzou50 wants to merge 32 commits into
mainfrom
pna-tutorial

Conversation

@henryzou50

Copy link
Copy Markdown
Collaborator

Summary

Adds a new tutorial, "Improving expectation values with propagated noise absorption (PNA)." It is an updated, documentation-ready version of the PNA tutorial from the QDC Challenges 2025 repo: https://github.com/qiskit-community/qdc-challenges-2025/blob/main/day3_tutorials/Track_A/pna/propagated_noise_absorption.ipynb

PNA mitigates two-qubit gate noise by propagating the inverse of learned noise channels into the measured observable (using samplomatic, NoiseLearnerV3, and qiskit-addon-pna), then sampling the randomized circuits with the new QuantumProgram/Executor classes in Qiskit Runtime. The tutorial walks through the full four-step Qiskit pattern on a 30-site mirrored kicked-Ising circuit and compares PNA against PNA+TREX, PNA+PS, and PNA+PS+TREX.

Major changes from the original

  • Updated to released Qiskit Runtime (0.47.0). Migrated off the executor_preview branch. Executor, QuantumProgram, and NoiseLearnerV3 are now imported from the top-level qiskit_ibm_runtime; noise-learner options are passed as a plain dict (no NoiseLearnerV3Options import).
  • Removed hardcoded credentials. Replaced the shared_service (token + instance CRN) and the named QiskitRuntimeService(name="qdc-2025") with a plain QiskitRuntimeService() that reads saved credentials.
  • Runs live, no saved jobs. Removed all saved-job loading (the shared_service.job(...) IDs and load_saved_* branches); the noise learner and Executor now execute live, with the job tagged TUT_PNA.
  • Backend-agnostic qubit selection. Replaced the hardcoded 30-qubit ibm_kingston chain with a find_qubit_chain helper that builds a connected, low-error line from the backend's coupling map, and selects the backend with least_busy. Transpilation stays at optimization_level=0 with the chain pinned as initial_layout, preserving the mirrored two-qubit-gate layer structure that boxing and noise learning rely on.
  • API fix. The measurement basis-change input was hardcoded as basis2, which no longer matches the samplex interface; it now looks up the name from samplex.inputs().get_specs(...).
  • Reformatted to the tutorial template. Added title/description frontmatter, learning outcomes, prerequisites, background, requirements, setup, and next steps. The small-scale simulator section is kept but explains why simulation is skipped (PNA mitigates learned hardware noise).
  • Content corrections and copyediting. Fixed the learned-noise-rates discussion (the original claimed two-qubit rates exceed one-qubit rates, the opposite of what the data shows; now backend-agnostic), and general cleanup.

Files

  • New: docs/tutorials/propagated-noise-absorption.ipynb + images under public/docs/images/tutorials/propagated-noise-absorption/ (3 schematics and the extracted cell outputs).
  • Registered in docs/tutorials/_toc.json and docs/tutorials/index.mdx (Error mitigation section), added to the notebook-CI exclude list in scripts/config/notebook-testing.toml, and given an owner in qiskit_bot.yaml.

Testing

Ran on IBM Quantum hardware, tox -e lint, the notebook normalizer, spelling, and internal-link checks all pass.

Adapt the PNA tutorial from the QDC Challenges 2025 repo [1] into a
documentation tutorial, updated for the stable Qiskit Runtime release and
restructured to follow the standard tutorial template.

New files:
- docs/tutorials/propagated-noise-absorption.ipynb
- public/docs/images/tutorials/propagated-noise-absorption/ (3 schematics
  + extracted cell outputs)

Registered in docs/tutorials/_toc.json and docs/tutorials/index.mdx under
"Error mitigation", excluded from notebook CI in
scripts/config/notebook-testing.toml (consistent with other tutorials), and
given an owner in qiskit_bot.yaml.

Major changes from the original [1]:

- API: migrated off the `executor_preview` branch to the released
  qiskit-ibm-runtime 0.47.0. `Executor`, `QuantumProgram`, and
  `NoiseLearnerV3` are now imported from the top-level package; noise-learner
  options are passed as a plain dict instead of importing
  `NoiseLearnerV3Options`.

- Credentials: replaced the hardcoded `shared_service` (token + `instance`
  CRN) and the named `QiskitRuntimeService(name="qdc-2025")` with a plain
  `service = QiskitRuntimeService()` that reads saved credentials.

- Live execution: removed all saved-job loading (the `shared_service.job(...)`
  IDs and the `load_saved_nl_result` / `load_exec_results_from_disk`
  branches). The noise learner and Executor now run live, and the job is
  tagged `TUT_PNA`.

- Bug fix: the measurement basis-change input was hardcoded as `basis2`,
  which no longer matches the samplex interface (it expects `basis0` here).
  Replaced with a lookup over `samplex.inputs().get_specs(...)` so the name
  is discovered from the circuit's box structure rather than hardcoded. Also
  fixed the execution `shape` to be a real 1-tuple.

- Structure: reformatted to the tutorial template (title/description
  frontmatter, learning outcomes, prerequisites, background, requirements,
  setup, next steps). The small-scale simulator section is kept but
  explains why simulation is skipped (PNA mitigates learned hardware noise),
  and the workflow is presented as the four-step large-scale hardware
  example.

- Content: corrected the learned-noise-rates discussion, which had claimed two-qubit rates exceed one-qubit rates (the opposite of what the plot shows); rewrote it to be device-dependent.
Make the tutorial runnable on any backend instead of being tied to a
hardcoded ibm_kingston chain.

- Add a `find_qubit_chain` helper (defined in the Setup section) that walks
  the backend's coupling map and greedily builds a connected, low-error line
  of `num_qubits`. This replaces the hardcoded 30-qubit layout. Transpilation
  stays at optimization_level=0 with the chain pinned as `initial_layout`, so
  the mirrored two-qubit-gate layer structure that the boxing and
  noise-learning steps depend on is preserved exactly.

- Select the backend dynamically with `service.least_busy(...)` rather than
  pinning ibm_kingston.

- Make the learned-noise-rates commentary backend-agnostic; it no longer
  names a specific device.

- Regenerate the extracted output figures from a fresh hardware run.
@henryzou50 henryzou50 requested a review from a team June 3, 2026 19:26
@qiskit-bot

Copy link
Copy Markdown
Contributor

One or more of the following people are relevant to this code:

  • @nathanearnestnoble

@review-notebook-app

Copy link
Copy Markdown

Check out this pull request on  ReviewNB

See visual diffs & provide feedback on Jupyter Notebooks.


Powered by ReviewNB

@nathanearnestnoble

Copy link
Copy Markdown
Collaborator

Should tie "layer_pair_depths" to be informed by depth of circuit to be mitigated.

Comment thread docs/tutorials/propagated-noise-absorption.ipynb Outdated
Comment thread docs/tutorials/propagated-noise-absorption.ipynb Outdated
Comment thread docs/tutorials/propagated-noise-absorption.ipynb Outdated
Comment thread docs/tutorials/propagated-noise-absorption.ipynb Outdated
Comment thread docs/tutorials/propagated-noise-absorption.ipynb Outdated
Comment thread docs/tutorials/propagated-noise-absorption.ipynb Outdated
Comment thread docs/tutorials/propagated-noise-absorption.ipynb Outdated
Comment thread docs/tutorials/propagated-noise-absorption.ipynb Outdated
Comment thread docs/tutorials/propagated-noise-absorption.ipynb Outdated
Comment thread docs/tutorials/propagated-noise-absorption.ipynb Outdated
Comment thread docs/tutorials/propagated-noise-absorption.ipynb Outdated
Comment thread docs/tutorials/propagated-noise-absorption.ipynb Outdated
Comment thread docs/tutorials/propagated-noise-absorption.ipynb Outdated
Comment thread docs/tutorials/propagated-noise-absorption.ipynb Outdated
Comment thread docs/tutorials/propagated-noise-absorption.ipynb Outdated
Comment thread docs/tutorials/propagated-noise-absorption.ipynb Outdated
Comment thread docs/tutorials/propagated-noise-absorption.ipynb Outdated
Comment thread docs/tutorials/propagated-noise-absorption.ipynb Outdated
Co-authored-by: abbycross <across@us.ibm.com>
henryzou50 and others added 8 commits June 25, 2026 19:48
Co-authored-by: abbycross <across@us.ibm.com>
Co-authored-by: abbycross <across@us.ibm.com>
Co-authored-by: abbycross <across@us.ibm.com>
Co-authored-by: abbycross <across@us.ibm.com>
Co-authored-by: abbycross <across@us.ibm.com>
Co-authored-by: abbycross <across@us.ibm.com>
Co-authored-by: abbycross <across@us.ibm.com>
Co-authored-by: abbycross <across@us.ibm.com>
henryzou50 and others added 4 commits June 25, 2026 19:50
Co-authored-by: abbycross <across@us.ibm.com>
Co-authored-by: abbycross <across@us.ibm.com>
Co-authored-by: abbycross <across@us.ibm.com>
Co-authored-by: abbycross <across@us.ibm.com>
henryzou50 and others added 4 commits June 25, 2026 19:51
Co-authored-by: abbycross <across@us.ibm.com>
Co-authored-by: abbycross <across@us.ibm.com>
Co-authored-by: abbycross <across@us.ibm.com>
Co-authored-by: abbycross <across@us.ibm.com>
Co-authored-by: abbycross <across@us.ibm.com>
Replace the hardcoded layer_pair_depths [1, 2, 4, 8, 12, 16, 24, 32, 40, 48]
with a schedule derived from the circuit being mitigated. Measure the
two-qubit-layer depth on the pre-boxed ISA circuit
(depth_2q = isa_circuit.depth(num_qubits == 2)), halve it for layer pairs
(max_layer_pair_depth = depth_2q // 2), and cap the fixed candidate schedule at
that value so we never learn deeper than the circuit. After boxing, two-qubit
gates are hidden inside full-width BoxOp instructions, so num_qubits == 2 on
boxed_circuit matches nothing and QuantumCircuit.depth does not recurse into
boxes; the pre-boxed ISA circuit gives the true 2q critical-path depth.

For this 30-qubit, 10-Trotter-step mirror circuit, depth_2q = 40, so the
schedule becomes [1, 2, 4, 8, 12, 16, 20] — dropping 24/32/40/48, which were
deeper than the circuit and caused noise learning beyond the mitigated depth.

Also pin the backend to ibm_fez (replacing the least_busy selection) and refresh
cell outputs and figures from the new run.
Co-authored-by: abbycross <across@us.ibm.com>
@henryzou50

henryzou50 commented Jun 26, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks for the review and suggestions @abbycross. I applied the changes and also the change Nate request of having "layer_pair_depths" to be informed by depth of circuit to be mitigated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

4 participants