def execute(self, circuits, had_transpiled: bool = False): """ A wrapper to interface with quantum backend. Args: circuits (Union['QuantumCircuit', List['QuantumCircuit']]): circuits to execute had_transpiled: whether or not circuits had been transpiled Returns: Result: result object TODO: Maybe we can combine the circuits for the main ones and calibration circuits before assembling to the qobj. """ from qiskit.utils.run_circuits import run_qobj, run_circuits from qiskit.utils.measurement_error_mitigation import \ (get_measured_qubits_from_qobj, get_measured_qubits, build_measurement_error_mitigation_circuits, build_measurement_error_mitigation_qobj) # maybe compile if not had_transpiled: circuits = self.transpile(circuits) # fix for providers that don't support QasmQobj until a bigger refactor happens from qiskit.providers import BackendV1 circuit_job = isinstance(self._backend, BackendV1) and \ not is_aer_provider(self._backend) and \ not is_basicaer_provider(self._backend) and \ not is_ibmq_provider(self._backend) # assemble if not circuit_job: qobj = self.assemble(circuits) if self._meas_error_mitigation_cls is not None: qubit_index, qubit_mappings = get_measured_qubits(circuits) \ if circuit_job else get_measured_qubits_from_qobj(qobj) qubit_index_str = '_'.join([str(x) for x in qubit_index]) + \ "_{}".format(self._meas_error_mitigation_shots or self._run_config.shots) meas_error_mitigation_fitter, timestamp = \ self._meas_error_mitigation_fitters.get(qubit_index_str, (None, 0.)) if meas_error_mitigation_fitter is None: # check the asked qubit_index are the subset of build matrices for key, _ in self._meas_error_mitigation_fitters.items(): stored_qubit_index = [int(x) for x in key.split("_")[:-1]] stored_shots = int(key.split("_")[-1]) if len(qubit_index) < len(stored_qubit_index): tmp = list(set(qubit_index + stored_qubit_index)) if sorted(tmp) == sorted(stored_qubit_index) and \ self._run_config.shots == stored_shots: # the qubit used in current job is the subset and shots are the same meas_error_mitigation_fitter, timestamp = \ self._meas_error_mitigation_fitters.get(key, (None, 0.)) meas_error_mitigation_fitter = \ meas_error_mitigation_fitter.subset_fitter( qubit_sublist=qubit_index) logger.info( "The qubits used in the current job is the subset of " "previous jobs, " "reusing the calibration matrix if it is not out-of-date." ) build_cals_matrix = self.maybe_refresh_cals_matrix(timestamp) or \ meas_error_mitigation_fitter is None if build_cals_matrix: if circuit_job: logger.info( "Updating to also run measurement error mitigation.") use_different_shots = not ( self._meas_error_mitigation_shots is None or self._meas_error_mitigation_shots == self._run_config.shots) temp_run_config = copy.deepcopy(self._run_config) if use_different_shots: temp_run_config.shots = self._meas_error_mitigation_shots cal_circuits, state_labels, circuit_labels = \ build_measurement_error_mitigation_circuits( qubit_index, self._meas_error_mitigation_cls, self._backend, self._backend_config, self._compile_config) if use_different_shots: cals_result = run_circuits( cal_circuits, self._backend, qjob_config=self._qjob_config, backend_options=self._backend_options, noise_config=self._noise_config, run_config=self._run_config.to_dict(), job_callback=self._job_callback) self._time_taken += cals_result.time_taken result = run_circuits( circuits, self._backend, qjob_config=self.qjob_config, backend_options=self.backend_options, noise_config=self._noise_config, run_config=self.run_config.to_dict(), job_callback=self._job_callback) self._time_taken += result.time_taken else: circuits[0:0] = cal_circuits result = run_circuits( circuits, self._backend, qjob_config=self.qjob_config, backend_options=self.backend_options, noise_config=self._noise_config, run_config=self.run_config.to_dict(), job_callback=self._job_callback) self._time_taken += result.time_taken cals_result = result else: logger.info( "Updating qobj with the circuits for measurement error mitigation." ) use_different_shots = not ( self._meas_error_mitigation_shots is None or self._meas_error_mitigation_shots == self._run_config.shots) temp_run_config = copy.deepcopy(self._run_config) if use_different_shots: temp_run_config.shots = self._meas_error_mitigation_shots cals_qobj, state_labels, circuit_labels = \ build_measurement_error_mitigation_qobj(qubit_index, self._meas_error_mitigation_cls, self._backend, self._backend_config, self._compile_config, temp_run_config) if use_different_shots or is_aer_qasm(self._backend): cals_result = run_qobj(cals_qobj, self._backend, self._qjob_config, self._backend_options, self._noise_config, self._skip_qobj_validation, self._job_callback) self._time_taken += cals_result.time_taken result = run_qobj(qobj, self._backend, self._qjob_config, self._backend_options, self._noise_config, self._skip_qobj_validation, self._job_callback) self._time_taken += result.time_taken else: # insert the calibration circuit into main qobj if the shots are the same qobj.experiments[0:0] = cals_qobj.experiments result = run_qobj(qobj, self._backend, self._qjob_config, self._backend_options, self._noise_config, self._skip_qobj_validation, self._job_callback) self._time_taken += result.time_taken cals_result = result logger.info( "Building calibration matrix for measurement error mitigation." ) meas_error_mitigation_fitter = \ self._meas_error_mitigation_cls(cals_result, state_labels, qubit_list=qubit_index, circlabel=circuit_labels) self._meas_error_mitigation_fitters[qubit_index_str] = \ (meas_error_mitigation_fitter, time.time()) else: result = run_circuits(circuits, self._backend, qjob_config=self.qjob_config, backend_options=self.backend_options, noise_config=self._noise_config, run_config=self._run_config.to_dict(), job_callback=self._job_callback) if circuit_job else \ run_qobj(qobj, self._backend, self._qjob_config, self._backend_options, self._noise_config, self._skip_qobj_validation, self._job_callback) self._time_taken += result.time_taken if meas_error_mitigation_fitter is not None: logger.info("Performing measurement error mitigation.") skip_num_circuits = len(result.results) - len(circuits) # remove the calibration counts from result object to assure the length of # ExperimentalResult is equal length to input circuits result.results = result.results[skip_num_circuits:] tmp_result = copy.deepcopy(result) for qubit_index_str, c_idx in qubit_mappings.items(): curr_qubit_index = [ int(x) for x in qubit_index_str.split("_") ] tmp_result.results = [result.results[i] for i in c_idx] if curr_qubit_index == qubit_index: tmp_fitter = meas_error_mitigation_fitter else: tmp_fitter = meas_error_mitigation_fitter.subset_fitter( curr_qubit_index) tmp_result = tmp_fitter.filter.apply( tmp_result, self._meas_error_mitigation_method) for i, n in enumerate(c_idx): result.results[n] = tmp_result.results[i] else: result = run_circuits(circuits, self._backend, qjob_config=self.qjob_config, backend_options=self.backend_options, noise_config=self._noise_config, run_config=self._run_config.to_dict(), job_callback=self._job_callback) if circuit_job else \ run_qobj(qobj, self._backend, self._qjob_config, self._backend_options, self._noise_config, self._skip_qobj_validation, self._job_callback) self._time_taken += result.time_taken if self._circuit_summary: self._circuit_summary = False return result
def execute(self, circuits, had_transpiled: bool = False): """ A wrapper to interface with quantum backend. Args: circuits (Union['QuantumCircuit', List['QuantumCircuit']]): circuits to execute had_transpiled: whether or not circuits had been transpiled Raises: QiskitError: Invalid error mitigation fitter class QiskitError: TensoredMeasFitter class doesn't support subset fitter MissingOptionalLibraryError: Ignis not installed Returns: Result: result object TODO: Maybe we can combine the circuits for the main ones and calibration circuits before assembling to the qobj. """ from qiskit.utils.run_circuits import run_qobj, run_circuits from qiskit.utils.measurement_error_mitigation import ( get_measured_qubits_from_qobj, get_measured_qubits, build_measurement_error_mitigation_circuits, build_measurement_error_mitigation_qobj, ) if had_transpiled: # Convert to a list or make a copy. # The measurement mitigation logic expects a list and # may change it in place. This makes sure that logic works # and any future logic that may change the input. # It also makes the code easier: it will always deal with a list. if isinstance(circuits, list): circuits = circuits.copy() else: circuits = [circuits] else: # transpile here, the method always returns a copied list circuits = self.transpile(circuits) from qiskit.providers import Backend circuit_job = isinstance(self._backend, Backend) if self.is_statevector and self.backend_name == "aer_simulator_statevector": try: from qiskit.providers.aer.library import SaveStatevector def _find_save_state(data): for instr, _, _ in reversed(data): if isinstance(instr, SaveStatevector): return True return False if isinstance(circuits, list): for circuit in circuits: if not _find_save_state(circuit.data): circuit.save_statevector() else: if not _find_save_state(circuits.data): circuits.save_statevector() except ImportError: pass # assemble if not circuit_job: qobj = self.assemble(circuits) if self._meas_error_mitigation_cls is not None: qubit_index, qubit_mappings = ( get_measured_qubits(circuits) if circuit_job else get_measured_qubits_from_qobj(qobj) ) mit_pattern = self._mit_pattern if mit_pattern is None: mit_pattern = [[i] for i in range(len(qubit_index))] qubit_index_str = "_".join([str(x) for x in qubit_index]) + "_{}".format( self._meas_error_mitigation_shots or self._run_config.shots ) meas_error_mitigation_fitter, timestamp = self._meas_error_mitigation_fitters.get( qubit_index_str, (None, 0.0) ) if meas_error_mitigation_fitter is None: # check the asked qubit_index are the subset of build matrices for key, _ in self._meas_error_mitigation_fitters.items(): stored_qubit_index = [int(x) for x in key.split("_")[:-1]] stored_shots = int(key.split("_")[-1]) if len(qubit_index) < len(stored_qubit_index): tmp = list(set(qubit_index + stored_qubit_index)) if ( sorted(tmp) == sorted(stored_qubit_index) and self._run_config.shots == stored_shots ): # the qubit used in current job is the subset and shots are the same ( meas_error_mitigation_fitter, timestamp, ) = self._meas_error_mitigation_fitters.get(key, (None, 0.0)) meas_error_mitigation_fitter = ( meas_error_mitigation_fitter.subset_fitter( qubit_sublist=qubit_index ) ) logger.info( "The qubits used in the current job is the subset of " "previous jobs, " "reusing the calibration matrix if it is not out-of-date." ) build_cals_matrix = ( self.maybe_refresh_cals_matrix(timestamp) or meas_error_mitigation_fitter is None ) cal_circuits = None prepended_calibration_circuits: int = 0 if build_cals_matrix: if circuit_job: logger.info("Updating to also run measurement error mitigation.") use_different_shots = not ( self._meas_error_mitigation_shots is None or self._meas_error_mitigation_shots == self._run_config.shots ) temp_run_config = copy.deepcopy(self._run_config) if use_different_shots: temp_run_config.shots = self._meas_error_mitigation_shots ( cal_circuits, state_labels, circuit_labels, ) = build_measurement_error_mitigation_circuits( qubit_index, self._meas_error_mitigation_cls, self._backend, self._backend_config, self._compile_config, mit_pattern=mit_pattern, ) if use_different_shots: cals_result = run_circuits( cal_circuits, self._backend, qjob_config=self._qjob_config, backend_options=self._backend_options, noise_config=self._noise_config, run_config=self._run_config.to_dict(), job_callback=self._job_callback, max_job_retries=self._max_job_retries, ) self._time_taken += cals_result.time_taken result = run_circuits( circuits, self._backend, qjob_config=self.qjob_config, backend_options=self.backend_options, noise_config=self._noise_config, run_config=self.run_config.to_dict(), job_callback=self._job_callback, max_job_retries=self._max_job_retries, ) self._time_taken += result.time_taken else: circuits[0:0] = cal_circuits prepended_calibration_circuits = len(cal_circuits) result = run_circuits( circuits, self._backend, qjob_config=self.qjob_config, backend_options=self.backend_options, noise_config=self._noise_config, run_config=self.run_config.to_dict(), job_callback=self._job_callback, max_job_retries=self._max_job_retries, ) self._time_taken += result.time_taken cals_result = result else: logger.info("Updating qobj with the circuits for measurement error mitigation.") use_different_shots = not ( self._meas_error_mitigation_shots is None or self._meas_error_mitigation_shots == self._run_config.shots ) temp_run_config = copy.deepcopy(self._run_config) if use_different_shots: temp_run_config.shots = self._meas_error_mitigation_shots ( cals_qobj, state_labels, circuit_labels, ) = build_measurement_error_mitigation_qobj( qubit_index, self._meas_error_mitigation_cls, self._backend, self._backend_config, self._compile_config, temp_run_config, mit_pattern=mit_pattern, ) if use_different_shots or is_aer_qasm(self._backend): cals_result = run_qobj( cals_qobj, self._backend, self._qjob_config, self._backend_options, self._noise_config, self._skip_qobj_validation, self._job_callback, self._max_job_retries, ) self._time_taken += cals_result.time_taken result = run_qobj( qobj, self._backend, self._qjob_config, self._backend_options, self._noise_config, self._skip_qobj_validation, self._job_callback, self._max_job_retries, ) self._time_taken += result.time_taken else: # insert the calibration circuit into main qobj if the shots are the same qobj.experiments[0:0] = cals_qobj.experiments result = run_qobj( qobj, self._backend, self._qjob_config, self._backend_options, self._noise_config, self._skip_qobj_validation, self._job_callback, self._max_job_retries, ) self._time_taken += result.time_taken cals_result = result logger.info("Building calibration matrix for measurement error mitigation.") meas_type = _MeasFitterType.type_from_class(self._meas_error_mitigation_cls) if meas_type == _MeasFitterType.COMPLETE_MEAS_FITTER: meas_error_mitigation_fitter = self._meas_error_mitigation_cls( cals_result, state_labels, qubit_list=qubit_index, circlabel=circuit_labels ) elif meas_type == _MeasFitterType.TENSORED_MEAS_FITTER: meas_error_mitigation_fitter = self._meas_error_mitigation_cls( cals_result, mit_pattern=state_labels, circlabel=circuit_labels ) self._meas_error_mitigation_fitters[qubit_index_str] = ( meas_error_mitigation_fitter, time.time(), ) else: result = ( run_circuits( circuits, self._backend, qjob_config=self.qjob_config, backend_options=self.backend_options, noise_config=self._noise_config, run_config=self._run_config.to_dict(), job_callback=self._job_callback, max_job_retries=self._max_job_retries, ) if circuit_job else run_qobj( qobj, self._backend, self._qjob_config, self._backend_options, self._noise_config, self._skip_qobj_validation, self._job_callback, self._max_job_retries, ) ) self._time_taken += result.time_taken if meas_error_mitigation_fitter is not None: logger.info("Performing measurement error mitigation.") if ( hasattr(self._run_config, "parameterizations") and len(self._run_config.parameterizations) > 0 and len(self._run_config.parameterizations[0]) > 0 and len(self._run_config.parameterizations[0][0]) > 0 ): num_circuit_templates = len(self._run_config.parameterizations) num_param_variations = len(self._run_config.parameterizations[0][0]) num_circuits = num_circuit_templates * num_param_variations else: input_circuits = circuits[prepended_calibration_circuits:] num_circuits = len(input_circuits) skip_num_circuits = len(result.results) - num_circuits # remove the calibration counts from result object to assure the length of # ExperimentalResult is equal length to input circuits result.results = result.results[skip_num_circuits:] tmp_result = copy.deepcopy(result) for qubit_index_str, c_idx in qubit_mappings.items(): curr_qubit_index = [int(x) for x in qubit_index_str.split("_")] tmp_result.results = [result.results[i] for i in c_idx] if curr_qubit_index == qubit_index: tmp_fitter = meas_error_mitigation_fitter elif _MeasFitterType.COMPLETE_MEAS_FITTER == _MeasFitterType.type_from_instance( meas_error_mitigation_fitter ): tmp_fitter = meas_error_mitigation_fitter.subset_fitter(curr_qubit_index) else: raise QiskitError( "{} doesn't support subset_fitter.".format( meas_error_mitigation_fitter.__class__.__name__ ) ) tmp_result = tmp_fitter.filter.apply( tmp_result, self._meas_error_mitigation_method ) for i, n in enumerate(c_idx): # convert counts to integer and remove 0 values tmp_result.results[i].data.counts = { k: round(v) for k, v in tmp_result.results[i].data.counts.items() if round(v) != 0 } result.results[n] = tmp_result.results[i] else: result = ( run_circuits( circuits, self._backend, qjob_config=self.qjob_config, backend_options=self.backend_options, noise_config=self._noise_config, run_config=self._run_config.to_dict(), job_callback=self._job_callback, max_job_retries=self._max_job_retries, ) if circuit_job else run_qobj( qobj, self._backend, self._qjob_config, self._backend_options, self._noise_config, self._skip_qobj_validation, self._job_callback, self._max_job_retries, ) ) self._time_taken += result.time_taken if self._circuit_summary: self._circuit_summary = False return result
def execute(self, circuits, had_transpiled: bool = False): """ A wrapper to interface with quantum backend. Args: circuits (Union['QuantumCircuit', List['QuantumCircuit']]): circuits to execute had_transpiled: whether or not circuits had been transpiled Returns: Result: result object TODO: Maybe we can combine the circuits for the main ones and calibration circuits before assembling to the qobj. """ from qiskit.utils.run_circuits import run_qobj, run_circuits from qiskit.utils.measurement_error_mitigation import ( get_measured_qubits_from_qobj, get_measured_qubits, build_measurement_error_mitigation_circuits, build_measurement_error_mitigation_qobj, ) # maybe compile if not had_transpiled: circuits = self.transpile(circuits) from qiskit.providers import BackendV1 circuit_job = isinstance(self._backend, BackendV1) if self.is_statevector and self._backend.name( ) == "aer_simulator_statevector": try: from qiskit.providers.aer.library import SaveStatevector def _find_save_state(data): for instr, _, _ in reversed(data): if isinstance(instr, SaveStatevector): return True return False if isinstance(circuits, list): for circuit in circuits: if not _find_save_state(circuit.data): circuit.save_statevector() else: if not _find_save_state(circuits.data): circuits.save_statevector() except ImportError: pass # assemble if not circuit_job: qobj = self.assemble(circuits) if self._meas_error_mitigation_cls is not None: qubit_index, qubit_mappings = (get_measured_qubits(circuits) if circuit_job else get_measured_qubits_from_qobj(qobj)) qubit_index_str = "_".join([str(x) for x in qubit_index]) + "_{}".format( self._meas_error_mitigation_shots or self._run_config.shots) meas_error_mitigation_fitter, timestamp = self._meas_error_mitigation_fitters.get( qubit_index_str, (None, 0.0)) if meas_error_mitigation_fitter is None: # check the asked qubit_index are the subset of build matrices for key, _ in self._meas_error_mitigation_fitters.items(): stored_qubit_index = [int(x) for x in key.split("_")[:-1]] stored_shots = int(key.split("_")[-1]) if len(qubit_index) < len(stored_qubit_index): tmp = list(set(qubit_index + stored_qubit_index)) if (sorted(tmp) == sorted(stored_qubit_index) and self._run_config.shots == stored_shots): # the qubit used in current job is the subset and shots are the same ( meas_error_mitigation_fitter, timestamp, ) = self._meas_error_mitigation_fitters.get( key, (None, 0.0)) meas_error_mitigation_fitter = ( meas_error_mitigation_fitter.subset_fitter( qubit_sublist=qubit_index)) logger.info( "The qubits used in the current job is the subset of " "previous jobs, " "reusing the calibration matrix if it is not out-of-date." ) build_cals_matrix = (self.maybe_refresh_cals_matrix(timestamp) or meas_error_mitigation_fitter is None) if build_cals_matrix: if circuit_job: logger.info( "Updating to also run measurement error mitigation.") use_different_shots = not ( self._meas_error_mitigation_shots is None or self._meas_error_mitigation_shots == self._run_config.shots) temp_run_config = copy.deepcopy(self._run_config) if use_different_shots: temp_run_config.shots = self._meas_error_mitigation_shots ( cal_circuits, state_labels, circuit_labels, ) = build_measurement_error_mitigation_circuits( qubit_index, self._meas_error_mitigation_cls, self._backend, self._backend_config, self._compile_config, ) if use_different_shots: cals_result = run_circuits( cal_circuits, self._backend, qjob_config=self._qjob_config, backend_options=self._backend_options, noise_config=self._noise_config, run_config=self._run_config.to_dict(), job_callback=self._job_callback, ) self._time_taken += cals_result.time_taken result = run_circuits( circuits, self._backend, qjob_config=self.qjob_config, backend_options=self.backend_options, noise_config=self._noise_config, run_config=self.run_config.to_dict(), job_callback=self._job_callback, ) self._time_taken += result.time_taken else: circuits[0:0] = cal_circuits result = run_circuits( circuits, self._backend, qjob_config=self.qjob_config, backend_options=self.backend_options, noise_config=self._noise_config, run_config=self.run_config.to_dict(), job_callback=self._job_callback, ) self._time_taken += result.time_taken cals_result = result else: logger.info( "Updating qobj with the circuits for measurement error mitigation." ) use_different_shots = not ( self._meas_error_mitigation_shots is None or self._meas_error_mitigation_shots == self._run_config.shots) temp_run_config = copy.deepcopy(self._run_config) if use_different_shots: temp_run_config.shots = self._meas_error_mitigation_shots ( cals_qobj, state_labels, circuit_labels, ) = build_measurement_error_mitigation_qobj( qubit_index, self._meas_error_mitigation_cls, self._backend, self._backend_config, self._compile_config, temp_run_config, ) if use_different_shots or is_aer_qasm(self._backend): cals_result = run_qobj( cals_qobj, self._backend, self._qjob_config, self._backend_options, self._noise_config, self._skip_qobj_validation, self._job_callback, ) self._time_taken += cals_result.time_taken result = run_qobj( qobj, self._backend, self._qjob_config, self._backend_options, self._noise_config, self._skip_qobj_validation, self._job_callback, ) self._time_taken += result.time_taken else: # insert the calibration circuit into main qobj if the shots are the same qobj.experiments[0:0] = cals_qobj.experiments result = run_qobj( qobj, self._backend, self._qjob_config, self._backend_options, self._noise_config, self._skip_qobj_validation, self._job_callback, ) self._time_taken += result.time_taken cals_result = result logger.info( "Building calibration matrix for measurement error mitigation." ) meas_error_mitigation_fitter = self._meas_error_mitigation_cls( cals_result, state_labels, qubit_list=qubit_index, circlabel=circuit_labels) self._meas_error_mitigation_fitters[qubit_index_str] = ( meas_error_mitigation_fitter, time.time(), ) else: result = (run_circuits( circuits, self._backend, qjob_config=self.qjob_config, backend_options=self.backend_options, noise_config=self._noise_config, run_config=self._run_config.to_dict(), job_callback=self._job_callback, ) if circuit_job else run_qobj( qobj, self._backend, self._qjob_config, self._backend_options, self._noise_config, self._skip_qobj_validation, self._job_callback, )) self._time_taken += result.time_taken if meas_error_mitigation_fitter is not None: logger.info("Performing measurement error mitigation.") if (hasattr(self._run_config, "parameterizations") and len(self._run_config.parameterizations) > 0 and len(self._run_config.parameterizations[0]) > 0 and len(self._run_config.parameterizations[0][0]) > 0): num_circuit_templates = len( self._run_config.parameterizations) num_param_variations = len( self._run_config.parameterizations[0][0]) num_circuits = num_circuit_templates * num_param_variations else: num_circuits = len(circuits) skip_num_circuits = len(result.results) - num_circuits # remove the calibration counts from result object to assure the length of # ExperimentalResult is equal length to input circuits result.results = result.results[skip_num_circuits:] tmp_result = copy.deepcopy(result) for qubit_index_str, c_idx in qubit_mappings.items(): curr_qubit_index = [ int(x) for x in qubit_index_str.split("_") ] tmp_result.results = [result.results[i] for i in c_idx] if curr_qubit_index == qubit_index: tmp_fitter = meas_error_mitigation_fitter else: tmp_fitter = meas_error_mitigation_fitter.subset_fitter( curr_qubit_index) tmp_result = tmp_fitter.filter.apply( tmp_result, self._meas_error_mitigation_method) for i, n in enumerate(c_idx): result.results[n] = tmp_result.results[i] else: result = (run_circuits( circuits, self._backend, qjob_config=self.qjob_config, backend_options=self.backend_options, noise_config=self._noise_config, run_config=self._run_config.to_dict(), job_callback=self._job_callback, ) if circuit_job else run_qobj( qobj, self._backend, self._qjob_config, self._backend_options, self._noise_config, self._skip_qobj_validation, self._job_callback, )) self._time_taken += result.time_taken if self._circuit_summary: self._circuit_summary = False return result