Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
257 changes: 232 additions & 25 deletions docs/guides/classical-feedforward-and-control-flow.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "markdown",
"id": "96086a58-1a50-4af1-b76e-5d490157efe4",
"id": "72a56be1-db57-4364-acf3-57814453b64e",
"metadata": {},
"source": [
"---\n",
Expand All @@ -16,7 +16,7 @@
},
{
"cell_type": "markdown",
"id": "ef85eedb-3040-4cb0-9ae4-e6825d0b8b99",
"id": "7f636096-9a03-4f72-823b-4b9219d496f0",
"metadata": {
"tags": [
"version-info"
Expand Down Expand Up @@ -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",
Expand All @@ -57,9 +57,22 @@
},
{
"cell_type": "markdown",
"id": "5627c18e-0bb7-48c0-b91e-a0d7e731fb5c",
"id": "b2953dd4-218e-4daa-a753-0d2aa5e0a0bb",
"metadata": {},
"source": [
"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`](../api/qiskit/qiskit.circuit.QuantumCircuit). The constructs and their corresponding methods are:\n",
"\n",
"- If statement - [`QuantumCircuit.if_test`](../api/qiskit/qiskit.circuit.QuantumCircuit#if_test)\n",
"- Switch statement - [`QuantumCircuit.switch`](../api/qiskit/qiskit.circuit.QuantumCircuit#switch)\n",
"- For loop - [`QuantumCircuit.for_loop`](../api/qiskit/qiskit.circuit.QuantumCircuit#for_loop)\n",
"- While loop - [`QuantumCircuit.while_loop`](../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. In the rest of this guide, we will explain each of these constructs and how to use them.\n",
"\n",
"<Admonition type=\"caution\">\n",
" There are some limitations of classical feedforward and control flow operations on quantum hardware that might impact your program. For more information, see [Job limits](/docs/guides/job-limits).\n",
"</Admonition>\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",
Expand All @@ -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": [
"<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\" />"
"<Image src=\"/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/101aaa8f-7061-4924-9b50-806d7e1ab728-0.avif\" alt=\"Output of the previous code cell\" />"
]
},
"execution_count": 1,
Expand Down Expand Up @@ -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",
Expand All @@ -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": [
"<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\" />"
"<Image src=\"/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/1f6737fe-bc45-4d0c-b7b4-1096e2d7e14a-0.avif\" alt=\"Output of the previous code cell\" />"
]
},
"execution_count": 2,
Expand Down Expand Up @@ -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",
Expand All @@ -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": [
"<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\" />"
"<Image src=\"/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/37ec3fa6-04b5-4165-b8d2-bae5fd238331-0.avif\" alt=\"Output of the previous code cell\" />"
]
},
"execution_count": 3,
Expand Down Expand Up @@ -198,7 +211,201 @@
},
{
"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 allows one to specify more cases for the branching logic. In the example below, we apply a Hadamard gate to a qubit and measure it. If the result is 0, we apply an X gate on the qubit, and if the result is 1, we 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": [
"<Image src=\"/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/fc2bc3c3-eab1-41f0-b696-5e8b30155d55-0.avif\" alt=\"Output of the previous code cell\" />"
]
},
"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 we 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, as demonstrated in the following example. Here, we also show 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",
"In the example below, we apply Hadamard gates to two qubits and measure them. If the result is either 00 or 11, we apply a Z gate to the third qubit. If the result is 01, we apply a Y gate. If none of the preceding cases matched, we 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": [
"<Image src=\"/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/a5d43b4c-c538-4f34-8cf3-92c2c0d26fdd-0.avif\" alt=\"Output of the previous code cell\" />"
]
},
"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",
"In the example below, we use a for loop to apply 5 X gates to a qubit and then measure it. Because we perform 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": [
"<Image src=\"/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/53a26ce5-3564-47a0-8803-c9c46db86923-0.avif\" alt=\"Output of the previous code cell\" />"
]
},
"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",
"In the example below, we apply Hadamard gates to two qubits and measure them. Then, we create 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": [
"<Image src=\"/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/174a9675-3c8b-4b5e-808e-f7e0f8b9c805-0.avif\" alt=\"Output of the previous code cell\" />"
]
},
"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",
Expand All @@ -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": [
Expand Down Expand Up @@ -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": [
"<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\" />"
"<Image src=\"/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/d2fdf38a-e874-4de1-9a79-08aab97f9ecc-0.avif\" alt=\"Output of the previous code cell\" />"
]
},
"execution_count": 5,
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
Expand All @@ -295,7 +502,7 @@
},
{
"cell_type": "markdown",
"id": "0d9cb9a0-c8dc-44ba-8cb2-416bf3748c45",
"id": "62134a85-608f-4ad2-a76e-b0736bec9362",
"metadata": {},
"source": [
"<span id=\"store\"></span>\n",
Expand All @@ -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": [
"<Image src=\"/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/e64ec241-41e8-40f8-ab64-af236c6c7802-0.avif\" alt=\"Output of the previous code cell\" />"
"<Image src=\"/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/f76db731-afa1-4777-9482-25376aa86175-0.avif\" alt=\"Output of the previous code cell\" />"
]
},
"execution_count": 1,
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
Expand Down Expand Up @@ -358,7 +565,7 @@
},
{
"cell_type": "markdown",
"id": "9688221f-3da3-4a5b-aac9-aabf7b518d82",
"id": "f1b55508-04e8-4f53-9b13-33302102711d",
"metadata": {},
"source": [
"## Next steps\n",
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading
Loading