Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Added a simple generator for gate-dependent depolarizing noise. #180

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions forest/benchmarking/noise_model_generation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
from tqdm import tqdm
from forest.benchmarking.readout import estimate_joint_confusion_in_set
from forest.benchmarking.direct_fidelity_estimation import \
generate_exhaustive_process_dfe_experiment, acquire_dfe_data, estimate_dfe
from forest.benchmarking.randomized_benchmarking import average_gate_error_to_rb_decay
from pyquil import Program
from pyquil.api import QuantumComputer, get_benchmarker
from pyquil.noise import NoiseModel, KrausModel, pauli_kraus_map, combine_kraus_maps
from pyquil.device import gates_in_isa
from pyquil.gate_matrices import QUANTUM_GATES


def _do_dfe(qc: QuantumComputer, program: Program, num_shots: int = 10_000):
bm = get_benchmarker()
dfe_expt = generate_exhaustive_process_dfe_experiment(program, list(program.get_qubits()), bm)
dfe_results = acquire_dfe_data(qc, dfe_expt, num_shots=num_shots)
return estimate_dfe(dfe_results, 'process')[0]


def _depolarizing_channel(fidelity: float, dim: int):
p = average_gate_error_to_rb_decay(1 - fidelity, dim)
pr_id = p + (1 - p) / dim
pr_other = (1 - pr_id) / (dim ** 2 - 1)
probabilities = [pr_id] + [pr_other] * (dim ** 2 - 1)
return pauli_kraus_map(probabilities)


def generate_depolarizing_noise_model(qc: QuantumComputer, show_progress_bar: bool = True,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it reasonably sufficient (and/or fairly standard) to only consider a depolarizing noise model? What about things like cross-talk?

num_readout_shots: int = 10_000, num_dfe_shots: int = 10_000)\
-> NoiseModel:
"""
Generate a noise model with depolarizing channel on each native gate and single qubit readout
error using data gathered on the input qc.

The readout error is modeled as single qubit uncorrelated classical confusion matrices.

A depolarizing channel is assumed for each gate with parameter determined from the gate
fidelity as estimated by DFE with error mitigation.

Note that the output noise model can be assigned to a QuantumComputer via `qc.qam.noise_model`.

:param qc: the quantum computer whose noise you would like to simplistically model
:param show_progress_bar: if true then a tqdm progress bar will be displayed to STDOUT
:param num_readout_shots: number of shots when estimating each single qubit confusion matrix
:param num_dfe_shots: number of shots for process DFE experiment on each gate.
:return: a simplistic noise model with depolarizing channels on each gate as determined by
data collected on the input qc
"""
single_qubit_conf_matrices = estimate_joint_confusion_in_set(qc, num_shots=num_readout_shots,
joint_group_size=1)
# the keys need to be lone qubit indices
single_qubit_conf_matrices = {key[0]: val for key, val in single_qubit_conf_matrices.items()}

gates = gates_in_isa(qc.get_isa())
kraus_maps = []
for g in tqdm(gates, disable=not show_progress_bar):
if g.name in ('RZ', 'I'):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could these be subject to coherent errors?

# assume these are noiseless
continue

targets = tuple(t.index for t in g.qubits)
if len(g.params) > 0:
matrix = QUANTUM_GATES[g.name](*g.params)
else:
matrix = QUANTUM_GATES[g.name]

# estimate the fidelity of the gate using DFE
fidelity = min(_do_dfe(qc, Program(g), num_dfe_shots), 1.0)

# get kraus operators for the depolarizing channel that would give rise to this fidelity
noise_kraus = _depolarizing_channel(fidelity, 2 ** len(targets))

km = (KrausModel(g.name, tuple(g.params), targets,
combine_kraus_maps(noise_kraus, [matrix]), fidelity))
kraus_maps.append(km)

return NoiseModel(kraus_maps, single_qubit_conf_matrices)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would also be worth adding a helper function that would convert the NoiseModel here to a Program or a set of pragma instructions that a user could append to their program, in order for the latter to feel the effects of the noise model.