Example #1
0
    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
Example #2
0
    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
    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
Example #4
0
    def test_tensor_subset_fitter(self):
        """Test the subset fitter method of the tensor fitter."""

        # Construct a noise model where readout has errors of different strengths.
        noise_model = noise.NoiseModel()
        # big error
        read_err0 = noise.errors.readout_error.ReadoutError([[0.90, 0.10],
                                                             [0.25, 0.75]])
        # ideal
        read_err1 = noise.errors.readout_error.ReadoutError([[1.00, 0.00],
                                                             [0.00, 1.00]])
        # small error
        read_err2 = noise.errors.readout_error.ReadoutError([[0.98, 0.02],
                                                             [0.03, 0.97]])
        noise_model.add_readout_error(read_err0, (0, ))
        noise_model.add_readout_error(read_err1, (1, ))
        noise_model.add_readout_error(read_err2, (2, ))

        mit_pattern = [[idx] for idx in range(3)]
        backend = Aer.get_backend("aer_simulator")
        backend.set_options(seed_simulator=123)
        mit_circuits = build_measurement_error_mitigation_circuits(
            [0, 1, 2],
            TensoredMeasFitter,
            backend,
            backend_config={},
            compile_config={},
            mit_pattern=mit_pattern,
        )
        result = execute(mit_circuits[0], backend,
                         noise_model=noise_model).result()
        fitter = TensoredMeasFitter(result, mit_pattern=mit_pattern)
        cal_matrices = fitter.cal_matrices

        # Check that permutations and permuted subsets match.
        for subset in [[1, 0], [1, 2], [0, 2], [2, 0, 1]]:
            with self.subTest(subset=subset):
                new_fitter = fitter.subset_fitter(subset)
                for idx, qubit in enumerate(subset):
                    self.assertTrue(
                        np.allclose(new_fitter.cal_matrices[idx],
                                    cal_matrices[qubit]))

        self.assertRaisesRegex(
            QiskitError,
            "Qubit 3 is not in the mit pattern",
            fitter.subset_fitter,
            [0, 2, 3],
        )

        # Test that we properly correct a circuit with permuted measurements.
        circuit = QuantumCircuit(3, 3)
        circuit.x(range(3))
        circuit.measure(1, 0)
        circuit.measure(2, 1)
        circuit.measure(0, 2)

        result = execute(circuit,
                         backend,
                         noise_model=noise_model,
                         shots=1000,
                         seed_simulator=0).result()
        new_result = fitter.subset_fitter([1, 2, 0]).filter.apply(result)

        # The noisy result should have a poor 111 state, the mit. result should be good.
        self.assertTrue(result.get_counts()["111"] < 800)
        self.assertTrue(new_result.get_counts()["111"] > 990)