{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "943cf52c-41c8-4a2b-bf1d-6df8a90a6353",
      "metadata": {},
      "source": [
        "---\n",
        "title: Classical feedforward and control flow (dynamic circuits)\n",
        "description: Use Qiskit for classical feedforward and control flow, otherwise referred to as dynamic circuits\n",
        "---\n",
        "\n",
        "# Classical feedforward and control flow\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b1d96290-2e64-43aa-bae9-c74b8529894d",
      "metadata": {
        "tags": [
          "version-info"
        ]
      },
      "source": [
        "{/*\n",
        "  DO NOT EDIT THIS CELL!!!\n",
        "  This cell's content is generated automatically by a script. Anything you add\n",
        "  here will be removed next time the notebook is run. To add new content, create\n",
        "  a new cell before or after this one.\n",
        "  */}\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Package versions\">\n",
        "    The code on this page was developed using the following requirements.\n",
        "    We recommend using these versions or newer.\n",
        "\n",
        "    ```\n",
        "    qiskit[all]~=2.4.0\n",
        "    ```\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "85a4d698-ee2a-4b3d-9331-1b91eea49338",
      "metadata": {},
      "source": [
        "Dynamic circuits are powerful tools with which you can measure qubits in the middle of a quantum circuit execution and then perform classical logic operations within the circuit, based on the outcome of those mid-circuit measurements.  This process is also known as *classical feedforward*. While these are early days of understanding how best to take advantage of dynamic circuits, the quantum research community has already identified a number of use cases, such as the following:\n",
        "\n",
        "* Efficient quantum state preparation, such as [GHZ state](https://journals.aps.org/prxquantum/abstract/10.1103/PRXQuantum.5.030339), [W-state](https://arxiv.org/abs/2403.07604) (for more information about W-state, also refer to [\"State preparation by shallow circuits using feed forward\"](https://arxiv.org/abs/2307.14840)), and a broad class of [matrix product states](https://arxiv.org/abs/2404.16083)\n",
        "* [Efficient long-range entanglement](https://journals.aps.org/prxquantum/abstract/10.1103/PRXQuantum.5.030339) between qubits on the same chip by using shallow circuits\n",
        "* Efficient [sampling of IQP-like circuits](https://arxiv.org/pdf/2505.04705)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5d846edf-fc09-4808-bd62-3a8cfdcc1585",
      "metadata": {},
      "source": [
        "## `if` statement\n",
        "\n",
        "The `if` statement is used to conditionally perform operations based on the value of a classical bit or register.\n",
        "\n",
        "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.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "60924bfa-50ed-4d9d-a17b-9d64f2cc053f",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/60924bfa-50ed-4d9d-a17b-9d64f2cc053f-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.circuit import QuantumCircuit, QuantumRegister, ClassicalRegister\n",
        "\n",
        "qubits = QuantumRegister(1)\n",
        "clbits = ClassicalRegister(1)\n",
        "circuit = QuantumCircuit(qubits, clbits)\n",
        "(q0,) = qubits\n",
        "(c0,) = clbits\n",
        "\n",
        "circuit.h(q0)\n",
        "circuit.measure(q0, c0)\n",
        "with circuit.if_test((c0, 1)):\n",
        "    circuit.x(q0)\n",
        "circuit.measure(q0, c0)\n",
        "circuit.draw(\"mpl\")\n",
        "\n",
        "# example output counts: {'0': 1024}"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "bef3f447-7282-4de9-9410-6b671e9902c3",
      "metadata": {},
      "source": [
        "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.\n",
        "\n",
        "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.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "20f0640a-a3f7-41b3-aada-b66bc89b0555",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/20f0640a-a3f7-41b3-aada-b66bc89b0555-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 2,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qubits = QuantumRegister(2)\n",
        "clbits = ClassicalRegister(2)\n",
        "circuit = QuantumCircuit(qubits, clbits)\n",
        "(q0, q1) = qubits\n",
        "(c0, c1) = clbits\n",
        "\n",
        "circuit.h(q0)\n",
        "circuit.measure(q0, c0)\n",
        "with circuit.if_test((c0, 1)) as else_:\n",
        "    circuit.h(q1)\n",
        "with else_:\n",
        "    circuit.x(q1)\n",
        "circuit.measure(q1, c1)\n",
        "\n",
        "circuit.draw(\"mpl\")\n",
        "\n",
        "# example output counts: {'01': 260, '11': 272, '10': 492}"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f0f00f48-a1f2-40cc-b5f5-9a122d8dd24e",
      "metadata": {},
      "source": [
        "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.\n",
        "\n",
        "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 solid circle indicates conditioning on 1, while an outlined circle indicates conditioning on 0.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "98e8f552-4169-42a3-8182-e14e9ffb59e2",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/98e8f552-4169-42a3-8182-e14e9ffb59e2-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 3,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qubits = QuantumRegister(3)\n",
        "clbits = ClassicalRegister(3)\n",
        "circuit = QuantumCircuit(qubits, clbits)\n",
        "(q0, q1, q2) = qubits\n",
        "(c0, c1, c2) = clbits\n",
        "\n",
        "circuit.h([q0, q1])\n",
        "circuit.measure(q0, c0)\n",
        "circuit.measure(q1, c1)\n",
        "with circuit.if_test((clbits, 0b001)):\n",
        "    circuit.x(q2)\n",
        "circuit.measure(q2, c2)\n",
        "\n",
        "circuit.draw(\"mpl\")\n",
        "\n",
        "# example output counts: {'101': 269, '011': 260, '000': 252, '010': 243}"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ef8fd422-6bab-46c9-9455-c79244cf1fb7",
      "metadata": {},
      "source": [
        "## Classical expressions\n",
        "\n",
        "The Qiskit classical expression module [`qiskit.circuit.classical`](/docs/api/qiskit/circuit_classical) contains an exploratory representation of runtime operations on classical values during circuit execution. Due to hardware limitations, only `QuantumCircuit.if_test()`  conditions are currently supported.\n",
        "\n",
        "The following example shows that you can use the calculation of the parity to create an n-qubit GHZ state using dynamic circuits. First, generate $n/2$ Bell pairs on adjacent qubits. Then, glue these pairs together using a layer of CNOT gates in between pairs. You then measure the target qubit of all prior CNOT gates and reset each measured qubit to the state $\\vert 0 \\rangle$. You apply $X$ to every unmeasured site for which the parity of all preceding bits is odd. Finally, CNOT gates are applied to the measured qubits to re-establish the entanglement lost in the measurement.\n",
        "\n",
        "In the parity calculation, the first element of the constructed expression involves lifting the Python object `mr[0]` to a [`Value`](/docs/api/qiskit/circuit_classical#value) node (`lift` is used to turn arbitrary objects into classical expressions). This is not necessary for `mr[1]` and the possible following classical register, as they are inputs to `expr.bit_xor`, and any necessary lifting is done automatically in these cases. Such expressions can be built up in loops and other constructs.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "7581ac2f-53e9-43d0-bad0-2c80790172e1",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister\n",
        "from qiskit.circuit.classical import expr\n",
        "\n",
        "num_qubits = 8\n",
        "if num_qubits % 2 or num_qubits < 4:\n",
        "    raise ValueError(\"num_qubits must be an even integer ≥ 4\")\n",
        "meas_qubits = list(range(2, num_qubits, 2))  # qubits to measure and reset\n",
        "\n",
        "qr = QuantumRegister(num_qubits, \"qr\")\n",
        "mr = ClassicalRegister(len(meas_qubits), \"m\")\n",
        "qc = QuantumCircuit(qr, mr)\n",
        "\n",
        "# Create local Bell pairs\n",
        "qc.reset(qr)\n",
        "qc.h(qr[::2])\n",
        "for ctrl in range(0, num_qubits, 2):\n",
        "    qc.cx(qr[ctrl], qr[ctrl + 1])\n",
        "\n",
        "# Glue neighboring pairs\n",
        "for ctrl in range(1, num_qubits - 1, 2):\n",
        "    qc.cx(qr[ctrl], qr[ctrl + 1])\n",
        "\n",
        "# Measure boundary qubits between pairs,reset to 0\n",
        "for k, q in enumerate(meas_qubits):\n",
        "    qc.measure(qr[q], mr[k])\n",
        "    qc.reset(qr[q])\n",
        "\n",
        "# Parity-conditioned X corrections\n",
        "# Each non-measured qubit gets flipped iff the parity (XOR) of all\n",
        "# preceding measurement bits is 1\n",
        "for tgt in range(num_qubits):\n",
        "    if tgt in meas_qubits:  # skip measured qubits\n",
        "        continue\n",
        "    # all measurement registers whose physical qubit index < tgt\n",
        "    left_bits = [k for k, q in enumerate(meas_qubits) if q < tgt]\n",
        "    if not left_bits:  # skip if list empty\n",
        "        continue\n",
        "\n",
        "    # build XOR-parity expression\n",
        "    parity = expr.lift(\n",
        "        mr[left_bits[0]]\n",
        "    )  # lift the first bit to Value so it will be treated like a boolean.\n",
        "    for k in left_bits[1:]:\n",
        "        parity = expr.bit_xor(\n",
        "            mr[k], parity\n",
        "        )  # calculate parity with all other bits\n",
        "    with qc.if_test(parity):  # Add X if parity is 1\n",
        "        qc.x(qr[tgt])\n",
        "\n",
        "# Re-entangle measured qubits\n",
        "for ctrl in range(1, num_qubits - 1, 2):\n",
        "    qc.cx(qr[ctrl], qr[ctrl + 1])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "d0f0abdb-50d5-408d-a704-a1a555acdd85",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/d0f0abdb-50d5-408d-a704-a1a555acdd85-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 5,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qc.draw(output=\"mpl\", style=\"iqp\", idle_wires=False, fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7c80c5d0-a447-4590-8426-6eb33ae2d817",
      "metadata": {},
      "source": [
        "## Next steps\n",
        "\n",
        "<Admonition type=\"tip\" title=\"Recommendations\">\n",
        "  * Learn how to implement accurate dynamic decoupling by using [stretch](/docs/guides/stretch).\n",
        "  * Use [circuit schedule visualization](/docs/guides/qiskit-runtime-circuit-timing) to debug and optimize your dynamic circuits.\n",
        "  * [Execute dynamic circuits](/docs/guides/execute-dynamic-circuits).\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "id": "a1b8767d",
      "source": "© IBM Corp., 2017-2026"
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 4
}