From 50009aa6cbd2d12111d6fb9018d82a0408ad70be Mon Sep 17 00:00:00 2001 From: Auguste Hirth Date: Thu, 19 May 2022 20:54:44 -0700 Subject: [PATCH 01/10] Move Rabi Oscillations from Cirq to ReCirq --- docs/_toc.yaml | 5 + .../rabi_oscillations/rabi_oscillations.ipynb | 508 ++++++++++++++++++ recirq/rabi_oscillations/__init__.py | 18 + recirq/rabi_oscillations/rabi_oscillations.py | 118 ++++ .../rabi_oscillations_test.py | 33 ++ 5 files changed, 682 insertions(+) create mode 100644 docs/rabi_oscillations/rabi_oscillations.ipynb create mode 100644 recirq/rabi_oscillations/__init__.py create mode 100644 recirq/rabi_oscillations/rabi_oscillations.py create mode 100644 recirq/rabi_oscillations/rabi_oscillations_test.py diff --git a/docs/_toc.yaml b/docs/_toc.yaml index b1eaf922..e7f3be69 100644 --- a/docs/_toc.yaml +++ b/docs/_toc.yaml @@ -68,3 +68,8 @@ toc: path: /cirq/experiments/toric_code - title: "Ground State" path: /cirq/experiments/toric_code/toric_code_ground_state + +- heading: "Rabi oscillations" +- title: "Rabi Oscillation Experiment" + path: /cirq/experiments/rabi_oscillations/rabi_oscillations.ipynb + diff --git a/docs/rabi_oscillations/rabi_oscillations.ipynb b/docs/rabi_oscillations/rabi_oscillations.ipynb new file mode 100644 index 00000000..da8cbcad --- /dev/null +++ b/docs/rabi_oscillations/rabi_oscillations.ipynb @@ -0,0 +1,508 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "zJAHLtnyQah6" + }, + "source": [ + "##### Copyright 2020 The Cirq Developers" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "zuEmbgh8QaG1" + }, + "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": "W31l4SmqQSrM" + }, + "source": [ + "# Rabi oscillation experiment" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "2eDV4QFhQhlO" + }, + "source": [ + "\n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " View on QuantumAI\n", + " \n", + " Run in Google Colab\n", + " \n", + " View source on GitHub\n", + " \n", + " Download notebook\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "bd9529db1c0b" + }, + "outputs": [], + "source": [ + "try:\n", + " import cirq\n", + "except ImportError:\n", + " print(\"installing cirq...\")\n", + " !pip install --quiet cirq\n", + " print(\"installed cirq.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "kL2C06ln6h48" + }, + "source": [ + "In this experiment, you are going to use Cirq to check that rotating a qubit by an increasing angle, and then measuring the qubit, produces Rabi oscillations. This requires you to do the following things:\n", + "\n", + "1. Prepare the $|0\\rangle$ state.\n", + "2. Rotate by an angle $\\theta$ around the $X$ axis.\n", + "3. Measure to see if the result is a 1 or a 0.\n", + "4. Repeat steps 1-3 $k$ times.\n", + "5. Report the fraction of $\\frac{\\text{Number of 1's}}{k}$\n", + "found in step 3." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ACqqV6tJ7xXp" + }, + "source": [ + "## 1. Getting to know Cirq\n", + "\n", + "Cirq emphasizes the details of implementing quantum algorithms on near term devices.\n", + "For example, when you work on a qubit in Cirq you don't operate on an unspecified qubit that will later be mapped onto a device by a hidden step.\n", + "Instead, you are always operating on specific qubits at specific locations that you specify.\n", + "\n", + "Suppose you are working with a 54 qubit Sycamore chip.\n", + "This device is included in Cirq by default.\n", + "It is called `cirq_google.Sycamore`, and you can see its layout by printing it." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "rKoMKEw46XY7" + }, + "outputs": [], + "source": [ + "import cirq\n", + "import cirq_google\n", + "\n", + "working_device = cirq_google.Sycamore\n", + "print(working_device)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "FJJEbuk-98Gj" + }, + "source": [ + "For this experiment you only need one qubit and you can just pick whichever one you like." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "XoXekxuQ8bI0" + }, + "outputs": [], + "source": [ + "my_qubit = cirq.GridQubit(5, 6)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "8Tucm7os-uET" + }, + "source": [ + "Once you've chosen your qubit you can build circuits that use it." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "niH8sty--Hu0" + }, + "outputs": [], + "source": [ + "from cirq.contrib.svg import SVGCircuit\n", + "\n", + "# Create a circuit with X, Ry(pi/2) and H.\n", + "my_circuit = cirq.Circuit(\n", + " # Rotate the qubit pi/2 radians around the X axis.\n", + " cirq.rx(3.141 / 2).on(my_qubit),\n", + " # Measure the qubit.\n", + " cirq.measure(my_qubit, key=\"out\"),\n", + ")\n", + "SVGCircuit(my_circuit)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "-zbI-2KUMU66" + }, + "source": [ + "Now you can simulate sampling from your circuit using `cirq.Simulator`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "IqUn4uv9_IVo" + }, + "outputs": [], + "source": [ + "sim = cirq.Simulator()\n", + "samples = sim.sample(my_circuit, repetitions=10)\n", + "samples" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "k-uAT6sHdGib" + }, + "source": [ + "You can also get properties of the circuit, such as the density matrix of the circuit's output or the state vector just before the terminal measurement." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "83OqpReyHyUK" + }, + "outputs": [], + "source": [ + "state_vector_before_measurement = sim.simulate(my_circuit[:-1])\n", + "sampled_state_vector_after_measurement = sim.simulate(my_circuit)\n", + "\n", + "print(f\"State before measurement:\")\n", + "print(state_vector_before_measurement)\n", + "print(f\"State after measurement:\")\n", + "print(sampled_state_vector_after_measurement)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "1raIf8dsWHLJ" + }, + "source": [ + "You can also examine the outputs from a noisy environment.\n", + "For example, an environment where 10% depolarization is applied to each qubit after each operation in the circuit:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "P7VW97ugWE_h" + }, + "outputs": [], + "source": [ + "noisy_sim = cirq.DensityMatrixSimulator(noise=cirq.depolarize(0.1))\n", + "noisy_post_measurement_state = noisy_sim.simulate(my_circuit)\n", + "noisy_pre_measurement_state = noisy_sim.simulate(my_circuit[:-1])\n", + "\n", + "print(\"Noisy state after measurement:\" + str(noisy_post_measurement_state))\n", + "print(\"Noisy state before measurement:\" + str(noisy_pre_measurement_state))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "2h6yoOl4Rmwt" + }, + "source": [ + "## 2. Parameterized Circuits and Sweeps\n", + "\n", + "Now that you have some of the basics end to end, you can create a parameterized circuit that rotates by an angle $\\theta$:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "n6h6yuyGM58s" + }, + "outputs": [], + "source": [ + "import sympy\n", + "\n", + "theta = sympy.Symbol(\"theta\")\n", + "\n", + "parameterized_circuit = cirq.Circuit(\n", + " cirq.rx(theta).on(my_qubit), cirq.measure(my_qubit, key=\"out\")\n", + ")\n", + "SVGCircuit(parameterized_circuit)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "rU3BBOp0S4sM" + }, + "source": [ + "In the above block you saw that there is a `sympy.Symbol` that you placed in the circuit. Cirq supports symbolic computation involving circuits. What this means is that when you construct `cirq.Circuit` objects you can put placeholders in many of the classical control parameters of the circuit which you can fill with values later on.\n", + "\n", + "Now if you wanted to use `cirq.simulate` or `cirq.sample` with the parameterized circuit you would also need to specify a value for `theta`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "SMdz-yAZSwrU" + }, + "outputs": [], + "source": [ + "samples_at_theta_equals_2 = sim.sample(\n", + " parameterized_circuit, params={theta: 2}, repetitions=10\n", + ")\n", + "samples_at_theta_equals_2" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "H_H13Hc8g873" + }, + "source": [ + "You can also specify *multiple* values of `theta`, and get samples back for each value." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "0zjZxGY6hIsu" + }, + "outputs": [], + "source": [ + "samples_at_multiple_theta = sim.sample(\n", + " parameterized_circuit, params=[{theta: 0.5}, {theta: 3.141}], repetitions=10\n", + ")\n", + "samples_at_multiple_theta" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "juuWvOEphaaE" + }, + "source": [ + "Cirq has shorthand notation you can use to sweep `theta` over a range of values." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "8lCb3049hqXn" + }, + "outputs": [], + "source": [ + "samples_at_swept_theta = sim.sample(\n", + " parameterized_circuit,\n", + " params=cirq.Linspace(theta, start=0, stop=3.14159, length=5),\n", + " repetitions=5,\n", + ")\n", + "samples_at_swept_theta" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "wqaORMoKiAIW" + }, + "source": [ + "The result value being returned by `sim.sample` is a `pandas.DataFrame` object.\n", + "Pandas is a common library for working with table data in python.\n", + "You can use standard pandas methods to analyze and summarize your results." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "bLzGV8nFiS9o" + }, + "outputs": [], + "source": [ + "import pandas\n", + "\n", + "big_results = sim.sample(\n", + " parameterized_circuit,\n", + " params=cirq.Linspace(theta, start=0, stop=3.14159, length=20),\n", + " repetitions=10_000,\n", + ")\n", + "\n", + "# big_results is too big to look at. Plot cross tabulated data instead.\n", + "pandas.crosstab(big_results.theta, big_results.out).plot()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "b2TkL28AmBSQ" + }, + "source": [ + "## 3. The ReCirq experiment\n", + "\n", + "[ReCirq](https://github.com/quantumlib/ReCirq) comes with a pre-written Rabi oscillation experiment `recirq.rabi_oscillations`.\n", + "This method takes a `cirq.Sampler`, which could be a simulator or a network connection to real hardware.\n", + "The method takes a few more experimental parameters, and returns a result object\n", + "that can be plotted." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ma0pVZwSThQx" + }, + "outputs": [], + "source": [ + "import datetime\n", + "from recirq.rabi_oscillations import rabi_oscillations\n", + "\n", + "result = rabi_oscillations(\n", + " sampler=noisy_sim, qubit=my_qubit, num_points=50, repetitions=10000\n", + ")\n", + "result.plot()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "U-oezaJAnzJ8" + }, + "source": [ + "Notice that you can tell from the plot that you used the noisy simulator you defined earlier.\n", + "You can also tell that the amount of depolarization is roughly 10%." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "V6uE-yFxoT-3" + }, + "source": [ + "## 4. Exercise: Find the best qubit\n", + "\n", + "As you have seen, you can use Cirq to perform a Rabi oscillation experiment.\n", + "You can either make the experiment yourself out of the basic pieces made available by Cirq, or use the prebuilt experiment method.\n", + "\n", + "Now you're going to put this knowledge to the test.\n", + "\n", + "There is some amount of depolarizing noise on each qubit.\n", + "Your goal is to characterize every qubit from the Sycamore chip using a Rabi oscillation experiment, and find the qubit with the lowest noise according to the secret noise model." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "-eISq1eqXYWx" + }, + "outputs": [], + "source": [ + "import hashlib\n", + "\n", + "\n", + "class SecretNoiseModel(cirq.NoiseModel):\n", + " def noisy_operation(self, op):\n", + " # Hey! No peeking!\n", + " q = op.qubits[0]\n", + " v = hashlib.sha256(str(q).encode()).digest()[0] / 256\n", + " yield cirq.depolarize(v).on(q)\n", + " yield op\n", + "\n", + "\n", + "secret_noise_sampler = cirq.DensityMatrixSimulator(noise=SecretNoiseModel())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Rvf87Wqrp-lu" + }, + "outputs": [], + "source": [ + "q = cirq_google.Sycamore.qubits[3]\n", + "print(\"qubit\", repr(q))\n", + "rabi_oscillations(sampler=secret_noise_sampler, qubit=q).plot()" + ] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [ + "V6uE-yFxoT-3" + ], + "name": "rabi_oscillations.ipynb", + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.12" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/recirq/rabi_oscillations/__init__.py b/recirq/rabi_oscillations/__init__.py new file mode 100644 index 00000000..743ab4ab --- /dev/null +++ b/recirq/rabi_oscillations/__init__.py @@ -0,0 +1,18 @@ +# Copyright 2022 The Cirq Developers +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from recirq.rabi_oscillations.rabi_oscillations import ( + rabi_oscillations, + RabiResult, +) diff --git a/recirq/rabi_oscillations/rabi_oscillations.py b/recirq/rabi_oscillations/rabi_oscillations.py new file mode 100644 index 00000000..c2418747 --- /dev/null +++ b/recirq/rabi_oscillations/rabi_oscillations.py @@ -0,0 +1,118 @@ +# Copyright 2022 The Cirq Developers +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Any, Iterator, List, Optional, Sequence, Tuple, TYPE_CHECKING +import numpy as np +import sympy + +from matplotlib import pyplot as plt + +# this is for older systems with matplotlib <3.2 otherwise 3d projections fail +from mpl_toolkits import mplot3d # pylint: disable=unused-import +from cirq import circuits, ops, study + +if TYPE_CHECKING: + import cirq + + +class RabiResult: + """Results from a Rabi oscillation experiment.""" + + def __init__( + self, rabi_angles: Sequence[float], excited_state_probabilities: Sequence[float] + ): + """Inits RabiResult. + + Args: + rabi_angles: The rotation angles of the qubit around the x-axis + of the Bloch sphere. + excited_state_probabilities: The corresponding probabilities that + the qubit is in the excited state. + """ + self._rabi_angles = rabi_angles + self._excited_state_probs = excited_state_probabilities + + @property + def data(self) -> Sequence[Tuple[float, float]]: + """Returns a sequence of tuple pairs with the first item being a Rabi + angle and the second item being the corresponding excited state + probability. + """ + return [ + (angle, prob) + for angle, prob in zip(self._rabi_angles, self._excited_state_probs) + ] + + def plot(self, ax: Optional[plt.Axes] = None, **plot_kwargs: Any) -> plt.Axes: + """Plots excited state probability vs the Rabi angle (angle of rotation + around the x-axis). + + Args: + ax: the plt.Axes to plot on. If not given, a new figure is created, + plotted on, and shown. + **plot_kwargs: Arguments to be passed to 'plt.Axes.plot'. + Returns: + The plt.Axes containing the plot. + """ + show_plot = not ax + if not ax: + fig, ax = plt.subplots(1, 1, figsize=(8, 8)) + ax.set_ylim([0, 1]) + ax.plot(self._rabi_angles, self._excited_state_probs, "ro-", **plot_kwargs) + ax.set_xlabel(r"Rabi Angle (Radian)") + ax.set_ylabel("Excited State Probability") + if show_plot: + fig.show() + return ax + + +def rabi_oscillations( + sampler: "cirq.Sampler", + qubit: "cirq.Qid", + max_angle: float = 2 * np.pi, + *, + repetitions: int = 1000, + num_points: int = 200, +) -> RabiResult: + """Runs a Rabi oscillation experiment. + + Rotates a qubit around the x-axis of the Bloch sphere by a sequence of Rabi + angles evenly spaced between 0 and max_angle. For each rotation, repeat + the circuit a number of times and measure the average probability of the + qubit being in the |1> state. + + Args: + sampler: The quantum engine or simulator to run the circuits. + qubit: The qubit under test. + max_angle: The final Rabi angle in radians. + repetitions: The number of repetitions of the circuit for each Rabi + angle. + num_points: The number of Rabi angles. + + Returns: + A RabiResult object that stores and plots the result. + """ + theta = sympy.Symbol("theta") + circuit = circuits.Circuit(ops.X(qubit) ** theta) + circuit.append(ops.measure(qubit, key="z")) + sweep = study.Linspace( + key="theta", start=0.0, stop=max_angle / np.pi, length=num_points + ) + results = sampler.run_sweep(circuit, params=sweep, repetitions=repetitions) + angles = np.linspace(0.0, max_angle, num_points) + excited_state_probs = np.zeros(num_points) + for i in range(num_points): + excited_state_probs[i] = np.mean(results[i].measurements["z"]) + + return RabiResult(angles, excited_state_probs) diff --git a/recirq/rabi_oscillations/rabi_oscillations_test.py b/recirq/rabi_oscillations/rabi_oscillations_test.py new file mode 100644 index 00000000..0848845c --- /dev/null +++ b/recirq/rabi_oscillations/rabi_oscillations_test.py @@ -0,0 +1,33 @@ +# Copyright 2022 The Cirq Developers +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import numpy as np + +from cirq import GridQubit +from cirq import sim +from recirq.rabi_oscillations import rabi_oscillations + + +def test_rabi_oscillations(): + # Check that the excited state population matches the ideal case within a + # small statistical error. + simulator = sim.Simulator() + qubit = GridQubit(0, 0) + results = rabi_oscillations(simulator, qubit, np.pi, repetitions=1000) + data = np.asarray(results.data) + angles = data[:, 0] + actual_pops = data[:, 1] + target_pops = 0.5 - 0.5 * np.cos(angles) + rms_err = np.sqrt(np.mean((target_pops - actual_pops) ** 2)) + assert rms_err < 0.1 From b829d849a8646f74f0826f44588027f34fa5e621 Mon Sep 17 00:00:00 2001 From: Auguste Hirth Date: Thu, 19 May 2022 20:58:58 -0700 Subject: [PATCH 02/10] Delete an empty line --- docs/_toc.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/_toc.yaml b/docs/_toc.yaml index e7f3be69..132e015a 100644 --- a/docs/_toc.yaml +++ b/docs/_toc.yaml @@ -72,4 +72,3 @@ toc: - heading: "Rabi oscillations" - title: "Rabi Oscillation Experiment" path: /cirq/experiments/rabi_oscillations/rabi_oscillations.ipynb - From 0343ae0b258ebaeb9e8efdfab2bec5e75c5875ce Mon Sep 17 00:00:00 2001 From: Auguste Hirth Date: Thu, 19 May 2022 21:04:46 -0700 Subject: [PATCH 03/10] Fix Buttons --- docs/rabi_oscillations/rabi_oscillations.ipynb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/rabi_oscillations/rabi_oscillations.ipynb b/docs/rabi_oscillations/rabi_oscillations.ipynb index da8cbcad..798586d8 100644 --- a/docs/rabi_oscillations/rabi_oscillations.ipynb +++ b/docs/rabi_oscillations/rabi_oscillations.ipynb @@ -48,16 +48,16 @@ "source": [ "\n", " \n", " \n", " \n", " \n", "
\n", - " View on QuantumAI\n", + " View on QuantumAI\n", " \n", - " Run in Google Colab\n", + " Run in Google Colab\n", " \n", - " View source on GitHub\n", + " View source on GitHub\n", " \n", - " Download notebook\n", + " Download notebook\n", "
" ] From af58339acc14db689caf59502a3e24cd9bb3bf41 Mon Sep 17 00:00:00 2001 From: Auguste Hirth Date: Fri, 20 May 2022 09:39:42 -0700 Subject: [PATCH 04/10] Run nbfmt --- docs/rabi_oscillations/rabi_oscillations.ipynb | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/docs/rabi_oscillations/rabi_oscillations.ipynb b/docs/rabi_oscillations/rabi_oscillations.ipynb index 798586d8..f4d1527f 100644 --- a/docs/rabi_oscillations/rabi_oscillations.ipynb +++ b/docs/rabi_oscillations/rabi_oscillations.ipynb @@ -486,23 +486,10 @@ "toc_visible": true }, "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", + "display_name": "Python 3", "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.12" } }, "nbformat": 4, - "nbformat_minor": 1 + "nbformat_minor": 0 } From 790f63ac3247d53dd8a2780a4817883719575b71 Mon Sep 17 00:00:00 2001 From: Auguste Hirth Date: Fri, 20 May 2022 11:35:10 -0700 Subject: [PATCH 05/10] Move to benchmarks directory --- docs/_toc.yaml | 2 +- .../rabi_oscillations.ipynb | 0 recirq/benchmarks/__init__.py | 4 ++++ .../rabi_oscillations.py | 0 .../rabi_oscillations_test.py | 0 recirq/rabi_oscillations/__init__.py | 18 ------------------ 6 files changed, 5 insertions(+), 19 deletions(-) rename docs/{rabi_oscillations => benchmarks}/rabi_oscillations.ipynb (100%) rename recirq/{rabi_oscillations => benchmarks}/rabi_oscillations.py (100%) rename recirq/{rabi_oscillations => benchmarks}/rabi_oscillations_test.py (100%) delete mode 100644 recirq/rabi_oscillations/__init__.py diff --git a/docs/_toc.yaml b/docs/_toc.yaml index 132e015a..7806a14c 100644 --- a/docs/_toc.yaml +++ b/docs/_toc.yaml @@ -71,4 +71,4 @@ toc: - heading: "Rabi oscillations" - title: "Rabi Oscillation Experiment" - path: /cirq/experiments/rabi_oscillations/rabi_oscillations.ipynb + path: /cirq/experiments/benchmarks/rabi_oscillations.ipynb diff --git a/docs/rabi_oscillations/rabi_oscillations.ipynb b/docs/benchmarks/rabi_oscillations.ipynb similarity index 100% rename from docs/rabi_oscillations/rabi_oscillations.ipynb rename to docs/benchmarks/rabi_oscillations.ipynb diff --git a/recirq/benchmarks/__init__.py b/recirq/benchmarks/__init__.py index 2b6ff390..44f117b5 100644 --- a/recirq/benchmarks/__init__.py +++ b/recirq/benchmarks/__init__.py @@ -11,3 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +from recirq.benchmarks.rabi_oscillations import ( + rabi_oscillations, + RabiResult, +) diff --git a/recirq/rabi_oscillations/rabi_oscillations.py b/recirq/benchmarks/rabi_oscillations.py similarity index 100% rename from recirq/rabi_oscillations/rabi_oscillations.py rename to recirq/benchmarks/rabi_oscillations.py diff --git a/recirq/rabi_oscillations/rabi_oscillations_test.py b/recirq/benchmarks/rabi_oscillations_test.py similarity index 100% rename from recirq/rabi_oscillations/rabi_oscillations_test.py rename to recirq/benchmarks/rabi_oscillations_test.py diff --git a/recirq/rabi_oscillations/__init__.py b/recirq/rabi_oscillations/__init__.py deleted file mode 100644 index 743ab4ab..00000000 --- a/recirq/rabi_oscillations/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright 2022 The Cirq Developers -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from recirq.rabi_oscillations.rabi_oscillations import ( - rabi_oscillations, - RabiResult, -) From 11a355a35c2d088f2bf900a486947e9493eb1192 Mon Sep 17 00:00:00 2001 From: Auguste Hirth Date: Fri, 20 May 2022 11:35:49 -0700 Subject: [PATCH 06/10] Fix buttons --- docs/benchmarks/rabi_oscillations.ipynb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/benchmarks/rabi_oscillations.ipynb b/docs/benchmarks/rabi_oscillations.ipynb index f4d1527f..a4d5717a 100644 --- a/docs/benchmarks/rabi_oscillations.ipynb +++ b/docs/benchmarks/rabi_oscillations.ipynb @@ -48,16 +48,16 @@ "source": [ "\n", " \n", " \n", " \n", " \n", "
\n", - " View on QuantumAI\n", + " View on QuantumAI\n", " \n", - " Run in Google Colab\n", + " Run in Google Colab\n", " \n", - " View source on GitHub\n", + " View source on GitHub\n", " \n", - " Download notebook\n", + " Download notebook\n", "
" ] From 4591f9394504f36f6cc01b98a697be7a290f9abf Mon Sep 17 00:00:00 2001 From: Auguste Hirth Date: Fri, 20 May 2022 11:45:24 -0700 Subject: [PATCH 07/10] Fix Imports --- docs/benchmarks/rabi_oscillations.ipynb | 2 +- recirq/benchmarks/rabi_oscillations_test.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/benchmarks/rabi_oscillations.ipynb b/docs/benchmarks/rabi_oscillations.ipynb index a4d5717a..17dabfd4 100644 --- a/docs/benchmarks/rabi_oscillations.ipynb +++ b/docs/benchmarks/rabi_oscillations.ipynb @@ -405,7 +405,7 @@ "outputs": [], "source": [ "import datetime\n", - "from recirq.rabi_oscillations import rabi_oscillations\n", + "from recirq.benchmarks import rabi_oscillations\n", "\n", "result = rabi_oscillations(\n", " sampler=noisy_sim, qubit=my_qubit, num_points=50, repetitions=10000\n", diff --git a/recirq/benchmarks/rabi_oscillations_test.py b/recirq/benchmarks/rabi_oscillations_test.py index 0848845c..5c84c6b2 100644 --- a/recirq/benchmarks/rabi_oscillations_test.py +++ b/recirq/benchmarks/rabi_oscillations_test.py @@ -16,7 +16,7 @@ from cirq import GridQubit from cirq import sim -from recirq.rabi_oscillations import rabi_oscillations +from recirq.benchmarks import rabi_oscillations def test_rabi_oscillations(): From 0d2a96f8c76a54b72aa8c77491b317090cbc9e58 Mon Sep 17 00:00:00 2001 From: Auguste Hirth Date: Mon, 23 May 2022 10:25:29 -0700 Subject: [PATCH 08/10] Feedback changes v1 --- docs/benchmarks/rabi_oscillations.ipynb | 35 +++++++++------------ recirq/benchmarks/rabi_oscillations.py | 17 +++++----- recirq/benchmarks/rabi_oscillations_test.py | 9 ++++-- 3 files changed, 27 insertions(+), 34 deletions(-) diff --git a/docs/benchmarks/rabi_oscillations.ipynb b/docs/benchmarks/rabi_oscillations.ipynb index 17dabfd4..5cb7b9a8 100644 --- a/docs/benchmarks/rabi_oscillations.ipynb +++ b/docs/benchmarks/rabi_oscillations.ipynb @@ -75,7 +75,11 @@ "except ImportError:\n", " print(\"installing cirq...\")\n", " !pip install --quiet cirq\n", - " print(\"installed cirq.\")" + " print(\"installed cirq.\")\n", + " import cirq\n", + "\n", + "import numpy as np\n", + "import cirq_google" ] }, { @@ -119,9 +123,6 @@ }, "outputs": [], "source": [ - "import cirq\n", - "import cirq_google\n", - "\n", "working_device = cirq_google.Sycamore\n", "print(working_device)" ] @@ -168,7 +169,7 @@ "# Create a circuit with X, Ry(pi/2) and H.\n", "my_circuit = cirq.Circuit(\n", " # Rotate the qubit pi/2 radians around the X axis.\n", - " cirq.rx(3.141 / 2).on(my_qubit),\n", + " cirq.rx(np.pi / 2).on(my_qubit),\n", " # Measure the qubit.\n", " cirq.measure(my_qubit, key=\"out\"),\n", ")\n", @@ -193,8 +194,7 @@ "outputs": [], "source": [ "sim = cirq.Simulator()\n", - "samples = sim.sample(my_circuit, repetitions=10)\n", - "samples" + "samples = sim.sample(my_circuit, repetitions=10)" ] }, { @@ -297,10 +297,7 @@ }, "outputs": [], "source": [ - "samples_at_theta_equals_2 = sim.sample(\n", - " parameterized_circuit, params={theta: 2}, repetitions=10\n", - ")\n", - "samples_at_theta_equals_2" + "sim.sample(parameterized_circuit, params={theta: 2}, repetitions=10)" ] }, { @@ -320,10 +317,7 @@ }, "outputs": [], "source": [ - "samples_at_multiple_theta = sim.sample(\n", - " parameterized_circuit, params=[{theta: 0.5}, {theta: 3.141}], repetitions=10\n", - ")\n", - "samples_at_multiple_theta" + "sim.sample(parameterized_circuit, params=[{theta: 0.5}, {theta: np.pi}], repetitions=10)" ] }, { @@ -343,12 +337,11 @@ }, "outputs": [], "source": [ - "samples_at_swept_theta = sim.sample(\n", + "sim.sample(\n", " parameterized_circuit,\n", - " params=cirq.Linspace(theta, start=0, stop=3.14159, length=5),\n", + " params=cirq.Linspace(theta, start=0, stop=np.pi, length=5),\n", " repetitions=5,\n", - ")\n", - "samples_at_swept_theta" + ")" ] }, { @@ -374,7 +367,7 @@ "\n", "big_results = sim.sample(\n", " parameterized_circuit,\n", - " params=cirq.Linspace(theta, start=0, stop=3.14159, length=20),\n", + " params=cirq.Linspace(theta, start=0, stop=np.pi, length=20),\n", " repetitions=10_000,\n", ")\n", "\n", @@ -390,7 +383,7 @@ "source": [ "## 3. The ReCirq experiment\n", "\n", - "[ReCirq](https://github.com/quantumlib/ReCirq) comes with a pre-written Rabi oscillation experiment `recirq.rabi_oscillations`.\n", + "[ReCirq](https://github.com/quantumlib/ReCirq) comes with a pre-written Rabi oscillation experiment `recirq.benchmarks.rabi_oscillations`.\n", "This method takes a `cirq.Sampler`, which could be a simulator or a network connection to real hardware.\n", "The method takes a few more experimental parameters, and returns a result object\n", "that can be plotted." diff --git a/recirq/benchmarks/rabi_oscillations.py b/recirq/benchmarks/rabi_oscillations.py index c2418747..d9eb1445 100644 --- a/recirq/benchmarks/rabi_oscillations.py +++ b/recirq/benchmarks/rabi_oscillations.py @@ -20,10 +20,7 @@ # this is for older systems with matplotlib <3.2 otherwise 3d projections fail from mpl_toolkits import mplot3d # pylint: disable=unused-import -from cirq import circuits, ops, study - -if TYPE_CHECKING: - import cirq +import cirq class RabiResult: @@ -32,7 +29,7 @@ class RabiResult: def __init__( self, rabi_angles: Sequence[float], excited_state_probabilities: Sequence[float] ): - """Inits RabiResult. + """Initializes RabiResult. Args: rabi_angles: The rotation angles of the qubit around the x-axis @@ -78,8 +75,8 @@ def plot(self, ax: Optional[plt.Axes] = None, **plot_kwargs: Any) -> plt.Axes: def rabi_oscillations( - sampler: "cirq.Sampler", - qubit: "cirq.Qid", + sampler: cirq.Sampler, + qubit: cirq.Qid, max_angle: float = 2 * np.pi, *, repetitions: int = 1000, @@ -104,9 +101,9 @@ def rabi_oscillations( A RabiResult object that stores and plots the result. """ theta = sympy.Symbol("theta") - circuit = circuits.Circuit(ops.X(qubit) ** theta) - circuit.append(ops.measure(qubit, key="z")) - sweep = study.Linspace( + circuit = cirq.Circuit(cirq.X(qubit) ** theta) + circuit.append(cirq.measure(qubit, key="z")) + sweep = cirq.study.Linspace( key="theta", start=0.0, stop=max_angle / np.pi, length=num_points ) results = sampler.run_sweep(circuit, params=sweep, repetitions=repetitions) diff --git a/recirq/benchmarks/rabi_oscillations_test.py b/recirq/benchmarks/rabi_oscillations_test.py index 5c84c6b2..1a9eff7e 100644 --- a/recirq/benchmarks/rabi_oscillations_test.py +++ b/recirq/benchmarks/rabi_oscillations_test.py @@ -20,11 +20,14 @@ def test_rabi_oscillations(): - # Check that the excited state population matches the ideal case within a - # small statistical error. + """Check that the excited state population matches the ideal case within a + small statistical error. + """ simulator = sim.Simulator() qubit = GridQubit(0, 0) - results = rabi_oscillations(simulator, qubit, np.pi, repetitions=1000) + results = rabi_oscillations( + simulator, qubit, np.pi, repetitions=1000, num_points=1000 + ) data = np.asarray(results.data) angles = data[:, 0] actual_pops = data[:, 1] From 98358f78e38341262c4f53e229d27fc5efb1dab9 Mon Sep 17 00:00:00 2001 From: Auguste Hirth Date: Tue, 24 May 2022 15:28:04 -0700 Subject: [PATCH 09/10] Feedback v2 --- docs/benchmarks/rabi_oscillations.ipynb | 10 +++++----- recirq/benchmarks/rabi_oscillations.py | 15 +++++++-------- recirq/benchmarks/rabi_oscillations_test.py | 7 +++---- 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/docs/benchmarks/rabi_oscillations.ipynb b/docs/benchmarks/rabi_oscillations.ipynb index 5cb7b9a8..7d33d432 100644 --- a/docs/benchmarks/rabi_oscillations.ipynb +++ b/docs/benchmarks/rabi_oscillations.ipynb @@ -72,11 +72,13 @@ "source": [ "try:\n", " import cirq\n", + " import recirq\n", "except ImportError:\n", - " print(\"installing cirq...\")\n", + " !pip install -U pip\n", " !pip install --quiet cirq\n", - " print(\"installed cirq.\")\n", + " !pip install --quiet recirq\n", " import cirq\n", + " import recirq\n", "\n", "import numpy as np\n", "import cirq_google" @@ -384,9 +386,7 @@ "## 3. The ReCirq experiment\n", "\n", "[ReCirq](https://github.com/quantumlib/ReCirq) comes with a pre-written Rabi oscillation experiment `recirq.benchmarks.rabi_oscillations`.\n", - "This method takes a `cirq.Sampler`, which could be a simulator or a network connection to real hardware.\n", - "The method takes a few more experimental parameters, and returns a result object\n", - "that can be plotted." + "This method takes a `cirq.Sampler`, which could be a simulator or a network connection to real hardware, as well as a qubit to test and two iteration parameters, `num_points` and `repetitions`. The result is a sequence of the expected probabilities of the chosen qubit at each of the Rabi angles in a sequence `num_points` long." ] }, { diff --git a/recirq/benchmarks/rabi_oscillations.py b/recirq/benchmarks/rabi_oscillations.py index d9eb1445..3a8b5916 100644 --- a/recirq/benchmarks/rabi_oscillations.py +++ b/recirq/benchmarks/rabi_oscillations.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Any, Iterator, List, Optional, Sequence, Tuple, TYPE_CHECKING +from typing import Any, Optional, Sequence, Tuple import numpy as np import sympy @@ -24,7 +24,9 @@ class RabiResult: - """Results from a Rabi oscillation experiment.""" + """Results from a Rabi oscillation experiment. This consists of a set of x-axis + angles following a sine wave and corresponding measurement probabilities for each. + """ def __init__( self, rabi_angles: Sequence[float], excited_state_probabilities: Sequence[float] @@ -46,10 +48,7 @@ def data(self) -> Sequence[Tuple[float, float]]: angle and the second item being the corresponding excited state probability. """ - return [ - (angle, prob) - for angle, prob in zip(self._rabi_angles, self._excited_state_probs) - ] + return list(zip(self._rabi_angles, self._excited_state_probs)) def plot(self, ax: Optional[plt.Axes] = None, **plot_kwargs: Any) -> plt.Axes: """Plots excited state probability vs the Rabi angle (angle of rotation @@ -101,10 +100,10 @@ def rabi_oscillations( A RabiResult object that stores and plots the result. """ theta = sympy.Symbol("theta") - circuit = cirq.Circuit(cirq.X(qubit) ** theta) + circuit = cirq.Circuit(cirq.X(qubit) ** (theta / np.pi)) circuit.append(cirq.measure(qubit, key="z")) sweep = cirq.study.Linspace( - key="theta", start=0.0, stop=max_angle / np.pi, length=num_points + key="theta", start=0.0, stop=max_angle, length=num_points ) results = sampler.run_sweep(circuit, params=sweep, repetitions=repetitions) angles = np.linspace(0.0, max_angle, num_points) diff --git a/recirq/benchmarks/rabi_oscillations_test.py b/recirq/benchmarks/rabi_oscillations_test.py index 1a9eff7e..08122830 100644 --- a/recirq/benchmarks/rabi_oscillations_test.py +++ b/recirq/benchmarks/rabi_oscillations_test.py @@ -14,8 +14,7 @@ import numpy as np -from cirq import GridQubit -from cirq import sim +import cirq from recirq.benchmarks import rabi_oscillations @@ -23,8 +22,8 @@ def test_rabi_oscillations(): """Check that the excited state population matches the ideal case within a small statistical error. """ - simulator = sim.Simulator() - qubit = GridQubit(0, 0) + simulator = cirq.sim.Simulator() + qubit = cirq.GridQubit(0, 0) results = rabi_oscillations( simulator, qubit, np.pi, repetitions=1000, num_points=1000 ) From 67d6af8f81029a7cc1abbd4d358b4003683a5684 Mon Sep 17 00:00:00 2001 From: Auguste Hirth Date: Wed, 25 May 2022 19:48:56 -0700 Subject: [PATCH 10/10] Added further explanation of Rabi experiment --- docs/benchmarks/rabi_oscillations.ipynb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/benchmarks/rabi_oscillations.ipynb b/docs/benchmarks/rabi_oscillations.ipynb index 7d33d432..14c2cfba 100644 --- a/docs/benchmarks/rabi_oscillations.ipynb +++ b/docs/benchmarks/rabi_oscillations.ipynb @@ -385,8 +385,9 @@ "source": [ "## 3. The ReCirq experiment\n", "\n", - "[ReCirq](https://github.com/quantumlib/ReCirq) comes with a pre-written Rabi oscillation experiment `recirq.benchmarks.rabi_oscillations`.\n", - "This method takes a `cirq.Sampler`, which could be a simulator or a network connection to real hardware, as well as a qubit to test and two iteration parameters, `num_points` and `repetitions`. The result is a sequence of the expected probabilities of the chosen qubit at each of the Rabi angles in a sequence `num_points` long." + "[ReCirq](https://github.com/quantumlib/ReCirq) comes with a pre-written Rabi oscillation experiment `recirq.benchmarks.rabi_oscillations`, which performs the steps outlined at the start of this tutorial to create a circuit that exhibits Rabi Oscillations or [Rabi Cycles](https://en.wikipedia.org/wiki/Rabi_cycle). \n", + "\n", + "This method takes a `cirq.Sampler`, which could be a simulator or a network connection to real hardware, as well as a qubit to test and two iteration parameters, `num_points` and `repetitions`. It then runs `repetitions` many experiments on the provided `sampler`, where each experiment is a circuit that rotates the chosen `qubit` by some $\\theta$ Rabi angle around the $X$ axis (by applying an exponentiated $X$ gate). The result is a sequence of the expected probabilities of the chosen qubit at each of the Rabi angles. " ] }, {