Source code for qiskit_experiments.library.characterization.analysis.local_readout_error_analysis

# This code is part of Qiskit.
#
# (C) Copyright IBM 2021, 2022.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.
"""
Analysis class to characterize local readout error
"""
import numpy as np
import matplotlib.pyplot as plt
from qiskit.result import marginal_distribution
from qiskit_experiments.data_processing import LocalReadoutMitigator
from qiskit_experiments.framework import ExperimentData
from qiskit_experiments.framework.matplotlib import get_non_gui_ax
from qiskit_experiments.framework import BaseAnalysis, AnalysisResultData, Options


[docs] class LocalReadoutErrorAnalysis(BaseAnalysis): r""" Local readout error characterization analysis # section: overview This class generates the assignment matrices characterizing the readout error for each of the given qubits from the experiment result, and returns the resulting :class:`~qiskit.result.LocalReadoutMitigator` Each such matrix is a :math:`2\times 2` matrix :math:`A`. Such that :math:`A_{y,x}` is the probability to observe :math:`y` given the true outcome should be :math:`x`, where :math:`x,y \in \left\{0,1\right\}` can be 0 and 1. In the experiment, two circuits are constructed - one for 0 outcome for all qubits and one for 1 outcome. From the observed results on the circuit, the probability for each :math:`x,y` is determined, and :math:`A_{y,x}` is set accordingly. Analysis Results: * "Local Readout Mitigator": The :class:`~qiskit.result.LocalReadoutMitigator`. Analysis Figures: * (Optional) A figure of the assignment matrix. Note: producing this figure scales exponentially with the number of qubits. # section: reference .. ref_arxiv:: 1 2006.14044 """ @classmethod def _default_options(cls) -> Options: """Return default analysis options. Analysis Options: plot (bool): Set ``True`` to create figure for fit result. ax (AxesSubplot): Optional. A matplotlib axis object to draw. """ options = super()._default_options() # since the plot size grows exponentially with the number of qubits, plotting is off by default options.plot = False options.ax = None return options def _run_analysis( self, experiment_data: ExperimentData ) -> tuple[list[AnalysisResultData], list["matplotlib.figure.Figure"]]: data = experiment_data.data() qubits = experiment_data.metadata["physical_qubits"] matrices = self._generate_matrices(data) result_mitigator = LocalReadoutMitigator(matrices, qubits=qubits) analysis_results = [AnalysisResultData("Local Readout Mitigator", result_mitigator)] if self.options.plot: figure = assignment_matrix_visualization( result_mitigator.assignment_matrix(), ax=self.options.ax ) figures = [figure] else: figures = None return analysis_results, figures def _generate_matrices(self, data) -> list[np.array]: num_qubits = len(data[0]["metadata"]["state_label"]) counts = [None, None] for result in data: for i in range(2): if result["metadata"]["state_label"] == str(i) * num_qubits: counts[i] = result["counts"] matrices = [] for k in range(num_qubits): matrix = np.zeros([2, 2], dtype=float) marginalized_counts = [] shots = [] for i in range(2): marginal_cts = marginal_distribution(counts[i], [k]) marginalized_counts.append(marginal_cts) shots.append(sum(marginal_cts.values())) # matrix[i][j] is the probability of counting i for expected j for i in range(2): for j in range(2): matrix[i][j] = marginalized_counts[j].get(str(i), 0) / shots[j] matrices.append(matrix) return matrices
def assignment_matrix_visualization(assignment_matrix, ax=None): """Displays a visualization of the assignment matrix compared to the identity""" if ax is None: ax = get_non_gui_ax() figure = ax.get_figure() n = len(assignment_matrix) diff = np.abs(assignment_matrix - np.eye(n)) im2 = ax.matshow(diff, cmap=plt.cm.Reds, vmin=0, vmax=0.2) ax.set_yticks(np.arange(n)) ax.set_xticks(np.arange(n)) ax.set_yticklabels(n * [""]) ax.set_xticklabels(n * [""]) ax.set_title(r"$|A - I |$", fontsize=16) ax.set_xlabel("Prepared State") ax.xaxis.set_label_position("top") ax.set_ylabel("Measured State") figure.colorbar(im2, ax=ax) return figure