Source code for qiskit.visualization.gate_map

# -*- coding: utf-8 -*-

# This code is part of Qiskit.
#
# (C) Copyright IBM 2017, 2018.
#
# 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.

"""A module for visualizing device coupling maps"""

import math
import numpy as np
from qiskit.exceptions import QiskitError
from .matplotlib import HAS_MATPLOTLIB
from .exceptions import VisualizationError

if HAS_MATPLOTLIB:
    import matplotlib
    from matplotlib import get_backend
    import matplotlib.pyplot as plt  # pylint: disable=import-error
    import matplotlib.patches as mpatches
    import matplotlib.gridspec as gridspec
    from matplotlib import ticker


class _GraphDist():
    """Transform the circles properly for non-square axes.
    """

    def __init__(self, size, ax, x=True):
        self.size = size
        self.ax = ax  # pylint: disable=invalid-name
        self.x = x

    @property
    def dist_real(self):
        """Compute distance.
        """
        x0, y0 = self.ax.transAxes.transform(  # pylint: disable=invalid-name
            (0, 0))
        x1, y1 = self.ax.transAxes.transform(  # pylint: disable=invalid-name
            (1, 1))
        value = x1 - x0 if self.x else y1 - y0
        return value

    @property
    def dist_abs(self):
        """Distance abs
        """
        bounds = self.ax.get_xlim() if self.x else self.ax.get_ylim()
        return bounds[0] - bounds[1]

    @property
    def value(self):
        """Return value.
        """
        return (self.size / self.dist_real) * self.dist_abs

    def __mul__(self, obj):
        return self.value * obj


[docs]def plot_gate_map(backend, figsize=None, plot_directed=False, label_qubits=True, qubit_size=24, line_width=4, font_size=12, qubit_color=None, qubit_labels=None, line_color=None, font_color='w', ax=None): """Plots the gate map of a device. Args: backend (BaseBackend): A backend instance, figsize (tuple): Output figure size (wxh) in inches. plot_directed (bool): Plot directed coupling map. label_qubits (bool): Label the qubits. qubit_size (float): Size of qubit marker. line_width (float): Width of lines. font_size (int): Font size of qubit labels. qubit_color (list): A list of colors for the qubits qubit_labels (list): A list of qubit labels line_color (list): A list of colors for each line from coupling_map. font_color (str): The font color for the qubit labels. ax (Axes): A Matplotlib axes instance. Returns: Figure: A Matplotlib figure instance. Raises: QiskitError: if tried to pass a simulator. ImportError: if matplotlib not installed. Example: .. jupyter-execute:: :hide-code: :hide-output: from qiskit.test.ibmq_mock import mock_get_backend mock_get_backend('FakeVigo') .. jupyter-execute:: from qiskit import QuantumCircuit, execute, IBMQ from qiskit.visualization import plot_gate_map %matplotlib inline provider = IBMQ.load_account() accountProvider = IBMQ.get_provider(hub='ibm-q') backend = accountProvider.get_backend('ibmq_vigo') plot_gate_map(backend) """ if not HAS_MATPLOTLIB: raise ImportError('Must have Matplotlib installed. To install, ' 'run "pip install matplotlib".') if backend.configuration().simulator: raise QiskitError('Requires a device backend, not simulator.') input_axes = False if ax: input_axes = True mpl_data = {} mpl_data[1] = [[0, 0]] mpl_data[20] = [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4], [1, 0], [1, 1], [1, 2], [1, 3], [1, 4], [2, 0], [2, 1], [2, 2], [2, 3], [2, 4], [3, 0], [3, 1], [3, 2], [3, 3], [3, 4]] mpl_data[15] = [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4], [0, 5], [0, 6], [1, 7], [1, 6], [1, 5], [1, 4], [1, 3], [1, 2], [1, 1], [1, 0]] mpl_data[16] = [[1, 0], [0, 0], [0, 1], [0, 2], [0, 3], [0, 4], [0, 5], [0, 6], [0, 7], [1, 7], [1, 6], [1, 5], [1, 4], [1, 3], [1, 2], [1, 1]] mpl_data[5] = [[1, 0], [0, 1], [1, 1], [1, 2], [2, 1]] mpl_data[27] = [[1, 0], [1, 1], [2, 1], [3, 1], [1, 2], [3, 2], [0, 3], [1, 3], [3, 3], [4, 3], [1, 4], [3, 4], [1, 5], [2, 5], [3, 5], [1, 6], [3, 6], [0, 7], [1, 7], [3, 7], [4, 7], [1, 8], [3, 8], [1, 9], [2, 9], [3, 9], [3, 10]] mpl_data[28] = [[0, 2], [0, 3], [0, 4], [0, 5], [0, 6], [1, 2], [1, 6], [2, 0], [2, 1], [2, 2], [2, 3], [2, 4], [2, 5], [2, 6], [2, 7], [2, 8], [3, 0], [3, 4], [3, 8], [4, 0], [4, 1], [4, 2], [4, 3], [4, 4], [4, 5], [4, 6], [4, 7], [4, 8]] mpl_data[53] = [[0, 2], [0, 3], [0, 4], [0, 5], [0, 6], [1, 2], [1, 6], [2, 0], [2, 1], [2, 2], [2, 3], [2, 4], [2, 5], [2, 6], [2, 7], [2, 8], [3, 0], [3, 4], [3, 8], [4, 0], [4, 1], [4, 2], [4, 3], [4, 4], [4, 5], [4, 6], [4, 7], [4, 8], [5, 2], [5, 6], [6, 0], [6, 1], [6, 2], [6, 3], [6, 4], [6, 5], [6, 6], [6, 7], [6, 8], [7, 0], [7, 4], [7, 8], [8, 0], [8, 1], [8, 2], [8, 3], [8, 4], [8, 5], [8, 6], [8, 7], [8, 8], [9, 2], [9, 6]] config = backend.configuration() num_qubits = config.n_qubits cmap = config.coupling_map if qubit_labels is None: qubit_labels = list(range(num_qubits)) else: if len(qubit_labels) != num_qubits: raise QiskitError('Length of qubit labels ' 'does not equal number ' 'of qubits.') if num_qubits in mpl_data.keys(): grid_data = mpl_data[num_qubits] else: if not input_axes: fig, ax = plt.subplots(figsize=(5, 5)) # pylint: disable=invalid-name ax.axis('off') return fig x_max = max([d[1] for d in grid_data]) y_max = max([d[0] for d in grid_data]) max_dim = max(x_max, y_max) if figsize is None: if num_qubits == 1 or (x_max / max_dim > 0.33 and y_max / max_dim > 0.33): figsize = (5, 5) else: figsize = (9, 3) if ax is None: fig, ax = plt.subplots(figsize=figsize) # pylint: disable=invalid-name ax.axis('off') # set coloring if qubit_color is None: qubit_color = ['#648fff'] * config.n_qubits if line_color is None: line_color = ['#648fff'] * len(cmap) if cmap else [] # Add lines for couplings if num_qubits != 1: for ind, edge in enumerate(cmap): is_symmetric = False if edge[::-1] in cmap: is_symmetric = True y_start = grid_data[edge[0]][0] x_start = grid_data[edge[0]][1] y_end = grid_data[edge[1]][0] x_end = grid_data[edge[1]][1] if is_symmetric: if y_start == y_end: x_end = (x_end - x_start) / 2 + x_start elif x_start == x_end: y_end = (y_end - y_start) / 2 + y_start else: x_end = (x_end - x_start) / 2 + x_start y_end = (y_end - y_start) / 2 + y_start ax.add_artist(plt.Line2D([x_start, x_end], [-y_start, -y_end], color=line_color[ind], linewidth=line_width, zorder=0)) if plot_directed: dx = x_end - x_start # pylint: disable=invalid-name dy = y_end - y_start # pylint: disable=invalid-name if is_symmetric: x_arrow = x_start + dx * 0.95 y_arrow = -y_start - dy * 0.95 dx_arrow = dx * 0.01 dy_arrow = -dy * 0.01 head_width = 0.15 else: x_arrow = x_start + dx * 0.5 y_arrow = -y_start - dy * 0.5 dx_arrow = dx * 0.2 dy_arrow = -dy * 0.2 head_width = 0.2 ax.add_patch(mpatches.FancyArrow(x_arrow, y_arrow, dx_arrow, dy_arrow, head_width=head_width, length_includes_head=True, edgecolor=None, linewidth=0, facecolor=line_color[ind], zorder=1)) # Add circles for qubits for var, idx in enumerate(grid_data): _idx = [idx[1], -idx[0]] width = _GraphDist(qubit_size, ax, True) height = _GraphDist(qubit_size, ax, False) ax.add_artist(mpatches.Ellipse( _idx, width, height, color=qubit_color[var], zorder=1)) if label_qubits: ax.text(*_idx, s=qubit_labels[var], horizontalalignment='center', verticalalignment='center', color=font_color, size=font_size, weight='bold') ax.set_xlim([-1, x_max + 1]) ax.set_ylim([-(y_max + 1), 1]) if not input_axes: if get_backend() in ['module://ipykernel.pylab.backend_inline', 'nbAgg']: plt.close(fig) return fig return None
[docs]def plot_circuit_layout(circuit, backend, view='virtual'): """Plot the layout of a circuit transpiled for a given target backend. Args: circuit (QuantumCircuit): Input quantum circuit. backend (BaseBackend): Target backend. view (str): Layout view: either 'virtual' or 'physical'. Returns: Figure: A matplotlib figure showing layout. Raises: QiskitError: Invalid view type given. VisualizationError: Circuit has no layout attribute. Example: .. jupyter-execute:: :hide-code: :hide-output: from qiskit.test.ibmq_mock import mock_get_backend mock_get_backend('FakeVigo') .. jupyter-execute:: import numpy as np from qiskit import QuantumCircuit, IBMQ, transpile from qiskit.visualization import plot_histogram, plot_gate_map, plot_circuit_layout from qiskit.tools.monitor import job_monitor import matplotlib.pyplot as plt %matplotlib inline IBMQ.load_account() ghz = QuantumCircuit(3, 3) ghz.h(0) for idx in range(1,3): ghz.cx(0,idx) ghz.measure(range(3), range(3)) provider = IBMQ.get_provider(hub='ibm-q') backend = provider.get_backend('ibmq_vigo') new_circ_lv3 = transpile(ghz, backend=backend, optimization_level=3) plot_circuit_layout(new_circ_lv3, backend) """ if circuit._layout is None: raise QiskitError('Circuit has no layout. ' 'Perhaps it has not been transpiled.') num_qubits = backend.configuration().n_qubits qubits = [] qubit_labels = [None] * num_qubits if view == 'virtual': for key, val in circuit._layout.get_virtual_bits().items(): if key.register.name != 'ancilla': qubits.append(val) qubit_labels[val] = key.index elif view == 'physical': for key, val in circuit._layout.get_physical_bits().items(): if val.register.name != 'ancilla': qubits.append(key) qubit_labels[key] = key else: raise VisualizationError("Layout view must be 'virtual' or 'physical'.") qcolors = ['#648fff'] * num_qubits for k in qubits: qcolors[k] = 'k' cmap = backend.configuration().coupling_map lcolors = ['#648fff'] * len(cmap) for idx, edge in enumerate(cmap): if edge[0] in qubits and edge[1] in qubits: lcolors[idx] = 'k' fig = plot_gate_map(backend, qubit_color=qcolors, qubit_labels=qubit_labels, line_color=lcolors) return fig
[docs]def plot_error_map(backend, figsize=(12, 9), show_title=True): """Plots the error map of a given backend. Args: backend (IBMQBackend): Given backend. figsize (tuple): Figure size in inches. show_title (bool): Show the title or not. Returns: Figure: A matplotlib figure showing error map. Raises: VisualizationError: Input is not IBMQ backend. ImportError: If seaborn is not installed Example: .. jupyter-execute:: :hide-code: :hide-output: from qiskit.test.ibmq_mock import mock_get_backend mock_get_backend('FakeVigo') .. jupyter-execute:: from qiskit import QuantumCircuit, execute, IBMQ from qiskit.visualization import plot_error_map %matplotlib inline IBMQ.load_account() provider = IBMQ.get_provider(hub='ibm-q') backend = provider.get_backend('ibmq_vigo') plot_error_map(backend) """ try: import seaborn as sns except ImportError: raise ImportError('Must have seaborn installed to use plot_error_map. ' 'To install, run "pip install seaborn".') color_map = sns.cubehelix_palette(reverse=True, as_cmap=True) props = backend.properties().to_dict() config = backend.configuration().to_dict() num_qubits = config['n_qubits'] # U2 error rates single_gate_errors = [0]*num_qubits for gate in props['gates']: if gate['gate'] == 'u2': _qubit = gate['qubits'][0] single_gate_errors[_qubit] = gate['parameters'][0]['value'] # Convert to percent single_gate_errors = 100 * np.asarray(single_gate_errors) avg_1q_err = np.mean(single_gate_errors) single_norm = matplotlib.colors.Normalize( vmin=min(single_gate_errors), vmax=max(single_gate_errors)) q_colors = [color_map(single_norm(err)) for err in single_gate_errors] cmap = config['coupling_map'] directed = False line_colors = [] if cmap: directed = False if num_qubits < 20: for edge in cmap: if not [edge[1], edge[0]] in cmap: directed = True break cx_errors = [] for line in cmap: for item in props['gates']: if item['qubits'] == line: cx_errors.append(item['parameters'][0]['value']) break else: continue # Convert to percent cx_errors = 100 * np.asarray(cx_errors) avg_cx_err = np.mean(cx_errors) cx_norm = matplotlib.colors.Normalize( vmin=min(cx_errors), vmax=max(cx_errors)) line_colors = [color_map(cx_norm(err)) for err in cx_errors] # Measurement errors read_err = [] for qubit in range(num_qubits): for item in props['qubits'][qubit]: if item['name'] == 'readout_error': read_err.append(item['value']) read_err = 100 * np.asarray(read_err) avg_read_err = np.mean(read_err) max_read_err = np.max(read_err) fig = plt.figure(figsize=figsize) gridspec.GridSpec(nrows=2, ncols=3) grid_spec = gridspec.GridSpec(12, 12, height_ratios=[1] * 11 + [0.5], width_ratios=[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2]) left_ax = plt.subplot(grid_spec[2:10, :1]) main_ax = plt.subplot(grid_spec[:11, 1:11]) right_ax = plt.subplot(grid_spec[2:10, 11:]) bleft_ax = plt.subplot(grid_spec[-1, :5]) if cmap: bright_ax = plt.subplot(grid_spec[-1, 7:]) plot_gate_map(backend, qubit_color=q_colors, line_color=line_colors, qubit_size=28, line_width=5, plot_directed=directed, ax=main_ax) main_ax.axis('off') main_ax.set_aspect(1) if cmap: single_cb = matplotlib.colorbar.ColorbarBase(bleft_ax, cmap=color_map, norm=single_norm, orientation='horizontal') tick_locator = ticker.MaxNLocator(nbins=5) single_cb.locator = tick_locator single_cb.update_ticks() single_cb.update_ticks() bleft_ax.set_title('H error rate (%) [Avg. = {}]'.format(round(avg_1q_err, 3))) if cmap is None: bleft_ax.axis('off') bleft_ax.set_title('H error rate (%) = {}'.format(round(avg_1q_err, 3))) if cmap: cx_cb = matplotlib.colorbar.ColorbarBase(bright_ax, cmap=color_map, norm=cx_norm, orientation='horizontal') tick_locator = ticker.MaxNLocator(nbins=5) cx_cb.locator = tick_locator cx_cb.update_ticks() bright_ax.set_title('CNOT error rate (%) [Avg. = {}]'.format(round(avg_cx_err, 3))) if num_qubits < 10: num_left = num_qubits num_right = 0 else: num_left = math.ceil(num_qubits / 2) num_right = num_qubits - num_left left_ax.barh(range(num_left), read_err[:num_left], align='center', color='#DDBBBA') left_ax.axvline(avg_read_err, linestyle='--', color='#212121') left_ax.set_yticks(range(num_left)) left_ax.set_xticks([0, round(avg_read_err, 2), round(max_read_err, 2)]) left_ax.set_yticklabels([str(kk) for kk in range(num_left)], fontsize=12) left_ax.invert_yaxis() left_ax.set_title('Readout Error (%)', fontsize=12) for spine in left_ax.spines.values(): spine.set_visible(False) if num_right: right_ax.barh(range(num_left, num_qubits), read_err[num_left:], align='center', color='#DDBBBA') right_ax.axvline(avg_read_err, linestyle='--', color='#212121') right_ax.set_yticks(range(num_left, num_qubits)) right_ax.set_xticks([0, round(avg_read_err, 2), round(max_read_err, 2)]) right_ax.set_yticklabels([str(kk) for kk in range(num_left, num_qubits)], fontsize=12) right_ax.invert_yaxis() right_ax.invert_xaxis() right_ax.yaxis.set_label_position("right") right_ax.yaxis.tick_right() right_ax.set_title('Readout Error (%)', fontsize=12) else: right_ax.axis('off') for spine in right_ax.spines.values(): spine.set_visible(False) if show_title: fig.suptitle('{name} Error Map'.format(name=backend.name()), fontsize=24, y=0.9) if get_backend() in ['module://ipykernel.pylab.backend_inline', 'nbAgg']: plt.close(fig) return fig