Classical feedforward and control flow
Package versions
The code on this page was developed using the following requirements. We recommend using these versions or newer.
qiskit[all]~=2.0.0
Starting 2 June 2025 and continuing through the year, IBM Quantum® will begin a gradual rollout of new features to dynamic circuits that will enable them at the utility scale. See the announcement for more details.
As part of the rollout, the following have been removed:
- The
while
,for
, andswitch
control flow constructs - The ability to use control flow instructions inside the body of a branch (as in, nested control flow)
- Conditional measurements
New QPUs released after this deprecation will not support dynamic circuits until the updated features are released. Additionally, after the release, QPUs with older control electronics will not support dynamic circuits. To check whether a specific QPU supports dynamic circuits, use this code:
# returns True if backend supports dynamic circuits
"dynamic_circuits" in backend.configuration().supported_features
This guide demonstrates the functionality available in the Qiskit SDK for performing classical feedforward and control flow. These features are sometimes referred to collectively as "dynamic circuits." Classical feedforward refers to the ability to measure qubits in the middle of a circuit and perform additional quantum operations that depend on the measurement outcome. Qiskit supports four control flow constructs for classical feedforward, each implemented as a method on QuantumCircuit
. The constructs and their corresponding methods are:
- If statement -
QuantumCircuit.if_test
- If statement -
QuantumCircuit.if_else
Each of these methods returns a context manager and is typically used in a with
statement. In the rest of this guide, we will explain each of these constructs and how to use them.
- There are some limitations of classical feedforward and control flow operations on quantum hardware that might impact your program. For more information, see Hardware considerations and limitations for classical feedforward and control flow.
- Qiskit Runtime does not support all dynamic circuits features that Qiskit supports. See the QASM3 feature table to determine which features are supported on Qiskit and Qiskit Runtime.
If statement
The if statement is used to conditionally perform operations based on the value of a classical bit or register.
In the example below, we apply a Hadamard gate to a qubit and measure it. If the result is 1, then we apply an X gate on the qubit, which has the effect of flipping it back to the 0 state. We then measure the qubit again. The resulting measurement outcome should be 0 with 100% probability.
from qiskit.circuit import QuantumCircuit, QuantumRegister, ClassicalRegister
qubits = QuantumRegister(1)
clbits = ClassicalRegister(1)
circuit = QuantumCircuit(qubits, clbits)
(q0,) = qubits
(c0,) = clbits
circuit.h(q0)
circuit.measure(q0, c0)
with circuit.if_test((c0, 1)):
circuit.x(q0)
circuit.measure(q0, c0)
circuit.draw("mpl")
# example output counts: {'0': 1024}
Output:
The with
statement can be given an assignment target which is itself a context manager that can be stored and subsequently used to create an else block, which is executed whenever the contents of the if block are not executed.
In the example below, we initialize registers with two qubits and two classical bits. We apply a Hadamard gate to the first qubit and measure it. If the result is 1, then we apply a Hadamard gate on the second qubit; otherwise, we apply an X gate on the second qubit. Finally, we measure the second qubit as well.
qubits = QuantumRegister(2)
clbits = ClassicalRegister(2)
circuit = QuantumCircuit(qubits, clbits)
(q0, q1) = qubits
(c0, c1) = clbits
circuit.h(q0)
circuit.measure(q0, c0)
with circuit.if_test((c0, 1)) as else_:
circuit.h(q1)
with else_:
circuit.x(q1)
circuit.measure(q1, c1)
circuit.draw("mpl")
# example output counts: {'01': 260, '11': 272, '10': 492}
Output:
In addition to conditioning on a single classical bit, it's also possible to condition on the value of a classical register composed of multiple bits.
In the example below, we apply Hadamard gates to two qubits and measure them. If the result is 01
, that is, the first qubit is 1 and the second qubit is 0, then we apply an X gate to a third qubit. Finally, we measure the third qubit. Note that for clarity, we chose to specify the state of the third classical bit, which is 0, in the if condition. In the circuit drawing, the condition is indicated by the circles on the classical bits being conditioned on. A black circle indicates conditioning on 1, while a white circle indicates conditioning on 0.
qubits = QuantumRegister(3)
clbits = ClassicalRegister(3)
circuit = QuantumCircuit(qubits, clbits)
(q0, q1, q2) = qubits
(c0, c1, c2) = clbits
circuit.h([q0, q1])
circuit.measure(q0, c0)
circuit.measure(q1, c1)
with circuit.if_test((clbits, 0b001)):
circuit.x(q2)
circuit.measure(q2, c2)
circuit.draw("mpl")
# example output counts: {'101': 269, '011': 260, '000': 252, '010': 243}
Output:
Limitations
Be aware of the following constraints when using dynamic circuits:
- Whenever you do a measure followed by an
if (c)
, the values that are measured and subsequently used in the if condition has a limit of 60 bits. - Nested conditionals are not allowed.
- Having
reset
inside conditionals is not supported.
Next steps
- See an example of dynamic circuits in the Repeat until success tutorial.
- For considerations and limitations related to running dynamic circuits on quantum hardware, see the Hardware considerations and limitations for classical feedforward and control flow guide.
- Review the circuit library API reference.