diff --git a/docs/guides/classical-feedforward-and-control-flow.ipynb b/docs/guides/classical-feedforward-and-control-flow.ipynb index 4d774c4b483..039eb6a4c3f 100644 --- a/docs/guides/classical-feedforward-and-control-flow.ipynb +++ b/docs/guides/classical-feedforward-and-control-flow.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "markdown", - "id": "96086a58-1a50-4af1-b76e-5d490157efe4", + "id": "72a56be1-db57-4364-acf3-57814453b64e", "metadata": {}, "source": [ "---\n", @@ -16,7 +16,7 @@ }, { "cell_type": "markdown", - "id": "ef85eedb-3040-4cb0-9ae4-e6825d0b8b99", + "id": "7f636096-9a03-4f72-823b-4b9219d496f0", "metadata": { "tags": [ "version-info" @@ -45,7 +45,7 @@ }, { "cell_type": "markdown", - "id": "99f0e64b-a94a-416b-8162-30b1a9862e19", + "id": "ea7e102f-6e41-4bdd-95be-5dd13225952b", "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", @@ -57,9 +57,22 @@ }, { "cell_type": "markdown", - "id": "5627c18e-0bb7-48c0-b91e-a0d7e731fb5c", + "id": "b2953dd4-218e-4daa-a753-0d2aa5e0a0bb", "metadata": {}, "source": [ + "Qiskit supports four control flow constructs for classical feedforward, each implemented as a method on [`QuantumCircuit`](/docs/api/qiskit/qiskit.circuit.QuantumCircuit). The constructs and their corresponding methods are:\n", + "\n", + "- If statement - [`QuantumCircuit.if_test`](/docs/api/qiskit/qiskit.circuit.QuantumCircuit#if_test)\n", + "- Switch statement - [`QuantumCircuit.switch`](/docs/api/qiskit/qiskit.circuit.QuantumCircuit#switch)\n", + "- For loop - [`QuantumCircuit.for_loop`](/docs/api/qiskit/qiskit.circuit.QuantumCircuit#for_loop)\n", + "- While loop - [`QuantumCircuit.while_loop`](/docs/api/qiskit/qiskit.circuit.QuantumCircuit#while_loop)\n", + "\n", + "Each of these methods returns a [context manager](https://docs.python.org/3/reference/datamodel.html#with-statement-context-managers) and is typically used in a `with` statement. The remainder of this guide explains each of these constructs and how to use them.\n", + "\n", + "\n", + " There are some limitations of classical feedforward and control flow operations on quantum hardware that might impact your program. For more information, see [Execute dynamic circuits](/docs/guides/execute-dynamic-circuits).\n", + "\n", + "\n", "## `if` statement\n", "\n", "The `if` statement is used to conditionally perform operations based on the value of a classical bit or register.\n", @@ -70,13 +83,13 @@ { "cell_type": "code", "execution_count": 1, - "id": "9173934e-d09d-40ae-bcff-8a582be22dcd", + "id": "f0f191a7-d59d-415f-a11b-9f39e431269b", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "\"Output" + "\"Output" ] }, "execution_count": 1, @@ -105,7 +118,7 @@ }, { "cell_type": "markdown", - "id": "6286036e-300d-48a9-aa89-158d181a6eff", + "id": "867d8f76-9cba-47fd-a341-ac40db6ee073", "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", @@ -116,13 +129,13 @@ { "cell_type": "code", "execution_count": 2, - "id": "fcbd6923-b2bf-455b-bced-84aa539f8ac6", + "id": "d40249f1-d951-49e4-9ee9-662d3568f32f", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "\"Output" + "\"Output" ] }, "execution_count": 2, @@ -152,7 +165,7 @@ }, { "cell_type": "markdown", - "id": "649aa80e-31f1-460a-b12d-7a451bea7851", + "id": "ba7b688a-e961-4361-9edf-47b387704f9d", "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", @@ -163,13 +176,13 @@ { "cell_type": "code", "execution_count": 3, - "id": "686c8c5f-330a-4aae-b42a-852d4c4730e4", + "id": "6ccfd81b-0bda-409e-bd9a-116848df631b", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "\"Output" + "\"Output" ] }, "execution_count": 3, @@ -198,12 +211,206 @@ }, { "cell_type": "markdown", - "id": "9ff45446-8c18-414f-ae88-2718f5bf7d3f", + "id": "f85c34ed-bca6-40b9-9db2-e534f8c79010", + "metadata": {}, + "source": [ + "## Switch statement\n", + "\n", + "The switch statement is used to select actions based on the value of a classical bit or register. It is similar to an if statement, but you can specify more cases for the branching logic. The example below applies a Hadamard gate to a qubit and measures it. If the result is 0, apply an X gate on the qubit, and if the result is 1, apply a Z gate. The resulting measurement outcome should be 1 with 100% probability." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "04b82e33-7c95-4042-a5e9-d00ff075ca02", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\"Output" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "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.switch(c0) as case:\n", + " with case(0):\n", + " circuit.x(q0)\n", + " with case(1):\n", + " circuit.z(q0)\n", + "circuit.measure(q0, c0)\n", + "\n", + "circuit.draw(\"mpl\")\n", + "\n", + "# example output counts: {'1': 1024}" + ] + }, + { + "cell_type": "markdown", + "id": "e0da6aa3-736e-4eb5-ad36-8626236f7604", + "metadata": {}, + "source": [ + "Because the example above used a single classical bit, there were only two possible cases, so you could have achieved the same result using an if-else statement. The switch case is mainly useful when branching on the value of a classical register composed of multiple bits. The following example shows how to construct a default case, which is executed if none of the preceding cases are. Note that in a switch statement, only one of the blocks are ever executed. There is no fallthrough.\n", + "\n", + "The example below applies Hadamard gates to two qubits and measures them. If the result is either 00 or 11, apply a Z gate to the third qubit. If the result is 01, apply a Y gate. If none of the preceding cases matched, apply an X gate. Finally, measure the third qubit." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "6aaba57e-7841-47d3-8f31-f922cb2b81f7", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\"Output" + ] + }, + "execution_count": 5, + "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.switch(clbits) as case:\n", + " with case(0b000, 0b011):\n", + " circuit.z(q2)\n", + " with case(0b001):\n", + " circuit.y(q2)\n", + " with case(case.DEFAULT):\n", + " circuit.x(q2)\n", + "circuit.measure(q2, c2)\n", + "\n", + "circuit.draw(\"mpl\")\n", + "\n", + "# example output counts: {'101': 267, '110': 249, '011': 265, '000': 243}" + ] + }, + { + "cell_type": "markdown", + "id": "e5f1da75-abcc-42de-8aa6-6f2a6d450ddd", + "metadata": {}, + "source": [ + "## For loop\n", + "\n", + "A for loop is used to iterate over a sequence of classical values and perform some operations during each iteration.\n", + "\n", + "The following example uses a for loop to apply 5 X gates to a qubit and then measures it. Because it performs an odd number of X gates, the overall effect is to flip the qubit from the 0 state to the 1 state." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "c6c91715-7a98-46a8-885e-92d3d1f99557", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\"Output" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "qubits = QuantumRegister(1)\n", + "clbits = ClassicalRegister(1)\n", + "circuit = QuantumCircuit(qubits, clbits)\n", + "(q0,) = qubits\n", + "(c0,) = clbits\n", + "\n", + "with circuit.for_loop(range(5)) as _:\n", + " circuit.x(q0)\n", + "circuit.measure(q0, c0)\n", + "\n", + "circuit.draw(\"mpl\")\n", + "\n", + "# example output counts: {'1': 1024}" + ] + }, + { + "cell_type": "markdown", + "id": "98e7b4f3-e73e-4caf-9326-11b45bd6cfcf", + "metadata": {}, + "source": [ + "## While loop\n", + "\n", + "A while loop is used to repeat instructions while some condition is satisfied.\n", + "\n", + "The example below applies Hadamard gates to two qubits and measures them. Then it creates a while loop that repeats this procedure while the measurement outcome is 11. As a result, the final measurement should never be 11, with the remaining possibilities appearing with approximately equal frequency." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "c26465ff-5d3e-4799-8c68-c327abff5694", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\"Output" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "qubits = QuantumRegister(2)\n", + "clbits = ClassicalRegister(2)\n", + "circuit = QuantumCircuit(qubits, clbits)\n", + "\n", + "q0, q1 = qubits\n", + "c0, c1 = clbits\n", + "\n", + "circuit.h([q0, q1])\n", + "circuit.measure(q0, c0)\n", + "circuit.measure(q1, c1)\n", + "with circuit.while_loop((clbits, 0b11)):\n", + " circuit.h([q0, q1])\n", + " circuit.measure(q0, c0)\n", + " circuit.measure(q1, c1)\n", + "\n", + "circuit.draw(\"mpl\")\n", + "\n", + "# example output counts: {'01': 334, '10': 368, '00': 322}" + ] + }, + { + "cell_type": "markdown", + "id": "672080db-913d-4511-ab63-48ca48b60fa5", "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", + "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.\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", @@ -213,8 +420,8 @@ }, { "cell_type": "code", - "execution_count": 4, - "id": "c90c4755-947c-4503-9bee-0237c2b2103b", + "execution_count": 8, + "id": "8c8ad702-1097-411f-983d-b5654f75059f", "metadata": {}, "outputs": [], "source": [ @@ -274,17 +481,17 @@ }, { "cell_type": "code", - "execution_count": 5, - "id": "b5fdd320-da61-4fc5-86ed-8eefa104965e", + "execution_count": 9, + "id": "a5d808f5-d424-4133-a557-89d2f2a2c853", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "\"Output" + "\"Output" ] }, - "execution_count": 5, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } @@ -295,7 +502,7 @@ }, { "cell_type": "markdown", - "id": "0d9cb9a0-c8dc-44ba-8cb2-416bf3748c45", + "id": "62134a85-608f-4ad2-a76e-b0736bec9362", "metadata": {}, "source": [ "\n", @@ -310,17 +517,17 @@ }, { "cell_type": "code", - "execution_count": 1, - "id": "e64ec241-41e8-40f8-ab64-af236c6c7802", + "execution_count": 10, + "id": "953fa3ca-f542-47ea-9cf2-36a616ecb7f7", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "\"Output" + "\"Output" ] }, - "execution_count": 1, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -358,7 +565,7 @@ }, { "cell_type": "markdown", - "id": "9688221f-3da3-4a5b-aac9-aabf7b518d82", + "id": "f1b55508-04e8-4f53-9b13-33302102711d", "metadata": {}, "source": [ "## Next steps\n", diff --git a/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/101aaa8f-7061-4924-9b50-806d7e1ab728-0.avif b/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/101aaa8f-7061-4924-9b50-806d7e1ab728-0.avif new file mode 100644 index 00000000000..52d18bc29e6 Binary files /dev/null and b/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/101aaa8f-7061-4924-9b50-806d7e1ab728-0.avif differ diff --git a/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/174a9675-3c8b-4b5e-808e-f7e0f8b9c805-0.avif b/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/174a9675-3c8b-4b5e-808e-f7e0f8b9c805-0.avif new file mode 100644 index 00000000000..b922f2fde46 Binary files /dev/null and b/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/174a9675-3c8b-4b5e-808e-f7e0f8b9c805-0.avif differ diff --git a/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/1f6737fe-bc45-4d0c-b7b4-1096e2d7e14a-0.avif b/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/1f6737fe-bc45-4d0c-b7b4-1096e2d7e14a-0.avif new file mode 100644 index 00000000000..f2c75a1b2b7 Binary files /dev/null and b/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/1f6737fe-bc45-4d0c-b7b4-1096e2d7e14a-0.avif differ diff --git a/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/20f0640a-a3f7-41b3-aada-b66bc89b0555-0.svg b/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/20f0640a-a3f7-41b3-aada-b66bc89b0555-0.svg deleted file mode 100644 index 0d66b12693e..00000000000 --- a/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/20f0640a-a3f7-41b3-aada-b66bc89b0555-0.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/37ec3fa6-04b5-4165-b8d2-bae5fd238331-0.avif b/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/37ec3fa6-04b5-4165-b8d2-bae5fd238331-0.avif new file mode 100644 index 00000000000..8cb4d3a0c97 Binary files /dev/null and b/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/37ec3fa6-04b5-4165-b8d2-bae5fd238331-0.avif differ diff --git a/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/53a26ce5-3564-47a0-8803-c9c46db86923-0.avif b/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/53a26ce5-3564-47a0-8803-c9c46db86923-0.avif new file mode 100644 index 00000000000..d332870b2ba Binary files /dev/null and b/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/53a26ce5-3564-47a0-8803-c9c46db86923-0.avif differ diff --git a/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/60924bfa-50ed-4d9d-a17b-9d64f2cc053f-0.svg b/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/60924bfa-50ed-4d9d-a17b-9d64f2cc053f-0.svg deleted file mode 100644 index 65f5f15ffbe..00000000000 --- a/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/60924bfa-50ed-4d9d-a17b-9d64f2cc053f-0.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/98e8f552-4169-42a3-8182-e14e9ffb59e2-0.svg b/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/98e8f552-4169-42a3-8182-e14e9ffb59e2-0.svg deleted file mode 100644 index ee624b8b10f..00000000000 --- a/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/98e8f552-4169-42a3-8182-e14e9ffb59e2-0.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/a5d43b4c-c538-4f34-8cf3-92c2c0d26fdd-0.avif b/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/a5d43b4c-c538-4f34-8cf3-92c2c0d26fdd-0.avif new file mode 100644 index 00000000000..754e44c630b Binary files /dev/null and b/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/a5d43b4c-c538-4f34-8cf3-92c2c0d26fdd-0.avif differ diff --git a/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/d0f0abdb-50d5-408d-a704-a1a555acdd85-0.svg b/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/d0f0abdb-50d5-408d-a704-a1a555acdd85-0.svg deleted file mode 100644 index 427fa3c3cde..00000000000 --- a/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/d0f0abdb-50d5-408d-a704-a1a555acdd85-0.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/d2fdf38a-e874-4de1-9a79-08aab97f9ecc-0.avif b/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/d2fdf38a-e874-4de1-9a79-08aab97f9ecc-0.avif new file mode 100644 index 00000000000..2985894d232 Binary files /dev/null and b/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/d2fdf38a-e874-4de1-9a79-08aab97f9ecc-0.avif differ diff --git a/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/e64ec241-41e8-40f8-ab64-af236c6c7802-0.avif b/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/f76db731-afa1-4777-9482-25376aa86175-0.avif similarity index 100% rename from public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/e64ec241-41e8-40f8-ab64-af236c6c7802-0.avif rename to public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/f76db731-afa1-4777-9482-25376aa86175-0.avif diff --git a/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/fc2bc3c3-eab1-41f0-b696-5e8b30155d55-0.avif b/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/fc2bc3c3-eab1-41f0-b696-5e8b30155d55-0.avif new file mode 100644 index 00000000000..c00904074f9 Binary files /dev/null and b/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/fc2bc3c3-eab1-41f0-b696-5e8b30155d55-0.avif differ