# -*- coding: utf-8 -*-
# This file is part of Kaleidoscope.
#
# (C) Copyright IBM 2020.
#
# 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.
# This code is part of Qiskit.
#
# (C) Copyright IBM 2017, 2019.
#
# 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.
"""Interactive gate map for IBM Quantum Experience devices."""
import plotly.graph_objects as go
from qiskit.providers.ibmq.ibmqbackend import IBMQBackend
from qiskit.test.mock.fake_backend import FakeBackend
from qiskit.providers.models.backendproperties import BackendProperties
from kaleidoscope.errors import KaleidoscopeError
from kaleidoscope.qiskit.services._simulators import DeviceSimulator
from kaleidoscope.qiskit.backends.pseudobackend import properties_to_pseudobackend
from kaleidoscope.interactive.plotly_wrapper import PlotlyWidget, PlotlyFigure
from kaleidoscope.qiskit.backends.device_layouts import LAYOUTS
[docs]def system_gate_map(
backend,
figsize=(None, None),
label_qubits=True,
qubit_size=None,
line_width=None,
font_size=None,
qubit_colors="#2f4b7c",
qubit_labels=None,
line_colors="#2f4b7c",
font_color="white",
background_color='white',
as_widget=False):
"""Plots an interactive gate map of a device.
Args:
backend (IBMQBackend or FakeBackend or DeviceSimulator or Properties): Plot the error map
for a backend.
figsize (tuple): Output figure size (wxh) in pixels.
label_qubits (bool): Labels for the qubits.
qubit_size (float): Size of qubit marker.
line_width (float): Width of lines.
font_size (float): Font size of qubit labels.
qubit_colors (str or list): A list of colors for the qubits. If a single color is given,
it's used for all qubits.
qubit_labels (list): A list of qubit labels
line_colors (str or list): A list of colors for each line from the coupling map. If a
single color is given, it's used for all lines.
font_color (str): The font color for the qubit labels.
background_color (str): The background color, either 'white' or 'black'.
as_widget (bool): Return the figure as a widget.
Returns:
PlotlyFigure or PlotlyWidget: Returned figure instance.
Raises:
KaleidoscopeError: Invalid input object.
Example:
.. jupyter-execute::
from qiskit import *
from kaleidoscope.qiskit.backends import system_gate_map
pro = IBMQ.load_account()
backend = pro.backends.ibmq_vigo
system_gate_map(backend)
"""
if not isinstance(backend, (IBMQBackend, DeviceSimulator,
FakeBackend, BackendProperties)):
raise KaleidoscopeError('Input is not a valid backend or properties object.')
if isinstance(backend, BackendProperties):
backend = properties_to_pseudobackend(backend)
config = backend.configuration()
n_qubits = config.n_qubits
cmap = config.coupling_map
# set coloring
if isinstance(qubit_colors, str):
qubit_colors = [qubit_colors] * n_qubits
if isinstance(line_colors, str):
line_colors = [line_colors] * len(cmap) if cmap else []
if str(n_qubits) in LAYOUTS['layouts'].keys():
kind = 'generic'
if backend.name() in LAYOUTS['special_names']:
if LAYOUTS['special_names'][backend.name()] in LAYOUTS['layouts'][str(n_qubits)]:
kind = LAYOUTS['special_names'][backend.name()]
grid_data = LAYOUTS['layouts'][str(n_qubits)][kind]
else:
fig = go.Figure()
fig.update_layout(showlegend=False,
plot_bgcolor=background_color,
paper_bgcolor=background_color,
width=figsize[0], height=figsize[1],
margin=dict(t=30, l=0, r=0, b=0))
if as_widget:
return PlotlyWidget(fig)
return PlotlyFigure(fig)
offset = 0
if cmap:
if n_qubits in [14, 15, 16]:
offset = 1
if qubit_size is None:
qubit_size = 24
if font_size is None:
font_size = 10
if line_width is None:
line_width = 4
if figsize == (None, None):
figsize = (400, 200)
elif n_qubits == 27:
if qubit_size is None:
qubit_size = 24
if font_size is None:
font_size = 10
if line_width is None:
line_width = 4
if figsize == (None, None):
figsize = (400, 300)
else:
if qubit_size is None:
qubit_size = 32
if font_size is None:
font_size = 14
if line_width is None:
line_width = 6
if figsize == (None, None):
figsize = (300, 300)
else:
if figsize == (None, None):
figsize = (300, 300)
if qubit_size is None:
qubit_size = 30
fig = go.Figure()
# Add lines for couplings
if cmap:
for ind, edge in enumerate(cmap):
is_symmetric = False
if edge[::-1] in cmap:
is_symmetric = True
y_start = grid_data[edge[0]][0] + offset
x_start = grid_data[edge[0]][1]
y_end = grid_data[edge[1]][0] + offset
x_end = grid_data[edge[1]][1]
if is_symmetric:
if y_start == y_end:
x_end = (x_end - x_start) / 2 + x_start
x_mid = x_end
y_mid = y_start
elif x_start == x_end:
y_end = (y_end - y_start) / 2 + y_start
x_mid = x_start
y_mid = y_end
else:
x_end = (x_end - x_start) / 2 + x_start
y_end = (y_end - y_start) / 2 + y_start
x_mid = x_end
y_mid = y_end
else:
if y_start == y_end:
x_mid = (x_end - x_start) / 2 + x_start
y_mid = y_end
elif x_start == x_end:
x_mid = x_end
y_mid = (y_end - y_start) / 2 + y_start
else:
x_mid = (x_end - x_start) / 2 + x_start
y_mid = (y_end - y_start) / 2 + y_start
fig.add_trace(
go.Scatter(x=[x_start, x_mid, x_end],
y=[-y_start, -y_mid, -y_end],
mode="lines",
hoverinfo='none',
line=dict(width=line_width,
color=line_colors[ind])))
# Add the qubits themselves
qubit_text = []
qubit_str = "<b>Qubit {}"
for num in range(n_qubits):
qubit_text.append(qubit_str.format(qubit_labels[num] if qubit_labels else num))
if qubit_labels is None:
qubit_labels = [str(ii) for ii in range(n_qubits)]
if n_qubits > 50:
if qubit_size is None:
qubit_size = 20
if font_size is None:
font_size = 9
fig.add_trace(go.Scatter(
x=[d[1] for d in grid_data],
y=[-d[0]-offset for d in grid_data],
mode="markers+text",
marker=go.scatter.Marker(size=qubit_size,
color=qubit_colors,
opacity=1),
text=qubit_labels if label_qubits else '',
textposition="middle center",
textfont=dict(size=font_size, color=font_color),
hoverinfo="text" if label_qubits else 'none',
hovertext=qubit_text))
fig.update_xaxes(visible=False)
_range = None
if offset:
_range = [-3.5, 0.5]
fig.update_yaxes(visible=False, range=_range)
fig.update_layout(showlegend=False,
plot_bgcolor=background_color,
paper_bgcolor=background_color,
width=figsize[0], height=figsize[1],
margin=dict(t=30, l=0, r=0, b=0))
if as_widget:
return PlotlyWidget(fig)
return PlotlyFigure(fig)