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": [ + "\"Output" + ] + }, + "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