QubitLab
IDELearnPlaygroundDocsCommunity
Log in
QubitLab
IDELearnPlaygroundDocsCommunity
Log in
HomeLearnCatalogRanksPlaygroundDocs
  1. Docs
  2. Dynamic circuits: if/else, loops and conditions
Learn
  • Quantum basics
  • OpenQASM 3 cheat sheet
  • All gates, with the math
  • Every gate, interactive
  • Entanglement: how CNOT connects qubits
Circuits
  • Dynamic circuits: if/else, loops and conditions
Lessons
  • Learning path: from one qubit to algorithms
  • Quantum machine learning by hand
Run
  • Compile (transpile): levels, basis gates, topology
  • Simulators, noise, T1/T2 and fake backends
  • Python in the Playground
  • GitHub and git in the Playground
  • Articles and sharing
Analyze
  • Metrics: comparing distributions
  • Q-sphere and Bloch spheres
Hardware
  • Real IBM Quantum hardware
  • Device topology and calibration heat maps
  • Benchmark circuits: MQT Bench and QASMBench
Advanced
  • Circuit cutting, in depth
Story
  • The story of quantum computing
  • The Hamiltonian: where gates come from
  • What to expect next
Documentation/Circuits/Dynamic circuits: if/else, loops and conditions

Dynamic circuits: if/else, loops and conditions

A dynamic circuit measures some qubits in the middle and lets the classical result decide what happens next: run a correction, repeat a block until it succeeds, pick one of several branches. OpenQASM 3 writes this with if, else, while, for and switch; Qiskit writes it with `with qc.if_test(...)` blocks. QubitLab draws every one of them in the composer, so you can build them from the palette, read the condition on the frame, and jump to the matching line of QASM or Python.

Why measure in the middle?

Teleportation, error correction, repeat-until-success state preparation and many hardware-efficient algorithms all need feed-forward: a measurement outcome that is used while the circuit is still running. Without control flow you would have to defer every measurement to the end and replace the classical decision with extra quantum gates, which costs qubits and depth.

if / else in OpenQASM 3

OPENQASM 3.0;
include "stdgates.inc";
qubit[3] q;
bit[3] c;
h q[0];
h q[1];
c[0] = measure q[0];
c[1] = measure q[1];
if ((c[0] ^ c[1]) == true) {
  x q[2];
} else {
  z q[2];
}
c[2] = measure q[2];
Odd parity of the two measured bits flips q2; even parity applies a phase instead.
ConditionMeaning
if (c[0])bit 0 is 1
if (c[0] == false) · if (!c[0])bit 0 is 0
if (c == 3)the whole register reads 3 (c[0] is the least-significant bit, so c[0] = c[1] = 1)
if (c[0] && c[1]) · if (c[0] || c[1])both bits set · at least one set
if ((c[0] ^ c[1]) == true)exactly one bit set (parity)
if (c[0] != c[1])the bits differ
} else if (c[1]) {chained branches

Qiskit itself only imports `bit`, `!bit`, `bit == true/false` and `register == int`. QubitLab rewrites every other condition into nested single-bit tests before Qiskit sees it, so you can write the natural form and still simulate, compile and export to Python.

The same circuit in Qiskit (Python)

from qiskit import QuantumCircuit
from qiskit.circuit.classical import expr

qc = QuantumCircuit(3, 3)
qc.h(0)
qc.h(1)
qc.measure(0, 0)
qc.measure(1, 1)
with qc.if_test(expr.bit_xor(c[0], c[1])) as else_:
    qc.x(2)
with else_:
    qc.z(2)
qc.measure(2, 2)

# single bit:        with qc.if_test((c[0], 1)):
# whole register:    with qc.if_test((c, 3)):
# combined bits:     expr.logic_and(c[0], expr.logic_not(c[1]))
Switch the code panel to Python and QubitLab writes this for you from the current circuit; type it yourself and it is translated back to OpenQASM 3 by reading the AST, never by running it.

Loops: while, for, break

OPENQASM 3.0;
include "stdgates.inc";
qubit[2] q;
bit[2] c;
h q[0];
c[0] = measure q[0];
while (c[0] == true) {   // repeat until q0 measures 0
  x q[0];
  h q[0];
  c[0] = measure q[0];
}
for uint i in [0:1] {    // constant loops are unrolled: h q[0]; h q[1];
  h q[i];
}
for uint k in [0:3] {    // loops with break stay loops
  c[1] = measure q[1];
  if (c[1]) { break; }
  x q[1];
}
Qiskit: with qc.while_loop((c[0], 1)): … / with qc.for_loop(range(2)) as i: … / qc.break_loop().
  • while repeats its body as long as the condition holds; measure inside the body so it can end.
  • for with literal bounds is unrolled (the body is copied once per value, indices like q[(i+1)%3] are folded), so statevector tools still work on it. A for loop that contains break or continue is kept as a real loop and runs only on the shot-based simulator.
  • switch (c) { case 0 { … } case 1, 2 { … } default { … } } picks one arm by the register value; Qiskit: with qc.switch(c) as case: / with case(0): / with case(case.DEFAULT):.

Building them in the composer

  • Palette → Control flow: tap if, if / else, while, switch, break or continue, then tap the column where the block should start (or drag it there). The frame appears across all wires.
  • Drag gates into the frame (or tap a gate, then a cell inside it). The frame shrinks to the wires it uses.
  • Click the tag on the frame to edit the condition below the circuit; Unwrap keeps the gates and removes the frame; Delete removes both.
  • Double-click any gate or frame tag to select its statement in the QASM or Python panel. Code typed in the panel is drawn back the same way.
  • Pasted programs with several registers (mid_measurement, final_measurement, psi …) show a Rewrite for the composer button that merges them into one q and one c register with bit order kept.

Where dynamic circuits run

ToolDynamic circuits
SimulateYes. The ideal reference is sampled with 20 000 shots instead of a statevector.
Compile / Compare levelsYes; control flow passes through the transpiler.
Hardwareif/else runs on IBM Heron machines; check the backend's dynamic-circuit support for loops.
State · Trace · DebugNo: a branch has no single statevector. They say so and point you to Simulate.
Exercise

Parity branch

Open this circuit, run Simulate and read the probabilities. Then change the condition to c[0] && c[1] and predict how often q2 is flipped before running again.

OPENQASM 3.0;
include "stdgates.inc";
qubit[3] q;
bit[3] c;
h q[0];
h q[1];
c[0] = measure q[0];
c[1] = measure q[1];
if ((c[0] ^ c[1]) == true) {
  x q[2];
} else {
  z q[2];
}
c[2] = measure q[2];
Open in IDE
Hint

The two H gates make all four values of c[1]c[0] equally likely.

Check your answer

With XOR, c[2] = 1 for 01 and 10: half the shots. With AND only 11 flips q2: a quarter of the shots.

Exercise

Repeat until success

Build the while loop from the Loops section (or open the example “Repeat until success”). What does c read at the end, and why is it always the same?

OPENQASM 3.0;
include "stdgates.inc";
qubit[2] q;
bit[2] c;
h q[0];
c[0] = measure q[0];
while (c[0] == true) {
  x q[0];
  h q[0];
  c[0] = measure q[0];
}
x q[1];
c[1] = measure q[1];
Open in IDE
Hint

The loop only exits when c[0] is 0.

Check your answer

c = 10 in every shot: c[0] must be 0 to leave the loop and q1 is always flipped afterwards. The number of loop rounds is random, the result is not.

← Previous
Every gate, interactive
Next →
Entanglement: how CNOT connects qubits
On this page
  • Why measure in the middle?
  • if / else in OpenQASM 3
  • The same circuit in Qiskit (Python)
  • Loops: while, for, break
  • Building them in the composer
  • Where dynamic circuits run
Try it in the IDE →
QubitLab
IDELearnPlaygroundDocsCommunity
Log in
QubitLab
IDELearnPlaygroundDocsCommunity
Log in