Introduction to Dynamic Circuits on Braket
Overview
# --- Setup cell added by QCR (not part of the original tutorial) ---
# Source: amazon-braket/amazon-braket-examples @ 0c0818f315479aab9deebed7e7ed7533ac581923, Apache License 2.0.
# Installs the example's dependencies. If a later cell still reports a missing
# package, restart the runtime/kernel and run again from the top.
%pip install -q amazon-braket-sdk==1.117.3
Introduction to Dynamic Circuits with Amazon Braket on IQM Garnet
In this notebook we introduce experimental dynamic circuit primitives on IQM Garnet through mid-circuit measurements (MCM) and feedforward (FF) techniques on Amazon Braket. We show the basic syntax supported on Amazon Braket and IQM Garnet, demonstrate active qubit reset and active bit flip protection experiments, detail ways to experiment with local simulators, and provide further details for using these capabilities on IQM Garnet.
What are Dynamic Circuits?
Dynamic circuits are quantum circuits involving mid-circuit measurements, qubit resets, and feedforward or classically conditioned gates. Over the last few years, most quantum devices have allowed for static quantum circuits, where all measurements are taken at the end of a quantum circuit. However, this often does not use qubits efficiently and does not allow for feedback within a circuit. One can show with the principle of deferred measurement, that the dynamic circuit and static circuit pictures are entirely equivalent.
A simple example is a bit-flip check operation on a data qubit that we would like to perform
A key identity for dynamic circuits is:
which we can verify by considering the effect of a unitary on an arbitrary state. Namely, for some states
and
Here it does not matter whether we apply the gate and then measure, or conditionally apply
- You can verify this principle holds for density matrices as well.
- Post-selection of a particular result can be used more generally to post-select pure states.
On real devices, this capability of measuring before the end of the circuit is known as mid-circuit measurement, and the experimental technique of feedforward allows us to condition quantum gates on the measurement outcome. These experimental operations are highly non-trivial, and their practical implementation can vary based on devices, software options, and qubit selection. Here we will focus on the implementation for IQM devices, namely IQM Garnet.
Access in Braket
In Braket, mid-circuit measurements are (as of June 2025) supported as an Experimental feature. We first specify the experimental capability context:
from braket.experimental_capabilities import EnableExperimentalCapability
We can enable this context with a with statement, and then use the Circuit().measure_ff and Circuit().cc_prx gates to specify that our measurement is being used in a dynamic circuit context. Later in the notebooks we will simplify these operations to cc_x and cc_z, which effectively combine these operations.
Configuring the Notebook
First, let's handle relevant imports and configure the notebook. If you do not want to run these on the actual hardware, don't execute the second cell, and continue until the Local Simulation section.
from math import pi
from braket.circuits import Circuit
from braket.experimental_capabilities import EnableExperimentalCapability
from braket.tracking import Tracker
track = Tracker().start()use_qpu = True
if use_qpu:
import iqm_config
qd = iqm_config.qdHello Reset!
Here we detail a simple active reset protocol. Namely, we prepare some state, measure it, and apply a
Here we classically condition a
with EnableExperimentalCapability():
circuit = Circuit()
circuit.prx(1, pi/2, 0.0)
circuit.measure_ff(1, 1)
circuit.cc_prx(1, pi, .0, 1)
circuit = Circuit().add_verbatim_box(circuit)
print(circuit)
if use_qpu:
res0 = qd.run(circuit, shots=100).result()
print(res0.measurement_counts)T : │ 0 │ 1 │ 2 │ 3 │ 4 │
┌─────────────────┐ ┌───────┐ ┌─────────────────────┐
q1 : ───StartVerbatim───┤ PRx(1.57, 0.00) ├─┤ MFF→1 ├─┤ 1→CCPRx(3.14, 0.00) ├───EndVerbatim───
└─────────────────┘ └───────┘ └─────────────────────┘
T : │ 0 │ 1 │ 2 │ 3 │ 4 │
Counter({'0': 95, '1': 5})
And we have effectively reset the circuit using a dynamic circuit primitive!
Multi-Qubit Dynamic Circuits
The next step involves multi-qubit feedback, which we demonstrate with a simple bitflip protection circuit. First, we construct a non-zero state as a data qubit, and then use a measured ancilla to reset it. In the device case, we use an ancilla qubit with MCM and a classically conditioned X gate to correct the qubit.
qreg = [1,2]
with EnableExperimentalCapability():
qc = Circuit()
qc.prx(qreg[0], pi/2,pi/2).prx(qreg[0], pi, 0) # H gate
qc.prx(qreg[1], pi/2,pi/2).prx(qreg[1], pi, 0) # H gate
qc.cz(qreg[0],qreg[1])
qc.prx(qreg[1], -pi, 0).prx(qreg[1], -pi/2,pi/2) # H+ gate
qc.measure_ff(qreg[1],0)
qc.cc_prx(qreg[0], pi, 0, 0)
qc.cc_prx(qreg[1], pi, 0, 0)
qc = Circuit().add_verbatim_box(qc)
print(qc)
if use_qpu:
res1 = qd.run(qc, shots=100).result()
print('Shots with reset: ')
print(res1.measurement_counts)T : │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │
┌─────────────────┐ ┌──────────────┐ ┌──────────────────┐
q1 : ───StartVerbatim───┤ PRx(1.57, 1.57) ├─┤ PRx(3.14, 0) ├───●───┤ 0→CCPRx(3.14, 0) ├───────────────────────────────────────────────────────EndVerbatim───
║ └─────────────────┘ └──────────────┘ │ └──────────────────┘ ║
║ ┌─────────────────┐ ┌──────────────┐ ┌─┴─┐ ┌───────────────┐ ┌──────────────────┐ ┌───────┐ ┌──────────────────┐ ║
q2 : ─────────╨─────────┤ PRx(1.57, 1.57) ├─┤ PRx(3.14, 0) ├─┤ Z ├──┤ PRx(-3.14, 0) ├───┤ PRx(-1.57, 1.57) ├─┤ MFF→0 ├─┤ 0→CCPRx(3.14, 0) ├────────╨────────
└─────────────────┘ └──────────────┘ └───┘ └───────────────┘ └──────────────────┘ └───────┘ └──────────────────┘
T : │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │
Shots with reset:
Counter({'00': 87, '01': 10, '10': 3})
We can also probe the result without the active reset:
qreg = [1,2]
with EnableExperimentalCapability():
qc = Circuit()
qc.prx(qreg[0], pi/2,pi/2).prx(qreg[0], pi, 0) # H gate
qc.prx(qreg[1], pi/2,pi/2).prx(qreg[1], pi, 0) # H gate
qc.cz(qreg[0],qreg[1])
qc.prx(qreg[1], pi/2,pi/2).prx(qreg[1], pi, 0) # H gate
qc.measure_ff(qreg[1],0)
qc.cc_prx(qreg[0], pi, 0, 0)
# qc.cc_prx(qreg[1], pi, 0, 0)
qc = Circuit().add_verbatim_box(qc)
print(qc)
if use_qpu:
res2 = qd.run(qc, shots=100).result()
print('Shots with reset: ')
print(res2.measurement_counts)T : │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │
┌─────────────────┐ ┌──────────────┐ ┌──────────────────┐
q1 : ───StartVerbatim───┤ PRx(1.57, 1.57) ├─┤ PRx(3.14, 0) ├───●───┤ 0→CCPRx(3.14, 0) ├──────────────────────────────EndVerbatim───
║ └─────────────────┘ └──────────────┘ │ └──────────────────┘ ║
║ ┌─────────────────┐ ┌──────────────┐ ┌─┴─┐ ┌─────────────────┐ ┌──────────────┐ ┌───────┐ ║
q2 : ─────────╨─────────┤ PRx(1.57, 1.57) ├─┤ PRx(3.14, 0) ├─┤ Z ├─┤ PRx(1.57, 1.57) ├──┤ PRx(3.14, 0) ├─┤ MFF→0 ├────────╨────────
└─────────────────┘ └──────────────┘ └───┘ └─────────────────┘ └──────────────┘ └───────┘
T : │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │
Shots with reset:
Counter({'00': 56, '01': 34, '10': 5, '11': 5})
And we have successfully applied our first multi-qubit reset operations!
Local Simulation
The measurement and classically controlled feedforward heres allow us to effectively implement an if style logic, which for many applications can be aggregated into a single gate, a classical controlled cc_x gate.
Here, we use a form which concatenates the measurement, control, and qubit reset in one gate. We then can use the local Braket backends (braket_dm) to carry out these simulations. To simplify notation as well, we will move from the native gates to standard Clifford gates.
- Note,
cc_xis a custom, user-defined gate, defined inlocal_config.py. Use theresetkeyword to specify an active reset.
import local_config
qd = local_config.qdImporting local_config registers the correct set of gates, and adds the cc_x gate.
circuit = Circuit()
circuit.h(0)
circuit.cc_x([0])
print(circuit)
res3 = qd.run(circuit, shots=100).result()
print(res3.measurement_counts)T : │ 0 │ 1 │
┌─────────────────┐ ┌──────────────┐ ┌────┐
q0 : ─┤ PRx(1.57, 1.57) ├─┤ PRx(3.14, 0) ├─┤ KR ├─
└─────────────────┘ └──────────────┘ └────┘
T : │ 0 │ 1 │
Counter({'0': 100})
Now, we can implement the same two-qubit experiment as well.
circuit = Circuit()
circuit.h(0)
circuit.cnot(0,1)
circuit.cc_x([1,0], reset=False)
print(circuit)
res4 = qd.run(circuit, shots=100).result()
print(res4.measurement_counts)T : │ 0 │ 1 │ 2 │ 3 │ 4 │
┌─────────────────┐ ┌──────────────┐ ┌────┐
q0 : ─┤ PRx(1.57, 1.57) ├─┤ PRx(3.14, 0) ├───●──────────────────────────────────────────┤ KR ├─
└─────────────────┘ └──────────────┘ │ └─┬──┘
┌─────────────────┐ ┌──────────────┐ ┌─┴─┐ ┌───────────────┐ ┌──────────────────┐ ┌─┴──┐
q1 : ─┤ PRx(1.57, 1.57) ├─┤ PRx(3.14, 0) ├─┤ Z ├─┤ PRx(-3.14, 0) ├─┤ PRx(-1.57, 1.57) ├─┤ KR ├─
└─────────────────┘ └──────────────┘ └───┘ └───────────────┘ └──────────────────┘ └────┘
T : │ 0 │ 1 │ 2 │ 3 │ 4 │
Counter({'01': 51, '00': 49})
And we have demonstrated our classical controlled measurement and feedback for qubit and data reset operations!
Predicted Costs
The local example can be run at no cost. The QPU costs are given below:
print("Quantum Task Summary")
print(track.quantum_tasks_statistics())
print(
"\nNote: Charges shown are estimates based on your Amazon Braket simulator and quantum processing unit (QPU) task usage.\nEstimated charges shown may differ from your actual charges. Estimated charges do not factor in any discounts or credits,\nand you may experience additional charges based on your use of other services such as Amazon Elastic Compute Cloud (Amazon EC2).",
)
print(
f"\nEstimated cost to run this example: {track.qpu_tasks_cost()} USD",
)Quantum Task Summary
{<_IQM.Garnet: 'arn:aws:braket:eu-north-1::device/qpu/iqm/Garnet'>: {'shots': 300, 'tasks': {'COMPLETED': 3}}}
Note: Charges shown are estimates based on your Amazon Braket simulator and quantum processing unit (QPU) task usage.
Estimated charges shown may differ from your actual charges. Estimated charges do not factor in any discounts or credits,
and you may experience additional charges based on your use of other services such as Amazon Elastic Compute Cloud (Amazon EC2).
Estimated cost to run this example: 1.3350000000 USD
Notes on IQM Devices and Usage in Braket
For IQM's Garnet, there are a few notes on dynamic circuit creation for practical use. These are summarized here and further detailed in the Braket Developer Guide.
- Current systems only allow a surjective mapping from control qubits to target qubits; each channel can listen to only a single qubit source.
- All feedback qubits should only have one source!
- The device layout for IQM Garnet has two "groups", which limit the measurement and feed forward applications. Make sure your qubits and operations are in these groups.
- The
measure_ffgate does not implement active qubit reset, socc_xhas an optional reset flag (with defaultreset=True). - Use of verbatim boxes requires pre-transpilation to IQM-native gates.
- Some Braket
ResultTypeinstances may not be supported, and so basic measurement instructions are recommended.
Conclusions
In this notebook we began our exploration of dynamic circuits using IQM's Garnet with Amazon Braket. Dynamic circuits represent a powerful tool beyond static circuit structures which will be essential for future quantum computing applications, and which we explore in the next notebooks.
References:
- Zhou, Leung, Chuang. Methodology for quantum logic construction. (2000) arXiv:0002039.
- Corcoles, Takia, Inoue et al. Exploiting dynamic quantum circuits in a quantum algorithm with superconducting qubits. (2021) Phys. Rev. Lett. 127, 100501, arXiv
- Explore Experimental Capabilities. Amazon Braket Developer Guide (June 2025) https://docs.aws.amazon.com/braket/latest/developerguide/braket-experimental-capabilities.html
This entry was created automatically from publicly available records. QCR links to public sources and only stores repository content where the license permits redistribution.
Versions
Cite all versions? Use the base QCR ID to always reference the latest version of this entry.
Join the Discussion
Comments (0)
No comments yet. Be the first to share your thoughts!