Skip to content
Merged
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
8 changes: 5 additions & 3 deletions cirq-core/cirq/ops/raw_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
311 changes: 311 additions & 0 deletions docs/classical_control.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,311 @@
{
"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
}