From 56d8cbc506f1a4f91f96e8c91d3fa77232b435c9 Mon Sep 17 00:00:00 2001 From: Orion Martin <40585662+95-martin-orion@users.noreply.github.com> Date: Wed, 25 May 2022 15:52:27 -0700 Subject: [PATCH 1/5] CControl docs, first pass --- cirq-core/cirq/ops/raw_types.py | 8 +- docs/classical_control.ipynb | 205 ++++++++++++++++++++++++++++++++ 2 files changed, 210 insertions(+), 3 deletions(-) create mode 100644 docs/classical_control.ipynb diff --git a/cirq-core/cirq/ops/raw_types.py b/cirq-core/cirq/ops/raw_types.py index d64c1fe923e..dd51abfdfa5 100644 --- a/cirq-core/cirq/ops/raw_types.py +++ b/cirq-core/cirq/ops/raw_types.py @@ -626,9 +626,11 @@ def with_classical_controls( """Returns a classically controlled version of this operation. An operation that is classically controlled is executed iff all - conditions evaluate to True. Currently the only condition type is a - measurement key. A measurement key evaluates to True iff any qubit in - the corresponding measurement operation evaluated to a non-zero value. + conditions evaluate to True. Conditions can be either a measurement key + or a user-specified `cirq.Condition`. A measurement key evaluates to + True iff any qubit in the corresponding measurement operation evaluated + to a non-zero value; `cirq.Condition` supports more complex, + user-defined conditions. If no conditions are specified, returns self. diff --git a/docs/classical_control.ipynb b/docs/classical_control.ipynb new file mode 100644 index 00000000000..6acc30a21cf --- /dev/null +++ b/docs/classical_control.ipynb @@ -0,0 +1,205 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "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": {}, + "source": [ + "# Classical control" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " View on QuantumAI\n", + " \n", + " Run in Google Colab\n", + " \n", + " View source on GitHub\n", + " \n", + " Download notebook\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "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": {}, + "source": [ + "While some quantum algorithms can be defined entirely at the quantum level, there are many others (notably including teleportation and error correction) 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": {}, + "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 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": {}, + "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": {}, + "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 $|10\\rangle$ or $|01\\rangle$." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "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": {}, + "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": {}, + "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": {}, + "source": [ + "## Variable scope\n", + "\n", + "When used with `CircuitOperation`, classically controlled operations will be resolved using local repetition IDs, if any. 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": {}, + "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": {}, + "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": {}, + "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": { + "language_info": { + "name": "python" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} From b76254105b51cabfca2289089ca8bad25ec02975 Mon Sep 17 00:00:00 2001 From: Orion Martin <40585662+95-martin-orion@users.noreply.github.com> Date: Wed, 25 May 2022 15:54:36 -0700 Subject: [PATCH 2/5] nbformat --- docs/classical_control.ipynb | 72 ++++++++++++++++++++++++++---------- 1 file changed, 53 insertions(+), 19 deletions(-) diff --git a/docs/classical_control.ipynb b/docs/classical_control.ipynb index 6acc30a21cf..c852201c8f8 100644 --- a/docs/classical_control.ipynb +++ b/docs/classical_control.ipynb @@ -3,7 +3,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "b952a1c0faad" + }, "outputs": [], "source": [ "#@title Copyright 2022 The Cirq Developers\n", @@ -22,14 +24,18 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "3556e78efd03" + }, "source": [ "# Classical control" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "925dbb45c75e" + }, "source": [ "\n", "
\n", @@ -50,7 +56,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "d4c447ddd24e" + }, "outputs": [], "source": [ "try:\n", @@ -64,7 +72,9 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "8ccb64c25e3a" + }, "source": [ "While some quantum algorithms can be defined entirely at the quantum level, there are many others (notably including teleportation and error correction) which rely on classical measurement results from one part of the algorithm to control operations in a later section.\n", "\n", @@ -73,7 +83,9 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "b3ed39be4c06" + }, "source": [ "## Basic conditions\n", "\n", @@ -83,7 +95,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "df3dd6e3b308" + }, "outputs": [], "source": [ "q0, q1, q2 = cirq.LineQubit.range(3)\n", @@ -97,7 +111,9 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "3c64d94110ba" + }, "source": [ "## Sympy conditions\n", "\n", @@ -109,7 +125,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "9a7ff41b51c0" + }, "outputs": [], "source": [ "import sympy\n", @@ -127,7 +145,9 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "dfb58a6f479c" + }, "source": [ "## Combining conditions\n", "\n", @@ -137,7 +157,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "8be2002669fc" + }, "outputs": [], "source": [ "sympy_cond = sympy.Eq(a, 0)\n", @@ -153,7 +175,9 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "34d0fe9226e1" + }, "source": [ "## Variable scope\n", "\n", @@ -163,7 +187,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "6a7441827bd6" + }, "outputs": [], "source": [ "subcircuit = cirq.FrozenCircuit(\n", @@ -179,14 +205,18 @@ }, { "cell_type": "markdown", - "metadata": {}, + "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": {}, + "metadata": { + "id": "48666318febe" + }, "source": [ "## Compatibility\n", "\n", @@ -195,11 +225,15 @@ } ], "metadata": { - "language_info": { - "name": "python" + "colab": { + "name": "classical_control.ipynb", + "toc_visible": true }, - "orig_nbformat": 4 + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 0 } From 9e1ff0c79c3aed6510b6da5e106c08b0547bcaf4 Mon Sep 17 00:00:00 2001 From: Orion Martin <40585662+95-martin-orion@users.noreply.github.com> Date: Thu, 26 May 2022 10:05:29 -0700 Subject: [PATCH 3/5] Defer and teleport --- docs/classical_control.ipynb | 72 ++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/docs/classical_control.ipynb b/docs/classical_control.ipynb index c852201c8f8..16b2ee5eacc 100644 --- a/docs/classical_control.ipynb +++ b/docs/classical_control.ipynb @@ -109,6 +109,47 @@ "print(circuit)" ] }, + { + "cell_type": "markdown", + "metadata": { + "id": "4e416431b695" + }, + "source": [ + "Using just these conditions, we can construct the 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": { @@ -212,6 +253,37 @@ "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 generally 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": { From 2cae4b15b448fd474d16c2725409821430bb1f1c Mon Sep 17 00:00:00 2001 From: Orion Martin <40585662+95-martin-orion@users.noreply.github.com> Date: Tue, 31 May 2022 11:55:08 -0700 Subject: [PATCH 4/5] Review comments. --- docs/classical_control.ipynb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/classical_control.ipynb b/docs/classical_control.ipynb index 16b2ee5eacc..ba118922540 100644 --- a/docs/classical_control.ipynb +++ b/docs/classical_control.ipynb @@ -76,7 +76,7 @@ "id": "8ccb64c25e3a" }, "source": [ - "While some quantum algorithms can be defined entirely at the quantum level, there are many others (notably including teleportation and error correction) which rely on classical measurement results from one part of the algorithm to control operations in a later section.\n", + "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)." ] @@ -89,7 +89,7 @@ "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 if a preceding measurement with the same key measured one or more qubits in the $|1\\rangle$ state." + "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." ] }, { @@ -115,7 +115,7 @@ "id": "4e416431b695" }, "source": [ - "Using just these conditions, we can construct the quantum teleportation circuit:" + "Using just these conditions, we can construct the [quantum teleportation](/cirq/tutorials/educators/textbook_algorithms#quantum_teleportation) circuit:" ] }, { @@ -160,7 +160,7 @@ "\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 $|10\\rangle$ or $|01\\rangle$." + "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$." ] }, { @@ -222,7 +222,7 @@ "source": [ "## Variable scope\n", "\n", - "When used with `CircuitOperation`, classically controlled operations will be resolved using local repetition IDs, if any. A simple example of this is shown below, where the controls inside and outside a subcircuit rely on measurements in their respective scopes:" + "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:" ] }, { From ccb3a254af19860eeaceb18024712d8e1c17d339 Mon Sep 17 00:00:00 2001 From: Orion Martin <40585662+95-martin-orion@users.noreply.github.com> Date: Tue, 31 May 2022 13:27:16 -0700 Subject: [PATCH 5/5] minus generally --- docs/classical_control.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/classical_control.ipynb b/docs/classical_control.ipynb index ba118922540..bdfefbaabc9 100644 --- a/docs/classical_control.ipynb +++ b/docs/classical_control.ipynb @@ -261,7 +261,7 @@ "source": [ "## Using with transformers\n", "\n", - "Cirq [transformers](transformers.ipynb) are aware of classical control and will generally 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:" + "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:" ] }, {