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).
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.
import pygsti
from pygsti.processors import QubitProcessorSpec as QPS
from pygsti.processors import CliffordCompilationRules as CCR
/Users/tjproct/.pyenv/versions/3.7.4/lib/python3.7/site-packages/pandas/compat/__init__.py:85: UserWarning: Could not import the lzma module. Your installed Python is incomplete. Attempting to use lzma compression will result in a RuntimeError. warnings.warn(msg) /Users/tjproct/.pyenv/versions/3.7.4/lib/python3.7/site-packages/pandas/compat/__init__.py:85: UserWarning: Could not import the lzma module. Your installed Python is incomplete. Attempting to use lzma compression will result in a RuntimeError. warnings.warn(msg)
Let's define the layout and gates of a 4-qubit device that we want to do this experiment on.
n_qubits = 4
qubit_labels = ['Q'+str(i) for i in range(n_qubits)]
gate_names = ['Gc{}'.format(i) for i in range(24)] + ['Gcnot']
pspec = QPS(n_qubits, gate_names, qubit_labels=qubit_labels, geometry='ring')
compilations = {'absolute': CCR.create_standard(pspec, 'absolute', ('paulis', '1Qcliffords'), verbosity=0),
'paulieq': CCR.create_standard(pspec, 'paulieq', ('1Qcliffords', 'allcnots'), verbosity=0)}
Now let's generate the separate 1-4 qubit RB experiments. We'll run Mirror RB, but this works for all types of RB.
# The qubit sets of each size to benchmark, and sampling details.
qubits = {1: ['Q0',], 2:['Q0','Q1'], 3:['Q0','Q1','Q2'], 4:['Q0','Q1','Q2', 'Q3']}
# The depths for the different number of qubits.
depths = {1: [0, 2, 4, 8, 16, 32, 64, 128, 256, 512],
2: [0, 2, 4, 8, 16, 32, 64, 128],
3: [0, 2, 4, 8, 16, 32, 64],
4: [0, 2, 4, 8, 16, 32]}
# This loops through an generates the experiment design for each case.
designs = {}
for n in [1,2,3,4]:
designs[str(n)+'Q-RB'] = pygsti.protocols.MirrorRBDesign(pspec, depths[n], 10, qubit_labels=qubits[n],
clifford_compilations=compilations,
sampler='edgegrab', samplerargs=[0.5],
add_default_protocol=True)
- Sampling 10 circuits at MRB length 0 (1 of 10 depths) with seed 386582 - Sampling 10 circuits at MRB length 2 (2 of 10 depths) with seed 386592 - Sampling 10 circuits at MRB length 4 (3 of 10 depths) with seed 386602 - Sampling 10 circuits at MRB length 8 (4 of 10 depths) with seed 386612 - Sampling 10 circuits at MRB length 16 (5 of 10 depths) with seed 386622 - Sampling 10 circuits at MRB length 32 (6 of 10 depths) with seed 386632 - Sampling 10 circuits at MRB length 64 (7 of 10 depths) with seed 386642 - Sampling 10 circuits at MRB length 128 (8 of 10 depths) with seed 386652 - Sampling 10 circuits at MRB length 256 (9 of 10 depths) with seed 386662 - Sampling 10 circuits at MRB length 512 (10 of 10 depths) with seed 386672 - Sampling 10 circuits at MRB length 0 (1 of 8 depths) with seed 554178 - Sampling 10 circuits at MRB length 2 (2 of 8 depths) with seed 554188 - Sampling 10 circuits at MRB length 4 (3 of 8 depths) with seed 554198 - Sampling 10 circuits at MRB length 8 (4 of 8 depths) with seed 554208 - Sampling 10 circuits at MRB length 16 (5 of 8 depths) with seed 554218 - Sampling 10 circuits at MRB length 32 (6 of 8 depths) with seed 554228 - Sampling 10 circuits at MRB length 64 (7 of 8 depths) with seed 554238 - Sampling 10 circuits at MRB length 128 (8 of 8 depths) with seed 554248 - Sampling 10 circuits at MRB length 0 (1 of 7 depths) with seed 857212 - Sampling 10 circuits at MRB length 2 (2 of 7 depths) with seed 857222 - Sampling 10 circuits at MRB length 4 (3 of 7 depths) with seed 857232 - Sampling 10 circuits at MRB length 8 (4 of 7 depths) with seed 857242 - Sampling 10 circuits at MRB length 16 (5 of 7 depths) with seed 857252 - Sampling 10 circuits at MRB length 32 (6 of 7 depths) with seed 857262 - Sampling 10 circuits at MRB length 64 (7 of 7 depths) with seed 857272 - Sampling 10 circuits at MRB length 0 (1 of 6 depths) with seed 865565 - Sampling 10 circuits at MRB length 2 (2 of 6 depths) with seed 865575 - Sampling 10 circuits at MRB length 4 (3 of 6 depths) with seed 865585 - Sampling 10 circuits at MRB length 8 (4 of 6 depths) with seed 865595 - Sampling 10 circuits at MRB length 16 (5 of 6 depths) with seed 865605 - Sampling 10 circuits at MRB length 32 (6 of 6 depths) with seed 865615
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
.
oneQdesigns = []
for q in qubit_labels:
oneQdesigns.append(pygsti.protocols.MirrorRBDesign(pspec, depths[1], 10, qubit_labels=[q,],
clifford_compilations=compilations,
sampler='edgegrab', samplerargs=[0.],
add_default_protocol=True))
sim1Qdesign = pygsti.protocols.SimultaneousExperimentDesign(oneQdesigns)
- Sampling 10 circuits at MRB length 0 (1 of 10 depths) with seed 875900 - Sampling 10 circuits at MRB length 2 (2 of 10 depths) with seed 875910 - Sampling 10 circuits at MRB length 4 (3 of 10 depths) with seed 875920 - Sampling 10 circuits at MRB length 8 (4 of 10 depths) with seed 875930 - Sampling 10 circuits at MRB length 16 (5 of 10 depths) with seed 875940 - Sampling 10 circuits at MRB length 32 (6 of 10 depths) with seed 875950 - Sampling 10 circuits at MRB length 64 (7 of 10 depths) with seed 875960 - Sampling 10 circuits at MRB length 128 (8 of 10 depths) with seed 875970 - Sampling 10 circuits at MRB length 256 (9 of 10 depths) with seed 875980 - Sampling 10 circuits at MRB length 512 (10 of 10 depths) with seed 875990 - Sampling 10 circuits at MRB length 0 (1 of 10 depths) with seed 71217 - Sampling 10 circuits at MRB length 2 (2 of 10 depths) with seed 71227 - Sampling 10 circuits at MRB length 4 (3 of 10 depths) with seed 71237 - Sampling 10 circuits at MRB length 8 (4 of 10 depths) with seed 71247 - Sampling 10 circuits at MRB length 16 (5 of 10 depths) with seed 71257 - Sampling 10 circuits at MRB length 32 (6 of 10 depths) with seed 71267 - Sampling 10 circuits at MRB length 64 (7 of 10 depths) with seed 71277 - Sampling 10 circuits at MRB length 128 (8 of 10 depths) with seed 71287 - Sampling 10 circuits at MRB length 256 (9 of 10 depths) with seed 71297 - Sampling 10 circuits at MRB length 512 (10 of 10 depths) with seed 71307 - Sampling 10 circuits at MRB length 0 (1 of 10 depths) with seed 155657 - Sampling 10 circuits at MRB length 2 (2 of 10 depths) with seed 155667 - Sampling 10 circuits at MRB length 4 (3 of 10 depths) with seed 155677 - Sampling 10 circuits at MRB length 8 (4 of 10 depths) with seed 155687 - Sampling 10 circuits at MRB length 16 (5 of 10 depths) with seed 155697 - Sampling 10 circuits at MRB length 32 (6 of 10 depths) with seed 155707 - Sampling 10 circuits at MRB length 64 (7 of 10 depths) with seed 155717 - Sampling 10 circuits at MRB length 128 (8 of 10 depths) with seed 155727 - Sampling 10 circuits at MRB length 256 (9 of 10 depths) with seed 155737 - Sampling 10 circuits at MRB length 512 (10 of 10 depths) with seed 155747 - Sampling 10 circuits at MRB length 0 (1 of 10 depths) with seed 492081 - Sampling 10 circuits at MRB length 2 (2 of 10 depths) with seed 492091 - Sampling 10 circuits at MRB length 4 (3 of 10 depths) with seed 492101 - Sampling 10 circuits at MRB length 8 (4 of 10 depths) with seed 492111 - Sampling 10 circuits at MRB length 16 (5 of 10 depths) with seed 492121 - Sampling 10 circuits at MRB length 32 (6 of 10 depths) with seed 492131 - Sampling 10 circuits at MRB length 64 (7 of 10 depths) with seed 492141 - Sampling 10 circuits at MRB length 128 (8 of 10 depths) with seed 492151 - Sampling 10 circuits at MRB length 256 (9 of 10 depths) with seed 492161 - Sampling 10 circuits at MRB length 512 (10 of 10 depths) with seed 492171
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).
designs['1Q-SRB'] = sim1Qdesign
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.
qubit_error_rate = 0.002
def simulate_taking_data(data_template_filename):
"""Simulate taking data and filling the results into a template dataset.txt file"""
error_rates = {}
for gn in pspec.gate_names:
n = pspec.gate_num_qubits(gn)
gate_error_rate = n * qubit_error_rate
error_rates[gn] = [gate_error_rate/(4**n - 1)] * (4**n - 1)
noisemodel = pygsti.models.create_crosstalk_free_model(pspec, stochastic_error_probs=error_rates)
pygsti.io.fill_in_empty_dataset_with_fake_data(noisemodel, data_template_filename, num_samples=1000, seed=1234)
combdesign = pygsti.protocols.CombinedExperimentDesign(designs)
pygsti.io.write_empty_protocol_data(combdesign, '../tutorial_files/test_combrb_dir', clobber_ok=True)
# -- fill in the dataset file in tutorial_files/test_rb_dir/data/dataset.txt --
simulate_taking_data('../tutorial_files/test_combrb_dir/data/dataset.txt') # REPLACE with actual data-taking
data = pygsti.io.load_data_from_dir('../tutorial_files/test_combrb_dir')
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.
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.
protocol = pygsti.protocols.DefaultRunner()
results = protocol.run(data)
Running protocol RB at ./1Q-RB Running protocol RB at ./2Q-RB Running protocol RB at ./3Q-RB Running protocol RB at ./4Q-RB Running protocol RB at ./1Q-SRB/('Q0',) Running protocol RB at ./1Q-SRB/('Q1',) Running protocol RB at ./1Q-SRB/('Q2',) Running protocol RB at ./1Q-SRB/('Q3',)
results['1Q-SRB'].keys()
dict_keys([('Q0',), ('Q1',), ('Q2',), ('Q3',)])
The results
behaves like a dictionary, for accessing the individual results.
for i in ['1Q-RB', '2Q-RB', '3Q-RB' , '4Q-RB']:
r = results[i].for_protocol['RB'].fits['A-fixed'].estimates['r']
print('The RB error rate on {} qubit is {}'.format(i, r))
print()
for i in [('Q0',),('Q1',),('Q2',),('Q3',)]:
r = results['1Q-SRB'][i].for_protocol['RB'].fits['A-fixed'].estimates['r']
print('When running simultaneously, the RB error rate on {} qubit is {}'.format(i, r))
The RB error rate on 1Q-RB qubit is 0.007416058975985351 The RB error rate on 2Q-RB qubit is 0.01469694357489764 The RB error rate on 3Q-RB qubit is 0.0223674522807891 The RB error rate on 4Q-RB qubit is 0.030603327965670758 When running simultaneously, the RB error rate on ('Q0',) qubit is 0.007391539841511335 When running simultaneously, the RB error rate on ('Q1',) qubit is 0.007500220175417738 When running simultaneously, the RB error rate on ('Q2',) qubit is 0.007318437467928263 When running simultaneously, the RB error rate on ('Q3',) qubit is 0.007671444306106501
ws = pygsti.report.Workspace()
ws.init_notebook_mode(autodisplay=True)
for i in ['1Q-RB', '2Q-RB', '3Q-RB' , '4Q-RB']:
ws.RandomizedBenchmarkingPlot(results[i].for_protocol['RB'])
For more information and examples on running multiple benchmarking protocols on a processor, check out the volumetric benchmarking tutorial.