11from qiskit import QuantumCircuit , execute , Aer , transpile
2+
23from qiskit .result .result import Result
4+ from qiskit .providers .aer .noise import NoiseModel
35
46from qiskit .transpiler import PassManager , PassManagerConfig , CouplingMap
57from qiskit .transpiler .passes import Unroller , Optimize1qGates
1214
1315import random , os , pickle
1416
17+ from typing import Callable
18+
1519"""
1620-- ZERO NOISE EXTRAPOLATION for CNOT-gates --
1721
3337
3438class 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