Cross Entropy Benchmarking (XEB)
To demonstrate the cross entropy benchmarking routine, consider a noise model with two independent depolarising channels, one which only effects single qubit gates and a second that only effects two qubit gates.
[1]:
try:
import supermarq
except ImportError:
print("Installing supermarq...")
%pip install --quiet supermarq
print("Installed supermarq.")
print("You may need to restart the kernel to import newly installed packages.")
[2]:
from __future__ import annotations
import cirq
import numpy as np
class IndependentDepolariseNoiseModel(cirq.NoiseModel):
"""Applies single and two qubit depolarising channels independently"""
def __init__(self, single_qubit_error: float, two_qubit_error: float) -> None:
"""Args:
single_qubit_error: Single qubit pauli error
two_qubit_error: Two qubit pauli error
"""
super().__init__()
self.single_qubit_error = single_qubit_error
self.two_qubit_error = two_qubit_error
self.single_qubit_depolarise = cirq.DepolarizingChannel(p=single_qubit_error, n_qubits=1)
self.two_qubit_depolarise = cirq.DepolarizingChannel(p=two_qubit_error, n_qubits=2)
def noisy_operation(self, operation: cirq.Operation) -> list[cirq.OP_TREE]:
"""Produces a list of operations by applying each noise model
to the provided operation depending on the number of qubits it acts on.
"""
if len(operation.qubits) == 1:
return [operation, self.single_qubit_depolarise(*operation.qubits)]
if len(operation.qubits) == 2:
return [operation, self.two_qubit_depolarise(*operation.qubits)]
return [operation]
noise = IndependentDepolariseNoiseModel(single_qubit_error=0.005, two_qubit_error=0.02)
simulator = cirq.DensityMatrixSimulator(
noise=noise,
seed=0,
)
The XEB experiment allows us to estimate the fidelity of a “cycle” composed of pair of single qubit gates followed by a two qubit gate. If each single qubit gate is effected by a pauli error channel with rate \(p_1\) and each two qubit gate is effected by a two qubit depolarising channel with pauli \(p_2\) the overall cycle depolarising error is
[3]:
from supermarq.qcvv import XEB
experiment = XEB(
num_circuits=25, cycle_depths=[10, 20, 30, 40, 50, 60, 70, 80, 90, 100], random_seed=0
)
results = experiment.run_with_simulator(simulator)
[4]:
results.analyze(plot_results=True)
cycle_depolarising_error = (
16 / 15 * (1 - (1 - noise.single_qubit_error) ** 2 * (1 - noise.two_qubit_error))
)
cycle_depolarising_error_estimate = 1 - results.cycle_fidelity_estimate
print(f"Cycle depolarising error: {cycle_depolarising_error:.5f}")
print(f"Estimated cycle depolarising error: {cycle_depolarising_error_estimate:.5f}")
Estimated cycle fidelity: 0.96765 +/- 0.0010135
Cycle depolarising error: 0.03176
Estimated cycle depolarising error: 0.03235
Now lets repeat a similar experiment, still using two qubits but this time without entangling gates between them. In this case our noise model reduces to a pair of independent single qubit depolarising channels with pauli rates \(p_1\), or equivalently depolarising rates of \(e_{1q} = \tfrac34 p_1\).
Each cycle is made up of two single qubit gates (one on each qubit) so we obtain a cycle fidelity of
Thus we can estimate the single qubit pauli error as
[5]:
single_qubit_experiment = XEB(
two_qubit_gate=None,
num_circuits=25,
cycle_depths=[10, 20, 30, 40, 50, 60, 70, 80, 90, 100],
random_seed=0,
)
single_qubit_experiment_results = single_qubit_experiment.run_with_simulator(simulator=simulator)
[6]:
single_qubit_experiment_results.analyze(plot_results=True)
single_qubit_pauli_error_estimate = (
4 / 3 * (1 - np.sqrt(single_qubit_experiment_results.cycle_fidelity_estimate))
)
print(f"Single qubit pauli error: {noise.single_qubit_error:.5f}")
print(f"Estimated single qubit pauli error: {single_qubit_pauli_error_estimate:.5f}")
Estimated cycle fidelity: 0.99239 +/- 8.2339e-05
Single qubit pauli error: 0.00500
Estimated single qubit pauli error: 0.00508
We can now rearrange the equation above to estimate the two qubit depolarising error
[7]:
two_qubit_depolarising_error = 16 / 15 * noise.two_qubit_error
two_qubit_depolarising_error_estimate = (16 / 15) * (
1
- (
(1 - 15 / 16 * cycle_depolarising_error_estimate)
/ (1 - single_qubit_pauli_error_estimate) ** 2
)
)
print(f"Two qubit depolarising error: {two_qubit_depolarising_error:.5f}")
print(f"Estimated two qubit depolarising error: {two_qubit_depolarising_error_estimate:.5f}")
Two qubit depolarising error: 0.02133
Estimated two qubit depolarising error: 0.02176
The final tool we can use as part of XEB is to visualize the decoherence through speckle plots. These show how the probability of being in a given state transitions from ‘speckles’ at small cycle depths to being smoothed out at deeper circuits. For more details see Fig.S18 of https://arxiv.org/abs/1910.11333.
[8]:
results.plot_speckle();