Stochastic Calibration (SC)

This example will show how to characterize the noise acting in a system so that it can be corrected. We begin by initializing a noisy simulator with a 2-qubit rotation about \(Z\) by some angle \(\theta\). Then we show how to find \(\theta\) using stochastic calibration.

import numpy as np
import matplotlib.pyplot as plt
import trueq as tq

# make a noisy simulator
sim = tq.Simulator().add_depolarizing(p=0.001)
sim.add_overrotation(single_sys=0.01, multi_sys=0.01)

# adding a rotation by 12 degrees to the first qubit in every 2-qubit gate,
# i.e. Z(12) is the noise we are going to try to characterize
mat = tq.Gate.from_generators("Z", 12).mat
sim.add_kraus({2: [np.kron(mat, np.eye(2))]})


<trueq.simulation.simulator.Simulator object at 0x7efce682c470>

We are going to perform stochastic calibration for a \(CZ\) gate. We choose to look at the \(XI\) Pauli decay because it anticommutes with our suspected error, \(ZI\). Equivalently, we could have have chosen to use the \(YI\) Pauli decay to characterize our \(ZI\) error. To minimize the experimental footprint, we use data at a single sequence length as in [2].

cycle = tq.Cycle({(0, 1):}, immutable=True)

# generate SC circuits with 24 random cycles to get decays associated with XI
circuits = tq.make_sc(cycle, [24], pauli_decays=["XI"])



Find the expectation value and standard deviation of the circuit when corrections of the form \(Z(\phi)\) are applied on the first qubit prior to each \(CZ\) gate. The expectation values correspond to the \(XI\) diagonal entry of the superoperator in the Pauli basis; values close to \(1\) indicate that the suspected error is small.

# 20 equidistant points between -40 and 40 for trial values of phi
angles = np.linspace(-40, 40, 20)

# initialize ev and stds as all zeros with length of angles.
# ev stores expectation values; sds stores standard deviations
ev = np.zeros_like(angles)
sds = np.zeros_like(angles)

for j, phi in enumerate(angles):
    # adds a Z(phi) rotation on qubit 0 gate before every CZ gate
    c = tq.compilation.CycleSandwich(
        cycle, before=tq.Cycle({(0): tq.Gate.from_generators("Z", phi)})
    new_circs = tq.CircuitCollection(map(c.apply, circuits))

    # run circuit collection (with Z(phi)s inserted)

    # make a vector of expectation values for new_circs
    vec = [v for _, v in new_circs.expectation_values().items()]

    # take the mean expectation value and find standard deviation
    ev[j] = np.mean(vec)
    sds[j] = np.std(vec) / np.sqrt(len(circuits))

plot the expectation values as a function of \(\phi\):

plt.errorbar(angles, ev, sds)
plt.xlabel("Z compensation angle")
plt.ylabel("Expectation value after 24 applications")


Text(0, 0.5, 'Expectation value after 24 applications')

The maximum expectation value corresponds to the value of \(XI\) closest to 1, so finding the angle at which the plot peaks tells us which angle to rotate by to correct the noise. The peak occurs at approximately \(\phi = -12\), which is consistent with the noise applied by the simulator.

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

Gallery generated by Sphinx-Gallery