This tutorial demonstrates shows how to simulate Clifford RB sequences using $n$-qubit "implicit" models which build $n$-qubit process matrices from smaller building blocks. This restricts the noise allowed in the $n$-qubit model; in this tutorial we take $n=3$ and use a `LocalNoiseModel`

.

In [ ]:

```
import pygsti
import numpy as np
```

First, we follow the Clifford RB tutorial to generate a set of sequences. If you want to perform Direct RB instead, just replace this cell with the contents of the Direct RB tutorial up until the point where it creates `circuitlist`

:

In [ ]:

```
#Specify the device to be benchmarked - in this case 2 qubits
n_qubits = 3
qubit_labels = list(range(n_qubits))
gate_names = ['Gxpi2', 'Gypi2','Gcphase']
availability = {'Gcphase':[(i,i+1) for i in range(n_qubits-1)]}
pspec = pygsti.obj.ProcessorSpec(n_qubits, gate_names, availability=availability,
qubit_labels=qubit_labels)
#Specify RB parameters (k = number of repetitions at each length)
lengths = [0,1,2,4,8,16]
k = 10
subsetQs = qubit_labels
randomizeout = False # ==> all circuits have the *same* ideal outcome (the all-zeros bitstring)
#Generate clifford RB circuits
exp_design = pygsti.protocols.CliffordRBDesign(pspec, lengths, k, qubit_labels=subsetQs, randomizeout=randomizeout)
#Collect all the circuits into one list:
circuitlist = exp_design.all_circuits_needing_data
```

Now we need to create a model that can simulate circuits like this. The RB circuits use pyGSTi's "multi-qubit" conventions, which mean:

- RB circuits use our "multi-qubit" gate naming, so you have gates like
`Gxpi2:0`

and`Gcphase:0:1`

. - RB circuits do gates in parallel (this only matters for >1 qubits), so you have layers like
`[Gypi2:0Gypi2:1]`

"Implicit" models in pyGSTi (see the implicit model tutorial) are designed to efficiently describe multi-qubit processors. There are numerous ways of constructing implicit models, all of which can simulate the type of circuits described above. Here we'll demonstrate the simplest type: a "local noise model" (class `LocalNoiseModel`

) where the noise on a gate can only act on that gate's target qubits - so, for instance, 1-qubit gates are still given by 1-qubit operators, not $n$-qubit ones.

The construction of a local noise model follows the same pattern as building the `ProcessorSpec`

above (in fact, `pspec.models['target']`

*is* essentially the same model we build below except it was built with the default `parmeterization="static"`

argument.

In [ ]:

```
myModel = pygsti.obj.LocalNoiseModel.build_from_parameterization(n_qubits, gate_names,
availability=availability,
qubit_labels=qubit_labels,
parameterization="full")
```

Setting `parameterization="full"`

is important, as it lets us assign arbitrary numpy arrays to gates as we'll show below. If you need to use other gates that aren't built into pyGSTi, you can use the `nonstd_gate_unitaries`

argument of `build_from_parameterization`

(see the docstring).

The `build_from_parameterization`

function creates a model with ideal (perfect) gates. We'll now create a 1-qubit depolarization superoperator, and a corresponding 2-qubit one (just the tensor product of two 1-qubit ones) to add some simple noise.

In [ ]:

```
depol1Q = np.array([[1, 0, 0, 0],
[0, 0.99, 0, 0],
[0, 0, 0.99, 0],
[0, 0, 0, 0.99]], 'd') # 1-qubit depolarizing operator
depol2Q = np.kron(depol1Q,depol1Q)
```

As detailed in the implicit model tutorial, the gate operations of a `LocalNoiseModel`

are held in its `.operation_blks['gates']`

dictionary. We'll alter these by assigning new process matrices to each gate. In this case, it will be just a depolarized version of the original gate.

In [ ]:

```
myModel.operation_blks['gates']["Gxpi2"] = np.dot(depol1Q, myModel.operation_blks['gates']["Gxpi2"])
myModel.operation_blks['gates']["Gypi2"] = np.dot(depol1Q, myModel.operation_blks['gates']["Gypi2"])
myModel.operation_blks['gates']["Gcphase"] = np.dot(depol2Q, myModel.operation_blks['gates']["Gcphase"])
```

Here's what the gates look like now:

In [ ]:

```
print(myModel.operation_blks['gates']["Gxpi2"])
print(myModel.operation_blks['gates']["Gypi2"])
print(myModel.operation_blks['gates']["Gcphase"])
```

Now that our `Model`

object is set to go, generating simulated data is easy:

In [ ]:

```
ds = pygsti.construction.generate_fake_data(myModel, circuitlist, 100, seed=1234)
```

`DataSet`

¶To run an RB analysis, we just package up the experiment design and data set into a `ProtocolData`

object and give this to a `RB`

protocol's `run`

method. This returns a `RandomizedBenchmarkingResults`

object that can be used to plot the RB decay curve. (See the RB analysis tutorial for more details.)

In [ ]:

```
data = pygsti.protocols.ProtocolData(exp_design, ds)
results = pygsti.protocols.RB().run(data)
```

In [ ]:

```
%matplotlib inline
results.plot()
```

In [ ]:

```
```