From 85b5dd15bc6dcda5c14fca22808e094366a76cf7 Mon Sep 17 00:00:00 2001 From: Auguste Hirth Date: Thu, 14 Jul 2022 14:24:08 -0700 Subject: [PATCH 01/11] Add QVM pages and mentions in other pages --- docs/_book.yaml | 14 + docs/build/circuits.ipynb | 13 +- docs/hardware/_index.yaml | 6 + docs/hardware/devices.ipynb | 13 + docs/hardware/qubit_picking.ipynb | 355 ++++++++++ docs/simulate/_index.yaml | 20 + docs/simulate/noisy_simulation.ipynb | 111 ++-- docs/simulate/quantum_virtual_machine.ipynb | 276 ++++++++ docs/simulate/qvm_basic_example.ipynb | 432 +++++++++++++ docs/simulate/qvm_builder_code.ipynb | 224 +++++++ docs/simulate/qvm_stabilizer_example.ipynb | 648 +++++++++++++++++++ docs/simulate/simulation.ipynb | 4 +- docs/simulate/virtual_engine_interface.ipynb | 481 ++++++++++++++ docs/start/basics.ipynb | 19 + docs/start/intro.ipynb | 14 + docs/start/start.ipynb | 16 +- 16 files changed, 2586 insertions(+), 60 deletions(-) create mode 100644 docs/hardware/qubit_picking.ipynb create mode 100644 docs/simulate/quantum_virtual_machine.ipynb create mode 100644 docs/simulate/qvm_basic_example.ipynb create mode 100644 docs/simulate/qvm_builder_code.ipynb create mode 100644 docs/simulate/qvm_stabilizer_example.ipynb create mode 100644 docs/simulate/virtual_engine_interface.ipynb diff --git a/docs/_book.yaml b/docs/_book.yaml index 00c21a81767..368943f918d 100644 --- a/docs/_book.yaml +++ b/docs/_book.yaml @@ -84,6 +84,18 @@ upper_tabs: path: /cirq/simulate/params - title: "State Histograms" path: /cirq/simulate/state_histograms + - heading: "Quantum Virtual Machine" + - title: "Quantum Virtual Machine" + path: /cirq/simulate/quantum_virtual_machine + - title: "QVM Creation Template" + path: /cirq/simulate/qvm_builder_code + - title: "QVM Basic Example" + path: /cirq/simulate/qvm_basic_example + - title: "QVM Stabilizer Example" + path: /cirq/simulate/qvm_stabilizer_example + - title: "Virtual Engine Interface" + path: /cirq/simulate/virtual_engine_interface + - name: "Transform" contents: @@ -100,6 +112,8 @@ upper_tabs: path: /cirq/hardware - title: "Devices" path: /cirq/hardware/devices + - title: "Qubit Picking" + path: /cirq/hardware/qubit_picking #### AQT #### - heading: "AQT hardware" diff --git a/docs/build/circuits.ipynb b/docs/build/circuits.ipynb index 8d2fcfdf2ba..1d6c19a60dd 100644 --- a/docs/build/circuits.ipynb +++ b/docs/build/circuits.ipynb @@ -1,5 +1,14 @@ { "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "DkA0Fobtb9dM" + }, + "source": [ + "##### Copyright 2022 The Cirq Developers" + ] + }, { "cell_type": "code", "execution_count": null, @@ -9,8 +18,7 @@ }, "outputs": [], "source": [ - "# @title Copyright 2020 The Cirq Developers\n", - "# Licensed under the Apache License, Version 2.0 (the \"License\");\n", + "# @title 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", @@ -757,6 +765,7 @@ "\n", "Once you've built your circuit, read these to learn what you can do with it: \n", "- [Simulation](/cirq/simulate/simulation.ipynb) - run your circuit on the Cirq simulator to see what it does\n", + "- [Quantum Virtual Machine](/cirq/simulate/quantum_virtual_machine) - run your circuit on a specialized simulator that mimics actual quantum hardware, including noise.\n", "- [Transform circuits](/cirq/transform/transformers.ipynb) - run transformer functions to change your circuit in different ways\n", "\n", "If you need to import or export circuits into or out of Cirq, see: \n", diff --git a/docs/hardware/_index.yaml b/docs/hardware/_index.yaml index 47182dfc1b9..517cfe45cb2 100644 --- a/docs/hardware/_index.yaml +++ b/docs/hardware/_index.yaml @@ -15,6 +15,12 @@ landing_page: - heading: Run a circuit on a hardware device description: Cirq provides interfaces for running your circuits on quantum hardware provided by many different services. + options: + - cards + items: + - heading: Qubit Picking + description: Information to help you pick good qubits for running your circuit on a hardware or hardware-like device. + path: /cirq/hardware/qubit_picking - heading: AQT hardware description: Cirq's interface with Alpine Quantum Technologies hardware. diff --git a/docs/hardware/devices.ipynb b/docs/hardware/devices.ipynb index 2629fc2ea26..12a6066ca01 100644 --- a/docs/hardware/devices.ipynb +++ b/docs/hardware/devices.ipynb @@ -466,6 +466,19 @@ "nx.draw(my_metadata.nx_graph)" ] }, + { + "cell_type": "markdown", + "metadata": { + "id": "ddabb2b0bcc3" + }, + "source": [ + "## Use in a virtual Engine\n", + "\n", + "`Device`s can also be used to specify `cirq.SimulatedLocalEngine` instances, which let you validate and simulate circuits using the same interface that the quantum hardware does. Read more in the [Virtual Engine Interface](/cirq/simulate/virtual_engine_interface) page. \n", + "\n", + "Additionally, these virtual `Engine`s can be combined with noisy simulation that attempts to mimic existing hardware devices with the [Quantum Virtual Machine](/cirq/simulate/quantum_virtual_machine). " + ] + }, { "cell_type": "markdown", "metadata": { diff --git a/docs/hardware/qubit_picking.ipynb b/docs/hardware/qubit_picking.ipynb new file mode 100644 index 00000000000..49ee0212ae4 --- /dev/null +++ b/docs/hardware/qubit_picking.ipynb @@ -0,0 +1,355 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "DkA0Fobtb9dM" + }, + "source": [ + "##### Copyright 2022 The Cirq Developers" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "tUshu7YfcAAW" + }, + "outputs": [], + "source": [ + "# @title 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": "RIbn0pYo2E-Q" + }, + "source": [ + "# Qubit Picking" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "4j6Gq31OtDDk" + }, + "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": "markdown", + "metadata": { + "id": "f53d26973380" + }, + "source": [ + "When running a circuit on a noisy quantum hardware device, the choice and even ordering of hardware qubits used directly affects how reliably the device measures a correct result. This notebook covers some of the available qubit error information that can be useful for picking good hardware qubits to run your circuit on." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "pBl-1eHNHXS8" + }, + "outputs": [], + "source": [ + "# @title Setup\n", + "try:\n", + " import cirq\n", + "except ImportError:\n", + " print(\"installing cirq...\")\n", + " !pip install --quiet cirq\n", + " print(\"installed cirq.\")\n", + " import cirq\n", + "\n", + "import cirq_google\n", + "import numpy as np\n", + "from matplotlib import pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Q6YMeWnvDaMu" + }, + "source": [ + "## State of qubit selection in Cirq\n", + "\n", + "Cirq assumes that circuits you intend to run on quantum hardware (virtual or otherwise) are able to be placed on the device, and assumes that you are able to perform placement by hand. The information in this notebook serves to help you identify which qubits are the best to use, but it is up to you to map the qubits in your circuit to the \"good\" qubits available on the device.\n", + "\n", + "## Error characterization data\n", + "\n", + "Cirq provides characterization error data that is intended to represent median performance of actual Google quantum hardware as accurately as possible. The primary use of this data is for creating a `cirq.NoiseModel` for use in a [Quantum Virtual Machine](/cirq/simulate/quantum_virtual_machine), but it also provides information on what qubits are the best to use for your circuit. \n", + "\n", + "The following code demonstrates how to load that noise data as a `cirq_google.devices.GoogleNoiseProperties` object, which specifies the available data." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "hKfu5yVi2Ebs" + }, + "outputs": [], + "source": [ + "processor_id = \"rainbow\"\n", + "cal = cirq_google.engine.load_median_device_calibration(processor_id)\n", + "noise_props = cirq_google.noise_properties_from_calibration(cal)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "YS1j_WzgpumG" + }, + "source": [ + "### One qubit gate Pauli error data\n", + "\n", + "Pauli error defines decoherence of a single qubit in one of the Pauli [channels](/cirq/representing_noise) X, Y, or Z. If the errors are distributed in the uniform distribution over all three axes, the probability of applying an erroneous Pauli gate X, Y, or Z will be the Pauli error divided by three. See page 11 of [this Supplementary Information document](https://arxiv.org/abs/1910.11333){:.external} for more on Pauli error. \n", + "\n", + "Below is the single qubit Pauli error for the `cirq.PhasedXZGate` supported by the Rainbow processor, pulled from the `gate_pauli_errors` attribute of the noise properties object. You can inspect the error for the others as well. However, as of July 19th, 2022, the error estimation process results in identical Pauli error for all one-qubit gates." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "E70fyCU7puGr" + }, + "outputs": [], + "source": [ + "print(f\"One qubit error data: gate_pauli_errors\")\n", + "print(f\"Supported Gates: {noise_props.single_qubit_gates()}\")\n", + "fig, ax = plt.subplots(figsize=(10, 10))\n", + "gate = cirq.PhasedXZGate\n", + "measures = {\n", + " op_id.qubits: pauli_error\n", + " for op_id, pauli_error in noise_props.gate_pauli_errors.items()\n", + " if op_id.gate_type == gate\n", + "}\n", + "ax.set_title(f\"{gate.__name__} Pauli error\")\n", + "_ = cirq.Heatmap(measures).plot(ax)\n", + "fig.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "YZVP6TI8uIeL" + }, + "source": [ + "The provided error data shows identical Pauli error for all gate types, with relatively higher error for qubits `(4,1)` and `(7,6)`. Qubit `(7,2)` is noticeably lower error than the others, and could be prioritized to be mapped to a circuit qubit that executes many single-qubit operations. However, this is only one type of error; you should inspect the other error types before committing to use any particular qubits." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "_J58phZlVm9L" + }, + "source": [ + "### Two qubit gate Pauli error data\n", + "\n", + "The two qubit gates also cause Pauli decoherence, which is also stored in the `gate_pauli_errors` attribute. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Q4SNArjfMkB4" + }, + "outputs": [], + "source": [ + "two_qubit_gates = noise_props.two_qubit_gates()\n", + "print(f\"Two qubit error data: gate_pauli_errors\")\n", + "fig, axes = plt.subplots(1, 2, figsize=(20, 10))\n", + "axes = iter(axes)\n", + "for gate in two_qubit_gates:\n", + " measures = {\n", + " op_id.qubits: pauli_error\n", + " for op_id, pauli_error in noise_props.gate_pauli_errors.items()\n", + " if op_id.gate_type == gate\n", + " }\n", + " if measures:\n", + " ax = next(axes)\n", + " ax.set_title(f\"{gate.__name__} Pauli error\")\n", + " _ = cirq.TwoQubitInteractionHeatmap(measures).plot(ax)\n", + "\n", + "fig.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "pQtxZBXYt1P5" + }, + "source": [ + "This Pauli data informs that the qubit pairs `(6,2)-(7,2)` and `(7,2)-(7,3)` should be avoided at all costs, but the other qubits are roughly comparable." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "s8DEXJdKW38f" + }, + "source": [ + "### Two qubit gate FSim error\n", + "\n", + "FSim error represents [coherent](cirq/representing_noise#channels) two-qubit error that cannot be represented by Pauli channels (that is, it results from entanglement). Instead, it is represented as an additional `cirq.PhasedFSimGate` with small parameters that would be applied to a given qubit pair after any two-qubit gate's execution.\n", + "\n", + "The following example takes the norm of a couple of the parameters, as a rough approximate representation of the goodness of qubit pairs relative to one another. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "e1MXeJaKW3j0" + }, + "outputs": [], + "source": [ + "print(f\"Two qubit error data: fsim_errors\")\n", + "two_qubit_gates = noise_props.two_qubit_gates()\n", + "fig, axes = plt.subplots(1, 2, figsize=(20, 10))\n", + "axes = iter(axes)\n", + "for gate in two_qubit_gates:\n", + " measures = {\n", + " op_id.qubits: fsim_refit_gate\n", + " for op_id, fsim_refit_gate in noise_props.fsim_errors.items()\n", + " if op_id.gate_type == gate\n", + " }\n", + " if measures:\n", + " ax = next(axes)\n", + " # Norm the Fsim refit gate parameters as an approximate of how good a qubit is.\n", + " measures = {\n", + " qubits: np.linalg.norm([fsim_refit_gate.theta, fsim_refit_gate.phi])\n", + " for qubits, fsim_refit_gate in measures.items()\n", + " }\n", + " ax.set_title(f\"{gate.__name__} Pauli error\")\n", + " _ = cirq.TwoQubitInteractionHeatmap(measures).plot(ax)\n", + "\n", + "fig.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "0SKqbogVtSFs" + }, + "source": [ + "This fsim data would influence you to avoid the `(6,2)-(7,2)` qubit pair, and prefer the top left of the grid for high-priority qubit pairs (those that have two-qubit gates executed on them many times in your circuit). Additionally, the fact that the `cirq.SycamoreGate` error is so much lower than the `cirq.ISwapPowGate` error means the device was likely calibrated for the `SycamoreGate`, and you should [transform](/cirq/transform/transformers) your circuit with `cirq.optimize_for_target_gateset` to the `cirq_google.transformers.SycamoreTargetGateset` gate set, if possible.\n", + "\n", + "This particular type of error can be compensated for somewhat, by using [Floquet calibration](/cirq/noise/floquet_calibration_example), but this is out of scope for this notebook, and may require adaptation to work with the provided processor error data." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "BfJharjIarJb" + }, + "source": [ + "### Readout error\n", + "\n", + "Readout error manifests as a measurement of $|1\\rangle$ when it should have been $|0\\rangle$, or vice versa. Note that this is different from the Pauli error induced by the `cirq.MeasurementGate`. It's important to note that, while the magnitude of measurement error is higher in general than that of Pauli error, it should be not automatically be considered to be more impactful. This is due to the fact that Pauli error can affect qubits other than the measured one and that effective readout error compensation strategies exist (that won't be discussed here)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "nSDwjnLebmVb" + }, + "outputs": [], + "source": [ + "print(f\"One qubit error data: readout_errors\")\n", + "fig, axes = plt.subplots(1, 2, figsize=(20, 10))\n", + "for i, ax, title in zip(\n", + " range(2), axes.flat, [\"True |0> measured as |1>\", \"True |1> measured as |0>\"]\n", + "):\n", + " measures = {\n", + " qubit: readout_error[i] for qubit, readout_error in noise_props.readout_errors.items()\n", + " }\n", + " ax.set_title(title)\n", + " _ = cirq.Heatmap(measures).plot(ax, vmax=0.4, vmin=0)\n", + "fig.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "CipARD58sq_d" + }, + "source": [ + "This readout data indicates that you definitely want to avoid qubit `(7,2)`. If you're really trying to eke out the best performance possible, you may want to avoid qubits `(5,2)` and `(5,3)` as well. Note how the \"True $|1\\rangle$ measured as $|0\\rangle$\" error representing common decay is far larger and more impactful than the random excitation of $|0\\rangle$ to $|1\\rangle$ error. This is typical behavior and outside of exceptional circumstances, you can safely prioritize working around common decay error instead of random excitation error." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "WLfGbpVIune1" + }, + "source": [ + "## Overall qubit picking strategy\n", + "\n", + "Even though the single Pauli qubit data preferred qubit `(7,2)`, the coupled pairs attached to that qubit have abysmal error rates, meaning it should be avoided at all costs. Qubit `(4,1)` has some interesting properties in that its two-qubit gates are quite good, and so is its readout, but not its single-qubit Pauli error. It may be useful to use this qubit in an entangled system where only the other qubits have single-qubit gates applied to them. All of the other gates are roughly comparable based on these error rates. Ultimately, the choice of which hardware qubits have which circuit operations applied to them is up to your discretion." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "JwGtMdoxc-fu" + }, + "source": [ + "# Summary\n", + "\n", + "Cirq provides the following error types which serve to represent an actual Google quantum hardware device as accurately as currently possible: \n", + "- One- and two-qubit Pauli error for each `cirq.Gate` supported by the device\n", + "- Two-qubit Fsim error for each supported two-qubit gate that models non-Pauli error. \n", + "- Readout error for each qubit that models error in measurements.\n", + "\n", + "While often used to create [QVM](/cirq/simulate/quantum_virtual_machine)s, this data is also useful in the process of finding good qubits to use. By avoiding high error qubits whenever possible, you can maximize the reliability of your circuit. \n", + "\n", + "If you're working with an actual device that may experience drift, or a change in behavior over time, you may need to use more advanced noise compensation strategies, which you can read about in the [Noise](/cirq/noise) category." + ] + } + ], + "metadata": { + "colab": { + "name": "qubit_picking.ipynb", + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/docs/simulate/_index.yaml b/docs/simulate/_index.yaml index 27bd97b49af..06fbd2ef9a4 100644 --- a/docs/simulate/_index.yaml +++ b/docs/simulate/_index.yaml @@ -21,3 +21,23 @@ landing_page: - heading: State Histograms description: Visualize the results of simulation as a histogram over basis states. path: /cirq/simulate/state_histograms + - heading: Quantum Virtual Machine + description: Run circuits on a virtual version of quantum hardware, complete with an identical interface and noisy simulation that mimics hardware devices. + options: + - cards + items: + - heading: Quantum Virtual Machine + description: Build and use a QVM with a virtual Engine and realistic noise model. + path: /cirq/simulate/quantum_virtual_machine + - heading: QVM Circuit Preparation + description: Prepare and run a circuit on a QVM in detail. + path: /cirq/simulate/qvm_basic_example + - heading: QVM Stabilizer Example + description: Run a stabilizer circuit on QVMs representing different devices and different noise. + path: /cirq/simulate/qvm_stabilizer_example + - heading: QVM Creation Template + description: Run a device-ready circuit on a QVM with default settings. + path: /cirq/simulate/qvm_builder_code + - heading: Virtual Engine Interface + description: A virtual version of the Engine interface used with hardware. + path: /cirq/simulate/virtual_engine_interface diff --git a/docs/simulate/noisy_simulation.ipynb b/docs/simulate/noisy_simulation.ipynb index 9c99d2fc7a1..2c8601b442b 100644 --- a/docs/simulate/noisy_simulation.ipynb +++ b/docs/simulate/noisy_simulation.ipynb @@ -3,10 +3,10 @@ { "cell_type": "markdown", "metadata": { - "id": "LnV7yIFGeryz" + "id": "DkA0Fobtb9dM" }, "source": [ - "##### Copyright 2020 The Cirq Developers" + "##### Copyright 2022 The Cirq Developers" ] }, { @@ -14,11 +14,11 @@ "execution_count": null, "metadata": { "cellView": "form", - "id": "1kkohf-9esQm" + "id": "tUshu7YfcAAW" }, "outputs": [], "source": [ - "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", + "# @title 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", @@ -37,7 +37,7 @@ "id": "7zgataJVe0mU" }, "source": [ - "# Noise" + "# Noisy Simulation" ] }, { @@ -183,9 +183,7 @@ "print(f\"Bit flip channel acts on {nqubits} qubit(s).\\n\")\n", "\n", "# Apply the channel to each qubit in a circuit.\n", - "circuit = cirq.Circuit(\n", - " bit_flip.on_each(cirq.LineQubit.range(3))\n", - ")\n", + "circuit = cirq.Circuit(bit_flip.on_each(cirq.LineQubit.range(3)))\n", "print(circuit)" ] }, @@ -211,9 +209,7 @@ "controlled_bit_flip = bit_flip.controlled(num_controls=1)\n", "\n", "# Use it in a circuit.\n", - "circuit = cirq.Circuit(\n", - " controlled_bit_flip(*cirq.LineQubit.range(2))\n", - ")\n", + "circuit = cirq.Circuit(controlled_bit_flip(*cirq.LineQubit.range(2)))\n", "print(circuit)" ] }, @@ -264,15 +260,9 @@ "outputs": [], "source": [ "\"\"\"Get an asymmetric depolarizing channel.\"\"\"\n", - "depo = cirq.asymmetric_depolarize(\n", - " p_x=0.10,\n", - " p_y=0.05,\n", - " p_z=0.15,\n", - ")\n", + "depo = cirq.asymmetric_depolarize(p_x=0.10, p_y=0.05, p_z=0.15)\n", "\n", - "circuit = cirq.Circuit(\n", - " depo.on_each(cirq.LineQubit(0))\n", - ")\n", + "circuit = cirq.Circuit(depo(cirq.LineQubit(0)))\n", "print(circuit)" ] }, @@ -419,6 +409,7 @@ "outputs": [], "source": [ "import numpy as np\n", + "\n", "q0 = cirq.LineQubit(0)\n", "# This is equivalent to a bit-flip error with probability 0.1.\n", "mix = [\n", @@ -428,18 +419,11 @@ "bit_flip_mix = cirq.MixedUnitaryChannel(mix)\n", "\n", "# This is equivalent to an X-basis measurement.\n", - "ops = [\n", - " np.array([[1, 1], [1, 1]]) * 0.5,\n", - " np.array([[1, -1], [-1, 1]]) * 0.5,\n", - "]\n", + "ops = [np.array([[1, 1], [1, 1]]) * 0.5, np.array([[1, -1], [-1, 1]]) * 0.5]\n", "x_meas = cirq.KrausChannel(ops, key='x')\n", "\n", "# These circuits have the same behavior.\n", - "circuit = cirq.Circuit(\n", - " bit_flip_mix.on(q0),\n", - " cirq.H(q0),\n", - " x_meas.on(q0),\n", - ")\n", + "circuit = cirq.Circuit(bit_flip_mix.on(q0), cirq.H(q0), x_meas.on(q0))\n", "equiv_circuit = cirq.Circuit(\n", " cirq.bit_flip(0.1).on(q0),\n", " cirq.H(q0),\n", @@ -476,20 +460,23 @@ "outputs": [], "source": [ "\"\"\"Minimal example of defining a custom channel.\"\"\"\n", + "\n", + "\n", "class BitAndPhaseFlipChannel(cirq.Gate):\n", " def _num_qubits_(self) -> int:\n", " return 1\n", + "\n", " def __init__(self, p: float) -> None:\n", " self._p = p\n", - " \n", + "\n", " def _mixture_(self):\n", " ps = [1.0 - self._p, self._p]\n", " ops = [cirq.unitary(cirq.I), cirq.unitary(cirq.Y)]\n", " return tuple(zip(ps, ops))\n", - " \n", + "\n", " def _has_mixture_(self) -> bool:\n", " return True\n", - " \n", + "\n", " def _circuit_diagram_info_(self, args) -> str:\n", " return f\"BitAndPhaseFlip({self._p})\"" ] @@ -554,9 +541,7 @@ "outputs": [], "source": [ "\"\"\"Example of using a custom channel in a circuit.\"\"\"\n", - "circuit = cirq.Circuit(\n", - " bit_phase_flip.on_each(*cirq.LineQubit.range(3))\n", - ")\n", + "circuit = cirq.Circuit(bit_phase_flip.on_each(*cirq.LineQubit.range(3)))\n", "circuit" ] }, @@ -658,10 +643,7 @@ "\"\"\"Simulating a circuit with the density matrix simulator.\"\"\"\n", "# Get a circuit.\n", "qbit = cirq.GridQubit(0, 0)\n", - "circuit = cirq.Circuit(\n", - " cirq.X(qbit),\n", - " cirq.amplitude_damp(0.1).on(qbit)\n", - ")\n", + "circuit = cirq.Circuit(cirq.X(qbit), cirq.amplitude_damp(0.1).on(qbit))\n", "\n", "# Display it.\n", "print(\"Simulating circuit:\")\n", @@ -749,10 +731,7 @@ "outputs": [], "source": [ "\"\"\"Example of Monte Carlo wavefunction simulation with the `run` method.\"\"\"\n", - "circuit = cirq.Circuit(\n", - " cirq.bit_flip(p=0.5).on(qbit),\n", - " cirq.measure(qbit),\n", - ")\n", + "circuit = cirq.Circuit(cirq.bit_flip(p=0.5).on(qbit), cirq.measure(qbit))\n", "res = sim.run(circuit, repetitions=100)\n", "print(res.histogram(key=qbit))" ] @@ -794,9 +773,7 @@ "source": [ "\"\"\"One method to insert noise in a circuit.\"\"\"\n", "# Define some noiseless circuit.\n", - "circuit = cirq.testing.random_circuit(\n", - " qubits=3, n_moments=3, op_density=1, random_state=11\n", - ")\n", + "circuit = cirq.testing.random_circuit(qubits=3, n_moments=3, op_density=1, random_state=11)\n", "\n", "# Display the noiseless circuit.\n", "print(\"Circuit without noise:\")\n", @@ -904,10 +881,7 @@ "outputs": [], "source": [ "\"\"\"Define a density matrix simulator with a `cirq.NOISE_MODEL_LIKE` object.\"\"\"\n", - "\n", - "noisy_dsim = cirq.DensityMatrixSimulator(\n", - " noise=cirq.generalized_amplitude_damp(p=0.1, gamma=0.5)\n", - ")" + "noisy_dsim = cirq.DensityMatrixSimulator(noise=cirq.generalized_amplitude_damp(p=0.1, gamma=0.5))" ] }, { @@ -974,6 +948,45 @@ "circ.insert(0, cirq.bit_flip(p=0.1).on_each(qreg))\n", "print(circ)" ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "de5748df9323" + }, + "source": [ + "### Simulation with realistic noise\n", + "\n", + "Cirq also provides a couple `NoiseModel`s which are designed to mimic the noise behavior seen on Google quantum hardware devices. As of July 19, 2022, models that mimic the Rainbow or Weber Google quantum processors are publicly available in Cirq. You can instantiate these noise models as follows:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "2d83326239b3" + }, + "outputs": [], + "source": [ + "import cirq_google\n", + "\n", + "processor_id = \"rainbow\" # or \"weber\"\n", + "# Load the calibration data\n", + "cal = cirq_google.engine.load_median_device_calibration(processor_id)\n", + "# Turn calibration data into a noise properties object\n", + "noise_props = cirq_google.noise_properties_from_calibration(cal)\n", + "# Build a noise model from the noise properties\n", + "noise_model = cirq_google.NoiseModelFromGoogleNoiseProperties(noise_props)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "640b41a79b49" + }, + "source": [ + "While this `NoiseModel` can be used anywhere other noise models could be used, it is particularly useful in a [Quantum Virtual Machine](/cirq/simulate/quantum_virtual_machine). A QVM combines a realistic noise model and a [Device](/cirq/hardware/devices) object together and places them behind a `cirq.Engine`-style interface so that you can run circuits almost identically to how you would with a hardware device, and get results that approximate those a hardware device would produce. " + ] } ], "metadata": { diff --git a/docs/simulate/quantum_virtual_machine.ipynb b/docs/simulate/quantum_virtual_machine.ipynb new file mode 100644 index 00000000000..c894527d6ba --- /dev/null +++ b/docs/simulate/quantum_virtual_machine.ipynb @@ -0,0 +1,276 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "DkA0Fobtb9dM" + }, + "source": [ + "##### Copyright 2022 The Cirq Developers" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "tUshu7YfcAAW" + }, + "outputs": [], + "source": [ + "# @title 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": "ed597a8b13ef" + }, + "source": [ + "# Quantum Virtual Machine" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "HDiKQEXika1y" + }, + "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": "markdown", + "metadata": { + "id": "CycSD8LM2A5G" + }, + "source": [ + "The quantum virtual machine is a virtual Google quantum processor that you can run circuits on by using the [virtual engine interface](/cirq/simulate/virtual_engine_interface). Behind this interface, it uses simulation with noise data to mimic Google quantum hardware processors with high accuracy: In internal tests, the virtual and actual hardware are within experimental error of each other. Additionally, it supports internal use of the high-performance [qsim](/qsim) simulator, for fast execution of larger circuits. The QVM should be used as a preparation step before running on Google hardware, and as a substitute for Google hardware when it is not available.\n", + "\n", + "If you just want to use the QVM for realistic noisy simulation, you can copy and build upon the [QVM Creation Template](/cirq/simulate/qvm_builder_code), which provides a concise and portable way to instantiate an `Engine` class that you can realistically simulate circuit runs with. After doing so, skip forward to the [How to use a QVM](#how_to_use_a_qvm) section. If you're interested in how the QVM is prepared for use, continue on to the following section." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "p31cCK_T1ylm" + }, + "source": [ + "## Setup" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "43IpRYMY1Ynr" + }, + "outputs": [], + "source": [ + "# @title Install `cirq_google` and `qsimcirq`\n", + "\n", + "try:\n", + " import cirq\n", + " import cirq_google\n", + "except ImportError:\n", + " print(\"installing cirq...\")\n", + " !pip install --quiet cirq-google\n", + " print(\"installed cirq.\")\n", + " import cirq\n", + " import cirq_google\n", + "\n", + "try:\n", + " import qsimcirq\n", + "except ImportError:\n", + " print(\"installing qsimcirq...\")\n", + " !pip install --quiet qsimcirq\n", + " print(f\"installed qsimcirq.\")\n", + " import qsimcirq" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "TNz3r23U1c-H" + }, + "source": [ + "## How to build a QVM\n", + "\n", + "### Choose a processor to virtualize\n", + "\n", + "Currently, the necessary data is publicly accessible only for the Weber and Rainbow processors. Read more about Google's processors [here](/hardware)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "YaLtjwcFy4AC" + }, + "outputs": [], + "source": [ + "# Choose a processor (\"rainbow\" or \"weber\")\n", + "processor_id = \"weber\"" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "rD-o-Abdy_rV" + }, + "source": [ + "### Build a noisy simulator with a hardware noise model\n", + "\n", + "- Load median device noise data for the processor you have chosen. Learn more about device noise data [here](/cirq/representing_noise)\n", + "- Transform the median device noise data to a Cirq noise properties object\n", + "- Create a noise model using your noise properties\n", + "- Set up a qsim sampler which runs noisy simulations using your noise model. Learn more about noisy simulation with qsim here in the [Noisy simulation with qsim page](qsim/tutorials/noisy_qsimcirq)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ygV7yCoBy6I9" + }, + "outputs": [], + "source": [ + "# Load the median device noise calibration for your selected processor.\n", + "cal = cirq_google.engine.load_median_device_calibration(processor_id)\n", + "# Create the noise properties object.\n", + "noise_props = cirq_google.noise_properties_from_calibration(cal)\n", + "# Create a noise model from the noise properties.\n", + "noise_model = cirq_google.NoiseModelFromGoogleNoiseProperties(noise_props)\n", + "# Prepare a qsim simulator using the noise model.\n", + "sim = qsimcirq.QSimSimulator(noise=noise_model)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "5HQUregUzAMk" + }, + "source": [ + "The qsim documentation explains how simulation performance depends on choice of hardware. If you would like use a larger number of qubits on your virtual device (eg 25-32 qubits), parallelizing the simulation over multiple compute nodes is advised. You can do this using Google Cloud hardware as is described in the [qsim Multinode Tutorial](/qsim/tutorials/multinode).\n", + "\n", + "### Set up the virtual engine with a virtual processor, packaging in the noisy simulator\n", + "To ensure that the workflow for using a virtual quantum processor is the same as the workflow for using a real quantum processor, a quantum virtual engine implements the same interface as the `cirq.Engine` for used Google's quantum hardware. Learn more about Google’s quantum engine in the [Quantum Virtual Engine Interface page](/cirq/simulate/virtual_engine_interface).\n", + "- Create a device object. Learn more about the device object in Cirq here in the [Devices page](/cirq/hardware/devices)\n", + "- Create a simulated processor object for the engine to consume (`SimulatedLocalProcessor`)\n", + "- Create a virtual engine (`SimulatedLocalEngine`)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "SkhFDV7n19-4" + }, + "outputs": [], + "source": [ + "# Package the simulator and device in an Engine.\n", + "# The device object\n", + "device = cirq_google.engine.create_device_from_processor_id(processor_id)\n", + "# The simulated processor object\n", + "sim_processor = cirq_google.engine.SimulatedLocalProcessor(\n", + " processor_id=processor_id, sampler=sim, device=device, calibrations={cal.timestamp // 1000: cal}\n", + ")\n", + "# The virtual engine\n", + "sim_engine = cirq_google.engine.SimulatedLocalEngine([sim_processor])\n", + "print(\n", + " \"Your quantum virtual machine\",\n", + " processor_id,\n", + " \"is ready, here is the qubit grid:\",\n", + " \"\\n========================\\n\",\n", + ")\n", + "print(sim_engine.get_processor(processor_id).get_device())" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "3uE8x8wP2N8N" + }, + "source": [ + "## How to use a QVM\n", + "\n", + "The following code runs a circuit on your QVM by using the `run` function of a sampler from the simulated engine:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "iuyahfFd2Tgl" + }, + "outputs": [], + "source": [ + "q0 = cirq.GridQubit(4, 4)\n", + "q1 = cirq.GridQubit(4, 5)\n", + "circuit = cirq.Circuit(cirq.Z(q0), cirq.SQRT_ISWAP(q0, q1), cirq.measure([q0, q1], key=\"measure\"))\n", + "\n", + "results = sim_engine.get_sampler(processor_id).run(circuit, repetitions=3000)\n", + "\n", + "print(results.histogram(key=\"measure\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "gll88JAl2WED" + }, + "source": [ + "As in the example linked above, your circuit needs to be “device ready”. This means that: \n", + "- The gates in the circuit need to be in the set of legal gates on the device\n", + "- The circuit needs to operate on qubits available on the virtual device. \n", + "- The topology of your circuit must correspond to the topology of the device (i.e., 2-qubit gates must act on adjacent qubits).\n", + "\n", + "For a hands-on example of the steps necessary to prepare a circuit to be run on the QVM, see the [QVM Basic Example](/cirq/simulate/qvm_basic_example) page.\n", + "\n", + "The steps necessary to make a circuit device-ready are summarized here:\n", + "1. Transform your circuit to use the correct gate set with `cirq.optimize_for_target_gateset`. Read [Transformers](/cirq/transform/transformers) for more on how to modify circuits. \n", + "2. Choose qubits on the virtual device for your circuit to run on. The connectivity required by your circuit must be supported by the connectivity present in your chosen qubit set. See [Qubit Picking](/cirq/hardware/qubit_picking) for more advice.\n", + "3. Map your transformed circuit to those qubits with `cirq.Circuit`'s `transform_qubits` function. This may require some careful planning depending on your particular circuit. \n", + "\n", + "You also need to decide on the number of repetitions your circuit will be used in the trajectory simulation. This number determines how accurately the quantum virtual machine will simulate the true quantum state of your circuit. For more details on this see [this paper](https://arxiv.org/abs/2111.02396){:.external}. We recommend using 10,000+ repetitions for research simulations, and 3,000 repetitions for learning simulations. If you are just getting a feel for the tools you can set the number of repetitions lower temporarily (eg 1 to 10) to speed things up.\n" + ] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [], + "name": "quantum_virtual_machine.ipynb", + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/docs/simulate/qvm_basic_example.ipynb b/docs/simulate/qvm_basic_example.ipynb new file mode 100644 index 00000000000..a7ebff3dd3f --- /dev/null +++ b/docs/simulate/qvm_basic_example.ipynb @@ -0,0 +1,432 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "DkA0Fobtb9dM" + }, + "source": [ + "##### Copyright 2022 The Cirq Developers" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "tUshu7YfcAAW" + }, + "outputs": [], + "source": [ + "# @title 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": "4ySIERZGZN0d" + }, + "source": [ + "# QVM Basic Example" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "vGUeqO9jn1vc" + }, + "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": "markdown", + "metadata": { + "id": "cd6e59ef3edd" + }, + "source": [ + "This notebook walks through running a simple circuit on the [Quantum Virtual Machine](/cirq/simulate/quantum_virtual_machine), including the necessary constraints on a device-runnable circuit and how to satisfy them. " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Lfira0gPf0Gd" + }, + "source": [ + "## **Install** Cirq and qsim" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "zs5J6wAXqvtW" + }, + "outputs": [], + "source": [ + "# @title Install `cirq_google` and `qsimcirq`\n", + "\n", + "try:\n", + " import cirq\n", + " import cirq_google\n", + "except ImportError:\n", + " print(\"installing cirq...\")\n", + " !pip install --quiet cirq-google\n", + " print(\"installed cirq.\")\n", + " import cirq\n", + " import cirq_google\n", + "\n", + "try:\n", + " import qsimcirq\n", + "except ImportError:\n", + " print(\"installing qsimcirq...\")\n", + " !pip install --quiet qsimcirq\n", + " print(f\"installed qsimcirq.\")\n", + " import qsimcirq\n", + "\n", + "# Other modules used in this colab\n", + "import matplotlib.pyplot as plt\n", + "import time" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "p2JAfQa8gVSe" + }, + "source": [ + "## Create a **Quantum Virtual Machine**\n", + "\n", + "The following cell builds a Quantum Virtual Machine that mimics a particular Google quantum hardware device (currently Rainbow or Weber), the \"long way\": \n", + "- Constructing a `cirq.NoiseModel` object from device calibration data saved in Cirq. See [Representing Noise](/cirq/representing_noise) for more on noise models. \n", + "- Building a `qsimcirq.QsimSimulator` that uses this noise model. See [Noisy Simulation](/cirq/simulate/noisy_simulation) and [Noise simulation with qsim](/qsim/tutorials/noisy_qsimcirq) for more. \n", + "- Creating a `cirq.Device` that imposes the same constraints on circuits that the original device would. See [Devices](/cirq/hardware/devices) for more on these constraint objects. \n", + "- Packaging the simulator and device into an object that implements the `cirq.Engine` interface that the hardware device would use. \n", + "\n", + "If you don't need this level of control, you can also instantiate a QVM with `cirq_google.engine.create_default_noisy_quantum_virtual_machine`, as in [QVM Creation Template](/cirq/simulate/qvm_builder_code). " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "pbHCUPLpq5WE" + }, + "outputs": [], + "source": [ + "# @title Choose a processor (\"rainbow\" or \"weber\")\n", + "processor_id = \"weber\" # @param {type:\"string\"}\n", + "\n", + "# Construct a simulator with a noise model based on the specified processor.\n", + "cal = cirq_google.engine.load_median_device_calibration(processor_id)\n", + "noise_props = cirq_google.noise_properties_from_calibration(cal)\n", + "noise_model = cirq_google.NoiseModelFromGoogleNoiseProperties(noise_props)\n", + "sim = qsimcirq.QSimSimulator(noise=noise_model)\n", + "\n", + "# Create a device from the public device description\n", + "device = cirq_google.engine.create_device_from_processor_id(processor_id)\n", + "# Build the simulated local processor from the simulator and device.\n", + "sim_processor = cirq_google.engine.SimulatedLocalProcessor(\n", + " processor_id=processor_id, sampler=sim, device=device, calibrations={cal.timestamp // 1000: cal}\n", + ")\n", + "# Package the processor to use an Engine interface\n", + "sim_engine = cirq_google.engine.SimulatedLocalEngine([sim_processor])\n", + "print(\n", + " \"Your quantum virtual machine\",\n", + " processor_id,\n", + " \"is ready, here is the qubit grid:\",\n", + " \"\\n========================\\n\",\n", + ")\n", + "print(sim_engine.get_processor(processor_id).get_device())" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "TJfN17frwo-0" + }, + "source": [ + "## **Create** a circuit, **transform** it (to make it executable on Google quantum hardware) and **choose qubits** on the processor. \n", + "\n", + "The circuit you use needs to be _device ready_, which means it: \n", + "- Is comprised of operations from the device's gate set. \n", + "- Is applied to qubits that exist on the device. \n", + "- Respects the connectivity of qubits on the device.\n", + "\n", + "Below is an example of a circuit that has the correct topology to be placed on the Weber device, and how it is prepared to be run on the QVM." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "a_arTtfcwqrz" + }, + "source": [ + "### Create a GHZ state builder circuit\n", + "\n", + "The generalized [Greenberger–Horne–Zeilinger (GHZ) state](https://en.wikipedia.org/wiki/Greenberger%E2%80%93Horne%E2%80%93Zeilinger_state){:.external} has the form $\\frac{|00..0⟩ + |11..1⟩}{\\sqrt{2}}$ and in this case will be constructed using 17 qubits, with a Hadamard and a sequence of CNOT gates:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "mZFn6OmwwqaR" + }, + "outputs": [], + "source": [ + "# Define an abstract line of 17 qubits\n", + "number_of_qubits = 17\n", + "qubits = cirq.LineQubit.range(number_of_qubits)\n", + "\n", + "# Create a GHZ circuit on this qubit line\n", + "ghz_circuit = cirq.Circuit(\n", + " cirq.H(qubits[0]),\n", + " *[cirq.CNOT(qubits[i - 1], qubits[i]) for i in range(1, number_of_qubits)],\n", + " cirq.measure(*qubits, key='out'),\n", + ")\n", + "print(ghz_circuit)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "tc5L80jjMknb" + }, + "source": [ + "Notice that this circuit consists of a sequence of CNOT gates applied consecutively to a single chain of qubits. The connectivity required by the circuit is simple in the sense that it needs a line of qubits which are only connected to their adjacent neighbor in the sequence. As constructed, this consists of 17 `cirq.LineQubit`s indexed `0, 1, 2...16`. " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "gmgGLI7eZLQt" + }, + "source": [ + "### Transform the circuit \n", + "\n", + "Before executing a circuit on (virtual) quantum hardware, the operations in the circuit need to be translated to use the types of gates the device supports. The `cirq.optimize_for_target_gateset` function does this for you, transforming the operations to use the `cirq.SqrtIswapTargetGateset`, which is supported by the Weber processor that this QVM is based on. Learn more about the gate set constraints of Google hardware at the [Hardware](/hardware) page." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "MqdssGOhY9-S" + }, + "outputs": [], + "source": [ + "# Convert the gates in the GHZ circuit to the \"SqrtIswap\" gateset, which the device uses.\n", + "translated_ghz_circuit = cirq.optimize_for_target_gateset(\n", + " ghz_circuit, context=cirq.TransformerContext(deep=True), gateset=cirq.SqrtIswapTargetGateset()\n", + ")\n", + "print(translated_ghz_circuit)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "JfFfiNkbDDQy" + }, + "source": [ + "### Choose qubits on the virtual device\n", + "\n", + "Choose qubits on the device to execute your device ready circuit on. Look at the device map (as above) and choose a set of qubits that fit your circuit (eg a line or a block). The Rainbow and Weber devices have different topologies, some qubit maps may be possible on only one of these devices. As noted, the GHZ example circuit as constructed will fit on a 17 qubit chain of adjacent qubits on the device, so you only need to find this consecutive line of qubits. See [Qubit Picking](/cirq/hardware/qubit_picking) for more advice and methods for selecting qubits. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "k4PsLLFnDGN-" + }, + "outputs": [], + "source": [ + "# Choose qubits on the virtual device\n", + "device_qubit_chain = [\n", + " cirq.GridQubit(5, 2),\n", + " cirq.GridQubit(5, 3),\n", + " cirq.GridQubit(4, 3),\n", + " cirq.GridQubit(4, 2),\n", + " cirq.GridQubit(4, 1),\n", + " cirq.GridQubit(5, 1),\n", + " cirq.GridQubit(6, 1),\n", + " cirq.GridQubit(6, 2),\n", + " cirq.GridQubit(6, 3),\n", + " cirq.GridQubit(6, 4),\n", + " cirq.GridQubit(6, 5),\n", + " cirq.GridQubit(7, 5),\n", + " cirq.GridQubit(8, 5),\n", + " cirq.GridQubit(8, 4),\n", + " cirq.GridQubit(8, 3),\n", + " cirq.GridQubit(7, 3),\n", + " cirq.GridQubit(7, 4),\n", + "]\n", + "# Layout:\n", + "#\n", + "# q(4, 1)───q(4, 2)───q(4, 3)\n", + "# │ │\n", + "# │ │\n", + "# q(5, 1) q(5, 2)───q(5, 3)\n", + "# │\n", + "# │\n", + "# q(6, 1)───q(6, 2)───q(6, 3)───q(6, 4)───q(6, 5)\n", + "# │\n", + "# │\n", + "# q(7, 3)───q(7, 4) q(7, 5)\n", + "# │ │\n", + "# │ │\n", + "# q(8, 3)───q(8, 4)───q(8, 5)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "UD28ccnyrezn" + }, + "source": [ + "### Map the transformed circuit to the qubits you chose on the device\n", + "\n", + "The transformed GHZ circuit still needs to be re-mapped to use the selected qubits. The `transform_qubits` function of `cirq.Circuit` does this automatically, returning a new transformed circuit when given a qubit mapping function. \n", + "\n", + "Because the connectivity qubit chain in the GHZ circuit example follows the sequence of `cirq.LineQubit`s in `qubits`, it suffices to zip the circuit's qubits together with the chosen device qubits, since both are connected chains of 17 qubits. The dictionary built from these paired qubits can then be turned into a simple lambda function for use with `transform_qubits`, as follows:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "znPgxQ81rjb3" + }, + "outputs": [], + "source": [ + "# Map the line of circuit qubits to the chosen line of device qubits.\n", + "qubit_map = dict(zip(qubits, device_qubit_chain))\n", + "# Then replace qubits in the circuit according to that map.\n", + "deviceready_ghz_circuit = translated_ghz_circuit.transform_qubits(lambda q: qubit_map[q])\n", + "print(deviceready_ghz_circuit)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "dWYXJmyWqg3x" + }, + "source": [ + "### **Running other circuits**\n", + "\n", + "In principle you can run any custom [Circuit](/cirq/build/circuits) with a quantum virtual machine, but realistically there are some constraints. As mentioned, the circuits need to be mappable to the device. Additionally, the number of qubits that are simulatable depends highly on the hardware available to you and how long you are able to run your simulation. As the QVM is instantiated as above, with a `qsimcirq.QSimSimulator`, it only uses the default, local [qsim](https://quantumai.google/qsim) simulator. However, qsim has plenty of support for being run in a [Google Cloud instance](/qsim/tutorials/gcp_before_you_begin){:.external}, with a variable amount of compute power. In order to get the most capacity possible for qsim, use [Multinode Simulation](/qsim/tutorials/multinode).\n", + "\n", + "For an example of building and running a much larger circuit, see the [QVM Stabilizer Example](/cirq/simulate/qvm_stabilizer_example) tutorial. " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Zxv0RtJuhaof" + }, + "source": [ + "## **Execute** Your Circuit on the Quantum Virtual Machine\n", + "\n", + "You can run the now device-ready circuit as you would with any other `cirq.Engine` instance, but getting a sampler from it and using the `run` function on the circuits. Your choice of `repetitions` is intrinsically related to the accuracy of your simulated results. We recommend 3000 repetitions for trial runs, and 10,000 repetitions for accuracy-critical runs, but you can stick to one to ten repetitions when testing a code pipeline. You can read more about this in [this paper](https://arxiv.org/abs/2111.02396){:.external}." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "bFjnNSqRZsFu" + }, + "outputs": [], + "source": [ + "# @title Execute your device ready circuit on the Quantum Virtual Machine\n", + "circuit = deviceready_ghz_circuit\n", + "\n", + "repetitions = 3000\n", + "start = time.time()\n", + "results = sim_engine.get_sampler(processor_id).run(circuit, repetitions=repetitions)\n", + "elapsed = time.time() - start\n", + "\n", + "print('Circuit successfully executed on your quantum virtual machine', processor_id)\n", + "print(f'QVM runtime: {elapsed:.04g}s ({repetitions} repetitions)')\n", + "print('You can now print or plot \"results\"')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "na6nqbvviW7U" + }, + "source": [ + "## **Visualize** Output\n", + "\n", + "Finally, you can use a [state histogram](/cirq/simulate/state_histograms) to plot the measured results." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "O92KP1EwZwV9" + }, + "outputs": [], + "source": [ + "ax = cirq.plot_state_histogram(results.histogram(key='out'))\n", + "ax.get_xaxis().set_ticks([])\n", + "plt.gcf().set_size_inches(10, 4)\n", + "plt.show(ax)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "XOTvkKq_Z1UY" + }, + "source": [ + "The leftmost and rightmost bars correspond to $|00..0\\rangle$ and $|11..1\\rangle$, respectively, which matches expectation for a GHZ state. Natural $|1\\rangle → |0\\rangle$ decay causes $|11..1\\rangle$ to be much less common than $|00..0\\rangle$, and other states also appear due to the various error mechanisms in the hardware that are mimicked by the simulated noise model. Learn more about these errors [here](https://arxiv.org/abs/2111.02396){:.external}.\n" + ] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [ + "Lfira0gPf0Gd" + ], + "name": "qvm_basic_example.ipynb", + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/docs/simulate/qvm_builder_code.ipynb b/docs/simulate/qvm_builder_code.ipynb new file mode 100644 index 00000000000..647a7e8e623 --- /dev/null +++ b/docs/simulate/qvm_builder_code.ipynb @@ -0,0 +1,224 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "DkA0Fobtb9dM" + }, + "source": [ + "##### Copyright 2022 The Cirq Developers" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "tUshu7YfcAAW" + }, + "outputs": [], + "source": [ + "# @title 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": "_JFVRPQ1l17m" + }, + "source": [ + "# QVM Creation Template" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "E6JaKuNTl9SA" + }, + "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": "markdown", + "metadata": { + "id": "8e6bafdbda4d" + }, + "source": [ + "This notebook includes a couple of clean and succinct code blocks that you can build on or copy and paste elsewhere in order to make use of the [Quantum Virtual Machine](/cirq/simulate/quantum_virtual_machine) without worrying about how it works inside. " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Lfira0gPf0Gd" + }, + "source": [ + "## **Install** Cirq and qsim" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "zs5J6wAXqvtW" + }, + "outputs": [], + "source": [ + "# @title Install `cirq_google` and `qsimcirq`\n", + "\n", + "try:\n", + " import cirq\n", + " import cirq_google\n", + "except ImportError:\n", + " print(\"installing cirq...\")\n", + " !pip install --quiet cirq-google\n", + " print(\"installed cirq.\")\n", + " import cirq\n", + " import cirq_google\n", + "\n", + "try:\n", + " import qsimcirq\n", + "except ImportError:\n", + " print(\"installing qsimcirq...\")\n", + " !pip install --quiet qsimcirq\n", + " print(f\"installed qsimcirq.\")\n", + " import qsimcirq\n", + "\n", + "import time" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "p2JAfQa8gVSe" + }, + "source": [ + "## Create a **Quantum Virtual Machine**.\n", + "\n", + "Instantiate a `cirq.SimulatedLocalEngine` that uses the [Virtual Engine Interface](/cirq/simulate/virtual_engine_interface)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "pbHCUPLpq5WE" + }, + "outputs": [], + "source": [ + "# @title Choose a processor (\"rainbow\" or \"weber\")\n", + "processor_id = \"rainbow\" # @param {type:\"string\"}\n", + "\n", + "# Instantiate an engine.\n", + "sim_engine = cirq_google.engine.create_default_noisy_quantum_virtual_machine(\n", + " processor_id=processor_id, simulator_class=qsimcirq.QSimSimulator\n", + ")\n", + "print(\n", + " \"Your quantum virtual machine\",\n", + " processor_id,\n", + " \"is ready, here is the qubit grid:\",\n", + " \"\\n========================\\n\",\n", + ")\n", + "print(sim_engine.get_processor(processor_id).get_device())" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "TJfN17frwo-0" + }, + "source": [ + "## **Create** a device-ready circuit." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "BYxi9xpXjJdI" + }, + "source": [ + "To learn how to create a device ready circuit, have a look at the [QVM Circuit Preparation](/cirq/simulate/qvm_basic_example) page." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "FCoKJhGri8lR" + }, + "outputs": [], + "source": [ + "# create your device ready circuit here!\n", + "your_circuit_name = cirq.Circuit()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Zxv0RtJuhaof" + }, + "source": [ + "## **Execute** Your circuit on the Quantum Virtual Machine." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "bFjnNSqRZsFu" + }, + "outputs": [], + "source": [ + "# @title Enter the name of your device ready circuit and execute it on the Quantum Virtual Machine\n", + "circuit = your_circuit_name # @param\n", + "\n", + "reps = 3000\n", + "start = time.time()\n", + "results = sim_engine.get_sampler(processor_id).run(circuit, repetitions=reps)\n", + "elapsed = time.time() - start\n", + "\n", + "print('Circuit successfully executed on your quantum virtual machine', processor_id)\n", + "print(f'QVM runtime: {elapsed:.04g}s ({reps} reps)')\n", + "print('You can now print or plot \"results\"')" + ] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [], + "name": "qvm_builder_code.ipynb", + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/docs/simulate/qvm_stabilizer_example.ipynb b/docs/simulate/qvm_stabilizer_example.ipynb new file mode 100644 index 00000000000..085d96e8e3d --- /dev/null +++ b/docs/simulate/qvm_stabilizer_example.ipynb @@ -0,0 +1,648 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "DkA0Fobtb9dM" + }, + "source": [ + "##### Copyright 2022 The Cirq Developers" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "tUshu7YfcAAW" + }, + "outputs": [], + "source": [ + "# @title 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": "0_WkiXErntE5" + }, + "source": [ + "# QVM Stabilizer Example" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "BODT5jJI4dZI" + }, + "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": "markdown", + "metadata": { + "id": "5d5f1638ebdf" + }, + "source": [ + "This notebook demonstrates how to use a [Quantum Virtual Machine](/cirq/simulate/quantum_virtual_machine) with larger, more elaborate circuits to demonstrate [stabilizer](https://en.wikipedia.org/wiki/Stabilizer_code){:.external} circuits and how they can reveal hardware errors." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Lfira0gPf0Gd" + }, + "source": [ + "## **Install** Cirq and qsim, Create **Quantum Virtual Machine**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "zs5J6wAXqvtW" + }, + "outputs": [], + "source": [ + "# @title Install `cirq_google` and `qsimcirq`\n", + "\n", + "try:\n", + " import cirq\n", + " import cirq_google\n", + "except ImportError:\n", + " print(\"installing cirq...\")\n", + " !pip install --quiet cirq-google\n", + " print(\"installed cirq.\")\n", + " import cirq\n", + " import cirq_google\n", + "\n", + "try:\n", + " import qsimcirq\n", + "except ImportError:\n", + " print(\"installing qsimcirq...\")\n", + " !pip install --quiet qsimcirq\n", + " print(f\"installed qsimcirq.\")\n", + " import qsimcirq\n", + "\n", + "# Other modules used in this colab\n", + "import matplotlib.pyplot as plt\n", + "import time\n", + "import random" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "pbHCUPLpq5WE" + }, + "outputs": [], + "source": [ + "# @title Create Quantum Virtual Machine: Choose a processor (\"rainbow\" or \"weber\")\n", + "processor_id = \"rainbow\" # @param {type:\"string\"}\n", + "\n", + "# Instantiate the engine.\n", + "sim_engine = cirq_google.engine.create_default_noisy_quantum_virtual_machine(\n", + " processor_id=processor_id, simulator_class=qsimcirq.QSimSimulator\n", + ")\n", + "print(\n", + " \"Your quantum virtual machine\",\n", + " processor_id,\n", + " \"is ready, here is the qubit grid:\",\n", + " \"\\n========================\\n\",\n", + ")\n", + "print(sim_engine.get_processor(processor_id).get_device())" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "UncGyI-egm8d" + }, + "source": [ + "## **Introduction** to stabilizer measurements\n", + "\n", + "The following code blocks measure a Z stabilizer as described by [Fowler et al (2012)](https://arxiv.org/abs/1208.0928). This type of circuit is central to the field of quantum error correction via the idea of a [Stabilizer Code](https://en.wikipedia.org/wiki/Stabilizer_code){:.external}. \n", + "\n", + "![image.png](data:image/png;base64,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)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "jSH1HAz25W6G" + }, + "source": [ + "This circuit is constructed such that the central \"measure\" qubit will be in the $|1\\rangle$ state if an odd number of the four surrounding \"data\" qubits (named a-d in the figure) have a bit-flip error (corresponding to an X gate)." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Hh8gyQWM62zE" + }, + "source": [ + "## Stabilizer measurements on a **small grid**\n", + "\n", + "The examples below demonstrate a single Z stabilizer, similar to the image above. " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "QspgLC3WHGJf" + }, + "source": [ + "### Without noise\n", + "\n", + "In a perfectly noiseless Z stabilizer, all qubits will remain in the $|0\\rangle$ state." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "FOitwZQvHBPQ" + }, + "outputs": [], + "source": [ + "data_qubits = [cirq.NamedQubit('data_' + str(x)) for x in 'abcd']\n", + "measure_qubit = cirq.NamedQubit('_meas')\n", + "stabilizer_circuit = cirq.Circuit(\n", + " *[cirq.CX(data_qubit, measure_qubit) for data_qubit in data_qubits],\n", + " cirq.measure(measure_qubit, key='meas'),\n", + ")\n", + "\n", + "print(f'Z-stabilizer circuit:')\n", + "print('========================')\n", + "print(stabilizer_circuit)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "xXHsAF5FIDcM" + }, + "outputs": [], + "source": [ + "simulator = cirq.Simulator()\n", + "result = simulator.run(stabilizer_circuit, repetitions=100)\n", + "ax = cirq.plot_state_histogram(result)\n", + "plt.show(ax)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "5Zwhyvi3IqIC" + }, + "source": [ + "### With fixed noise\n", + "\n", + "If one of the qubits is flipped, the measure qubit will also flip to match the parity of the data qubits." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "J48W_of2Ir_p" + }, + "outputs": [], + "source": [ + "random_data_qubit = random.choice(data_qubits)\n", + "stabilizer_circuit_with_error = cirq.X(random_data_qubit) + stabilizer_circuit\n", + "\n", + "print(f'Z-stabilizer circuit with single error:')\n", + "print('========================')\n", + "print(stabilizer_circuit_with_error)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "MtJdnKIxI2rc" + }, + "outputs": [], + "source": [ + "result = simulator.run(stabilizer_circuit_with_error, repetitions=100)\n", + "ax = cirq.plot_state_histogram(result)\n", + "plt.show(ax)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "BZMxGdueKrLu" + }, + "source": [ + "### With hardware noise on the QVM\n", + "\n", + "With hardware-like noise, the stabilizer circuit becomes much more interesting. An arbitrary error could occur at any point:\n", + "\n", + "* On a data qubit before or after the CNOT\n", + "* On the measure qubit before or after the CNOTs\n", + "* On the measure qubit _between_ CNOTs\n", + "* Multiple errors in any combination of the above locations\n", + "\n", + "The only indication of that error comes from the output of the measure qubit. By creating a grid of stabilizers and observing how they change over time, it's possible to decode when and where errors occured and compensate for them.\n", + "\n", + "The example below only runs a single cycle of one Z stabilizer, so it can't pinpoint error precisely. However, by measuring the data qubits afterwards it's possible to guess at where the error(s) took place." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "VWx6GaiUKpkW" + }, + "outputs": [], + "source": [ + "# Add measurements to the data qubits.\n", + "stabilizer_circuit_for_hardware = stabilizer_circuit + (\n", + " cirq.Moment(cirq.measure(data_qubit, key=str(data_qubit)[-1]) for data_qubit in data_qubits)\n", + ")\n", + "print(f'Z-stabilizer circuit with data measurement:')\n", + "print('========================')\n", + "print(stabilizer_circuit_for_hardware)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "X9SgEuPzfwbD" + }, + "outputs": [], + "source": [ + "# Device_stabilizer_plaquette is an X-shaped region of qubits\n", + "# on the actual device.\n", + "device_stabilizer_plaquette = [\n", + " cirq.GridQubit(5, 3),\n", + " cirq.GridQubit(5, 2),\n", + " cirq.GridQubit(4, 3),\n", + " cirq.GridQubit(5, 4),\n", + " cirq.GridQubit(6, 3),\n", + "]\n", + "\n", + "# Translate the circuit to a suitable gate set.\n", + "test_stabilizer_circuit = cirq.optimize_for_target_gateset(\n", + " stabilizer_circuit_for_hardware,\n", + " context=cirq.TransformerContext(deep=True),\n", + " gateset=cirq.SqrtIswapTargetGateset(),\n", + ")\n", + "# Map circuit qubits to hardware ones.\n", + "qubit_map = dict(zip([measure_qubit] + data_qubits, device_stabilizer_plaquette))\n", + "# Re-map the circuit to the hardware qubits.\n", + "test_stabilizer_circuit = test_stabilizer_circuit.transform_qubits(lambda q: qubit_map[q])\n", + "print(f'Z-stabilizer circuit optimized for {processor_id}:')\n", + "print('========================')\n", + "print(test_stabilizer_circuit)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "JiUTetihmEA8" + }, + "outputs": [], + "source": [ + "# Run for 1k repetitions.\n", + "repetitions = 1000\n", + "start = time.time()\n", + "results = sim_engine.get_sampler(processor_id).run(test_stabilizer_circuit, repetitions=repetitions)\n", + "elapsed = time.time() - start\n", + "print(f'{repetitions} repetitions completed in {elapsed:.03f}s')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "c6lmcI_ID7zp" + }, + "source": [ + "Each result in the histogram below corresponds to a different set of possible errors. Below are some of the most likely cases for each measured result, or \"syndrome\", but there are many other possible cases not listed.\n", + "\n", + "* No flips (`0_0000`) could be no error, or two errors on the same qubit.\n", + "* A single data flip (e.g. `0_1000`) could be a post-CNOT data error, or a pre-CNOT data error and a measurement error.\n", + "* A data flip and a measure flip (e.g. `1_1000`) could be a pre-CNOT data error or post-CNOT errors on both flipped qubits.\n", + "* Two data flips (e.g. `0_1100`) could be pre-CNOT or post-CNOT errors on both flipped qubits.\n", + "\n", + "...and so on, for more unusual cases." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ydV-1HmnLHT9" + }, + "outputs": [], + "source": [ + "# A labeling function.\n", + "def fold_func(bits) -> str:\n", + " suffix = \"\".join(map(str, [bits[i][0] for i in range(4)]))\n", + " return f\"{bits[0][0]}_{suffix}\"\n", + "\n", + "\n", + "hist = results.multi_measurement_histogram(keys=['meas'] + list('abcd'), fold_func=fold_func)\n", + "\n", + "print(\"Results (_)\")\n", + "ax = cirq.plot_state_histogram(hist)\n", + "plt.setp(ax.get_xticklabels(), rotation=30, horizontalalignment='right')\n", + "plt.show(ax)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "6XgoJWPaH5Qi" + }, + "source": [ + "As a final exercise on this circuit, it's possible to display a 2D heatmap of measurement results. This will show which qubits measured a $|1\\rangle$ most often; on a hardware device, this could be used to highlight the performance of specific qubits. See [Heatmaps](/cirq/noise/heatmaps) for more on visualizing error." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "7NIqBbdWkrMQ" + }, + "outputs": [], + "source": [ + "meas_map = {qubit_map[measure_qubit]: sum(results.measurements['meas']) / repetitions}\n", + "\n", + "data_map = {\n", + " qubit_map[dq]: sum(results.measurements[str(dq)[-1]]) / repetitions for dq in data_qubits\n", + "}\n", + "\n", + "heatmap = cirq.Heatmap({**meas_map, **data_map})\n", + "heatmap.plot()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "CERJOdfP7Ctx" + }, + "source": [ + "## Stabilizer measurements on a **large grid**\n", + "\n", + "The next examples scale up the stabilizer grid to a 2x3 block of three Z stabilizers and three X stabilizers. Combining both stabilizer types allows many types of error to be detected and compensated for, although some ambiguity still remains. It also manually maps the circuit to the hardware qubits.\n", + "\n", + "A real logical qubit would require many more stabilizers to be fault-tolerant; however, this toy example is already near the upper bound of what a full statevector simulator can simulate on personal-level computers." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "g__a69njShB_" + }, + "outputs": [], + "source": [ + "# Consider the following grid, where numbers represent\n", + "# measure qubits and letters represent data qubits:\n", + "#\n", + "# A\n", + "# B0C\n", + "# D1E2F\n", + "# G3H4J\n", + "# K5L\n", + "# M\n", + "#\n", + "# Center Z-plaquettes on [0, 3, 4] and\n", + "# X-plaquettes on [1, 2, 5]\n", + "\n", + "# Instantiate the alphabetical data qubits and numerical measurement qubits.\n", + "grid_data_qubits = {x: cirq.NamedQubit(x) for x in 'ABCDEFGHJKLM'}\n", + "grid_meas_qubits = {x: cirq.NamedQubit(str(x)) for x in range(6)}\n", + "\n", + "# Build the diamond shaped stabilizer circuit from six layered smaller stabilizers.\n", + "stabilizer_grid_circuit = cirq.Circuit(\n", + " cirq.H.on_each(grid_meas_qubits[x] for x in [1, 2, 5]),\n", + " *[cirq.CX(grid_data_qubits[x], grid_meas_qubits[0]) for x in 'ABCE'],\n", + " *[cirq.CX(grid_meas_qubits[1], grid_data_qubits[x]) for x in 'BDEG'],\n", + " *[cirq.CX(grid_meas_qubits[2], grid_data_qubits[x]) for x in 'CEFH'],\n", + " *[cirq.CX(grid_data_qubits[x], grid_meas_qubits[3]) for x in 'EGHK'],\n", + " *[cirq.CX(grid_data_qubits[x], grid_meas_qubits[4]) for x in 'FHJL'],\n", + " *[cirq.CX(grid_meas_qubits[5], grid_data_qubits[x]) for x in 'HKLM'],\n", + " cirq.H.on_each(grid_meas_qubits[x] for x in [1, 2, 5]),\n", + " *[cirq.measure(mq) for mq in grid_meas_qubits.values()],\n", + " *[cirq.measure(dq) for dq in grid_data_qubits.values()],\n", + ")\n", + "# Map the named qubits of the stabilizer circuit to GridQubits on the hardware.\n", + "qubit_map = {\n", + " cirq.NamedQubit('A'): cirq.GridQubit(4, 3),\n", + " cirq.NamedQubit('B'): cirq.GridQubit(5, 2),\n", + " cirq.NamedQubit('0'): cirq.GridQubit(5, 3),\n", + " cirq.NamedQubit('C'): cirq.GridQubit(5, 4),\n", + " cirq.NamedQubit('D'): cirq.GridQubit(6, 1),\n", + " cirq.NamedQubit('1'): cirq.GridQubit(6, 2),\n", + " cirq.NamedQubit('E'): cirq.GridQubit(6, 3),\n", + " cirq.NamedQubit('2'): cirq.GridQubit(6, 4),\n", + " cirq.NamedQubit('F'): cirq.GridQubit(6, 5),\n", + " cirq.NamedQubit('G'): cirq.GridQubit(7, 2),\n", + " cirq.NamedQubit('3'): cirq.GridQubit(7, 3),\n", + " cirq.NamedQubit('H'): cirq.GridQubit(7, 4),\n", + " cirq.NamedQubit('4'): cirq.GridQubit(7, 5),\n", + " cirq.NamedQubit('J'): cirq.GridQubit(7, 6),\n", + " cirq.NamedQubit('K'): cirq.GridQubit(8, 3),\n", + " cirq.NamedQubit('5'): cirq.GridQubit(8, 4),\n", + " cirq.NamedQubit('L'): cirq.GridQubit(8, 5),\n", + " cirq.NamedQubit('M'): cirq.GridQubit(9, 4),\n", + "}\n", + "stabilizer_grid_circuit = stabilizer_grid_circuit.transform_qubits(lambda q: qubit_map[q])\n", + "print(stabilizer_grid_circuit)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ljEDw02_kzTT" + }, + "source": [ + "### [Optional] View 3D circuit\n", + "\n", + "Large circuits that are mapped to grids are suitable to be visualized in 3D with `cirq_web`, if you find it useful, as follows:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "BsSR-ndEi0Tq" + }, + "outputs": [], + "source": [ + "!pip install -q cirq-web --pre\n", + "import cirq_web\n", + "\n", + "circuit_vis = cirq_web.Circuit3D(stabilizer_grid_circuit)\n", + "display(circuit_vis)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "3T0UsKjVJZTb" + }, + "source": [ + "### Without noise\n", + "\n", + "The noiseless version of the larger grid is slightly more exciting than the small grid example: the X measure qubits will measure a random state since their neighbors are initialized in the Z basis. However, subsequent measurements will remain consistent.\n", + "\n", + "The example below runs a single cycle of the 2x3 grid 100 times, then does a Z-basis measurement of all data qubits. Since each of these is a separate execution of the circuit, no correlation is expected between repetitions." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "2YwmAqBJSPHM" + }, + "outputs": [], + "source": [ + "noiseless_sim = qsimcirq.QSimSimulator()\n", + "\n", + "repetitions = 100\n", + "start = time.time()\n", + "results = noiseless_sim.run(stabilizer_grid_circuit, repetitions=repetitions)\n", + "elapsed = time.time() - start\n", + "print(f'{repetitions} repetitions completed in {elapsed:.03f}s')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "o1D_wxTCScFf" + }, + "outputs": [], + "source": [ + "# Set to view results from each repetition.\n", + "repetition = 0 # @param {type:\"number\"}\n", + "meas_map = {\n", + " qubit_map[q]: results.measurements[str(q)][repetition] for q in grid_meas_qubits.values()\n", + "}\n", + "\n", + "data_map = {\n", + " qubit_map[q]: results.measurements[str(q)][repetition] for q in grid_data_qubits.values()\n", + "}\n", + "\n", + "heatmap = cirq.Heatmap({**meas_map, **data_map})\n", + "heatmap.plot()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "2PamsJlJSHhd" + }, + "source": [ + "### With hardware noise on the QVM\n", + "\n", + "Adding in hardware-like noise means that subsequent cycles of a stabilizer might disagree with one another. These inconsistencies can be interpreted as various error modes, which can be decoded to compensate for the errors observed.\n", + "\n", + "Decoding stabilizer error is a complex topic not covered here, but the pre-decoding results and data qubit measurements shown below may shed some light on how to approach this process." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "BQV2XcR5gd6X" + }, + "outputs": [], + "source": [ + "test_stabilizer_grid_circuit = cirq.optimize_for_target_gateset(\n", + " cirq.Circuit(cirq.decompose(stabilizer_grid_circuit)),\n", + " context=cirq.TransformerContext(deep=True),\n", + " gateset=cirq.SqrtIswapTargetGateset(),\n", + ")\n", + "print(test_stabilizer_grid_circuit)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "h3T2WqzibNfg" + }, + "outputs": [], + "source": [ + "repetitions = 100\n", + "start = time.time()\n", + "results = sim_engine.get_sampler(processor_id).run(\n", + " test_stabilizer_grid_circuit, repetitions=repetitions\n", + ")\n", + "elapsed = time.time() - start\n", + "print(f'{repetitions} repetitions completed in {elapsed:.03f}s')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "5dP0h-OCYJjL" + }, + "outputs": [], + "source": [ + "# Set to view results from each repetition.\n", + "repetition = 0 # @param {type:\"number\"}\n", + "meas_map = {\n", + " qubit_map[q]: results.measurements[str(q)][repetition] for q in grid_meas_qubits.values()\n", + "}\n", + "\n", + "data_map = {\n", + " qubit_map[q]: results.measurements[str(q)][repetition] for q in grid_data_qubits.values()\n", + "}\n", + "\n", + "heatmap = cirq.Heatmap({**meas_map, **data_map})\n", + "heatmap.plot()" + ] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [], + "name": "qvm_stabilizer_example.ipynb", + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/docs/simulate/simulation.ipynb b/docs/simulate/simulation.ipynb index 94e313bfcab..f1f6ba6afa0 100644 --- a/docs/simulate/simulation.ipynb +++ b/docs/simulate/simulation.ipynb @@ -97,7 +97,7 @@ "that keeps the evolution in a pure state (i.e. a single quantum state)\n", "or a mixed state (a mix of quantum states, each with a classical\n", "probability). Noisy evolutions are supported by the pure state\n", - "simulator, as long as they preserve the purity of the state.\n", + "simulator, as long as they preserve the purity of the state. If you are interested in truly noisy simulation that may not preserve purity, see the [Noisy Simulation](/cirq/simulate/noisy_simulation) page. \n", "\n", "Some external high-performance simulators also provide an interface\n", "to Cirq. These can often provide results faster than Cirq's\n", @@ -514,7 +514,7 @@ "source": [ "import sympy\n", "\n", - "rot_w_gate = cirq.X**sympy.Symbol('x')\n", + "rot_w_gate = cirq.X ** sympy.Symbol('x')\n", "circuit = cirq.Circuit()\n", "circuit.append([rot_w_gate(q0), rot_w_gate(q1)])\n", "print(circuit)\n", diff --git a/docs/simulate/virtual_engine_interface.ipynb b/docs/simulate/virtual_engine_interface.ipynb new file mode 100644 index 00000000000..1c09d9d58d4 --- /dev/null +++ b/docs/simulate/virtual_engine_interface.ipynb @@ -0,0 +1,481 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "DkA0Fobtb9dM" + }, + "source": [ + "##### Copyright 2022 The Cirq Developers" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "tUshu7YfcAAW" + }, + "outputs": [], + "source": [ + "# @title 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": "5v5kLs-DU9qp" + }, + "source": [ + "# Quantum Virtual Engine" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "wRVl7p4zv8eT" + }, + "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": "markdown", + "metadata": { + "id": "BCeleGCgmY4y" + }, + "source": [ + "Cirq provides the [Quantum Virtual Machine](/cirq/simulate/quantum_virtual_machine), which consists of two components: \n", + "- The Quantum Virtual Engine: A class that implements the same interface as `cirq_google.Engine`, allowing you to simulate circuits with the same software interface that the real hardware uses. \n", + "- Realistic noise models that mimic the behavior of real quantum hardware.\n", + "\n", + "This tutorial covers the former of the two components, the Quantum Virtual Engine, and how to run circuits on existing and custom virtual processor models." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "4Sif48OM1vPM" + }, + "source": [ + "## Setup" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "AL_CcSjjmL8n" + }, + "outputs": [], + "source": [ + "try:\n", + " import cirq\n", + "except ImportError:\n", + " print(\"installing cirq...\")\n", + " !pip install --quiet cirq\n", + " print(\"installed cirq.\")\n", + " import cirq\n", + "\n", + "import cirq_google\n", + "import sympy" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "zKWtgtrYZIVy" + }, + "source": [ + "Communication with real quantum hardware in Cirq is done through the `cirq_google.Engine` class. Each `Engine` can contain multiple quantum processors, and the `Engine` class provides functions to run circuits and manage jobs sent to those processors. The Virtual Engine in Cirq is an instance of the class `cirq_google.SimulatedLocalEngine` that runs circuits on the built-in Cirq [Simulator](/cirq/simulation) instead of on hardware, but uses the same interface as `Engine`. This is useful for testing your circuit and code pipeline before running on actual hardware, and can be used as a substitute when the real hardware is not available.\n", + "\n", + "The interface implemented by both `cirq_google.Engine` and `cirq_google.SimulatedLocalEngine` is called `cirq_google.AbstractEngine`, and defines the various functions and types involved with using either option. When writing functions of your own, this interface enables you to seamlessly support simulated and real-hardware versions of the `Engine` interface. " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "kuso8OxNo3t0" + }, + "source": [ + "## Instantiate a virtual Engine\n", + "\n", + "The easiest way to create a `cirq_google.SimulatedLocalEngine` is to make one from one or more processor templates. \n", + "Example processor device specifications can be found in \n", + "the [devices/specifications](https://github.com/quantumlib/Cirq/tree/master/cirq-google/cirq_google/devices/specifications) folder of `cirq_google` in the Cirq Github repository. These device specifications closely match previous versions of Google quantum hardware, and can serve as templates for processors in a `SimulatedLocalEngine`. When Google hardware becomes publicly available again in the future, it will have device specifications like these that differ in details, but not in format.\n", + "\n", + "You can create a `cirq_google.SimulatedLocalEngine` that includes these example device specifications using `cirq_google.engine.create_noiseless_virtual_engine_from_latest_templates()`. For example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "dBbX5ll_blLI" + }, + "outputs": [], + "source": [ + "engine = cirq_google.engine.create_noiseless_virtual_engine_from_latest_templates()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "fwoJCTe0VPxl" + }, + "source": [ + "You can then use this Engine object to perform operations as if it included real hardware. However, all interactions will be local and mocked with these example processors. Program execution will be done by the cirq Simulator.\n", + "\n", + "For instance, you can list the processors and their device layouts, which are the same as those specified in the `devices/specification` folder:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "wF6ay4KPVPTL" + }, + "outputs": [], + "source": [ + "for proc in engine.list_processors():\n", + " print(proc.processor_id)\n", + " print('-----------------')\n", + " print(proc.get_device())\n", + " print('\\n\\n\\n')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "sXsTR4ZpXfka" + }, + "source": [ + "## Run circuits and sweeps\n", + "\n", + "After creating the `SimulatedLocalEngine`, you can use any function that you might use with a normal `Engine` that has real quantum processors in it. Most importantly, this includes the ability to run circuits. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "xmEzIfseVPg4" + }, + "outputs": [], + "source": [ + "# Choose one of the (simulated) processors to run on.\n", + "weber = engine.get_processor('weber')\n", + "sampler = weber.get_sampler()\n", + "\n", + "# Run a simple circuit for ten repetitions\n", + "result = sampler.run(cirq.Circuit(cirq.measure(cirq.GridQubit(7, 2))), repetitions=10)\n", + "print(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "H8aIHqEBYDnr" + }, + "source": [ + "Note that, even though this is a simulated processor device, there are still device constraints that must be met by a circit in order for it to be executed. For example, the gates and qubits used by the circuit must be supported by the device:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Ky1fiTLPYIqM" + }, + "outputs": [], + "source": [ + "# Weber does not have a (7, 1) qubit.\n", + "try:\n", + " sampler.run(cirq.Circuit(cirq.measure(cirq.GridQubit(7, 1))), repetitions=10)\n", + "except ValueError as e:\n", + " print(e)\n", + "\n", + "# Weber does not support the H gate on qubit (7, 2).\n", + "try:\n", + " sampler.run(\n", + " cirq.Circuit(cirq.H(cirq.GridQubit(7, 2)), cirq.measure(cirq.GridQubit(7, 2))),\n", + " repetitions=10,\n", + " )\n", + "except ValueError as e:\n", + " print(e)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "FtCpP5evY2Ss" + }, + "source": [ + "You can also run [Parameter Sweeps](/cirq/simulate/parameter_sweeps) with the `run_sweep` function, which returns a `cirq.Job`-type object instead of a `Result`. This way, jobs can be prepared and run asynchronously. When running a parameter sweep over many parameter options, or with particularly large circuits, it can be useful to set the job running and return for the results later, with the ability to check job execution status in between. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "0VECfWL0Y91w" + }, + "outputs": [], + "source": [ + "qubit = cirq.GridQubit(7, 2)\n", + "circuit = cirq.Circuit(cirq.X(qubit) ** sympy.Symbol('t'), cirq.measure(qubit, key='m'))\n", + "job = weber.run_sweep(circuit, params=cirq.Linspace('t', 0, 2, 20), repetitions=1000)\n", + "print(f'job is type {type(job)}')\n", + "print(f'job has id {job.id()} and status {job.execution_status()}')\n", + "print('')\n", + "\n", + "print('Now executing results!')\n", + "results = job.results()\n", + "print('')\n", + "print(f'job has id {job.id()} and status {job.execution_status()}')\n", + "\n", + "print('')\n", + "print('Results:')\n", + "for result in results:\n", + " print(result.histogram(key='m'))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "tRaVuulAbYat" + }, + "source": [ + "## Reservations and scheduling\n", + "\n", + "Other functions are available to `Engine` classes that are part of using the `Engine` as a service. These include reservations, scheduling, downtime, and others. Thes functions are also available with the virtual processors, though all of them will generally succeed since there are no other users using the virtual service." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Qc_zkuzdOCVn" + }, + "outputs": [], + "source": [ + "print(f'Next expected downtime: {weber.expected_down_time()}')\n", + "print(f'Next expected recovery: {weber.expected_recovery_time()}')\n", + "\n", + "# Creating two example reservations\n", + "import datetime\n", + "\n", + "now = datetime.datetime.now()\n", + "hour = datetime.timedelta(hours=1)\n", + "try:\n", + " weber.create_reservation(start_time=now, end_time=now + hour)\n", + " weber.create_reservation(\n", + " start_time=now + 2 * hour,\n", + " end_time=now + 3 * hour,\n", + " whitelisted_users=['mysterious_fake_user@nonexistentwebsite.domain'],\n", + " )\n", + "except ValueError as e:\n", + " # If you re-run this cell, it will note that you already have a reservation\n", + " print('Cannot reserve time, did you already reserve it? Error:')\n", + " print(e)\n", + "\n", + "print('')\n", + "print('Reservations:')\n", + "print('---------------')\n", + "print(f'{weber.list_reservations()}')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Y0CyKooF2k0_" + }, + "source": [ + "The processor also comes with a stock calibration metric report. By default, all of the error values are zero." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "an5RBcbK2jNs" + }, + "outputs": [], + "source": [ + "print('Calibrations:')\n", + "print('---------------')\n", + "calibration = weber.list_calibrations()[0]\n", + "print(f\"Calibration metrics: \\n {list(calibration.keys())}\")\n", + "# Example calibration data\n", + "for metric in [\"single_qubit_p00_error\", \"two_qubit_sycamore_gate_xeb_average_error_per_cycle\"]:\n", + " print(metric)\n", + " data = calibration[metric]\n", + " # Only print the first couple qubits/qubit pairs\n", + " for key in list(data.keys())[:3]:\n", + " print(f' {key}: {data[key]}')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "XFsv1dkrQqIs" + }, + "source": [ + "## Create a custom processor from a device\n", + "\n", + "You can also create processors to mimic other devices as needed. Each of these classes is customizable and can be modified to suit your simulation needs.\n", + "\n", + "You can create processors from existing devices, like `cirq_google.Sycamore`, with `cirq_google.engine.create_noiseless_virtual_engine_from_device`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "TBdZgcyGRFKy" + }, + "outputs": [], + "source": [ + "sycamore_engine = cirq_google.engine.create_noiseless_virtual_engine_from_device(\n", + " 'sycamore', cirq_google.Sycamore\n", + ")\n", + "\n", + "# Note that the previous function creates an engine with just one processor\n", + "print([proc.processor_id for proc in sycamore_engine.list_processors()])\n", + "print(sycamore_engine.get_processor('sycamore').get_device())" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "n0CXvI0XR9iv" + }, + "source": [ + "## Create a custom processor from a specification\n", + "\n", + "You can also create virtual engines from device specifications written in the [Protocol Buffer](https://developers.google.com/protocol-buffers) structured-data file format. This allows for detailed custom device creation, in the case where you want to see how a slightly modified existing device, or a completely new device, would work in Cirq.\n", + "\n", + "The previous specification files mentioned in the [devices/specifications](https://github.com/quantumlib/Cirq/tree/master/cirq-google/cirq_google/devices/specifications) in the Cirq repository are already in this file format. The details of this format are subject to change as Cirq is updated, but it is designed to be human-readable. If you want to work with a very custom device, the best place to start is by inspecting one of these files, but be aware that the format may change without notice." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "WS8vRtvMRxBj" + }, + "outputs": [], + "source": [ + "import importlib\n", + "from cirq_google.devices import specifications\n", + "\n", + "# Get the processor identifier and file location from MOST_RECENT_TEMPLATES.\n", + "processor_id, template_name = next(\n", + " iter(cirq_google.engine.virtual_engine_factory.MOST_RECENT_TEMPLATES.items())\n", + ")\n", + "# Read the protobuf template.\n", + "device_str = importlib.resources.read_text(specifications, template_name)\n", + "# Print just the first 10 lines of the very long protobuf specification.\n", + "print(f'Processor: {processor_id}')\n", + "print('\\n'.join(device_str.splitlines()[:10]))\n", + "print('...')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "MoPt-4l3B6-x" + }, + "source": [ + "In order to use this specification protobuf file string, parse it with `google.protobuf.text_format` and create the `SimulatedLocalEngine` with `cirq_google.engine.create_noiseless_virtual_engine_from_proto`. \n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "0Ix-jMPvB5qV" + }, + "outputs": [], + "source": [ + "import google.protobuf.text_format as text_format\n", + "\n", + "# Import the spec.\n", + "device_spec = cirq_google.api.v2.device_pb2.DeviceSpecification()\n", + "text_format.Parse(device_str, device_spec)\n", + "four_engine = cirq_google.engine.create_noiseless_virtual_engine_from_proto(\n", + " processor_id, device_spec, gate_sets=[cirq_google.XMON]\n", + ")\n", + "# Prepare a sampler.\n", + "print([proc.processor_id for proc in four_engine.list_processors()])\n", + "processor = four_engine.get_processor(processor_id)\n", + "print(processor.get_device())\n", + "sampler = processor.get_sampler()\n", + "\n", + "q1_1 = cirq.GridQubit(1, 1)\n", + "q1_2 = cirq.GridQubit(1, 2)\n", + "q2_1 = cirq.GridQubit(2, 1)\n", + "# Run a circuit with one each of Z, CZ, Measure, and CircuitOperation.\n", + "circuit = cirq.Circuit(\n", + " cirq.CircuitOperation(cirq.FrozenCircuit(cirq.Z(q2_1), cirq.CZ(q1_1, q1_2))),\n", + " cirq.measure(q1_1),\n", + " cirq.measure(q2_1),\n", + ")\n", + "print('results', '\\n')\n", + "try:\n", + " print(sampler.run(circuit))\n", + "except ValueError as e:\n", + " print(e)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "zOtDbCSas8qm" + }, + "source": [ + "# Summary\n", + "\n", + "Cirq provides the `cirq.SimulatedLocalEngine`. which allows you to run circuits on the Cirq Simulator through the same interface as the `cirq.Engine` object, which is used for running on real quantum hardware. This is useful both as a preparation step before running on real quantum hardware, and as a substitute when real hardware is unavailable.\n", + "\n", + "As presented in this page, the virtual Engine is completely noiseless. In order to learn about using the virtual Engine with noise models, including realistic noise models which closely mimic actual hardware, see the [Quantum Virtual Machine](/cirq/simulate/quantum_virtual_machine) page. " + ] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [], + "name": "virtual_engine_interface.ipynb", + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/docs/start/basics.ipynb b/docs/start/basics.ipynb index 154e33a8021..19c3cc5b2eb 100644 --- a/docs/start/basics.ipynb +++ b/docs/start/basics.ipynb @@ -437,6 +437,25 @@ "samples = s.run(bell_circuit, repetitions=1000)" ] }, + { + "cell_type": "markdown", + "metadata": { + "id": "a9a791442b74" + }, + "source": [ + "### Virtual Machine Simulation\n", + "\n", + "Cirq also provides the [Quantum Virtual Machine](/cirq/simulate/quantum_virtual_machine), which is a simulated virtual version of quantum hardware devices. It consists of two primary components: \n", + "1. A [virtual Engine interface](/cirq/simulate/virtual_engine_interface) that enables you to verify and run circuits with the same interface that quantum hardware would have.\n", + "2. A set of [noise models](cirq/simulate/representing_noise) that try to realistically replicate the noise present in actual Google quantum hardware devices.\n", + "\n", + "The QVM is intended to serve as a replacement for the Google quantum hardware, in two cases: \n", + "1. Running your circuit on a QVM can give an approximation of how your circuit runs under the influence of hardware-like noise. This can be useful to help you reconfigure or change your circuit to be less impacted by noise when run on actual quantum hardware.\n", + "2. During the preparation process before running your circuit(s) on hardware, you can seamlessly use a QVM to test that your workflow or pipeline works before eventually switching to the nearly-identical hardware interface.\n", + "\n", + "Read more about the QVM and its uses in the [Quantum Virtual Machine](/cirq/simulate/quantum_virtual_machine) page, or just start using it with the [QVM Creation Template](/cirq/simulate/qvm_builder_code) page." + ] + }, { "cell_type": "markdown", "metadata": { diff --git a/docs/start/intro.ipynb b/docs/start/intro.ipynb index f48a42ce8c1..9b01846a59b 100644 --- a/docs/start/intro.ipynb +++ b/docs/start/intro.ipynb @@ -1542,6 +1542,7 @@ "class RationalGate(cirq.Gate):\n", " def _num_qubits_(self) -> int:\n", " return 1\n", + "\n", " def _unitary_(self):\n", " return np.array([[3 / 5, 4 / 5], [-4 / 5, 3 / 5]])\n", "\n", @@ -1785,6 +1786,7 @@ "class HXGate(cirq.Gate):\n", " def _num_qubits_(self) -> int:\n", " return 1\n", + "\n", " def _decompose_(self, qubits):\n", " return cirq.H(*qubits), cirq.X(*qubits)\n", "\n", @@ -2597,6 +2599,17 @@ " raise ValueError(f\"Qubit {qubit} not on device\")" ] }, + { + "cell_type": "markdown", + "metadata": { + "id": "0ffeaed6f5e2" + }, + "source": [ + "# Quantum Virtual Machine\n", + "\n", + "Cirq provides the [Quantum Virtual Machine](/cirq/simulate/quantum_virtual_machine) as a way to run circuits using the same interface that quantum hardware uses and get results that approximate those the hardware would produce. It combines [Devices](/cirq/hardware/devices), [Noisy Simulation](/cirq/simulate/noisy_simulation), realistic [Noise Models](/cirq/simulate/representing_noise) and a [Virtual Engine Interface](/cirq/simulate/virtual_engine_interface) to produce a `cirq.SimulatedLocalEngine` that you can treat almost interchangeably with hardware devices. See the [Quantum Virtual Machine](/cirq/simulate/quantum_virtual_machine) page to learn more about how it works, or jump to the [QVM Creation Template](/cirq/simulate/qvm_builder_code) notebook to just start using it. " + ] + }, { "cell_type": "markdown", "metadata": { @@ -2839,6 +2852,7 @@ "class InconsistentXGate(cirq.Gate):\n", " def _num_qubits_(self) -> int:\n", " return 1\n", + "\n", " def _decompose_(self, qubits):\n", " yield cirq.H(qubits[0])\n", " yield cirq.Z(qubits[0])\n", diff --git a/docs/start/start.ipynb b/docs/start/start.ipynb index b8fecfaf1aa..f42f124ffb4 100644 --- a/docs/start/start.ipynb +++ b/docs/start/start.ipynb @@ -18,7 +18,7 @@ }, "outputs": [], "source": [ - "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", + "# @title 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", @@ -76,6 +76,7 @@ " print(\"installing cirq...\")\n", " !pip install --quiet cirq\n", " import cirq\n", + "\n", " print(\"installed cirq.\")" ] }, @@ -90,11 +91,8 @@ "# Pick a qubit.\n", "qubit = cirq.GridQubit(0, 0)\n", "\n", - "# Create a circuit\n", - "circuit = cirq.Circuit(\n", - " cirq.X(qubit)**0.5, # Square root of NOT.\n", - " cirq.measure(qubit, key='m') # Measurement.\n", - ")\n", + "# Create a circuit that applies a square root of NOT gate, then measures the qubit.\n", + "circuit = cirq.Circuit(cirq.X(qubit) ** 0.5, cirq.measure(qubit, key='m'))\n", "print(\"Circuit:\")\n", "print(circuit)\n", "\n", @@ -112,7 +110,11 @@ }, "source": [ "# Congratulations\n", - "You've just run your first Cirq program. If you would like to learn more about quantum computing, check out our [education page](/education). The Full API reference for Cirq can be found [here](/reference/python/cirq). If you are looking for vendor specific information that can be found on our vendor sub-pages:\n", + "You've just run your first Cirq program. \n", + "\n", + "To learn about running a circuit on a virtual machine that mimics existing quantum hardware, see [Quantum Virtual Machine](/cirq/simulate/quantum_virtual_machine).\n", + "\n", + "If you would like to learn more about quantum computing, check out our [education page](/education). The Full API reference for Cirq can be found [here](/reference/python/cirq). If you are looking for vendor specific information that can be found on our vendor sub-pages:\n", "\n", "\n", " [Alpine Quantum Technologies](/cirq/hardware/aqt/getting_started.ipynb)\n", From 21ca3ae83ca21bfc0becca81c1a2e6f2e96a9e3a Mon Sep 17 00:00:00 2001 From: Auguste Hirth Date: Mon, 18 Jul 2022 09:30:36 -0700 Subject: [PATCH 02/11] Pre fix --- docs/simulate/qvm_builder_code.ipynb | 2 +- docs/simulate/qvm_stabilizer_example.ipynb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/simulate/qvm_builder_code.ipynb b/docs/simulate/qvm_builder_code.ipynb index 647a7e8e623..ff49d949884 100644 --- a/docs/simulate/qvm_builder_code.ipynb +++ b/docs/simulate/qvm_builder_code.ipynb @@ -96,7 +96,7 @@ " import cirq_google\n", "except ImportError:\n", " print(\"installing cirq...\")\n", - " !pip install --quiet cirq-google\n", + " !pip install --quiet --pre cirq-google\n", " print(\"installed cirq.\")\n", " import cirq\n", " import cirq_google\n", diff --git a/docs/simulate/qvm_stabilizer_example.ipynb b/docs/simulate/qvm_stabilizer_example.ipynb index 085d96e8e3d..74b3118bd7d 100644 --- a/docs/simulate/qvm_stabilizer_example.ipynb +++ b/docs/simulate/qvm_stabilizer_example.ipynb @@ -96,7 +96,7 @@ " import cirq_google\n", "except ImportError:\n", " print(\"installing cirq...\")\n", - " !pip install --quiet cirq-google\n", + " !pip install --quiet --pre cirq-google\n", " print(\"installed cirq.\")\n", " import cirq\n", " import cirq_google\n", From 1295779f66d829f113376317165acfdc926c832e Mon Sep 17 00:00:00 2001 From: Auguste Hirth Date: Mon, 18 Jul 2022 09:41:40 -0700 Subject: [PATCH 03/11] Pre fix 2 --- dev_tools/notebooks/isolated_notebook_test.py | 2 ++ docs/simulate/qvm_basic_example.ipynb | 3 ++- docs/simulate/qvm_stabilizer_example.ipynb | 3 ++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/dev_tools/notebooks/isolated_notebook_test.py b/dev_tools/notebooks/isolated_notebook_test.py index a4ba61c758b..591d189f4a6 100644 --- a/dev_tools/notebooks/isolated_notebook_test.py +++ b/dev_tools/notebooks/isolated_notebook_test.py @@ -56,6 +56,8 @@ 'docs/named_topologies.ipynb', 'docs/representing_noise.ipynb', 'docs/start/intro.ipynb', + 'docs/simulate/qvm_builder_code.ipynb', + 'docs/simulate/qvm_stabilizer_example.ipynb', ] # By default all notebooks should be tested, however, this list contains exceptions to the rule diff --git a/docs/simulate/qvm_basic_example.ipynb b/docs/simulate/qvm_basic_example.ipynb index a7ebff3dd3f..5310db0694e 100644 --- a/docs/simulate/qvm_basic_example.ipynb +++ b/docs/simulate/qvm_basic_example.ipynb @@ -77,7 +77,8 @@ "id": "Lfira0gPf0Gd" }, "source": [ - "## **Install** Cirq and qsim" + "## **Install** Cirq and qsim\n", + "Note: this notebook relies on unreleased Cirq features. If you want to try these feature, make sure you install cirq via pip install cirq --pre" ] }, { diff --git a/docs/simulate/qvm_stabilizer_example.ipynb b/docs/simulate/qvm_stabilizer_example.ipynb index 74b3118bd7d..d87d7bc7d08 100644 --- a/docs/simulate/qvm_stabilizer_example.ipynb +++ b/docs/simulate/qvm_stabilizer_example.ipynb @@ -77,7 +77,8 @@ "id": "Lfira0gPf0Gd" }, "source": [ - "## **Install** Cirq and qsim, Create **Quantum Virtual Machine**" + "## **Install** Cirq and qsim, Create **Quantum Virtual Machine**\n", + "Note: this notebook relies on unreleased Cirq features. If you want to try these feature, make sure you install cirq via pip install cirq --pre" ] }, { From 5291e735978364e6c835b19e81d791a9c9ed6ed8 Mon Sep 17 00:00:00 2001 From: Auguste Hirth Date: Mon, 18 Jul 2022 09:50:03 -0700 Subject: [PATCH 04/11] pre fix 3 --- docs/simulate/qvm_builder_code.ipynb | 2 +- docs/simulate/qvm_stabilizer_example.ipynb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/simulate/qvm_builder_code.ipynb b/docs/simulate/qvm_builder_code.ipynb index ff49d949884..71bfb755e7b 100644 --- a/docs/simulate/qvm_builder_code.ipynb +++ b/docs/simulate/qvm_builder_code.ipynb @@ -96,7 +96,7 @@ " import cirq_google\n", "except ImportError:\n", " print(\"installing cirq...\")\n", - " !pip install --quiet --pre cirq-google\n", + " !pip install --quiet cirq-google --pre\n", " print(\"installed cirq.\")\n", " import cirq\n", " import cirq_google\n", diff --git a/docs/simulate/qvm_stabilizer_example.ipynb b/docs/simulate/qvm_stabilizer_example.ipynb index d87d7bc7d08..b62da8d5dde 100644 --- a/docs/simulate/qvm_stabilizer_example.ipynb +++ b/docs/simulate/qvm_stabilizer_example.ipynb @@ -97,7 +97,7 @@ " import cirq_google\n", "except ImportError:\n", " print(\"installing cirq...\")\n", - " !pip install --quiet --pre cirq-google\n", + " !pip install --quiet cirq-google --pre\n", " print(\"installed cirq.\")\n", " import cirq\n", " import cirq_google\n", From 75163ceff5dac5cd6cf17af9e6172334edcfa839 Mon Sep 17 00:00:00 2001 From: Auguste Hirth Date: Mon, 18 Jul 2022 09:55:47 -0700 Subject: [PATCH 05/11] Pre fix 4 --- docs/simulate/qvm_basic_example.ipynb | 3 +-- docs/simulate/qvm_builder_code.ipynb | 3 ++- docs/simulate/qvm_stabilizer_example.ipynb | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/simulate/qvm_basic_example.ipynb b/docs/simulate/qvm_basic_example.ipynb index 5310db0694e..a7ebff3dd3f 100644 --- a/docs/simulate/qvm_basic_example.ipynb +++ b/docs/simulate/qvm_basic_example.ipynb @@ -77,8 +77,7 @@ "id": "Lfira0gPf0Gd" }, "source": [ - "## **Install** Cirq and qsim\n", - "Note: this notebook relies on unreleased Cirq features. If you want to try these feature, make sure you install cirq via pip install cirq --pre" + "## **Install** Cirq and qsim" ] }, { diff --git a/docs/simulate/qvm_builder_code.ipynb b/docs/simulate/qvm_builder_code.ipynb index 71bfb755e7b..cf3c32970d3 100644 --- a/docs/simulate/qvm_builder_code.ipynb +++ b/docs/simulate/qvm_builder_code.ipynb @@ -77,7 +77,8 @@ "id": "Lfira0gPf0Gd" }, "source": [ - "## **Install** Cirq and qsim" + "## **Install** Cirq and qsim\n", + "Note: this notebook relies on unreleased Cirq features. If you want to try these features, make sure you install cirq via `pip install cirq --pre`." ] }, { diff --git a/docs/simulate/qvm_stabilizer_example.ipynb b/docs/simulate/qvm_stabilizer_example.ipynb index b62da8d5dde..b0f7bfc35c6 100644 --- a/docs/simulate/qvm_stabilizer_example.ipynb +++ b/docs/simulate/qvm_stabilizer_example.ipynb @@ -78,7 +78,7 @@ }, "source": [ "## **Install** Cirq and qsim, Create **Quantum Virtual Machine**\n", - "Note: this notebook relies on unreleased Cirq features. If you want to try these feature, make sure you install cirq via pip install cirq --pre" + "Note: this notebook relies on unreleased Cirq features. If you want to try these features, make sure you install cirq via `pip install cirq --pre`." ] }, { From bcb381f2b94489d79d629fdc268b45c29d6c9823 Mon Sep 17 00:00:00 2001 From: Auguste Hirth Date: Mon, 18 Jul 2022 10:40:38 -0700 Subject: [PATCH 06/11] Test fix and feedback --- docs/hardware/qubit_picking.ipynb | 8 ++++---- docs/simulate/_index.yaml | 2 +- docs/simulate/quantum_virtual_machine.ipynb | 2 +- docs/simulate/qvm_basic_example.ipynb | 14 +++++++------- docs/simulate/virtual_engine_interface.ipynb | 2 +- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/hardware/qubit_picking.ipynb b/docs/hardware/qubit_picking.ipynb index 49ee0212ae4..d9c15a1ae62 100644 --- a/docs/hardware/qubit_picking.ipynb +++ b/docs/hardware/qubit_picking.ipynb @@ -108,7 +108,7 @@ "\n", "Cirq provides characterization error data that is intended to represent median performance of actual Google quantum hardware as accurately as possible. The primary use of this data is for creating a `cirq.NoiseModel` for use in a [Quantum Virtual Machine](/cirq/simulate/quantum_virtual_machine), but it also provides information on what qubits are the best to use for your circuit. \n", "\n", - "The following code demonstrates how to load that noise data as a `cirq_google.devices.GoogleNoiseProperties` object, which specifies the available data." + "The following code demonstrates how to load that noise data as a `cirq_google.GoogleNoiseProperties` object, which specifies the available data." ] }, { @@ -134,7 +134,7 @@ "\n", "Pauli error defines decoherence of a single qubit in one of the Pauli [channels](/cirq/representing_noise) X, Y, or Z. If the errors are distributed in the uniform distribution over all three axes, the probability of applying an erroneous Pauli gate X, Y, or Z will be the Pauli error divided by three. See page 11 of [this Supplementary Information document](https://arxiv.org/abs/1910.11333){:.external} for more on Pauli error. \n", "\n", - "Below is the single qubit Pauli error for the `cirq.PhasedXZGate` supported by the Rainbow processor, pulled from the `gate_pauli_errors` attribute of the noise properties object. You can inspect the error for the others as well. However, as of July 19th, 2022, the error estimation process results in identical Pauli error for all one-qubit gates." + "Below is the single qubit Pauli error for the `cirq.PhasedXZGate` supported by the Rainbow processor, pulled from the `gate_pauli_errors` attribute of the noise properties object. You can inspect the error for the other supported one-qubit gates by replacing the `gate` variable below. However, as of July 19th, 2022, the error estimation process results in identical Pauli error for all one-qubit gates." ] }, { @@ -277,7 +277,7 @@ "source": [ "### Readout error\n", "\n", - "Readout error manifests as a measurement of $|1\\rangle$ when it should have been $|0\\rangle$, or vice versa. Note that this is different from the Pauli error induced by the `cirq.MeasurementGate`. It's important to note that, while the magnitude of measurement error is higher in general than that of Pauli error, it should be not automatically be considered to be more impactful. This is due to the fact that Pauli error can affect qubits other than the measured one and that effective readout error compensation strategies exist (that won't be discussed here)." + "Readout error manifests as a measurement of $|0\\rangle$ that should have been $|1\\rangle$, or vice versa. Note that this is different from the Pauli error induced by the `cirq.MeasurementGate`. It's important to note that, while the magnitude of measurement error is higher in general than that of Pauli error, it should be not automatically be considered to be more impactful. This is due to the fact that Pauli error can affect qubits other than the measured one and that effective readout error compensation strategies exist (that won't be discussed here)." ] }, { @@ -307,7 +307,7 @@ "id": "CipARD58sq_d" }, "source": [ - "This readout data indicates that you definitely want to avoid qubit `(7,2)`. If you're really trying to eke out the best performance possible, you may want to avoid qubits `(5,2)` and `(5,3)` as well. Note how the \"True $|1\\rangle$ measured as $|0\\rangle$\" error representing common decay is far larger and more impactful than the random excitation of $|0\\rangle$ to $|1\\rangle$ error. This is typical behavior and outside of exceptional circumstances, you can safely prioritize working around common decay error instead of random excitation error." + "This readout data indicates that you definitely want to avoid qubit `(7,2)`. If you're really trying to eke out the best performance possible, you may want to avoid qubits `(5,2)` and `(5,3)` as well. Note how the \"True $|1\\rangle$ measured as $|0\\rangle$\" error representing common decay is far larger and more impactful than the random excitation of $|0\\rangle$ to $|1\\rangle$ error. This is typical behavior and you can safely prioritize working around common decay error instead of random excitation error in most cases." ] }, { diff --git a/docs/simulate/_index.yaml b/docs/simulate/_index.yaml index 06fbd2ef9a4..fea8d9a1905 100644 --- a/docs/simulate/_index.yaml +++ b/docs/simulate/_index.yaml @@ -39,5 +39,5 @@ landing_page: description: Run a device-ready circuit on a QVM with default settings. path: /cirq/simulate/qvm_builder_code - heading: Virtual Engine Interface - description: A virtual version of the Engine interface used with hardware. + description: Details on the virtual version of the hardware Engine API and how to use it. path: /cirq/simulate/virtual_engine_interface diff --git a/docs/simulate/quantum_virtual_machine.ipynb b/docs/simulate/quantum_virtual_machine.ipynb index c894527d6ba..885e129861d 100644 --- a/docs/simulate/quantum_virtual_machine.ipynb +++ b/docs/simulate/quantum_virtual_machine.ipynb @@ -231,7 +231,7 @@ "source": [ "q0 = cirq.GridQubit(4, 4)\n", "q1 = cirq.GridQubit(4, 5)\n", - "circuit = cirq.Circuit(cirq.Z(q0), cirq.SQRT_ISWAP(q0, q1), cirq.measure([q0, q1], key=\"measure\"))\n", + "circuit = cirq.Circuit(cirq.X(q0), cirq.SQRT_ISWAP(q0, q1), cirq.measure([q0, q1], key=\"measure\"))\n", "\n", "results = sim_engine.get_sampler(processor_id).run(circuit, repetitions=3000)\n", "\n", diff --git a/docs/simulate/qvm_basic_example.ipynb b/docs/simulate/qvm_basic_example.ipynb index a7ebff3dd3f..c73bf5f2bae 100644 --- a/docs/simulate/qvm_basic_example.ipynb +++ b/docs/simulate/qvm_basic_example.ipynb @@ -122,7 +122,7 @@ "source": [ "## Create a **Quantum Virtual Machine**\n", "\n", - "The following cell builds a Quantum Virtual Machine that mimics a particular Google quantum hardware device (currently Rainbow or Weber), the \"long way\": \n", + "The following cell builds a Quantum Virtual Machine that mimics a particular Google quantum hardware device (currently Rainbow or Weber) using the following customizable steps: \n", "- Constructing a `cirq.NoiseModel` object from device calibration data saved in Cirq. See [Representing Noise](/cirq/representing_noise) for more on noise models. \n", "- Building a `qsimcirq.QsimSimulator` that uses this noise model. See [Noisy Simulation](/cirq/simulate/noisy_simulation) and [Noise simulation with qsim](/qsim/tutorials/noisy_qsimcirq) for more. \n", "- Creating a `cirq.Device` that imposes the same constraints on circuits that the original device would. See [Devices](/cirq/hardware/devices) for more on these constraint objects. \n", @@ -190,7 +190,7 @@ "source": [ "### Create a GHZ state builder circuit\n", "\n", - "The generalized [Greenberger–Horne–Zeilinger (GHZ) state](https://en.wikipedia.org/wiki/Greenberger%E2%80%93Horne%E2%80%93Zeilinger_state){:.external} has the form $\\frac{|00..0⟩ + |11..1⟩}{\\sqrt{2}}$ and in this case will be constructed using 17 qubits, with a Hadamard and a sequence of CNOT gates:" + "The generalized [Greenberger–Horne–Zeilinger (GHZ) state](https://en.wikipedia.org/wiki/Greenberger%E2%80%93Horne%E2%80%93Zeilinger_state){:.external} has the form $\\frac{|00..0⟩ + |11..1⟩}{\\sqrt{2}}$ and, in this case, will be constructed using 17 qubits, with a Hadamard and a sequence of CNOT gates:" ] }, { @@ -329,8 +329,8 @@ "# Map the line of circuit qubits to the chosen line of device qubits.\n", "qubit_map = dict(zip(qubits, device_qubit_chain))\n", "# Then replace qubits in the circuit according to that map.\n", - "deviceready_ghz_circuit = translated_ghz_circuit.transform_qubits(lambda q: qubit_map[q])\n", - "print(deviceready_ghz_circuit)" + "device_ready_ghz_circuit = translated_ghz_circuit.transform_qubits(lambda q: qubit_map[q])\n", + "print(device_ready_ghz_circuit)" ] }, { @@ -341,7 +341,7 @@ "source": [ "### **Running other circuits**\n", "\n", - "In principle you can run any custom [Circuit](/cirq/build/circuits) with a quantum virtual machine, but realistically there are some constraints. As mentioned, the circuits need to be mappable to the device. Additionally, the number of qubits that are simulatable depends highly on the hardware available to you and how long you are able to run your simulation. As the QVM is instantiated as above, with a `qsimcirq.QSimSimulator`, it only uses the default, local [qsim](https://quantumai.google/qsim) simulator. However, qsim has plenty of support for being run in a [Google Cloud instance](/qsim/tutorials/gcp_before_you_begin){:.external}, with a variable amount of compute power. In order to get the most capacity possible for qsim, use [Multinode Simulation](/qsim/tutorials/multinode).\n", + "In principle, you can run any custom [Circuit](/cirq/build/circuits) with a quantum virtual machine, but realistically there are some constraints. As mentioned, the circuits need to be mappable to the device. Additionally, the number of qubits that are simulatable depends highly on the hardware available to you and how long you are able to run your simulation. As the QVM is instantiated as above, with a `qsimcirq.QSimSimulator`, it only uses the default, local [qsim](https://quantumai.google/qsim) simulator. However, qsim has plenty of support for being run in a [Google Cloud instance](/qsim/tutorials/gcp_before_you_begin){:.external}, with a variable amount of compute power. In order to get the most capacity possible for qsim, use [Multinode Simulation](/qsim/tutorials/multinode).\n", "\n", "For an example of building and running a much larger circuit, see the [QVM Stabilizer Example](/cirq/simulate/qvm_stabilizer_example) tutorial. " ] @@ -354,7 +354,7 @@ "source": [ "## **Execute** Your Circuit on the Quantum Virtual Machine\n", "\n", - "You can run the now device-ready circuit as you would with any other `cirq.Engine` instance, but getting a sampler from it and using the `run` function on the circuits. Your choice of `repetitions` is intrinsically related to the accuracy of your simulated results. We recommend 3000 repetitions for trial runs, and 10,000 repetitions for accuracy-critical runs, but you can stick to one to ten repetitions when testing a code pipeline. You can read more about this in [this paper](https://arxiv.org/abs/2111.02396){:.external}." + "You can run the now device-ready circuit, as you would with any other `cirq.Engine` instance, by getting a sampler from it and using the `run` function on the circuits. Your choice of `repetitions` is intrinsically related to the accuracy of your simulated results. We recommend 3000 repetitions for trial runs, and 10,000 repetitions for accuracy-critical runs, but you can stick to one to ten repetitions when testing a code pipeline. You can read more about this in [this paper](https://arxiv.org/abs/2111.02396){:.external}." ] }, { @@ -367,7 +367,7 @@ "outputs": [], "source": [ "# @title Execute your device ready circuit on the Quantum Virtual Machine\n", - "circuit = deviceready_ghz_circuit\n", + "circuit = device_ready_ghz_circuit\n", "\n", "repetitions = 3000\n", "start = time.time()\n", diff --git a/docs/simulate/virtual_engine_interface.ipynb b/docs/simulate/virtual_engine_interface.ipynb index 1c09d9d58d4..df78ae5c9be 100644 --- a/docs/simulate/virtual_engine_interface.ipynb +++ b/docs/simulate/virtual_engine_interface.ipynb @@ -427,7 +427,7 @@ "device_spec = cirq_google.api.v2.device_pb2.DeviceSpecification()\n", "text_format.Parse(device_str, device_spec)\n", "four_engine = cirq_google.engine.create_noiseless_virtual_engine_from_proto(\n", - " processor_id, device_spec, gate_sets=[cirq_google.XMON]\n", + " processor_id, device_spec\n", ")\n", "# Prepare a sampler.\n", "print([proc.processor_id for proc in four_engine.list_processors()])\n", From f81e7a38dd5716d79e9d82bb5b4a70dd43d11104 Mon Sep 17 00:00:00 2001 From: Auguste Hirth Date: Mon, 18 Jul 2022 10:53:32 -0700 Subject: [PATCH 07/11] Pre fix 5 --- docs/simulate/qvm_builder_code.ipynb | 2 +- docs/simulate/qvm_stabilizer_example.ipynb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/simulate/qvm_builder_code.ipynb b/docs/simulate/qvm_builder_code.ipynb index cf3c32970d3..ab2fd176911 100644 --- a/docs/simulate/qvm_builder_code.ipynb +++ b/docs/simulate/qvm_builder_code.ipynb @@ -106,7 +106,7 @@ " import qsimcirq\n", "except ImportError:\n", " print(\"installing qsimcirq...\")\n", - " !pip install --quiet qsimcirq\n", + " !pip install --quiet qsimcirq --pre\n", " print(f\"installed qsimcirq.\")\n", " import qsimcirq\n", "\n", diff --git a/docs/simulate/qvm_stabilizer_example.ipynb b/docs/simulate/qvm_stabilizer_example.ipynb index b0f7bfc35c6..c025da7e3f3 100644 --- a/docs/simulate/qvm_stabilizer_example.ipynb +++ b/docs/simulate/qvm_stabilizer_example.ipynb @@ -106,7 +106,7 @@ " import qsimcirq\n", "except ImportError:\n", " print(\"installing qsimcirq...\")\n", - " !pip install --quiet qsimcirq\n", + " !pip install --quiet qsimcirq --pre\n", " print(f\"installed qsimcirq.\")\n", " import qsimcirq\n", "\n", From 205c397e233a31842167d30da4a9d6c77eab2f5e Mon Sep 17 00:00:00 2001 From: Auguste Hirth Date: Mon, 18 Jul 2022 11:15:12 -0700 Subject: [PATCH 08/11] Pre revert --- dev_tools/notebooks/isolated_notebook_test.py | 2 -- docs/simulate/qvm_builder_code.ipynb | 7 +++---- docs/simulate/qvm_stabilizer_example.ipynb | 7 +++---- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/dev_tools/notebooks/isolated_notebook_test.py b/dev_tools/notebooks/isolated_notebook_test.py index 591d189f4a6..a4ba61c758b 100644 --- a/dev_tools/notebooks/isolated_notebook_test.py +++ b/dev_tools/notebooks/isolated_notebook_test.py @@ -56,8 +56,6 @@ 'docs/named_topologies.ipynb', 'docs/representing_noise.ipynb', 'docs/start/intro.ipynb', - 'docs/simulate/qvm_builder_code.ipynb', - 'docs/simulate/qvm_stabilizer_example.ipynb', ] # By default all notebooks should be tested, however, this list contains exceptions to the rule diff --git a/docs/simulate/qvm_builder_code.ipynb b/docs/simulate/qvm_builder_code.ipynb index ab2fd176911..647a7e8e623 100644 --- a/docs/simulate/qvm_builder_code.ipynb +++ b/docs/simulate/qvm_builder_code.ipynb @@ -77,8 +77,7 @@ "id": "Lfira0gPf0Gd" }, "source": [ - "## **Install** Cirq and qsim\n", - "Note: this notebook relies on unreleased Cirq features. If you want to try these features, make sure you install cirq via `pip install cirq --pre`." + "## **Install** Cirq and qsim" ] }, { @@ -97,7 +96,7 @@ " import cirq_google\n", "except ImportError:\n", " print(\"installing cirq...\")\n", - " !pip install --quiet cirq-google --pre\n", + " !pip install --quiet cirq-google\n", " print(\"installed cirq.\")\n", " import cirq\n", " import cirq_google\n", @@ -106,7 +105,7 @@ " import qsimcirq\n", "except ImportError:\n", " print(\"installing qsimcirq...\")\n", - " !pip install --quiet qsimcirq --pre\n", + " !pip install --quiet qsimcirq\n", " print(f\"installed qsimcirq.\")\n", " import qsimcirq\n", "\n", diff --git a/docs/simulate/qvm_stabilizer_example.ipynb b/docs/simulate/qvm_stabilizer_example.ipynb index c025da7e3f3..085d96e8e3d 100644 --- a/docs/simulate/qvm_stabilizer_example.ipynb +++ b/docs/simulate/qvm_stabilizer_example.ipynb @@ -77,8 +77,7 @@ "id": "Lfira0gPf0Gd" }, "source": [ - "## **Install** Cirq and qsim, Create **Quantum Virtual Machine**\n", - "Note: this notebook relies on unreleased Cirq features. If you want to try these features, make sure you install cirq via `pip install cirq --pre`." + "## **Install** Cirq and qsim, Create **Quantum Virtual Machine**" ] }, { @@ -97,7 +96,7 @@ " import cirq_google\n", "except ImportError:\n", " print(\"installing cirq...\")\n", - " !pip install --quiet cirq-google --pre\n", + " !pip install --quiet cirq-google\n", " print(\"installed cirq.\")\n", " import cirq\n", " import cirq_google\n", @@ -106,7 +105,7 @@ " import qsimcirq\n", "except ImportError:\n", " print(\"installing qsimcirq...\")\n", - " !pip install --quiet qsimcirq --pre\n", + " !pip install --quiet qsimcirq\n", " print(f\"installed qsimcirq.\")\n", " import qsimcirq\n", "\n", From 9216d2a7db5a2f8c71c0cfedcadf79e86317f7a6 Mon Sep 17 00:00:00 2001 From: Auguste Hirth Date: Mon, 18 Jul 2022 17:34:51 -0700 Subject: [PATCH 09/11] Don't run qvm_builder_code --- dev_tools/notebooks/isolated_notebook_test.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dev_tools/notebooks/isolated_notebook_test.py b/dev_tools/notebooks/isolated_notebook_test.py index a4ba61c758b..323d93694d3 100644 --- a/dev_tools/notebooks/isolated_notebook_test.py +++ b/dev_tools/notebooks/isolated_notebook_test.py @@ -76,6 +76,8 @@ "examples/*fidelity*", # Also skipping stabilizer code testing. "examples/*stabilizer_code*", + # An intentionally empty/template code notebook. + "docs/simulate/qvm_builder_code.ipynb", *NOTEBOOKS_DEPENDING_ON_UNRELEASED_FEATURES, ] From 3810f28a0a07783a107a766bcd5f644cf7fdf929 Mon Sep 17 00:00:00 2001 From: Auguste Hirth Date: Mon, 18 Jul 2022 17:48:18 -0700 Subject: [PATCH 10/11] Don't run qvm_builder_code 2.0 --- dev_tools/notebooks/notebook_test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dev_tools/notebooks/notebook_test.py b/dev_tools/notebooks/notebook_test.py index d2ca59bc7a9..ad262e9e07e 100644 --- a/dev_tools/notebooks/notebook_test.py +++ b/dev_tools/notebooks/notebook_test.py @@ -41,6 +41,7 @@ 'docs/noise/qcvv/xeb_calibration_example.ipynb', 'docs/noise/calibration_api.ipynb', 'docs/noise/floquet_calibration_example.ipynb', + 'docs/simulate/qvm_builder_code.ipynb', ] From 4402ca11cedf71ace483d4edc7597bbcd67a78bd Mon Sep 17 00:00:00 2001 From: Auguste Hirth Date: Mon, 18 Jul 2022 17:55:54 -0700 Subject: [PATCH 11/11] Make qvm_builder_code USER runnable --- docs/simulate/qvm_builder_code.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/simulate/qvm_builder_code.ipynb b/docs/simulate/qvm_builder_code.ipynb index 647a7e8e623..5e9d5ea91ee 100644 --- a/docs/simulate/qvm_builder_code.ipynb +++ b/docs/simulate/qvm_builder_code.ipynb @@ -174,7 +174,7 @@ "outputs": [], "source": [ "# create your device ready circuit here!\n", - "your_circuit_name = cirq.Circuit()" + "your_circuit_name = cirq.Circuit(cirq.measure(cirq.GridQubit(4, 3)))" ] }, {