{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Running Multiple Randomized Benchmarking Experiments" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This tutorial shows how to easily run multiple RB experiments concurrently. This includes running RB on different subsets of a device, as well as running [simultaneous RB]() experiments. Here we'll demonstrate generating an experiment to run 1, 2, 3 and 4 qubit RB in sequence (i.e., separately), as well as running 1-qubit RB in parallel on all the qubits (i.e., simultaneously).\n", "\n", "Note that this functionality is not specific to RB: similar code could be used to combine multiple GST experiments, or GST and RB experiments, etc." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import pygsti" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's define the layout and gates of a 4-qubit device that we want to do this experiment on." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "n_qubits = 4\n", "qubit_labels = ['Q'+str(i) for i in range(n_qubits)]\n", "gate_names = ['Gc{}'.format(i) for i in range(24)] + ['Gcnot'] \n", "pspec = pygsti.obj.ProcessorSpec(n_qubits, gate_names, qubit_labels=qubit_labels, construct_models=('clifford',))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now let's generate the separate 1-4 qubit RB experiments. We'll run Mirror RB, but this works for all types of RB." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# The qubit sets of each size to benchmark, and sampling details.\n", "qubits = {1: ['Q0',], 2:['Q0','Q1'], 3:['Q0','Q1','Q2'], 4:['Q0','Q1','Q2', 'Q3']}\n", "# This specifies the mean number of two-qubit gates per layer in the random circuits.\n", "mean2Qgates = {n: n*0.25 for n in [2,3,4]}\n", "mean2Qgates[1] = 0\n", "# The depths for the different number of qubits.\n", "depths = {1: [0, 2, 4, 8, 16, 32, 64, 128, 256, 512],\n", " 2: [0, 2, 4, 8, 16, 32, 64, 128],\n", " 3: [0, 2, 4, 8, 16, 32, 64],\n", " 4: [0, 2, 4, 8, 16, 32]}\n", "\n", "# This loops through an generates the experiment design for each case.\n", "designs = {}\n", "for n in [1,2,3,4]:\n", " \n", " designs[str(n)+'Q-RB'] = pygsti.protocols.MirrorRBDesign(pspec, depths[n], 10, qubit_labels=qubits[n], \n", " sampler='edgegrab', samplerargs=[mean2Qgates[n]],\n", " add_default_protocol=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next, we generate the simultaneous 1-qubit RB experiment. We do this by constructing each of the 1-qubit experiment designs, and then combining them together in a `SimultaneousExperimentDesign`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "oneQdesigns = []\n", "for q in qubit_labels:\n", " oneQdesigns.append(pygsti.protocols.MirrorRBDesign(pspec, depths[1], 10, qubit_labels=[q,], \n", " sampler='edgegrab', samplerargs=[0.],\n", " add_default_protocol=True))\n", " \n", "sim1Qdesign = pygsti.protocols.SimultaneousExperimentDesign(oneQdesigns)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As we want to run this simultanoeus 1-qubit RB experiment alongside the 1-4 qubit RB experiments, we add it to the `designs` dictionary where we're storing all the experiment designs that are to be run together (but not in parallel)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "designs['1Q-SRB'] = sim1Qdesign" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Then we just combine them together in a `CombinedExperimentDesign`. This is then written to a directory in the same way as with all experiment designs. The dataset template contains all the circuits that need to be run. This will include all the circuits from all the sub-designs, including the simultaneous 1-qubit circuits in the necessary parallel form. After data is added to the template, it is then read-in in the same way as always." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "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, qubit_labels=qubit_labels, construct_models=('TP',))\n", " noisemodel = pspec.models['TP'].copy()\n", " for gate in noisemodel.operation_blks['gates'].values(): gate.depolarize(0.01)\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": [ "combdesign = pygsti.protocols.CombinedExperimentDesign(designs)\n", "\n", "pygsti.io.write_empty_protocol_data(combdesign, '../tutorial_files/test_combrb_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_combrb_dir/data/dataset.txt') # REPLACE with actual data-taking\n", "\n", "data = pygsti.io.load_data_from_dir('../tutorial_files/test_combrb_dir')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can then run any protocols that we want to on the imported data. Because we set `add_default_protocol=True` when creating the protocols, the imported data contains the `RB` protocols ready to run (with the appropriate optional arguments set for Mirror RB). We can run all these default protocols by creating a `pygsti.protocols.DefaultRunner()` protocol, and running it on the data.\n", "\n", "We can also run more protocols (e.g., a test for instability if the data is time-stamped) just by creating the relevant protocols objects, and passing them this data." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "protocol = pygsti.protocols.DefaultRunner()\n", "results = protocol.run(data)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "results['1Q-SRB'].keys()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `results` behaves like a dictionary, for accessing the individual results." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for i in ['1Q-RB', '2Q-RB', '3Q-RB' , '4Q-RB']:\n", " r = results[i].for_protocol['RB'].fits['A-fixed'].estimates['r']\n", " print('The RB error rate on {} qubit is {}'.format(i, r))\n", " \n", "print()\n", "for i in [('Q0',),('Q1',),('Q2',),('Q3',)]:\n", " r = results['1Q-SRB'][i].for_protocol['RB'].fits['A-fixed'].estimates['r']\n", " print('When running simultaneously, the RB error rate on {} qubit is {}'.format(i, r))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "ws = pygsti.report.Workspace()\n", "ws.init_notebook_mode(autodisplay=True)\n", "for i in ['1Q-RB', '2Q-RB', '3Q-RB' , '4Q-RB']:\n", " ws.RandomizedBenchmarkingPlot(results[i].for_protocol['RB'])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**For more information** and examples on running multiple benchmarking protocols on a processor, check out the [volumetric benchmarking tutorial](VolumetricBenchmarks.ipynb)." ] } ], "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 }