-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Document classical control #5403
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
56d8cbc
CControl docs, first pass
95-martin-orion b762541
nbformat
95-martin-orion 2f147f8
Merge branch 'master' into ccontrol-docs
tanujkhattar 9e1ff0c
Defer and teleport
95-martin-orion 2cae4b1
Review comments.
95-martin-orion ccb3a25
minus generally
95-martin-orion 2af8519
Merge branch 'master' into ccontrol-docs
CirqBot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,311 @@ | ||
| { | ||
augustehirth marked this conversation as resolved.
Show resolved
Hide resolved
augustehirth marked this conversation as resolved.
Show resolved
Hide resolved
augustehirth marked this conversation as resolved.
Show resolved
Hide resolved
augustehirth marked this conversation as resolved.
Show resolved
Hide resolved
augustehirth marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| "cells": [ | ||
| { | ||
| "cell_type": "code", | ||
| "execution_count": null, | ||
| "metadata": { | ||
| "id": "b952a1c0faad" | ||
| }, | ||
| "outputs": [], | ||
| "source": [ | ||
| "#@title Copyright 2022 The Cirq Developers\n", | ||
| "# Licensed under the Apache License, Version 2.0 (the \"License\");\n", | ||
| "# you may not use this file except in compliance with the License.\n", | ||
| "# You may obtain a copy of the License at\n", | ||
| "#\n", | ||
| "# https://www.apache.org/licenses/LICENSE-2.0\n", | ||
| "#\n", | ||
| "# Unless required by applicable law or agreed to in writing, software\n", | ||
| "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", | ||
| "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", | ||
| "# See the License for the specific language governing permissions and\n", | ||
| "# limitations under the License." | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "markdown", | ||
| "metadata": { | ||
| "id": "3556e78efd03" | ||
| }, | ||
| "source": [ | ||
| "# Classical control" | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "markdown", | ||
| "metadata": { | ||
| "id": "925dbb45c75e" | ||
| }, | ||
| "source": [ | ||
| "<table class=\"tfo-notebook-buttons\" align=\"left\">\n", | ||
| " <td>\n", | ||
| " <a target=\"_blank\" href=\"https://quantumai.google/cirq/circuits\"><img src=\"https://quantumai.google/site-assets/images/buttons/quantumai_logo_1x.png\" />View on QuantumAI</a>\n", | ||
| " </td>\n", | ||
| " <td>\n", | ||
| " <a target=\"_blank\" href=\"https://colab.research.google.com/github/quantumlib/Cirq/blob/master/docs/circuits.ipynb\"><img src=\"https://quantumai.google/site-assets/images/buttons/colab_logo_1x.png\" />Run in Google Colab</a>\n", | ||
| " </td>\n", | ||
| " <td>\n", | ||
| " <a target=\"_blank\" href=\"https://github.com/quantumlib/Cirq/blob/master/docs/circuits.ipynb\"><img src=\"https://quantumai.google/site-assets/images/buttons/github_logo_1x.png\" />View source on GitHub</a>\n", | ||
| " </td>\n", | ||
| " <td>\n", | ||
| " <a href=\"https://storage.googleapis.com/tensorflow_docs/Cirq/docs/circuits.ipynb\"><img src=\"https://quantumai.google/site-assets/images/buttons/download_icon_1x.png\" />Download notebook</a>\n", | ||
| " </td>\n", | ||
| "</table>" | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "code", | ||
| "execution_count": null, | ||
| "metadata": { | ||
| "id": "d4c447ddd24e" | ||
| }, | ||
| "outputs": [], | ||
| "source": [ | ||
| "try:\n", | ||
| " import cirq\n", | ||
| "except ImportError:\n", | ||
| " print(\"installing cirq...\")\n", | ||
| " !pip install --quiet cirq\n", | ||
| " import cirq\n", | ||
| " print(\"installed cirq.\")" | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "markdown", | ||
| "metadata": { | ||
| "id": "8ccb64c25e3a" | ||
| }, | ||
| "source": [ | ||
| "While some quantum algorithms can be defined entirely at the quantum level, there are many others (notably including [teleportation](/cirq/tutorials/educators/textbook_algorithms#quantum_teleportation) and [error correction](https://www.nature.com/articles/s41586-021-03588-y)) which rely on classical measurement results from one part of the algorithm to control operations in a later section.\n", | ||
| "\n", | ||
| "To represent this, Cirq provides the `ClassicallyControlledOperation`. Following the pattern of controlled operations, a classically-controlled version of any `Operation` can be constructed by calling its `with_classical_controls` method with the control condition(s)." | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "markdown", | ||
| "metadata": { | ||
| "id": "b3ed39be4c06" | ||
| }, | ||
| "source": [ | ||
| "## Basic conditions\n", | ||
| "\n", | ||
| "In the example below, `X` will only be applied to `q1` if the previous measurement \"a\" returns a 1. More generally, providing some string `\"cond\"` to `with_classical_controls` creates a `ClassicallyControlledOperation` with a `KeyCondition` whose key is `\"cond\"`. A `KeyCondition` will only trigger and apply the operation it controls if a preceding measurement with the same key measured one or more qubits in the $|1\\rangle$ state." | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "code", | ||
| "execution_count": null, | ||
| "metadata": { | ||
| "id": "df3dd6e3b308" | ||
| }, | ||
| "outputs": [], | ||
| "source": [ | ||
| "q0, q1, q2 = cirq.LineQubit.range(3)\n", | ||
| "circuit = cirq.Circuit(\n", | ||
| " cirq.H(q0),\n", | ||
| " cirq.measure(q0, key='a'),\n", | ||
| " cirq.X(q1).with_classical_controls('a'),\n", | ||
| ")\n", | ||
| "print(circuit)" | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "markdown", | ||
| "metadata": { | ||
| "id": "4e416431b695" | ||
| }, | ||
| "source": [ | ||
| "Using just these conditions, we can construct the [quantum teleportation](/cirq/tutorials/educators/textbook_algorithms#quantum_teleportation) circuit:" | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "code", | ||
| "execution_count": null, | ||
| "metadata": { | ||
| "id": "01ccc99c6a3c" | ||
| }, | ||
| "outputs": [], | ||
| "source": [ | ||
| "# Teleports `_message` from Alice to Bob.\n", | ||
| "alice = cirq.NamedQubit('alice')\n", | ||
| "bob = cirq.NamedQubit('bob')\n", | ||
| "message = cirq.NamedQubit('_message')\n", | ||
| "circuit = cirq.Circuit(\n", | ||
| " # Create Bell state to be shared between Alice and Bob.\n", | ||
| " cirq.H(alice),\n", | ||
| " cirq.CNOT(alice, bob),\n", | ||
| " # Create the message.\n", | ||
| " cirq.X(message) ** 0.371,\n", | ||
| " cirq.Y(message) ** 0.882,\n", | ||
| " # Bell measurement of the message and Alice's entangled qubit.\n", | ||
| " cirq.CNOT(message, alice),\n", | ||
| " cirq.H(message),\n", | ||
| " cirq.measure(message, key='M'),\n", | ||
| " cirq.measure(alice, key='A'),\n", | ||
| " # Uses the two classical bits from the Bell measurement to recover the\n", | ||
| " # original quantum message on Bob's entangled qubit.\n", | ||
| " cirq.X(bob).with_classical_controls('A'),\n", | ||
| " cirq.Z(bob).with_classical_controls('M'),\n", | ||
| ")\n", | ||
| "print(circuit)" | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "markdown", | ||
| "metadata": { | ||
| "id": "3c64d94110ba" | ||
| }, | ||
| "source": [ | ||
| "## Sympy conditions\n", | ||
| "\n", | ||
| "Cirq also supports more complex control conditions: providing some `sympy` expression `\"expr\"` to `with_classical_controls` creates a `ClassicallyControlledOperation` with a `SympyCondition`. That condition will only trigger if `\"expr\"` evaluates to a \"truthy\" value (`bool(expr) == True`), and uses measurement results to resolve any variables in the expression.\n", | ||
| "\n", | ||
| "In this example, `X` will only be applied to `q2` if `a == b`; in other words, $|q_0q_1\\rangle$ must be either $|00\\rangle$ or $|11\\rangle$." | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "code", | ||
| "execution_count": null, | ||
| "metadata": { | ||
| "id": "9a7ff41b51c0" | ||
| }, | ||
| "outputs": [], | ||
| "source": [ | ||
| "import sympy\n", | ||
| "\n", | ||
| "a, b, c = sympy.symbols('a b c')\n", | ||
| "sympy_cond = sympy.Eq(a, b)\n", | ||
| "circuit = cirq.Circuit(\n", | ||
| " cirq.H.on_each(q0, q1),\n", | ||
| " cirq.measure(q0, key='a'),\n", | ||
| " cirq.measure(q1, key='b'),\n", | ||
| " cirq.X(q2).with_classical_controls(sympy_cond)\n", | ||
| ")\n", | ||
| "print(circuit)" | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "markdown", | ||
| "metadata": { | ||
| "id": "dfb58a6f479c" | ||
| }, | ||
| "source": [ | ||
| "## Combining conditions\n", | ||
| "\n", | ||
| "Multiple conditions of either type can be specified to `with_classical_controls`, in which case the resulting `ClassicallyControlledOperation` will only trigger if _all_ conditions trigger. Similarly, calling `with_classical_controls` on an existing `ClassicallyControlledOperation` will require all new and pre-existing conditions to trigger for the operation to trigger." | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "code", | ||
| "execution_count": null, | ||
| "metadata": { | ||
| "id": "8be2002669fc" | ||
| }, | ||
| "outputs": [], | ||
| "source": [ | ||
| "sympy_cond = sympy.Eq(a, 0)\n", | ||
| "circuit = cirq.Circuit(\n", | ||
| " cirq.H.on_each(q0, q1, q2),\n", | ||
| " cirq.measure(q0, q1, key='a'),\n", | ||
| " cirq.measure(q2, key='b'),\n", | ||
| " cirq.X(q0).with_classical_controls('b', sympy_cond),\n", | ||
| " cirq.CZ(q1, q2).with_classical_controls('b').with_classical_controls(sympy_cond),\n", | ||
| ")\n", | ||
| "print(circuit)" | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "markdown", | ||
| "metadata": { | ||
| "id": "34d0fe9226e1" | ||
| }, | ||
| "source": [ | ||
| "## Variable scope\n", | ||
| "\n", | ||
| "When used with `CircuitOperation`, classically controlled operations will be resolved using local repetition IDs, if any. This is the only way to create a non-global variable scope within a circuit. A simple example of this is shown below, where the controls inside and outside a subcircuit rely on measurements in their respective scopes:" | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "code", | ||
| "execution_count": null, | ||
| "metadata": { | ||
| "id": "6a7441827bd6" | ||
| }, | ||
| "outputs": [], | ||
| "source": [ | ||
| "subcircuit = cirq.FrozenCircuit(\n", | ||
| " cirq.measure(q0, key='a'), cirq.X(q0).with_classical_controls('a')\n", | ||
| ")\n", | ||
| "circuit = cirq.Circuit(\n", | ||
| " cirq.measure(q0, key='a'),\n", | ||
| " cirq.CircuitOperation(subcircuit, repetitions=2),\n", | ||
| " cirq.X(q0).with_classical_controls('a')\n", | ||
| ")\n", | ||
| "print(circuit)" | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "markdown", | ||
| "metadata": { | ||
| "id": "b0807e8edb7f" | ||
| }, | ||
| "source": [ | ||
| "More complex scoping behavior is described in the [classically controlled operation tests](https://github.com/quantumlib/Cirq/blob/master/cirq-core/cirq/ops/classically_controlled_operation_test.py)." | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "markdown", | ||
| "metadata": { | ||
| "id": "520a5bbbea93" | ||
| }, | ||
| "source": [ | ||
| "## Using with transformers\n", | ||
| "\n", | ||
| "Cirq [transformers](transformers.ipynb) are aware of classical control and will avoid changes which move a control before its corresponding measurement. Additionally, for some simple cases the [`defer_measurements` transformer](https://github.com/daxfohl/Cirq/blob/e68ff85e9bb0c7373572cdc212c10f226cd40b0f/cirq-core/cirq/transformers/measurement_transformers.py#L58) can convert a classically-controlled circuit into a purely-quantum circuit:" | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "code", | ||
| "execution_count": null, | ||
| "metadata": { | ||
| "id": "e7bda8edb27a" | ||
| }, | ||
| "outputs": [], | ||
| "source": [ | ||
| "circuit = cirq.Circuit(\n", | ||
| " cirq.measure(q0, key='a'),\n", | ||
| " cirq.X(q1).with_classical_controls('a'),\n", | ||
| " cirq.measure(q1, key='b'),\n", | ||
| ")\n", | ||
| "deferred = cirq.defer_measurements(circuit)\n", | ||
| "print(\"Original circuit:\")\n", | ||
| "print(circuit)\n", | ||
| "print(\"Measurement deferred:\")\n", | ||
| "print(deferred)" | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "markdown", | ||
| "metadata": { | ||
| "id": "48666318febe" | ||
| }, | ||
| "source": [ | ||
| "## Compatibility\n", | ||
| "\n", | ||
| "The Cirq built-in simulators provide support for classical control, but caution should be exercised when exporting these circuits to other environments. `ClassicallyControlledOperation` is fundamentally different from other operations in that it requires access to the measurement results, and simulators or hardware that does not explicitly support this will not be able to run `ClassicallyControlledOperation`s." | ||
| ] | ||
| } | ||
| ], | ||
| "metadata": { | ||
| "colab": { | ||
| "name": "classical_control.ipynb", | ||
| "toc_visible": true | ||
| }, | ||
| "kernelspec": { | ||
| "display_name": "Python 3", | ||
| "name": "python3" | ||
| } | ||
| }, | ||
| "nbformat": 4, | ||
| "nbformat_minor": 0 | ||
| } | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.