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.
[ ]:
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.")
[7]:
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,
)
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
[8]:
from supermarq.qcvv import XEB
experiment = XEB()
experiment.prepare_experiment(num_circuits=25, cycle_depths=[1, 10, 50, 100])
experiment.run_with_simulator(simulator=simulator)
[9]:
if experiment.collect_data():
experiment.analyze_results(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 - experiment.results.cycle_fidelity_estimate
print(f"Cycle depolarising error: {cycle_depolarising_error:.5f}")
print(f"Estimated cycle depolarising error: {cycle_depolarising_error_estimate:.5f}")
Cycle depolarising error: 0.03176
Estimated cycle depolarising error: 0.03175
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
[10]:
single_qubit_experiment = XEB(two_qubit_gate=None)
single_qubit_experiment.prepare_experiment(num_circuits=25, cycle_depths=[10, 50, 100, 200])
single_qubit_experiment.run_with_simulator(simulator=simulator)
[11]:
if single_qubit_experiment.collect_data():
single_qubit_experiment.analyze_results(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}")
Single qubit pauli error: 0.00500
Estimated single qubit pauli error: 0.00532
We can now rearrange the equation above to estimate the two qubit depolarising error
[12]:
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.02065