{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "#
Practical Quantum Computing with Cirq
\n", "Ryan LaRose
\n", "Department of Computational Mathematics, Science, and Engineering, Michigan State University
\n", "Department of Physics and Astronomy, Michigan State University
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "###Abstract
\n", "In July 2018, the Quantum Computing Report featured an in-depth analysis of four major gate-model quantum software platforms: Forest by Rigetti, QISKit by IBM, ProjectQ by ETH Zurich, and the Quantum Developer Kit by Microsoft. Shortly after, Google announced the release of their own quantum software platform: Cirq. In this paper, we provide an overview and comparative analysis of this newly-released platform with respect to the previously-reviewed quantum software platforms. Our analysis proceeds similarly by covering requirements and installation, language syntax through example programs, quantum simulators, and quantum computer capabilities. We additionally cover more advanced features of the platform including quantum circuit manipulation/optimization, device-oriented circuits and quantum compiling, and strong support for variational quantum algorithms and near-term quantum computing.
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#I. Introduction
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "Quantum computing is transitioning from a theoretical to practical phase. Historically, researchers have asked questions about the possibilities of speedups through black-box access to abstract, idealized quantum computers. Recently, small, imperfect quantum computers have been fabricated and made available over the cloud. A significant body of literature is emerging as researchers use these devices to solve problems in nuclear physics [Du2018], quantum chemistry [Pe2014], condensed matter [La2018], optimization [Fa2014], number theory [An2018], graph theory [Wa2018], and even quantum computing itself [Kh2018]. While these problems are small and easily handled by conventional computers, the prospect of large-scale quantum computers could quickly change this. Even on current quantum computers, certain contrived problems may soon demonstrate \"quantum supremacy\" [Ne2017, Ma2018], an exciting landmark in the history of computation. \n", "
\n", "\n", "\n", "This theoretical-to-practical progression of the field necessitates access to quantum computers that is much different from black box access on pen and paper. Many institutions in industry and academia have recognized this and began building tools for this purpose, and a slew of startup companies has emerged to fill the gaps in the transition to practical quantum computing. The following diagram shows a partial snapshot of this rapidly evolving landscape:\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "Schematic diagram showing quantum computing companies and their position in the quantum software stack. \"Full-stack providers\" focus on all areas of the stack whereas \"target providers\" focus on particular areas. Because companies that do algorithms/applications frequently do software as well, we have combined these two categories on the right. (Similarly for hardware & compilation and control.)
\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "For most \"full-stack\" quantum computing companies, access to quantum computers is granted over the cloud, and the interaction between research scientists and quantum computers is mediated by a software platform with API access. To an outside observer, this interaction does not warrant much thought: it just needs to give users the ability to implement quantum gates on qubits. However, many practical considerations emerge when using a software interface to communicate with a real or simulated quantum computer. Among these are the following:\n", "
\n", "\n", "1. What gate operations are natively built-in?\n", "1. Can a gate that's not native be implemented into a quantum algorithm? How difficult is it to do this?\n", "1. How many quantum computers does the platform give access to?\n", "1. Is compilation handled automatically by the software? And to what degree of optimality?\n", "1. How do job requests to quantum computers get handled? In a queue, dedicated time?\n", "1. What quantum computer simulators can be used to test algorithms? How many qubits can be simulated? Is the simulator noisy or noiseless?\n", "1. Does every quantum algorithm have to be programmed manually? Or are some common subroutines built-in?\n", "1. What classical programming language is the software written in?\n", "1. How easy is it to create, work with, and manipulate quantum circuits?\n", "1. How easy is it to parametrize algorithms for near-term quantum computing?\n", "\n", "\n", "Each of these considerations is important from a practical perspective. For example, an algorithm on many qubits may be better implemented on a platform with a higher-performance simulator; an algorithm with many gates may be better for a platform with higher fidelity qubits; an algorithm with many non-standard gates may be better for a platform with an optimal compiler. Other considerations such as examples, tutorials, and documentation are equally important as they help bring in new users and answer questions of experienced users.\n", "
\n", "\n", "\n", "For these reasons, it is both valid and important to evaluate quantum software platforms as more than the simple interface they may appear to be. To this end, the Quantum Computing Report published an article [LaR2018] comparing Forest by Rigetti, QISKit by IBM, ProjectQ by ETH Zurich, and the Quantum Developer Kit by Microsoft. (Subsequently, other articles on quantum software have also been written, e.g. [Fi2018].) Each platform was found to have different strengths and different emphases that determined the set of problems best-suited for the environment. The purpose of this article is to introduce and analyze Cirq in a similar fashion.\n", "
\n", "\n", "\n", "To this end, the rest of the article is organized as follows. After briefly commenting on the format of this article, we cover installation, documentation, language syntax, and quantum computer/simulator support in Cirq. We then transition into more advanced features like circuit manipulation and optimization and circuits for a partcular quantum computer. Lastly, we conclude with example programs including a variational quantum algorithm to demonstrate the near-term capabilities of Cirq. Throughout, we refer back to previously covered software platforms to maintain the comparative analysis in our previous installation.\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##A. Format of the Article
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "This article was written as a Jupyter Notebook and exported as an HTML file. The HTML file is hosted on the Quantum Computing Report website and the Jupyter notebook is hosted on GitHub. In the HTML version, all code and all outputs are visible in the article, but the code is not able to run. To interactively run the code while reading through the article, see the Jupyter Notebook version. In order to run the code, a working installation of Cirq is required (see Installation below). The Cirq code in the notebook version will be kept up-to-date with future versions/releases of Cirq. The article assumes basic familiarity with quantum computing, for which many good resources now exist.\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#II. The Basics of Cirq
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Institution | \n", " \n", "Version | \n", " \n", " \n", " \n", "GitHub | \n", "Documentation | \n", "OS | \n", "Requirements | \n", "Classical Language | \n", "Quantum Language | \n", "Quantum Hardware | \n", "Simulator | \n", " \n", " \n", "
---|---|---|---|---|---|---|---|---|---|
Google Quantum AI | \n", "v0.4.0 | \n", "Git | \n", "Docs | \n", "Mac, Windows, Linux | \n", "Python 3.5 or greater (else Python 2.7) | \n", "Python | \n", "---- | \n", "Foxtail (22 qubits), Bristlecone (72 qubits) | \n", "~20-30 qubits | \n", "
\n", "Cirq is an open-source Python framework for \"creating, editing, and invoking Noisy Intermediate-Scale Quantum (NISQ) circuits\" [Ho2018]. The first version of the software was publicly announced in July 2018; the code is still in alpha testing and under development. As such, some features or code included in this article may need modifications for future versions of Cirq. This article should be considered a review for the version of Cirq at the time of writing, which is listed in the table above. (As mentioned above, the Jupyter Notebook version of this article, hosted online at [GitHub](https://github.com/rmlarose), will be kept up to date as future versions of Cirq are released.)\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "The components of Cirq. When installed onto a computer, Cirq provides a library for working with quantum circuits and a high-performance local quantum circuit simulator. As of December 2018, connection to hardware devices or the \"Quantum Engine\"/\"Quantum Cloud Services\" is unavailable to general users, but this is expected to change in the future.
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##A. Installation
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The easiest way to install `Cirq` is by using pip via\n", "\n", "```\n", "pip install cirq\n", "```\n", "\n", "at a command line. Without leaving the notebook, executing the cell below will try to install Cirq v0.4.0 on the user's computer. Alternatively, the source code for Cirq can be obtained from https://github.com/quantumlib/Cirq. For complete installation instructions on multiple platforms, see the documentation at https://cirq.readthedocs.io/en/latest/install.html. Readers who simply wish to read the article without using Cirq can ignore this step.\n", "
" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\"\"\"Attempts to pip install Cirq 0.4.0.\"\"\"\n", "#!pip install --upgrade pip\n", "#!pip install cirq==0.4.0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##B. Documentation and Tutorials
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "The documentation for Cirq contains instructions on installation for all three major operating systems, an in-depth tutorial for the variational quantum eigensolver, and details on three major components of the Cirq library: circuits, gates, and simulation. In addition, the section on Schedules and Devices details how Cirq can be used with specific quantum hardware and reflects the emphasis on near-term quantum computing. The documentation also contains a detailed API reference for the entire library and development guidelines for those who may want to contribute to the source code.\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##C. Language Syntax
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "As in our previous coverage of quantum software platforms, we include example programs to demonstrate the language syntax. Below, we implement the \"quantum random bit generator\" algorithm, which produces either zero or one output that is random by the laws of quantum mechanics. To use the functionality of Cirq, we first import the library (and additional libraries we'll use throughout the article).\n", "
" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "\"\"\"Library imports for the article.\"\"\"\n", "import cirq\n", "\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "%matplotlib inline" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "In what follows we create a circuit and instantiate it with the operations for the algorithm (Hadamard and measure).\n", "
" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "\"\"\"Create a random number generator circuit using Cirq.\"\"\"\n", "# get a qubit register\n", "qbits = [cirq.LineQubit(0)]\n", "\n", "# get a quantum circuit\n", "circ = cirq.Circuit()\n", "\n", "# add the instructions to the circuit\n", "circ.append([cirq.H(qbits[0]),\n", " cirq.measure(qbits[0], key=\"z\")])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "Note that Cirq defines qubits to be `LineQubit`s or `GridQubit`s, since these are common constructions in NISQ computers. The former is indexed by one integer, as we have done in Line 4 above, and the latter by two (x, y coordinates). Qubits are commonly defined in lists (or generally iterables) for easy indexing in algorithms. In line 6 above we instantiate a circuit, and in lines 9-10 we append the instructions for the algorithm. (There are multiple ways to add instructions to an algorithm in Cirq. For most of this article, we'll stick to the above method for simplicity. See Section III.A for alternatives.)\n", "
\n", "\n", "\n", "The Cirq library provides text diagram representation of quantum circuits, which can be visualized by printing out the circuit:\n", "
" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0: ───H───M('z')───\n" ] } ], "source": [ "\"\"\"Print out the random number generator circuit.\"\"\"\n", "print(circ)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "While these diagrams are not of publication quality like those that can be made in ProjectQ or even QISKit, they are a useful tool for verifying correctness of quantum circuits and debugging. Note that measurements are made with a `key` to easily access the results of running the circuit, as we will see below.\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##D. Quantum Computers
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "Cirq does not currently provide cloud access to Google's quantum computers for general users. Indeed, as per the documentation in Cirq's engine class:\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\"In order to run on[e] must have access to the Quantum Engine API. Access to this\n", "API is (as of June 22, 2018) restricted to invitation only.\"\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "Nonetheless, it is known that Google has quantum computers that have been stated to be made available over the cloud in the near future [Ho2018], using Cirq as an interface. Indeed, Cirq already provides details on these devices. For instance, the architecture of the 22-qubit FoxTail computer can be printed out in Cirq by doing:\n", "
" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "FoxTail has 22 qubits arranged as follows:\n", "\n", "(0, 0)───(0, 1)───(0, 2)───(0, 3)───(0, 4)───(0, 5)───(0, 6)───(0, 7)───(0, 8)───(0, 9)───(0, 10)\n", "│ │ │ │ │ │ │ │ │ │ │\n", "│ │ │ │ │ │ │ │ │ │ │\n", "(1, 0)───(1, 1)───(1, 2)───(1, 3)───(1, 4)───(1, 5)───(1, 6)───(1, 7)───(1, 8)───(1, 9)───(1, 10)\n" ] } ], "source": [ "\"\"\"Print out the architecture of the FoxTail quantum computer.\"\"\"\n", "s = \"FoxTail has {} qubits arranged as follows:\\n\"\n", "print(s.format(len(cirq.google.Foxtail.qubits)))\n", "print(cirq.google.Foxtail)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The 72-qubit Bristlecone computer, with which quantum supremacy may be demonstrated on, can be displayed similarly:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Bristlecone has 72 qubits arranged as follows:\n", "\n", " (0, 5)────(0, 6)\n", " │ │\n", " │ │\n", " (1, 4)───(1, 5)────(1, 6)────(1, 7)\n", " │ │ │ │\n", " │ │ │ │\n", " (2, 3)───(2, 4)───(2, 5)────(2, 6)────(2, 7)───(2, 8)\n", " │ │ │ │ │ │\n", " │ │ │ │ │ │\n", " (3, 2)───(3, 3)───(3, 4)───(3, 5)────(3, 6)────(3, 7)───(3, 8)───(3, 9)\n", " │ │ │ │ │ │ │ │\n", " │ │ │ │ │ │ │ │\n", " (4, 1)───(4, 2)───(4, 3)───(4, 4)───(4, 5)────(4, 6)────(4, 7)───(4, 8)───(4, 9)───(4, 10)\n", " │ │ │ │ │ │ │ │ │ │\n", " │ │ │ │ │ │ │ │ │ │\n", "(5, 0)───(5, 1)───(5, 2)───(5, 3)───(5, 4)───(5, 5)────(5, 6)────(5, 7)───(5, 8)───(5, 9)───(5, 10)───(5, 11)\n", " │ │ │ │ │ │ │ │ │ │\n", " │ │ │ │ │ │ │ │ │ │\n", " (6, 1)───(6, 2)───(6, 3)───(6, 4)───(6, 5)────(6, 6)────(6, 7)───(6, 8)───(6, 9)───(6, 10)\n", " │ │ │ │ │ │ │ │\n", " │ │ │ │ │ │ │ │\n", " (7, 2)───(7, 3)───(7, 4)───(7, 5)────(7, 6)────(7, 7)───(7, 8)───(7, 9)\n", " │ │ │ │ │ │\n", " │ │ │ │ │ │\n", " (8, 3)───(8, 4)───(8, 5)────(8, 6)────(8, 7)───(8, 8)\n", " │ │ │ │\n", " │ │ │ │\n", " (9, 4)───(9, 5)────(9, 6)────(9, 7)\n", " │ │\n", " │ │\n", " (10, 5)───(10, 6)\n" ] } ], "source": [ "\"\"\"Print out the architecture of the Bristlecone quantum computer.\"\"\"\n", "s = \"Bristlecone has {} qubits arranged as follows:\\n\"\n", "print(s.format(len(cirq.google.Bristlecone.qubits)))\n", "print(cirq.google.Bristlecone)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "The Foxtail and Bristlecone processors implement a Controlled-$Z$ gate as their two-qubit unitary (as opposed to a CNOT gate as is common with other architectures, e.g. IBM), but it is unclear to the author which particular single qubit gates are in the native gate set. (This statement is made based off of experiments compiling arbitrary gates into Foxtail/Bristlecone. See Section III.D below.) For reference, the Controlled-$Z$ gate has the following matrix representation:\n", "\\begin{equation}\n", "C(Z) = \\left[ \\begin{matrix} \n", "1 & 0 & 0 & 0 \\\\\n", "0 & 1 & 0 & 0 \\\\\n", "0 & 0 & 1 & 0 \\\\\n", "0 & 0 & 0 & -1 \\\\\n", "\\end{matrix} \\right] .\n", "\\end{equation}\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It should be noted that Cirq provides built-in functionality to convert its circuits to OpenQASM code:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "// Generated from Cirq v0.4.0\n", "\n", "OPENQASM 2.0;\n", "include \"qelib1.inc\";\n", "\n", "\n", "// Qubits: [0]\n", "qreg q[1];\n", "creg m_z[1];\n", "\n", "\n", "h q[0];\n", "measure q[0] -> m_z[0];\n", "\n" ] } ], "source": [ "\"\"\"Generate OpenQASM code for the random number generator circuit.\"\"\"\n", "print(circ.to_qasm())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "This functionality makes it very simple to run algorithms generated in Cirq on IBM's quantum computers. (For instance, by navigating to the IBM Q Experience website and using the online QASM editor. See the Figure below.)\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "Screenshot from the IBM Q Experience online QASM Editor using Cirq to generate QASM code. The code input into the editor is the same code obtained above by executing `circ.to_qasm()`. By selecting \"run\" or \"simulate\" on the IBM Q Experience website, one can execute the quantum algorithm on a real or simulated quantum computer, respectively.
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##E. Quantum Simulators
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "Although access to Google's quantum computers is currently restricted, Cirq provides two quantum computer simulators, the `Simulator` and the `XmonSimulator`, to locally execute quantum algorithms. The `Simulator` works for generic gates that implement their unitary matrix. The `XmonSimulator` is specialized for the native gate set of Google's quantum computers and can utilize multi-threading to improve performance in certain cases.\n", "
\n", "\n", "\n", "To run the random bit generator circuit above with the `Simulator`, we can do the following:\n", "
" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Counter({1: 31, 0: 19})\n" ] } ], "source": [ "\"\"\"Run the random number generator on the XmonSimulator.\"\"\"\n", "# get the simulator\n", "simulator = cirq.Simulator()\n", "\n", "# run the circuit\n", "out = simulator.run(circ, repetitions=50)\n", "\n", "# get the results and display them\n", "results = out.histogram(key=\"z\")\n", "print(results)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "The output is returned as a `Counter` object (Python built-in class in the `collections` library) that displays key-value pairs corresponding to the output and number of times that output was recorded. Cirq also provides the function `plot_state_histogram` to visualize the output distribution:\n", "
" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "scrolled": false }, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "