{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Clifford Randomized Benchmarking" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This tutorial contains a few details on how to run [Clifford Randomized Benchmarking](http://journals.aps.org/prl/abstract/10.1103/PhysRevLett.106.180504) that are not covered in the [RB overview tutorial](RB-Overview.ipynb). \n", "\n", "\n", "## What is Clifford RB? \n", "\n", "By Clifford randomized benchmarking we mean RB of the $n$-qubit Clifford group, as defined by Magesan *et al.* in [*Scalable and Robust Benchmarking of Quantum Processes*](http://journals.aps.org/prl/abstract/10.1103/PhysRevLett.106.180504). This protocol is routinely run on 1 and 2 qubits." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from __future__ import print_function #python 2 & 3 compatibility\n", "import pygsti" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Creating a Clifford RB experiment design\n", "\n", "The only aspects of running Clifford RB with pyGSTi that are not covered in the [RB overview tutorial](RB-Overview.ipynb) are some subtleties in generating a Clifford RB experiment design (and what those subtleties mean for interpretting the results). To cover these subtleties, here we go through the inputs used to generate a Clifford RB experiment design in more detail.\n", "\n", "### 1. Generic RB inputs\n", "\n", "The first inputs to create an RB experiment design are the same as in all RB protocols, and these are covered in the [RB overview tutorial](RB-Overview.ipynb). They are:\n", "\n", "- The device to benchmark (`pspec`).\n", "- The \"RB depths\" at which we will sample circuits (`depths`). For Clifford RB on $n$ qubits, the RB depth is the number of (uncompiled) $n$-qubit Clifford gates in the sequence minus two. This convention is chosen so that zero is the minimum RB depth for all RB methods in pyGSTi.\n", "- The number of circuits to sample at each length (`k`).\n", "- The qubits to benchmark (`qubits`).\n", "\n", "All other arguments to Clifford RB experiment design generation function are optional." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "n_qubits = 4\n", "qubit_labels = ['Q0','Q1','Q2','Q3'] \n", "gate_names = ['Gxpi2', 'Gxmpi2', 'Gypi2', 'Gympi2', 'Gcphase'] \n", "availability = {'Gcphase':[('Q0','Q1'), ('Q1','Q2'), ('Q2','Q3'), ('Q3','Q0')]}\n", "pspec = pygsti.obj.ProcessorSpec(n_qubits, gate_names, availability=availability, \n", " qubit_labels=qubit_labels, construct_models=('clifford',))\n", "\n", "depths = [0,1,2,4,8]\n", "k = 10\n", "qubits = ['Q0','Q1']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2. The target output\n", "In the standard formulation of Clifford RB, the circuit should always return the all-zeros bit-string if there is no errors. But it can be useful to randomized the \"target\" bit-string (e.g., then the asymptote in the RB decay is fixed to $1/2^n$ even with biased measurement errors). This randomization is specified via the `randomizeout` argument, and it defaults to `False` (the standard protocol)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "randomizeout = True" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 3. The Clifford compilation algorithm\n", "To generate a Clifford RB circuit in terms of native gates, it is necessary to decompose each $n$-qubit Clifford gate into the native gates. pyGSTi has a few different Clifford gate compilation algorithms, that can be accessed via the `compilerargs` optional argument. Note: **The Clifford RB error rate is compiler dependent!** So it is not possible to properly interpret the Clifford RB error rate without understanding at least some aspects of the compilation algorithm (e.g., the mean two-qubit gate count in a compiled $n$-qubit Clifford circuit). This is one of the reasons that [Direct RB](RB-DirectRB.ipynb) is arguably a preferable method to Clifford RB.\n", "\n", "None of the Clifford compilation algorithms in pyGSTi are a simple look-up table with some optimized property (e.g., minimized two-qubit gate count or depth). Look-up tables like this are typically used for 1- and 2-qubit Clifford RB experiments, but we instead used a method that scales to many qubits.\n", "\n", "There are multiple compilation algorithms in pyGSTi, and the algorithm can be set using the `compilerargs` argument (see the `pygsti.algorithms.compile_clifford` function for some details on the available algorithms, and the `CliffordRBDesign` docstring for how to specify the desired algorithm). The default algorthm is the one that we estimate to be our \"best\" algorithm in the regime of 1-20ish qubits. This algorithm (and some of the other algorithms) are randomized. So when creating a `CliffordRBDesign` you can also specify the number of randomization, via `citerations`. Increasing this will reduce the average depth and two-qubit gate count of each $n$-qubit Clifford gate, up to a point, making Clifford RB feasable on more qubits. \n", "But note that time to generate the circuits can increase quickly as `citerations` increases (because a depth $m$ circuit contains $(m+2)$ $n$-qubit Clifford gates to compile)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "citerations = 20" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "From here, everything proceeds as in the RB overview tutorial (except for adding in the optional arguments)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Here we construct an error model with 1% local depolarization on each qubit after each gate.\n", "gate_error_rate = 0.01\n", "def simulate_taking_data(data_template_filename):\n", " \"\"\"Simulate taking data and filling the results into a template dataset.txt file\"\"\"\n", " pspec = pygsti.obj.ProcessorSpec(n_qubits, gate_names, availability=availability, \n", " qubit_labels=qubit_labels, construct_models=('TP',))\n", " noisemodel = pspec.models['TP'].copy()\n", " for gate in noisemodel.operation_blks['gates'].values():\n", " if gate.dim == 16:\n", " gate.depolarize(1 - pygsti.tools.rbtools.r_to_p(1 - (1-gate_error_rate)**2, 4))\n", " if gate.dim == 4:\n", " gate.depolarize(1 - pygsti.tools.rbtools.r_to_p(gate_error_rate, 2))\n", " pygsti.io.fill_in_empty_dataset_with_fake_data(noisemodel, data_template_filename, num_samples=1000, seed=1234)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "design = pygsti.protocols.CliffordRBDesign(pspec, depths, k, qubit_labels=qubits, randomizeout=randomizeout,\n", " citerations=citerations)\n", "\n", "pygsti.io.write_empty_protocol_data(design, '../tutorial_files/test_rb_dir', clobber_ok=True)\n", "\n", "# -- fill in the dataset file in tutorial_files/test_rb_dir/data/dataset.txt --\n", "simulate_taking_data('../tutorial_files/test_rb_dir/data/dataset.txt') # REPLACE with actual data-taking\n", "\n", "data = pygsti.io.load_data_from_dir('../tutorial_files/test_rb_dir')\n", "\n", "protocol = pygsti.protocols.RB() \n", "results = protocol.run(data)\n", "ws = pygsti.report.Workspace()\n", "ws.init_notebook_mode(autodisplay=True)\n", "ws.RandomizedBenchmarkingPlot(results)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.8.6" } }, "nbformat": 4, "nbformat_minor": 1 }