Skip to content

Commit 3b9f015

Browse files
committed
some tweaks and bug fixes, modified comments
1 parent f5efa69 commit 3b9f015

File tree

1 file changed

+81
-17
lines changed

1 file changed

+81
-17
lines changed

zero_noise_extrapolation_cnot.py

Lines changed: 81 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from qiskit import QuantumCircuit, execute, Aer, transpile
2+
23
from qiskit.result.result import Result
4+
from qiskit.providers.aer.noise import NoiseModel
35

46
from qiskit.transpiler import PassManager, PassManagerConfig, CouplingMap
57
from qiskit.transpiler.passes import Unroller, Optimize1qGates
@@ -12,6 +14,8 @@
1214

1315
import random, os, pickle
1416

17+
from typing import Callable
18+
1519
"""
1620
-- ZERO NOISE EXTRAPOLATION for CNOT-gates --
1721
@@ -33,9 +37,55 @@
3337

3438
class ZeroNoiseExtrapolation:
3539

36-
def __init__(self, qc: QuantumCircuit, exp_val_func, backend=None, noise_model=None,
37-
n_amp_factors: int = 3, shots: int = 8192, pauli_twirl: bool = False, pass_manager: PassManager = None,
40+
def __init__(self, qc: QuantumCircuit, exp_val_func: Callable, backend=None, exp_val_options: dict = None,
41+
noise_model: NoiseModel = None, n_amp_factors: int = 3, shots: int = 8192,
42+
pauli_twirl: bool = False,pass_manager: PassManager = None,
3843
save_results: bool = False, experiment_name: str = "", option: dict = None):
44+
"""
45+
CONSTRUCTOR
46+
47+
Parameters
48+
----------
49+
qc : qiskit.QuantumCircuit
50+
A complete quantum circuit, with measurements, that we want to perform quantum error mitigation on.
51+
When run on a quantum backend, the circuit should output a set of measurements results from which the
52+
desired expectation value can be estimated.
53+
54+
exp_val_func : Callable
55+
A function that computes the desired expectation value based on the measurement results outputted by the
56+
quantum circuit. The function should take two arguments: a qiskit.result.result.Result object as its first,
57+
and a dictionary with possible options as its second.
58+
59+
backend :
60+
A qiskit backend, either an IBMQ quantum backend or a simulator backend, for circuit executions.
61+
62+
exp_val_options : dict, optional
63+
Options for the exp_val_func expectation value function
64+
65+
noise_model : qiskit.providers.aer.noise.NoiseModel, optional
66+
Custom noise model for circuit executions with the qasm simulator backend.
67+
68+
n_amp_factors : int
69+
The number of noise amplification factors to be used. For n number of amplification factors, the specific
70+
noise amplification factors will be [1, 3, 5, ..., 2*n - 1]. Larger amounts of noise amplification factors
71+
tend to give better results, but slower convergence thus requiring large amounts of shots.
72+
Higher noise amplification also increases circuit depth, scaling linearly with the amplification factor c_i,
73+
and at some point the circuit depth and the consecutive decoherence will eliminate any further advantage.
74+
75+
shots: int
76+
77+
78+
pauli_twirl : bool
79+
80+
pass_manager: qiskit.transpiler.PassManager, optional
81+
82+
save_results: bool, optional
83+
84+
experiment_name: string, optional
85+
86+
option: dict, optional
87+
88+
"""
3989
""" CONSTRUCTOR
4090
:param qc: The quantum circuit to be mitigated
4191
:param exp_val_func: A function that computes the observed expectation value of some operator measured by the
@@ -77,7 +127,6 @@ def __init__(self, qc: QuantumCircuit, exp_val_func, backend=None, noise_model=N
77127

78128
# Max number of shots for one circuit execution on IBMQ devices is 8192.
79129
# To do more shots, we have to partition them up into several executions.
80-
self.shots, self.repeats = None, None
81130
self.shots, self.repeats = self.partition_shots(shots)
82131

83132
# Do an initial optimization of the quantum circuit. Either with a custom pass manager, or with the
@@ -246,28 +295,34 @@ def transpile_circuit(self, qc: QuantumCircuit, custom_pass_manager: PassManager
246295

247296
return transpiled_circuit
248297

249-
def execute_circuits(self, qc: QuantumCircuit, shots=None) -> Result:
298+
def execute_circuit(self, qc: QuantumCircuit, shots=None) -> Result:
250299
"""
251-
Execute all circuits and return measurement counts. If shots > 8192, we need to partition the execution
252-
into several sub-executions.
253300
254-
Circuits are transpiled and optimized beforehand, thus we pass an empty PassManager to qiskit.execute
255-
to avoid unnecessary time spent on transpiling.
301+
Parameters
302+
----------
303+
qc
304+
shots
305+
306+
Returns
307+
-------
308+
309+
"""
310+
"""
311+
Execute a quantum circuit for the specified amount of shots to obtain a set of measurement results.
256312
257313
:param qc: Circuit to be executed
258-
:return: A list of count-dictionaries
314+
:return: Measurement results as a qiskit.result.result.Result object
259315
"""
260316

261317
if shots == None:
262-
repeats = self.repeats
263318
shots = self.shots
319+
repeats = self.repeats
264320
else:
265-
repeats = (shots // 8192) + 1
266-
shots = int(shots / repeats)
321+
shots, repeats = self.partition_shots(shots)
267322

268323
# The max number of shots on a single execution on the IBMQ devices is 8192.
269324
# If shots > 8192, we have to partition the execution into several sub-executions.
270-
# Note that several circuits can be entered into the IBMQ queue at once by being passed as a list.
325+
# Note that several circuits can be entered into the IBMQ queue at once by passing them in a list.
271326
execution_circuits = [qc.copy() for i in range(repeats)]
272327

273328
# non-simulator backends throws unexpected argument when passing noise_model argument to them
@@ -283,16 +338,25 @@ def execute_circuits(self, qc: QuantumCircuit, shots=None) -> Result:
283338
return circuit_measurement_results
284339

285340
def compute_exp_val(self, result: Result) -> (float, ndarray):
341+
"""
342+
343+
Parameters
344+
----------
345+
result
346+
347+
Returns
348+
-------
349+
350+
"""
286351
experiment_exp_vals = zeros(len(result.results))
287352
for i, experiment_result in enumerate(result.results):
288353
experiment_exp_vals[i] = self.exp_val_func(experiment_result)
289354
return average(experiment_exp_vals), experiment_exp_vals
290355

291-
def mitigate(self, shots=None, verbose: bool = False) -> float:
356+
def mitigate(self, verbose: bool = False) -> float:
292357
"""
293-
Do the error mitigation for CNOT noise in the given quantum circuit by zero-noise extrapolation.
358+
Do error mitigation for general CNOT-noise in the given quantum circuit by zero-noise extrapolation.
294359
295-
:param repeats: Number of repeats of the extrapolation to perform. The result is averaged over all repeats.
296360
:param verbose: Do prints during the computation, True / False
297361
:return: The mitigated expectation value
298362
"""
@@ -340,7 +404,7 @@ def mitigate(self, shots=None, verbose: bool = False) -> float:
340404
print("Results not found")
341405

342406
if not circuit_read_from_file:
343-
circuit_measurement_results = self.execute_circuits(noise_amplified_circuits[i])
407+
circuit_measurement_results = self.execute_circuit(noise_amplified_circuits[i])
344408
if self.save_results:
345409
self.write_to_file(self.experiment_name + "_r{:].results".format(self.noise_amplification_factors[i]),
346410
circuit_measurement_results)

0 commit comments

Comments
 (0)