diff --git a/docs/guides/classical-feedforward-and-control-flow.ipynb b/docs/guides/classical-feedforward-and-control-flow.ipynb
index 0d2eb4eeaf6..4d774c4b483 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": "943cf52c-41c8-4a2b-bf1d-6df8a90a6353",
+ "id": "96086a58-1a50-4af1-b76e-5d490157efe4",
"metadata": {},
"source": [
"---\n",
@@ -16,7 +16,7 @@
},
{
"cell_type": "markdown",
- "id": "b1d96290-2e64-43aa-bae9-c74b8529894d",
+ "id": "ef85eedb-3040-4cb0-9ae4-e6825d0b8b99",
"metadata": {
"tags": [
"version-info"
@@ -45,7 +45,7 @@
},
{
"cell_type": "markdown",
- "id": "85a4d698-ee2a-4b3d-9331-1b91eea49338",
+ "id": "99f0e64b-a94a-416b-8162-30b1a9862e19",
"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,7 +57,7 @@
},
{
"cell_type": "markdown",
- "id": "5d846edf-fc09-4808-bd62-3a8cfdcc1585",
+ "id": "5627c18e-0bb7-48c0-b91e-a0d7e731fb5c",
"metadata": {},
"source": [
"## `if` statement\n",
@@ -70,7 +70,7 @@
{
"cell_type": "code",
"execution_count": 1,
- "id": "60924bfa-50ed-4d9d-a17b-9d64f2cc053f",
+ "id": "9173934e-d09d-40ae-bcff-8a582be22dcd",
"metadata": {},
"outputs": [
{
@@ -105,7 +105,7 @@
},
{
"cell_type": "markdown",
- "id": "bef3f447-7282-4de9-9410-6b671e9902c3",
+ "id": "6286036e-300d-48a9-aa89-158d181a6eff",
"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,7 +116,7 @@
{
"cell_type": "code",
"execution_count": 2,
- "id": "20f0640a-a3f7-41b3-aada-b66bc89b0555",
+ "id": "fcbd6923-b2bf-455b-bced-84aa539f8ac6",
"metadata": {},
"outputs": [
{
@@ -152,7 +152,7 @@
},
{
"cell_type": "markdown",
- "id": "f0f00f48-a1f2-40cc-b5f5-9a122d8dd24e",
+ "id": "649aa80e-31f1-460a-b12d-7a451bea7851",
"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,7 +163,7 @@
{
"cell_type": "code",
"execution_count": 3,
- "id": "98e8f552-4169-42a3-8182-e14e9ffb59e2",
+ "id": "686c8c5f-330a-4aae-b42a-852d4c4730e4",
"metadata": {},
"outputs": [
{
@@ -198,7 +198,7 @@
},
{
"cell_type": "markdown",
- "id": "ef8fd422-6bab-46c9-9455-c79244cf1fb7",
+ "id": "9ff45446-8c18-414f-ae88-2718f5bf7d3f",
"metadata": {},
"source": [
"## Classical expressions\n",
@@ -214,7 +214,7 @@
{
"cell_type": "code",
"execution_count": 4,
- "id": "7581ac2f-53e9-43d0-bad0-2c80790172e1",
+ "id": "c90c4755-947c-4503-9bee-0237c2b2103b",
"metadata": {},
"outputs": [],
"source": [
@@ -275,7 +275,7 @@
{
"cell_type": "code",
"execution_count": 5,
- "id": "d0f0abdb-50d5-408d-a704-a1a555acdd85",
+ "id": "b5fdd320-da61-4fc5-86ed-8eefa104965e",
"metadata": {},
"outputs": [
{
@@ -295,7 +295,70 @@
},
{
"cell_type": "markdown",
- "id": "7c80c5d0-a447-4590-8426-6eb33ae2d817",
+ "id": "0d9cb9a0-c8dc-44ba-8cb2-416bf3748c45",
+ "metadata": {},
+ "source": [
+ "\n",
+ "### `Store`\n",
+ "\n",
+ "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 example, it is more natural and more efficient at runtime to write $B[0] \\oplus B[1] \\oplus B[2] \\ldots$, where $B = \\neg A$, than $(\\neg A[0]) \\oplus (\\neg A[1]) \\oplus (\\neg A[2]) \\ldots$. The former computes the negation in a single parallel step before the XOR chain, instead of evaluating each negation sequentially inside the expression.\n",
+ "\n",
+ "Full example:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "e64ec241-41e8-40f8-ab64-af236c6c7802",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 1,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "from qiskit.circuit import QuantumCircuit, QuantumRegister, ClassicalRegister\n",
+ "from qiskit.circuit.classical import expr\n",
+ "\n",
+ "qregs = QuantumRegister(4, \"q\")\n",
+ "creg = ClassicalRegister(3, \"c\")\n",
+ "# temp is a plain ClassicalRegister used as the store target\n",
+ "temp = ClassicalRegister(3, \"temp\")\n",
+ "qc = QuantumCircuit(qregs, creg, temp)\n",
+ "\n",
+ "qc.h([0, 1, 2])\n",
+ "qc.measure([0, 1, 2], creg)\n",
+ "\n",
+ "# Store bit-NOT of the full 3-bit register into temp\n",
+ "qc.store(temp, expr.bit_not(creg))\n",
+ "\n",
+ "# Compute parity of temp using bit-indexed XOR\n",
+ "parity = expr.bit_xor(\n",
+ " expr.bit_xor(expr.index(temp, 0), expr.index(temp, 1)),\n",
+ " expr.index(temp, 2),\n",
+ ")\n",
+ "\n",
+ "# Flip q3 if parity of ~creg is 1\n",
+ "with qc.if_test(parity):\n",
+ " qc.x(3)\n",
+ "\n",
+ "qc.measure([0, 1, 2], creg)\n",
+ "\n",
+ "qc.draw(\"mpl\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9688221f-3da3-4a5b-aac9-aabf7b518d82",
"metadata": {},
"source": [
"## Next steps\n",
diff --git a/docs/guides/estimator-input-output.ipynb b/docs/guides/estimator-input-output.ipynb
index db3d978eb85..a2170762b7a 100644
--- a/docs/guides/estimator-input-output.ipynb
+++ b/docs/guides/estimator-input-output.ipynb
@@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "markdown",
- "id": "4a99b08b-5a4e-4c2c-ba72-b932d8510bf2",
+ "id": "066d7e4d-a975-4519-b56f-095f861be3ac",
"metadata": {},
"source": [
"---\n",
@@ -16,7 +16,7 @@
},
{
"cell_type": "markdown",
- "id": "0f04fa5d-aae1-4a05-832b-be5e0f03f5b2",
+ "id": "23e7dff0-fde5-4c2d-89c2-fc5ab99240fe",
"metadata": {
"tags": [
"version-info"
@@ -46,7 +46,7 @@
},
{
"cell_type": "markdown",
- "id": "cd5b8a3a-fc21-4eaf-923c-1576db19d569",
+ "id": "90d0c1e0-28e7-48da-a35f-6016fddea82c",
"metadata": {},
"source": [
"This page gives an overview of the inputs and outputs of the Qiskit Runtime Estimator primitive, which executes workloads on IBM Quantum® compute resources. Estimator lets you efficiently define vectorized workloads by using a data structure called a [**Primitive Unified Bloc (PUB)**](/docs/guides/primitive-input-output#pubs). They are used as inputs to the [`run()`](/docs/api/qiskit-ibm-runtime/estimator-v2#run) method for the Estimator primitive, which executes the defined workload as a job. Then, after the job has completed, the results are returned in a format that is dependent on both the PUBs used as well as the runtime options specified from the primitive."
@@ -54,7 +54,7 @@
},
{
"cell_type": "markdown",
- "id": "d27b242b-5865-48cc-9052-577982a0b922",
+ "id": "83a5fdd8-6547-47c7-9441-a7458edc7896",
"metadata": {},
"source": [
"## Inputs\n",
@@ -83,7 +83,7 @@
},
{
"cell_type": "markdown",
- "id": "6b4da5a2-093a-4069-99ba-11e2f9c1f9a1",
+ "id": "846b3109-02a1-4783-ad3f-1c22f753c324",
"metadata": {},
"source": [
"---\n",
@@ -94,7 +94,7 @@
{
"cell_type": "code",
"execution_count": 1,
- "id": "f4b2c3b6-80bd-4d84-9b16-8bdb7502e06b",
+ "id": "2f50a9f5-2cc1-4d83-9fe1-1b3a8be0d766",
"metadata": {},
"outputs": [],
"source": [
@@ -170,7 +170,7 @@
},
{
"cell_type": "markdown",
- "id": "246bd44d-8f3d-40b6-b1c1-795cc3533b32",
+ "id": "90dccb20-1848-4367-a12d-434110ad5a5c",
"metadata": {},
"source": [
"## Outputs\n",
@@ -223,7 +223,7 @@
{
"cell_type": "code",
"execution_count": 2,
- "id": "defbebd5-f09f-4596-aff0-ae88cbf2555c",
+ "id": "53a4d5ae-109b-452b-bbc5-2d7940c5182c",
"metadata": {},
"outputs": [
{
@@ -252,7 +252,7 @@
],
"source": [
"print(\n",
- " f\"The result of the submitted job had {len(result)} PUB and has a value:\\n {result}\\n\"\n",
+ " f\"The result of the submitted job had {len(result)} PUBs and has a value:\\n {result}\\n\"\n",
")\n",
"print(\n",
" f\"The associated PubResult of this job has the following data bins:\\n {result[0].data}\\n\"\n",
@@ -270,7 +270,7 @@
},
{
"cell_type": "markdown",
- "id": "33af7b71-0562-4bb6-8098-8ddebb206032",
+ "id": "000ade51-d940-45f9-84ea-16ad283a930f",
"metadata": {},
"source": [
"#### How the Estimator primitive calculates error\n",
@@ -292,7 +292,7 @@
},
{
"cell_type": "markdown",
- "id": "cc748369-c7db-4d3d-a2a6-7973fa5c37fe",
+ "id": "c4341184-a41a-4442-bc05-838c90ea93b8",
"metadata": {},
"source": [
"## Result metadata\n",
@@ -307,7 +307,7 @@
{
"cell_type": "code",
"execution_count": 3,
- "id": "b740caa1-bbdb-421c-aae8-e389a8e55aa1",
+ "id": "626ba203-44e2-4b8f-b04d-04388b8b1fa1",
"metadata": {},
"outputs": [
{
diff --git a/docs/guides/execute-dynamic-circuits.ipynb b/docs/guides/execute-dynamic-circuits.ipynb
index 1a608b6aaea..71573112a70 100644
--- a/docs/guides/execute-dynamic-circuits.ipynb
+++ b/docs/guides/execute-dynamic-circuits.ipynb
@@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "markdown",
- "id": "a9095a6c-e720-4b4c-9eca-4b5234186400",
+ "id": "83596f71-5e63-4aa2-907b-75de8813d85a",
"metadata": {},
"source": [
"---\n",
@@ -16,7 +16,7 @@
},
{
"cell_type": "markdown",
- "id": "0b425be3-b17e-4e41-b393-63b0a58c054f",
+ "id": "7e9dc06d-85fa-4425-9bd1-ce5085be9741",
"metadata": {
"tags": [
"version-info"
@@ -46,7 +46,7 @@
},
{
"cell_type": "markdown",
- "id": "d59d8dd9-8c61-49ab-b43c-b34f87ebcce2",
+ "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",
@@ -66,7 +66,7 @@
},
{
"cell_type": "markdown",
- "id": "c1f79012-05ce-4854-908b-59ca6b472508",
+ "id": "c4616d43-f296-4a84-a79c-deb37fcdac15",
"metadata": {},
"source": [
"## Find backends that support dynamic circuits\n",
@@ -83,7 +83,7 @@
{
"cell_type": "code",
"execution_count": 1,
- "id": "0cd6971f-cb04-4ff9-89a8-7638fdcca0d1",
+ "id": "076db590-29db-4137-a043-45485c9f46df",
"metadata": {
"tags": [
"remove-cell"
@@ -100,14 +100,14 @@
{
"cell_type": "code",
"execution_count": 2,
- "id": "517e5e4d-3f48-4c2b-9084-222ed3cd2de7",
+ "id": "a63f07b1-9e8a-4086-ab01-552bd444dc9b",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
- "[, , , , ]\n"
+ "[, , , , ]\n"
]
}
],
@@ -121,7 +121,7 @@
},
{
"cell_type": "markdown",
- "id": "5992c1cd-f28a-4f40-b3f9-09374c9f61ca",
+ "id": "1dca7d79-99ea-42bd-86f7-182266907a85",
"metadata": {},
"source": [
"\n",
@@ -141,7 +141,7 @@
{
"cell_type": "code",
"execution_count": 3,
- "id": "8b1b8786-21bd-4a9c-b868-36f497738f10",
+ "id": "87dfb9c7-1dc2-4752-bdc1-17b9144369f4",
"metadata": {},
"outputs": [
{
@@ -180,7 +180,7 @@
},
{
"cell_type": "markdown",
- "id": "983e4d2b-7049-4be1-b628-eac093f96585",
+ "id": "2b603f88-2e0e-4819-8342-8e3662949ff3",
"metadata": {},
"source": [
"\n",
@@ -193,7 +193,19 @@
},
{
"cell_type": "markdown",
- "id": "88942666-966d-4eb6-81b5-2a9e1265fe0a",
+ "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/guides/classical-feedforward-and-control-flow#store) guide."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3f374a74-c331-40de-8594-686e471058a2",
"metadata": {},
"source": [
"## Full example\n",
@@ -204,14 +216,14 @@
{
"cell_type": "code",
"execution_count": 4,
- "id": "800ddb06-3b1a-4b9e-a92e-c782e4a3d412",
+ "id": "a7a9c998-4031-432f-978b-83edc040798f",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
- ">>> Job ID: d82864vtjchs73bnokf0 (DONE)\n"
+ ">>> Job ID: d88cakp789is7391vq0g (DONE)\n"
]
}
],
@@ -259,7 +271,7 @@
},
{
"cell_type": "markdown",
- "id": "e2ee6fb4-7b6d-4ee6-a625-0f92e40bd7f9",
+ "id": "c5b14dcf-edf4-4fef-bb49-e6b86f06afb0",
"metadata": {},
"source": [
"## Qiskit Runtime limitations\n",
@@ -342,7 +354,7 @@
},
{
"cell_type": "markdown",
- "id": "fb3c25a4-bde2-4d34-bbd2-670091a33968",
+ "id": "ca6e0493-d364-40bf-9f47-2e3feed9f82c",
"metadata": {},
"source": [
"## Use dynamic circuits with Estimator\n",
@@ -361,7 +373,7 @@
},
{
"cell_type": "markdown",
- "id": "5adac953-3305-4383-b522-901ecbd9bd31",
+ "id": "07045397-6db8-4151-a1e4-de24a8f39ab6",
"metadata": {},
"source": [
"## Restrictions\n",
@@ -371,7 +383,7 @@
},
{
"cell_type": "markdown",
- "id": "b5b33172-d1b6-418c-b06d-12e4c2a75738",
+ "id": "6688e2e3-766b-4194-99db-ae097e9b8bc7",
"metadata": {},
"source": [
"## Next steps\n",
@@ -380,6 +392,7 @@
"- Learn how to implement accurate dynamic decoupling by using [stretch](/docs/guides/stretch).\n",
"- Review the [classical feedforward and control flow](/docs/guides/classical-feedforward-and-control-flow) guide.\n",
"- Use [circuit schedule visualization](/docs/guides/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/guides/sampler-options#feature-compatibility) or [Executor](/docs/guides/executor-options#feature-compatibility) for details.\n",
""
]
}
diff --git a/docs/guides/executor-options.ipynb b/docs/guides/executor-options.ipynb
index e3f6f293612..1ae656f60ec 100644
--- a/docs/guides/executor-options.ipynb
+++ b/docs/guides/executor-options.ipynb
@@ -240,7 +240,9 @@
" - Dynamical decoupling\n",
"\n",
" Other notes:\n",
- " - Gate twirling can be applied to dynamic circuits, but only to gates not inside conditional blocks. Measurement twirling can only be applied to terminal measurements.\n",
+ " - Gate twirling can be applied to dynamic circuits, but only to gates not inside conditional blocks.\n",
+ " - Measurement twirling can only be applied to terminal measurements.\n",
+ " - Measurement twirling is incompatible with the [`store`](/docs/api/qiskit/circuit#store) instruction.\n",
" - Compatible with fractional gates when using `qiskit-ibm-runtime` v0.42.0 or later.\n",
"\n",
" \n",
diff --git a/docs/guides/sampler-options.ipynb b/docs/guides/sampler-options.ipynb
index 2ad61fb038d..754a1747b5a 100644
--- a/docs/guides/sampler-options.ipynb
+++ b/docs/guides/sampler-options.ipynb
@@ -510,7 +510,9 @@
" - Stretches\n",
"\n",
" Other notes:\n",
- " - Gate twirling can be applied to dynamic circuits, but only to gates not inside conditional blocks. Measurement twirling can only be applied to terminal measurements.\n",
+ " - Gate twirling can be applied to dynamic circuits, but only to gates not inside conditional blocks.\n",
+ " - Measurement twirling can only be applied to terminal measurements.\n",
+ " - Measurement twirling is incompatible with the [`store`](/docs/api/qiskit/circuit#store) instruction.\n",
" - Does not work with non-Clifford entanglers.\n",
" \n",
""
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/e64ec241-41e8-40f8-ab64-af236c6c7802-0.avif
new file mode 100644
index 00000000000..e55c137ebcb
Binary files /dev/null and b/public/docs/images/guides/classical-feedforward-and-control-flow/extracted-outputs/e64ec241-41e8-40f8-ab64-af236c6c7802-0.avif differ