Note

Click here to download the full example code

# Cycle benchmarking (CB)¶

This example page breaks down the process of implementing Cycle Benchmarking (CB), including the selection of useful parameters, using True-Qᵀᴹ. While the example uses a simulator to demonstrate how to run CB, the circuits generated by this protocol can also be used to characterize the process fidelity of a dressed cycle (a target cycle preceded by a cycle of random elements of the twirling group) in hardware. For example, see Executing Circuits on Qiskit Providers for information about how use True-Qᵀᴹ to submit circuits to hardware which uses a Qiskit backend.

## Choosing CB Parameters¶

True-Qᵀᴹ’s `make_cb()`

method generates a circuit collection
to perform cycle benchmarking. The first arguement required by
`make_cb()`

is the cycle to be benchmarked. The second
parameter is also a required parameter; the parameter `n_random_cycles`

tells
`make_cb()`

how many times to apply the dressed cycle during
the protocol.

The number of circuits for each circuit length, `n_circuits`

is 30 by default and
should be chosen to optimize the tradeoff between desired speed and accuracy of the
estimation.

The number of randomly chosen Pauli decay strings used to measure the process
fidelity, `n_decays`

, should be chosen to exceed
\(min(20, 4 * n_{qubits} - 1)\). The default value for `n_decays`

is 20 to
satisfy this bound. Choosing a value lower than \(min(20, 4 * n_{qubits} - 1)\)
may result in a biased estimate of the fidelity of the dressed cycle. For this example
we eschew this constraint to make the example run faster and the output shorter for
easier visualization, and instead let `n_decays = 6`

.

The `twirling_group`

parameter specifies which twirling group the random gates which
form the pre-compiled dressed cycles are pulled from. By default,
`make_cb()`

uses the Pauli group, `"P"`

.

The choice of circuit lengths in `n_random_cycles`

depends on the cycle being
characterized as well as the selection of twirling group. If the cycle is a Clifford
and the twirling group is `"P"`

, lengths should be chosen such that applying the
cycle to be benchmarked `n_random_cycles`

times will result in an identity
operation. In the example below, we benchmark a cycle containing an X gate and a
controlled-Z gate, both of which apply an identity operation when raised to even
powers. We therefore choose cycle lengths 4, 12, and 32. While the values of
`n_random_cycles`

can be any multiple of 2 for this example, users should be careful
to choose a range of values such that the exponential decay is evident in the plot;
this will ensure that the fit function gets enough information to accurately estimate
the fidelity of the dressed cycle. To validate that this condition has been satisfied,
users can plot the data from the CB circuits after running the circuits on a simulator
or on hardware to see where the chosen data points fall.

The final parameter is a bool, `propagate_correction`

, which tells
`make_cb()`

whether to compile correction gates for the
twirling group into neighbouring cycles (`propagate_correction = False`

) or
propagate them to the end of the circuit (`propagate_correction = True`

). By
default, `propagate_correction = False`

. Warning: *propagating correction to the
end of the circuit can result in arbitrary two-qubit gates at the end of the circuit!*
The final circuit can be converted to a user-specified gateset using True-Qᵀᴹ’s
Configuration tools.

## Applying Cycle Benchmarking¶

Import True-Qᵀᴹ and initialize a cycle to benchmark:

```
import trueq as tq
cycle = {(0,): tq.Gate.x, (1, 2): tq.Gate.cz}
```

Generate a circuit collection to run CB on the above cycle with `n_circuits = 30`

random circuits for each circuit length in `n_random_cycles = [4, 32, 64]`

and
`n_decays = 6`

randomly chosen Pauli decay strings. For the purpose of demonstrating
how to recognize a poor choice of `n_random_cycles`

, we generate a second CB circuit
collection with the same parameters, except `n_random_cycles = [2, 4, 6]`

. A good
choice of `n_random_cycles`

will result in a lower uncertainty in the fit parameters
and therefore a more accurate estimate of the average gate fidelity.

```
circuits = tq.make_cb(cycle, [4, 12, 32], 30, 6)
bad_circuits = tq.make_cb(cycle, [2, 4, 6], 30, 6)
```

Initialize a simulator with stochastic pauli noise and run the cycle benchmarking circuits on the simulator to populate the results:

```
sim = tq.Simulator().add_stochastic_pauli(px=0.01)
sim.run(circuits)
sim.run(bad_circuits)
```

Plot the results of the circuits with badly chosen `n_random_cycles`

:

```
bad_circuits.plot.raw(labels=[[0, 1, 2]])
```

We can see in the plots above that the data points from `n_random_cycles`

are close
together, in some cases nearly forming a linear rather than exponential decay. This
shows us that the parameters chosen for `n_random_cycles`

are not a good
representation of the data. We next plot the decay curves for the CB circuits with
`n_random_cycles = [4, 32, 64]`

:

```
circuits.plot.raw(labels=[[0, 1, 2]])
```

We can see from the plots above that the chosen `n_random_cycles`

were reasonable
for this example as they clearly outline an exponential decay.

The output parameters of this protocol are displayed below using the
`fit()`

function. When the circuits were generated,
`n_decays = 6`

random 3-qubit Paulis were chosen as representatives, and the rate of
decay of each was measured; these decay rates are reported. However, the parameter of
interest is the composite parameter `r`

, which is an estimate of the average gate
infidelity of the entire cycle.

```
circuits.fit(labels=[[0, 1, 2]])
```

**Total running time of the script:** ( 0 minutes 6.909 seconds)