{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "83596f71-5e63-4aa2-907b-75de8813d85a",
      "metadata": {},
      "source": [
        "---\n",
        "title: Execute dynamic circuits\n",
        "description: Use IBM Quantum Compute Service for classical feedforward and control flow, otherwise referred to as dynamic circuits\n",
        "---\n",
        "\n",
        "# Execute dynamic circuits\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2228a8a2-02b7-4a0b-bbe8-0c2933fbe44a",
      "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",
        "These improvements brought by dynamic circuits, however, come with trade-offs. Mid-circuit measurements and classical operations typically have longer execution time than two-qubit gates, and this increase in time might negate the benefits of reduced circuit depth. Therefore, reducing the length of mid-circuit measurement is a focus area of improvement as IBM Quantum® releases the [new version](/docs/guides/changelog-quantum-compute-service#new-version-dynamic-circuits) of dynamic circuits.  For other restrictions when using dynamic circuits, see the [Estimator](/docs/ibm-quantum-compute/estimator-options#options-compatibility-table) or [Sampler](/docs/ibm-quantum-compute/sampler-options#options-compatibility-table) Feature compatibility table.\n",
        "\n",
        "The [OpenQASM 3 specification](https://openqasm.com/language/classical.html#looping-and-branching) defines a number of control-flow structures, but IBM Quantum Compute Service currently only supports the conditional `if` statement. In Qiskit SDK, this corresponds to the [if\\_test](/docs/api/qiskit/qiskit.circuit.QuantumCircuit#if_test) method on [QuantumCircuit](/docs/api/qiskit/qiskit.circuit.QuantumCircuit). This method returns a [context manager](https://docs.python.org/3/reference/datamodel.html#with-statement-context-managers) and is typically used in a `with` statement. This guide describes how to use this conditional statement.\n",
        "\n",
        "<Admonition type=\"note\">\n",
        "  The code examples in this guide use the standard measure instruction for mid-circuit measurements. However, it is recommended that you use the `MidCircuitMeasure` instruction instead, if the backend supports it. See the [Mid-circuit measurements section](#midcircuit) for details.\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7e9dc06d-85fa-4425-9bd1-ce5085be9741",
      "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.6.1\n",
        "    qiskit-ibm-runtime~=0.50.0\n",
        "    ```\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c4616d43-f296-4a84-a79c-deb37fcdac15",
      "metadata": {},
      "source": [
        "## Find backends that support dynamic circuits\n",
        "\n",
        "To find all backends that your account can access and support dynamic circuits, run code like the following.  This example assumes that you have [saved your login credentials](/docs/ibm-quantum-compute/save-credentials).  You could also [explicitly specify credentials](/docs/ibm-quantum-compute/initialize-account#explicit) when initializing your IBM Quantum Compute Service account.  This would let you view backends available on a specific instance or plan type, for example.\n",
        "\n",
        "<Admonition type=\"note\" title=\"Notes\">\n",
        "  * The backends that are available to the account depend on the instance specified in the credentials.\n",
        "  * The new version of dynamic circuits is now available to all users on all backends. See [the announcement](/docs/guides/changelog-quantum-compute-service#new-dynamic-circuits) for more details.\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "a63f07b1-9e8a-4086-ab01-552bd444dc9b",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[<IBMBackend('ibm_boston')>, <IBMBackend('ibm_fez')>, <IBMBackend('ibm_kingston')>, <IBMBackend('ibm_marrakesh')>, <IBMBackend('ibm_phoenix')>, <IBMBackend('ibm_pittsburgh')>]\n"
          ]
        }
      ],
      "source": [
        "from qiskit_ibm_runtime import QiskitRuntimeService\n",
        "\n",
        "service = QiskitRuntimeService()\n",
        "dc_backends = service.backends(dynamic_circuits=True)\n",
        "print(dc_backends)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1dca7d79-99ea-42bd-86f7-182266907a85",
      "metadata": {},
      "source": [
        "<span id=\"midcircuit\" />\n",
        "\n",
        "## Mid-circuit measurements\n",
        "\n",
        "Prior to `qiskit-ibm-runtime` v0.43.0, `measure` was the only measurement instruction in Qiskit. Mid-circuit measurements, however, have different tuning requirements than *terminal* measurements (measurements that happen at the end of a circuit). For example, you need to consider the instruction duration when tuning a mid-circuit measurement because longer instructions cause noisier circuits. You don't need to consider instruction duration for terminal measurements because there are no instructions after terminal measurements.\n",
        "\n",
        "<Admonition type=\"note\">\n",
        "  The `MidCircuitMeasure` instruction maps to the `measure_2` instruction reported in the backend's `supported_instructions`. However,  `measure_2` is not supported on all backends. Use `service.backends(filters=lambda b: \"measure_2\" in b.supported_instructions)` to find backends that support it.  New measurements might be added in the future, but this is not guarenteed.\n",
        "</Admonition>\n",
        "\n",
        "### `MidCircuitMeasure` method\n",
        "\n",
        "In `qiskit-ibm-runtime` v0.43.0, the `MidCircuitMeasure` instruction was introduced. As the name suggests, it is a new measurement instruction that is optimized for mid-circuit on IBM® QPUs.  While you can use `QuantumCircuit.measure` for a mid-circuit measurement, because of its design, `MidCircuitMeasure` is typically a better choice.  For example, it adds less overhead to your circuit than when using `QuantumCircuit.measure`.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "87dfb9c7-1dc2-4752-bdc1-17b9144369f4",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "     ┌───┐┌────────────┐\n",
            "q_0: ┤ X ├┤0           ├\n",
            "     └───┘│            │\n",
            "q_1: ─────┤  Measure_2 ├\n",
            "          │            │\n",
            "c_0: ═════╡0           ╞\n",
            "          └────────────┘\n",
            "c_1: ═══════════════════\n",
            "                        \n"
          ]
        }
      ],
      "source": [
        "from qiskit import QuantumCircuit\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService\n",
        "from qiskit_ibm_runtime.circuit import MidCircuitMeasure\n",
        "\n",
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(\n",
        "    operational=True, simulator=False, dynamic_circuits=True\n",
        ")\n",
        "\n",
        "circ = QuantumCircuit(2, 2)\n",
        "circ.x(0)\n",
        "circ.append(MidCircuitMeasure(), [0], [0])\n",
        "# circ.measure([0], [0])\n",
        "# circ.measure_all()\n",
        "print(circ.draw(cregbundle=False))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2b603f88-2e0e-4819-8342-8e3662949ff3",
      "metadata": {},
      "source": [
        "<Admonition type=\"attention\" title=\"Important notes\">\n",
        "  * There must be at least one classical register in order to use measurements.\n",
        "  * The Sampler primitive requires circuit measurements. You can add circuit measurements with the Estimator primitive, but they are ignored.\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9401a5cc-49e0-48b6-8deb-88e9b7da5a5a",
      "metadata": {},
      "source": [
        "## `Store`\n",
        "\n",
        "With `qiskit-ibm-runtime` version 0.47.0 or later, you can use the [`store`](/docs/api/qiskit/circuit#store) instruction to save the result of a classical expression, if that expression will be used repeatedly. Operations are automatically parallelized, making your code significantly more efficient at runtime.\n",
        "\n",
        "For more information, see the [Classical feedforward and control flow](/docs/qiskit/classical-feedforward-and-control-flow#store) guide.\n",
        "\n",
        "<Admonition type=\"note\">\n",
        "  When you use `store` to save a value to a classical register on a real backend, that value is only saved in memory during execution and not copied or returned in the job result.\n",
        "\n",
        "  For example, in the following code, `temp` has the same value as `creg` during execution, and the `if_test` works as expected. But after the job finishes, the `temp` BitArray returned in the job result **does not** contain the value of `creg`.  That is, `job.result()[0].data.temp` is `0`.\n",
        "\n",
        "  ```python\n",
        "  creg = ClassicalRegister(3, \"c\")\n",
        "  temp = ClassicalRegister(3, \"temp\")\n",
        "  ...\n",
        "  qc.store(temp, creg)\n",
        "  with circuit.if_test((temp, 0b001)):\n",
        "      ...\n",
        "  ```\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3f374a74-c331-40de-8594-686e471058a2",
      "metadata": {},
      "source": [
        "## Full example\n",
        "\n",
        "The following code creates and runs a dynamic circuit on IBM hardware.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "a7a9c998-4031-432f-978b-83edc040798f",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            ">>>  Job ID:    dbjeaj0nceqs73ajs65g (DONE)\n"
          ]
        }
      ],
      "source": [
        "from qiskit_ibm_runtime import QiskitRuntimeService\n",
        "from qiskit.circuit import QuantumCircuit, QuantumRegister, ClassicalRegister\n",
        "from qiskit.transpiler import generate_preset_pass_manager\n",
        "\n",
        "# Legacy server-side primitive before qiskit-ibm-runtime v0.50.0\n",
        "# from qiskit_ibm_runtime import Sampler\n",
        "\n",
        "# Client-side primitive introduced in qiskit-ibm-runtime v0.50.0\n",
        "from qiskit_ibm_runtime.executor_sampler import Sampler\n",
        "\n",
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(\n",
        "    operational=True, simulator=False, dynamic_circuits=True\n",
        ")\n",
        "\n",
        "# Create a dynamic circuit\n",
        "\n",
        "qubits = QuantumRegister(1)\n",
        "clbits = ClassicalRegister(1)\n",
        "qc = QuantumCircuit(qubits, clbits)\n",
        "(q0,) = qubits\n",
        "(c0,) = clbits\n",
        "\n",
        "qc.h(q0)\n",
        "qc.measure(q0, c0)\n",
        "with qc.if_test((c0, 1)):\n",
        "    qc.x(q0)\n",
        "qc.measure(q0, c0)\n",
        "\n",
        "\n",
        "# Convert to an ISA circuit for the given backend\n",
        "\n",
        "pm = generate_preset_pass_manager(backend=backend, optimization_level=1)\n",
        "isa_circuit = pm.run(qc)\n",
        "\n",
        "# Generate samplers for backend targets\n",
        "sampler = Sampler(backend)\n",
        "\n",
        "# Submit jobs\n",
        "sampler_job = sampler.run([isa_circuit])\n",
        "result = sampler_job.result()\n",
        "\n",
        "print(\n",
        "    f\">>> {' Job ID:':<10}  {sampler_job.job_id()} ({sampler_job.status()})\"\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c5b14dcf-edf4-4fef-bb49-e6b86f06afb0",
      "metadata": {},
      "source": [
        "## Quantum Compute limitations\n",
        "\n",
        "Be aware of the following constraints when running dynamic circuits in Quantum Compute.\n",
        "\n",
        "* Due to the limited physical memory on control electronics, there is also a limit on the number of `if` statements and size of their operands. This limit is a function of the number of broadcasts and the number of broadcasted bits in a job (not a circuit).\n",
        "\n",
        "  When processing an `if` condition, measurement data needs to be transferred to the control logic to make that evaluation. A broadcast is a transfer of unique classical data, and broadcasted bits is the number of classical bits being transferred. Consider the following:\n",
        "\n",
        "  ```python\n",
        "  c0 = ClassicalRegister(3)\n",
        "  c1 = ClassicalRegister(5)\n",
        "  ...\n",
        "  with circuit.if_test((c0, 1)) ...\n",
        "  with circuit.if_test((c0, 3)) ...\n",
        "  with circuit.if_test((c1[2], 1)) ...\n",
        "  ```\n",
        "\n",
        "  In the previous code example, the first two `if_test` objects on `c0` are considered one broadcast because the content of `c0` did not change, and thus does not need to be re-broadcasted. The `if_test` on `c1` is a second broadcast. The first one broadcasts all three bits in `c0` and the second broadcasts just one bit, making a total of four broadcasted bits.\n",
        "\n",
        "  Currently, if you broadcast 60 bits each time, then the job can have approximately 300 broadcasts. If you broadcast just one bit each time, however, then the job can have 2400 broadcasts.\n",
        "\n",
        "* The operand used in an `if_test` statement must be 32 or fewer bits. Thus, if you are comparing an entire `ClassicalRegister`, the size of that `ClassicalRegister` must be 32 or fewer bits. If you are comparing just a single bit from a `ClassicalRegister`, however, that `ClassicalRegister` can be of any size (since the operand is only one bit).\n",
        "\n",
        "  For example, the \"Not valid\" code block does not work because `cr` is more than 32 bits.  You can, however, use a classical register wider than 32 bits if you are testing only one bit, as shown in the \"Valid\" code block.\n",
        "\n",
        "  <Tabs>\n",
        "    <TabItem value=\"Not valid\" label=\"Not valid\">\n",
        "      ```python\n",
        "         cr = ClassicalRegister(50)\n",
        "         qr = QuantumRegister(50)\n",
        "         circuit = QuantumCircuit(qr, cr)\n",
        "         ...\n",
        "         circ.measure(qr, cr)\n",
        "         with circ.if_test((cr, 15)):\n",
        "            ...\n",
        "      ```\n",
        "    </TabItem>\n",
        "\n",
        "    <TabItem value=\"Valid\" label=\"Valid\">\n",
        "      ```python\n",
        "         cr = ClassicalRegister(50)\n",
        "         qr = QuantumRegister(50)\n",
        "         circuit = QuantumCircuit(qr, cr)\n",
        "         ...\n",
        "         circ.measure(qr, cr)\n",
        "         with circ.if_test((cr[5], 1)):\n",
        "            ...\n",
        "      ```\n",
        "    </TabItem>\n",
        "  </Tabs>\n",
        "\n",
        "* Nested conditionals are not allowed. For example, the following code block will not work because it has an `if_test` inside another `if_test`:\n",
        "  <Tabs>\n",
        "    <TabItem value=\"Not valid\" label=\"Not valid\">\n",
        "      ```python\n",
        "         c1 = ClassicalRegister(1, \"c1\")\n",
        "         c2 = ClassicalRegister(2, \"c2\")\n",
        "         ...\n",
        "         with circ.if_test((c1, 1)):\n",
        "          with circ.if_test(c2, 1)):\n",
        "           ...\n",
        "      ```\n",
        "    </TabItem>\n",
        "\n",
        "    <TabItem value=\"Valid\" label=\"Valid\">\n",
        "      ```python\n",
        "      cr = ClassicalRegister(2)\n",
        "      ...\n",
        "      with circuit.if_test((cr, 0b11)):\n",
        "        ...\n",
        "      ```\n",
        "    </TabItem>\n",
        "  </Tabs>\n",
        "\n",
        "* Having `reset` or measurements inside conditionals is not supported.\n",
        "\n",
        "* Arithmetic operations are not supported.\n",
        "\n",
        "* See the [OpenQASM 3 feature table](/docs/qiskit/qasm-feature-table) to determine which OpenQASM 3 features are supported with Qiskit and Quantum Compute.\n",
        "\n",
        "* When OpenQASM 3 (instead of `QuantumCircuit`) is used as the input format to pass circuits to IBM Quantum primitives, only instructions that can be loaded into Qiskit are supported. Classical operations, for example, are not supported because they cannot be loaded into Qiskit. See [Import an OpenQASM 3 program into Qiskit](/docs/qiskit/interoperate-qiskit-qasm3#import-an-openqasm-3-program-into-qiskit) for more information.\n",
        "\n",
        "* The `for`, `while`, and `switch` instructions are not supported.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ca6e0493-d364-40bf-9f47-2e3feed9f82c",
      "metadata": {},
      "source": [
        "## Use dynamic circuits with Estimator\n",
        "\n",
        "Since Estimator does not support dynamic circuits, you can use [Sampler](/docs/ibm-quantum-compute/get-started-with-sampler) and build your own measurement circuits instead.\n",
        "\n",
        "To replicate Estimator's behavior, follow this process:\n",
        "\n",
        "1. Group the terms of all observables into a partition.  This can be done by using the [`PauliList` API](/docs/api/qiskit/qiskit.quantum_info.PauliList#group_qubit_wise_commuting), for example.\n",
        "   <Admonition type=\"note\">\n",
        "     You can use the [`BitArray`](/docs/api/qiskit/qiskit.primitives.BitArray#expectation_values) primitive attribute to compute the expectation values of the provided observables.\n",
        "   </Admonition>\n",
        "2. Execute one basis change circuit per partition (whichever basis change needs to be done for each partition). See the Measurement bases addon utility [`measurement_bases` module](https://qiskit.github.io/qiskit-addon-utils/apidocs/qiskit_addon_utils.exp_vals.html#qiskit_addon_utils.exp_vals.get_measurement_bases) for more information. For more information, see the [documentation](https://qiskit.github.io/qiskit-addon-utils/) for the Qiskit addon utilities package.\n",
        "3. Add back together the results for each partition.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "07045397-6db8-4151-a1e4-de24a8f39ab6",
      "metadata": {},
      "source": [
        "## Restrictions\n",
        "\n",
        "Review any [Feature compatibility table](/docs/ibm-quantum-compute/estimator-options#options-compatibility-table) to understand restrictions when using dynamic circuits. Note that feature compatibility is not primitive-dependent.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6688e2e3-766b-4194-99db-ae097e9b8bc7",
      "metadata": {},
      "source": [
        "## Next steps\n",
        "\n",
        "<Admonition type=\"tip\" title=\"Recommendations\">\n",
        "  * Learn how to implement accurate dynamic decoupling by using [stretch](/docs/qiskit/stretch).\n",
        "  * Review the [classical feedforward and control flow](/docs/qiskit/classical-feedforward-and-control-flow) guide.\n",
        "  * Use [circuit schedule visualization](/docs/ibm-quantum-compute/qiskit-runtime-circuit-timing) to debug and optimize your dynamic circuits.\n",
        "  * Not all functions are compatible with dynamic circuits. Check the feature compatibility section for [Sampler](/docs/ibm-quantum-compute/sampler-options#feature-compatibility) for details.\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
}