Esempio n. 1
0
def rshift(self, target):
    """Add a target backend to circuit.

    Parameters:
        target (BaseBackend): The target backend

    Returns:
        QuantumCircuit: QuantumCircuit with attached target_backend.

    Raises:
        KaleidoscopeError: Input is not a valid backend instance.
        KaleidoscopeError: Number of qubits larger than target backend.

    Example:

        .. jupyter-execute::

            from qiskit import QuantumCircuit
            import kaleidoscope.qiskit
            from kaleidoscope.qiskit.services import Simulators

            qc = QuantumCircuit(5, 5) >> Simulators.aer_vigo_simulator
            print(qc.target_backend)
    """
    if not isinstance(target, BaseBackend):
        raise KaleidoscopeError('Target is not a valid backend instance.')
    if self.num_qubits > target.configuration().num_qubits:
        raise KaleidoscopeError('Number of qubits larger than target backend.')
    self.target_backend = target  # pylint: disable=attribute-defined-outside-init
    return self
Esempio n. 2
0
 def __ne__(self, other):
     if (other is not None) and not isinstance(other, (bool, int)):
         raise KaleidoscopeError('Can only compare against boolean and int values.')
     if isinstance(other, int) and other not in [0, 1]:
         raise KaleidoscopeError('Integer comparison must be against 0 or 1.')
     out = [back for back in self._full_data if back.configuration().open_pulse != other]
     return BackendCollection(out)
Esempio n. 3
0
    def __call__(self, name=None):
        """Return all backends that satisfy the given criteria.

        If no criteria passed then returns all systems.

        Parameters:
            name (str or list): System name(s).

        Returns:
            IBMQBackend: A single backend instance if only one.
            BackendCollection: List of specified backends if more than one.

        Raises:
            KaleidoscopeError: No matching backends.
        """
        if name is not None:
            if not isinstance(name, list):
                out = [
                    back for back in self._default_added_backends
                    if back.name() == name
                ]
                if any(out):
                    return out[0]
                raise KaleidoscopeError('No matching backend name.')
            out = []
            for nm in name:
                out += [
                    back for back in self._default_added_backends
                    if back.name() == nm
                ]
            if any(out):
                return BackendCollection(out)
            raise KaleidoscopeError('No matching backend names.')
        return BackendCollection(self._default_added_backends)
Esempio n. 4
0
    def __ge__(self, other):
        if not isinstance(other, (str, datetime)):
            raise KaleidoscopeError('Equality can only be checked against a string or datetime')

        if isinstance(other, datetime):
            if other <= datetime.now():
                raise KaleidoscopeError('Datetime must be in the future.')
            tvals = (other, None)
        else:
            tvals = (time_intervals(other)[0], None)

        return self.get_reservations(tvals)
Esempio n. 5
0
def set_default_provider(self,
                         hub=None,
                         group=None,
                         project=None,
                         overwrite=False):
    """Set the default provider for IBM Q systems.

    Parameters:
        hub (str, AccountProvider): A hub name, or Qiskit provider instance
        group (str): A group name.
        project (str): A project name.
        overwrite (bool): Overwrite if already set.

    Raises:
        KaleidoscopeError: Input not a valid provider.
        KaleidoscopeError: Could not load kalrc.
        KaleidoscopeError: Default provider found and overwrite=False.
    """
    if isinstance(hub, AccountProvider):
        _temp = hub
        hub = _temp.credentials.hub
        group = _temp.credentials.group
        project = _temp.credentials.project
    else:
        pro = self.providers(hub, group, project)
        if not pro:
            raise KaleidoscopeError(
                'Input hub, group, and/or project not valid.')
        if len(pro) > 1:
            raise KaleidoscopeError('Inputs do not specify a unique provider.')
        pro = pro[0]
        hub = pro.credentials.hub
        group = pro.credentials.group
        project = pro.credentials.project

    provider_str = "//".join([hub, group, project])

    has_rc, rc_file = has_kal_rc()
    if not has_rc:
        raise KaleidoscopeError('Could not load kalrc.')

    if has_rc_key(rc_file, 'default_provider'):
        if not overwrite:
            raise KaleidoscopeError(
                'Default provider already set, use overwrite=True.')

    write_rc_key(rc_file, 'default_provider', provider_str)

    # Trigger a refresh of the Systems provider
    from kaleidoscope.qiskit.services import Systems  # pylint: disable=cyclic-import
    Systems._refresh()
Esempio n. 6
0
 def __le__(self, other):
     if not isinstance(other, int):
         raise KaleidoscopeError('Can only compare against ints')
     out = []
     for back in self:
         if hasattr(back.configuration(), 'quantum_volume'):
             qv_val = back.configuration().quantum_volume
             if qv_val and qv_val <= other:
                 out.append(back)
     return BackendCollection(out)
Esempio n. 7
0
    def __le__(self, other):
        if not isinstance(other, (str, datetime)):
            raise KaleidoscopeError('Equality can only be checked against a string or datetime')

        if isinstance(other, datetime):
            tvals = (None, other)
        else:
            tvals = (None, time_intervals(other)[1])

        return self.get_reservations(tvals)
Esempio n. 8
0
def get_default_provider(self):
    """Return the default provider, if any.

    Returns:
        str: Default provider.

    Raises:
        KaleidoscopeError: Could not load rcfile.
    """
    has_rc, rc_file = has_kal_rc()
    if not has_rc:
        raise KaleidoscopeError('Could not load kalrc.')
    return get_rc_key(rc_file, 'default_provider')
Esempio n. 9
0
def _bit_string_index(s):
    """Return the index of a string of 0s and 1s.

    Parameters:
        s (str): Bitstring.

    Returns:
        int: Index.

    Raises:
        KaleidoscopeError: If string is not binary.
    """
    n = len(s)
    k = s.count("1")
    if s.count("0") != n - k:
        raise KaleidoscopeError("s must be a string of 0 and 1")
    ones = [pos for pos, char in enumerate(s) if char == "1"]
    return _lex_index(n, k, ones)
Esempio n. 10
0
def _lex_index(n, k, lst):
    """Return  the lex index of a combination..

    Args:
        n (int): the total number of options .
        k (int): The number of elements.
        lst (list): list

    Returns:
        int: returns int index for lex order

    Raises:
        KaleidoscopeError: if length of list is not equal to k
    """
    if len(lst) != k:
        raise KaleidoscopeError("list should have length k")
    comb = list(map(lambda x: n - 1 - x, lst))
    dualm = sum([spsp.comb(comb[k - 1 - i], i + 1) for i in range(k)])
    return int(dualm)
Esempio n. 11
0
def get_rc_key(rc_file, key):
    """Get the desired key from an kal rc_file

    Parameters:
        rc_file (str): String specifying file location.
        key (str): The key name to be written.

    Returns:
        str: The key value.

    Raises:
        NoSectionError: rc_file missing kaleidoscope section.
        KaleidoscopeError: Key not found.
    """
    config = configparser.ConfigParser()
    config.read(rc_file)
    if not config.has_section('kaleidoscope'):
        raise configparser.NoSectionError('kaleidoscope')

    opts = config.options('kaleidoscope')
    if key not in opts:
        raise KaleidoscopeError('Key not found.')
    return config.get('kaleidoscope', key)
Esempio n. 12
0
def time_intervals(interval):
    """Computes the start and ending datetimes for a set of commonly used intervals.

    All times are converted into the local timezone by applying the UTC offset
    for the locality.

    Current allowed ``interval`` values are:

    - 'now'
    - 'today'
    - 'tomorrow'
    - 'this week'
    - 'next week'
    - 'this month'
    - 'next month'

    Parameters:
        interval (str): A string representing the human readable interval.

    Returns:
        tuple: Start and end datetimes for specified time interval.

    Raises:
        KaleidoscopeError: Input string does not correspond to a known time interval.
    """
    now = datetime.now(timezone.utc)
    week_day = datetime.today().weekday()
    days_in_month = calendar.monthrange(now.year, now.month)[1]
    # Get UTC offset in hours
    dd = now.astimezone()
    utc_offset = dd.utcoffset() // timedelta(hours=1)

    today_start = datetime(year=now.year,
                           month=now.month,
                           day=now.day,
                           hour=0,
                           minute=0,
                           second=0)

    today_end = datetime(year=now.year,
                         month=now.month,
                         day=now.day,
                         hour=23,
                         minute=59,
                         second=59)

    if interval == 'now':
        return now, now
    elif interval == 'today':
        return now, today_end - timedelta(hours=utc_offset)
    elif interval == 'tomorrow':
        start = today_end + timedelta(seconds=1)
        end = datetime(year=start.year,
                       month=start.month,
                       day=start.day,
                       hour=23,
                       minute=59,
                       second=59)
        return start - timedelta(hours=utc_offset), end - timedelta(
            hours=utc_offset)
    elif interval == 'this week':
        start = now
        end = today_end + timedelta(days=6 - week_day)
        return start, end - timedelta(hours=utc_offset)
    elif interval == 'next week':
        start = today_start - timedelta(days=week_day - 7)
        end = today_end + timedelta(days=13 - week_day)
        return start - timedelta(hours=utc_offset), end - timedelta(
            hours=utc_offset)
    elif interval == 'this month':
        start = now
        end = datetime(year=now.year,
                       month=now.month,
                       day=days_in_month,
                       hour=23,
                       minute=59,
                       second=59)
        return start, end - timedelta(hours=utc_offset)
    elif interval == 'next month':
        start = today_start + timedelta(days=days_in_month - now.day + 1)
        _days_in_month = calendar.monthrange(now.year, start.month)[1]
        end = datetime(year=start.year,
                       month=start.month,
                       day=_days_in_month,
                       hour=23,
                       minute=59,
                       second=59)
        return start - timedelta(hours=utc_offset), end - timedelta(
            hours=utc_offset)
    else:
        raise KaleidoscopeError(
            "Interval must be 'now', 'today', 'tomorrow', 'this week', \
                                'next week', 'this month', or 'next month'.")
Esempio n. 13
0
def qsphere(state,
            state_labels=True,
            state_labels_kind='bits',
            as_widget=False):
    """Plots a statevector of qubits using the qsphere
    representation.

    Parameters:
        state (ndarray): Statevector as 1D NumPy array.
        state_labels (bool): Show state labels.
        state_labels_kind (str): 'bits' (default) or 'ints'.
        as_widget (bool): Return a widget instance.

    Returns:
        PlotlyFigure or PlotlyWidget: Figure instance.

    Raises:
        KaleidoscopeError: Invalid statevector input.

    Example:

        .. jupyter-execute::

            from qiskit import QuantumCircuit
            from qiskit.quantum_info import Statevector
            import kaleidoscope.qiskit
            from kaleidoscope.interactive import qsphere

            qc = QuantumCircuit(3)
            qc.h(range(3))
            qc.ch(0,1)
            qc.s(2)
            qc.cz(2,1)
            state = qc.statevector()

            qsphere(state)
    """
    if state.__class__.__name__ in ['Statevector'] \
            and 'qiskit' in state.__class__.__module__:
        state = state.data

    if state.__class__.__name__ in ['DensityMatrix'] \
            and 'qiskit' in state.__class__.__module__:

        if not abs(1 - state.data.dot(state.data).trace().real) < 1e-6:
            raise KaleidoscopeError(
                'Input density matrix is not a pure state.')
        # pylint: disable=unexpected-keyword-arg
        _, evecs = la.eig(state.data)
        state = evecs[0].ravel()

    if len(state.shape) == 2:
        if not abs(1 - state.dot(state).trace().real) < 1e-6:
            raise KaleidoscopeError(
                'Input density matrix is not a pure state.')
        # pylint: disable=unexpected-keyword-arg
        _, evecs = la.eig(state.data)
        state = evecs[0].ravel()

    if len(state.shape) != 1:
        raise KaleidoscopeError('Input state is not 1D array.')

    if np.log2(state.shape[0]) % 1:
        raise KaleidoscopeError('Input is not a valid statevector of qubits.')

    eps = 1e-8
    norm = mpl.colors.Normalize(vmin=0, vmax=2 * np.pi)
    cmap = cc.cm.CET_C1s
    num_qubits = int(np.log2(state.shape[0]))

    xvals = []
    yvals = []
    zvals = []
    colors = []
    bases = []
    probs = []
    marker_sizes = []

    for idx in range(2**num_qubits):
        prob = (state[idx] * state[idx].conj()).real
        if prob > eps:
            elem = bin(idx)[2:].zfill(num_qubits)
            weight = elem.count("1")
            zvalue = -2 * weight / num_qubits + 1
            number_of_divisions = spsp.comb(num_qubits, weight)
            weight_order = _bit_string_index(elem)
            angle = (float(weight) / num_qubits) * (np.pi * 2) + \
                    (weight_order * 2 * (np.pi / number_of_divisions))

            if (weight > num_qubits / 2) or (
                ((weight == num_qubits / 2) and
                 (weight_order >= number_of_divisions / 2))):
                angle = np.pi - angle - (2 * np.pi / number_of_divisions)

            xvalue = np.sqrt(1 - zvalue**2) * np.cos(angle)
            yvalue = np.sqrt(1 - zvalue**2) * np.sin(angle)

            bases.append(elem)
            probs.append(prob)
            xvals.append(xvalue)
            yvals.append(yvalue)
            zvals.append(zvalue)

            phase = np.arctan2(state[idx].imag, state[idx].real)
            phase = phase if phase >= 0 else phase + 2 * np.pi
            colors.append(mpl.colors.rgb2hex(cmap(norm(phase))))
            marker_sizes.append(np.sqrt(prob) * 40)

    if state_labels_kind == 'ints':
        bases = [int(kk, 2) for kk in bases]

    # Output figure instance
    fig = make_subplots(rows=5,
                        cols=5,
                        specs=[[{
                            "type": "scene",
                            "rowspan": 5,
                            "colspan": 5
                        }, None, None, None, None],
                               [None, None, None, None, None],
                               [None, None, None, None, None],
                               [None, None, None, None, None],
                               [
                                   None, None, None, None, {
                                       "rowspan": 1,
                                       "colspan": 1,
                                       "type": "domain"
                                   }
                               ]])

    figsize = (350, 350)

    # List for vector annotations, if any
    fig_annotations = []

    fig.add_trace(BSPHERE(), row=1, col=1)

    # latitudes
    for kk in _qsphere_latitudes(zvals):
        fig.add_trace(kk, row=1, col=1)

    fig.add_trace(go.Scatter3d(
        x=[0],
        y=[0],
        z=[0],
        mode='markers',
        opacity=0.6,
        marker=dict(size=4, color='#555555'),
    ),
                  row=1,
                  col=1)

    for kk, _ in enumerate(xvals):
        fig.add_trace(go.Scatter3d(x=[0, xvals[kk]],
                                   y=[0, yvals[kk]],
                                   z=[0, zvals[kk]],
                                   mode="lines",
                                   hoverinfo=None,
                                   opacity=0.5,
                                   line=dict(color=colors[kk], width=3)),
                      row=1,
                      col=1)

        if state_labels:
            xanc = 'center'
            if xvals[kk] != 0:
                if xvals[kk] < 0:
                    xanc = 'right'
                else:
                    pass

            yanc = 'middle'
            if zvals[kk] != 0:
                if zvals[kk] < 0:
                    yanc = 'top'
                else:
                    yanc = 'bottom'

            fig_annotations.append(
                dict(
                    showarrow=False,
                    x=xvals[kk] * 1.1,
                    y=yvals[kk] * 1.1,
                    z=zvals[kk] * 1.1,
                    text="<b>|{}\u3009</b>".format(bases[kk]),
                    align='left',
                    opacity=0.7,
                    xanchor=xanc,
                    yanchor=yanc,
                    xshift=10,
                    bgcolor="#ffffff",
                    font=dict(
                        size=10,
                        color="#000000",
                    ),
                ))

    fig.add_trace(go.Scatter3d(
        x=xvals,
        y=yvals,
        z=zvals,
        mode='markers',
        opacity=1,
        marker=dict(size=marker_sizes, color=colors),
    ),
                  row=1,
                  col=1)

    slices = 128
    labels = [''] * slices
    values = [1] * slices

    phase_colors = [
        mpl.colors.rgb2hex(cmap(norm(2 * np.pi * kk / slices)))
        for kk in range(slices)
    ]

    fig.add_trace(go.Pie(labels=labels,
                         values=values,
                         hole=.6,
                         showlegend=False,
                         textinfo='none',
                         hoverinfo='none',
                         textposition="outside",
                         rotation=90,
                         textfont_size=12,
                         marker=dict(colors=phase_colors)),
                  row=5,
                  col=5)

    pie_x = fig.data[-1]['domain']['x']
    pie_y = fig.data[-1]['domain']['y']

    fig['layout'].update(annotations=[
        dict(
            xref='paper',
            yref='paper',
            x=(pie_x[1] - pie_x[0]) / 2 + pie_x[0],
            y=(pie_y[1] - pie_y[0]) / 2 + pie_y[0],
            text='Phase',
            xanchor="center",
            yanchor="middle",
            showarrow=False,
            font=dict(size=9),
        ),
        dict(
            xref='paper',
            yref='paper',
            x=pie_x[0] - 0.03,
            y=(pie_y[1] - pie_y[0]) / 2 + pie_y[0],
            text='\U0001D70B',
            xanchor="left",
            yanchor="middle",
            showarrow=False,
            font=dict(size=14),
        ),
        dict(
            xref='paper',
            yref='paper',
            x=pie_x[1] + 0.03,
            y=(pie_y[1] - pie_y[0]) / 2 + pie_y[0],
            text='0',
            xanchor="right",
            yanchor="middle",
            showarrow=False,
            font=dict(size=12),
        ),
        dict(
            xref='paper',
            yref='paper',
            x=(pie_x[1] - pie_x[0]) / 2 + pie_x[0],
            y=pie_y[1] + 0.05,
            text='\U0001D70B/2',
            xanchor="center",
            yanchor="top",
            showarrow=False,
            font=dict(size=12),
        ),
        dict(
            xref='paper',
            yref='paper',
            x=(pie_x[1] - pie_x[0]) / 2 + pie_x[0],
            y=pie_y[0] - 0.05,
            text='3\U0001D70B/2',
            xanchor="center",
            yanchor="bottom",
            showarrow=False,
            font=dict(size=12),
        )
    ])

    fig.update_layout(width=figsize[0],
                      height=figsize[1],
                      autosize=False,
                      hoverdistance=50,
                      showlegend=False,
                      scene_aspectmode='cube',
                      margin=dict(r=15, b=15, l=15, t=15),
                      scene=dict(annotations=fig_annotations,
                                 xaxis=dict(showbackground=False,
                                            range=[-1.2, 1.2],
                                            showspikes=False,
                                            visible=False),
                                 yaxis=dict(showbackground=False,
                                            range=[-1.2, 1.2],
                                            showspikes=False,
                                            visible=False),
                                 zaxis=dict(showbackground=False,
                                            range=[-1.2, 1.2],
                                            showspikes=False,
                                            visible=False)),
                      scene_camera=dict(eye=dict(x=0, y=-1.4, z=0.3)))

    if as_widget:
        return PlotlyWidget(fig)

    return PlotlyFigure(fig, modebar=True)
Esempio n. 14
0
 def __gt__(self, other):
     raise KaleidoscopeError('Not implimented')
Esempio n. 15
0
# -*- 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.
# pylint: disable=wrong-import-position

"""Qiskit specific functionality"""

from kaleidoscope import HAS_QISKIT
from kaleidoscope.errors import KaleidoscopeError

if not HAS_QISKIT:
    raise KaleidoscopeError('Must install qiskit-terra, qiskit-aer, and qiskit-ibmq-provider.')

import kaleidoscope.qiskit.overload
from .backends.mpl import *
from .backends.interactive import system_error_map
Esempio n. 16
0
def cnot_error_density(backends,
                       figsize=None,
                       colors=None,
                       offset=None,
                       scale='log',
                       covariance_factor=0.1,
                       xlim=None,
                       text_xval=None,
                       xticks=None):
    """Plot CNOT error distribution for one or more IBMQ backends.

    Parameters:
        backends (list or IBMQBackend or BackendProperties): A single or ist of IBMQBackend
                                                             instances or properties.
        figsize (tuple): Optional figure size in inches.
        colors (list): A list of Matplotlib compatible colors to plot with.
        offset (float): Positive offset for spacing out the backends.
        scale (str): 'linear' or 'log' scaling of x-axis.
        covariance_factor (float): Sets the width of the gaussian for each point.
        xlim (list or tuple): Optional lower and upper limits of cnot error values.
        text_xval (float): Optional xaxis value at which to start the backend text.
        xticks (list): Optional list of xaxis ticks to plot.

    Returns:
        Figure: A matplotlib Figure instance.

    Raises:
        KaleidoscopeError: A backend with < 2 qubits was passed.
        KaleidoscopeError: Number of colors did not match number of backends.

    Example:
        .. jupyter-execute::

            from qiskit import *
            from kaleidoscope.qiskit.backends import cnot_error_density
            provider = IBMQ.load_account()

            backends = []
            backends.append(provider.backends.ibmq_vigo)
            backends.append(provider.backends.ibmq_ourense)
            backends.append(provider.backends.ibmq_london)
            backends.append(provider.backends.ibmq_burlington)
            backends.append(provider.backends.ibmq_essex)

            cnot_error_density(backends)
    """

    if not isinstance(backends, list):
        backends = [backends]

    for idx, back in enumerate(backends):
        if isinstance(back, BackendProperties):
            backends[idx] = properties_to_pseudobackend(back)

    for back in backends:
        if back.configuration().n_qubits < 2:
            raise KaleidoscopeError('Number of backend qubits must be > 1')

    if scale not in ['linear', 'log']:
        raise KaleidoscopeError("scale must be 'linear' or 'log'.")

    # Attempt to autosize if figsize=None
    if figsize is None:
        if len(backends) > 1:
            fig = plt.figure(figsize=(12, len(backends) * 1.5))
        else:
            fig = plt.figure(figsize=(12, 2))
    else:
        fig = plt.figure(figsize=figsize)

    text_color = 'k'
    if offset is None:
        offset = 100 if len(backends) > 3 else 200
    offset = -offset
    if colors is None:
        colors = [DARK2[kk % 8] for kk in range(len(backends))]
    else:
        if len(colors) != len(backends):
            raise KaleidoscopeError(
                'Number of colors does not match number of backends.')

    cx_errors = []
    for idx, back in enumerate(backends):

        back_props = back.properties().to_dict()

        cx_errs = []
        meas_errs = []
        for gate in back_props['gates']:
            if len(gate['qubits']) == 2:
                # Ignore cx gates with values of 1.0
                if gate['parameters'][0]['value'] != 1.0:
                    cx_errs.append(gate['parameters'][0]['value'])

        for qubit in back_props['qubits']:
            for item in qubit:
                if item['name'] == 'readout_error':
                    meas_errs.append(item['value'])
        cx_errors.append(100 * np.asarray(cx_errs))

    max_cx_err = max([cerr.max() for cerr in cx_errors])
    min_cx_err = min([cerr.min() for cerr in cx_errors])

    if xlim is None:
        if scale == 'linear':
            xlim = [0, 1.5 * max_cx_err]
        else:
            xlim = [
                10**np.floor(np.log10(min_cx_err)),
                10**np.ceil(np.log10(max_cx_err))
            ]

    if text_xval is None:
        if scale == 'linear':
            text_xval = 0.8 * xlim[1]
        else:
            text_xval = 0.6 * xlim[1]
    for idx, back in enumerate(backends):
        cx_density = gaussian_kde(cx_errors[idx])
        xs = np.linspace(xlim[0], xlim[1], 2500)
        cx_density.covariance_factor = lambda: covariance_factor
        cx_density._compute_covariance()

        if scale == 'linear':
            plt.plot(xs,
                     100 * cx_density(xs) + offset * idx,
                     zorder=idx,
                     color=colors[idx])
        else:
            plt.semilogx(xs,
                         100 * cx_density(xs) + offset * idx,
                         zorder=idx,
                         color=colors[idx])
        plt.fill_between(xs,
                         offset * idx,
                         100 * cx_density(xs) + offset * idx,
                         zorder=idx,
                         color=colors[idx])

        qv_val = back.configuration().quantum_volume
        if qv_val:
            qv = "(QV" + str(qv_val) + ")"
        else:
            qv = ''

        bname = back.name().split('_')[-1].title() + " {}".format(qv)
        plt.text(text_xval,
                 offset * idx + 0.2 * (-offset),
                 bname,
                 fontsize=20,
                 color=colors[idx])

    fig.axes[0].get_yaxis().set_visible(False)
    # get rid of the frame
    for spine in plt.gca().spines.values():
        spine.set_visible(False)

    if xticks is None:
        if scale == 'linear':
            xticks = np.round(np.linspace(xlim[0], xlim[1], 4), 2)
    else:
        xticks = np.asarray(xticks)
    if xticks is not None:
        plt.xticks(np.floor(xticks), labels=np.floor(xticks), color=text_color)
    plt.xticks(fontsize=18)
    plt.xlim(xlim)
    plt.tick_params(axis='x', colors=text_color)
    plt.xlabel('Gate Error (%)', fontsize=18, color=text_color)
    plt.title('CNOT Error Distributions', fontsize=18, color=text_color)
    fig.tight_layout()

    if mpl.get_backend() in [
            'module://ipykernel.pylab.backend_inline', 'nbAgg'
    ]:
        plt.close(fig)
    return fig
Esempio n. 17
0
def probability_distribution(data,
                             figsize=(None, None),
                             colors=None,
                             scale='linear',
                             number_to_keep=None,
                             sort='asc',
                             target_string=None,
                             legend=None,
                             bar_labels=True,
                             state_labels_kind='bits',
                             state_labels=None,
                             title=None,
                             plot_background_color='#e5e0df',
                             background_color='#ffffff',
                             as_widget=False):
    """Interactive histogram plot of probability distributions.

    Parameters:
        data (list or dict): This is either a list of dictionaries or a single
            dict containing the values to represent (ex {'001': 130})
        figsize (tuple): Figure size in pixels.
        colors (list or str): String or list of strings for histogram bar colors.
        scale (str): Probability scale 'linear' (default) or 'log'.
        number_to_keep (int): The number of terms to plot and rest
            is made into a single bar called 'rest'.
        sort (string): Could be 'asc', 'desc', or 'hamming'.
        target_string (str): Target string if 'sort' is a distance measure.
        legend(list): A list of strings to use for labels of the data.
            The number of entries must match the length of data (if data is a
            list or 1 if it's a dict)
        bar_labels (bool): Label each bar in histogram with probability value.
        state_labels_kind (str): 'bits' (default) or 'ints'.
        state_labels (list): A list of custom state labels.
        title (str): A string to use for the plot title.
        plot_background_color (str): Set the background color behind histogram bars.
        background_color (str): Set the background color for axes.
        as_widget (bool): Return figure as an ipywidget.

    Returns:
        PlotlyFigure or PlotlyWidget:
            A figure for the rendered histogram.

    Raises:
        ValueError: When legend is provided and the length doesn't
                    match the input data.
        ImportError: When failed to load plotly.
        KaleidoscopeError: When state labels is not correct length.

    Example:
        .. jupyter-execute::

            from qiskit import *
            import kaleidoscope.qiskit
            from kaleidoscope.qiskit.services import Simulators
            from kaleidoscope.interactive import probability_distribution

            sim = Simulators.aer_vigo_simulator

            qc = QuantumCircuit(3, 3) >> sim
            qc.h(1)
            qc.cx(1,0)
            qc.cx(1,2)
            qc.measure(range(3), range(3))

            counts = qc.transpile().sample().result_when_done()
            probability_distribution(counts)
    """

    if sort not in VALID_SORTS:
        raise ValueError("Value of sort option, %s, isn't a "
                         "valid choice. Must be 'asc', "
                         "'desc', or 'hamming'")
    if sort in DIST_MEAS.keys() and target_string is None:
        err_msg = 'Must define target_string when using distance measure.'
        raise ValueError(err_msg)

    if isinstance(data, dict):
        data = [data]

    if legend and len(legend) != len(data):
        raise ValueError("Length of legendL (%s) doesn't match "
                         "number of input executions: %s" %
                         (len(legend), len(data)))

    text_color = find_text_color(background_color)

    labels = list(
        sorted(functools.reduce(lambda x, y: x.union(y.keys()), data, set())))
    if number_to_keep is not None:
        labels.append('rest')

    if sort in DIST_MEAS.keys():
        dist = []
        for item in labels:
            dist.append(DIST_MEAS[sort](item, target_string))

        labels = [
            list(x)
            for x in zip(*sorted(zip(dist, labels), key=lambda pair: pair[0]))
        ][1]
    # Set bar colors
    if colors is None:
        if len(data) == 1:
            colors = COLORS1
        elif len(data) == 2:
            colors = COLORS2
        elif len(data) == 3:
            colors = COLORS3
        elif len(data) == 4:
            colors = COLORS4
        elif len(data) == 5:
            colors = COLORS5
        else:
            colors = COLORS14
    elif isinstance(colors, str):
        colors = [colors]

    width = 1 / (len(data) + 1)  # the width of the bars

    labels_dict, all_pvalues, _ = _plot_histogram_data(data, labels,
                                                       number_to_keep)

    fig = go.Figure()
    for item, _ in enumerate(data):
        xvals = []
        yvals = []
        for idx, val in enumerate(all_pvalues[item]):
            xvals.append(idx + item * width)
            yvals.append(val)

        labels = list(labels_dict.keys())
        if state_labels_kind == 'ints':
            labels = [int(label, 2) for label in labels]
        if state_labels:
            if len(state_labels) != len(labels):
                raise KaleidoscopeError(
                    'Number of input state labels does not match data.')
            labels = state_labels

        hover_template = "<b>{x}</b><br>P = {y}"
        hover_text = [
            hover_template.format(x=labels[kk], y=np.round(yvals[kk], 3))
            for kk in range(len(yvals))
        ]

        fig.add_trace(
            go.Bar(x=xvals,
                   y=yvals,
                   width=width,
                   hoverinfo="text",
                   hovertext=hover_text,
                   marker_color=colors[item % len(colors)],
                   name=legend[item] if legend else '',
                   text=np.round(yvals, 3) if bar_labels else None,
                   textposition='auto'))

    xaxes_labels = list(labels_dict.keys())
    if state_labels_kind == 'ints':
        xaxes_labels = [int(label, 2) for label in xaxes_labels]

    if state_labels:
        if len(state_labels) != len(xaxes_labels):
            raise KaleidoscopeError(
                'Number of input state labels does not match data.')
        xaxes_labels = state_labels

    fig.update_xaxes(
        title='Basis state',
        titlefont_size=16,
        tickvals=list(range(len(labels_dict.keys()))),
        ticktext=xaxes_labels,
        tickfont_size=14,
        showline=True,
        linewidth=1,
        linecolor=text_color if text_color == 'white' else None,
    )

    fig.update_yaxes(
        title='Probability',
        titlefont_size=16,
        tickfont_size=14,
        showline=True,
        linewidth=1,
        linecolor=text_color if text_color == 'white' else None,
    )

    if scale == 'log':
        lower = np.min(
            [min(item.values()) / sum(item.values()) for item in data])
        lower = int(np.floor(np.log10(lower)))
        fig.update_yaxes(type="log", range=[lower, 0])
        fig.update_layout(yaxis=dict(
            tickmode='array',
            tickvals=[10**k for k in range(lower, 1)],
            ticktext=["10<sup>{}</sup>".format(k) for k in range(lower, 1)]))

    fig.update_layout(
        xaxis_tickangle=-70,
        showlegend=(legend is not None),
        width=figsize[0],
        height=figsize[1],
        plot_bgcolor=plot_background_color,
        paper_bgcolor=background_color,
        title=dict(text=title, x=0.5),
        title_font_size=18,
        font=dict(color=text_color),
    )
    if as_widget:
        return PlotlyWidget(fig)

    return PlotlyFigure(fig)
Esempio n. 18
0
 def __le__(self, other):
     if not isinstance(other, int):
         raise KaleidoscopeError('Can only compare against ints')
     out = [back for back in self if back.configuration().max_shots <= other]
     return BackendCollection(out)
Esempio n. 19
0
def bloch_sphere(vectors=None,
                 vectors_color=None,
                 vectors_alpha=None,
                 vectors_annotation=False,
                 points=None,
                 points_color=None,
                 points_alpha=None,
                 figsize=(350, 350),
                 label_fontsize=16,
                 annotation_fontsize=10,
                 as_widget=False):
    """Generates a Bloch sphere from a given collection of vector
    and/or points data expressed in cartesian coordinates, [x, y, z].

    Parameters:
        vectors (list, ndarray): Collection of one or more vectors to display.
        vectors_color (str or list): List of colors to use when plotting vectors.
        vectors_alpha (float or list): List of alphas to use when plotting vectors.
        vectors_annotation (bool or list): Boolean values to determine if a
                                           annotation should be displayed.
        points (list, ndarray): Collection of one or more points to display.
        points_color (str or list): List of colors to use when plotting points.
        points_alpha (float or list): List of alphas to use when plotting points.
        figsize (tuple): Figure size in pixels.
        label_fontsize (int): Font size for axes labels.
        annotation_fontsize (int): Font size for annotations.
        as_widget (bool): Return plot as a widget.

    Returns:
        PlotlyFigure or  PlotlyWidget: A Plotly figure or widget instance

    Raises:
        ValueError: Input lengths do not match.
        KaleidoscopeError: Invalid vector input.

    Example:
        .. jupyter-execute::

            import numpy as np
            from matplotlib.colors import LinearSegmentedColormap, rgb2hex
            from kaleidoscope.interactive import bloch_sphere

            cm = LinearSegmentedColormap.from_list('graypurple', ["#999999", "#AA00FF"])

            pointsx = [[0, -np.sin(th), np.cos(th)] for th in np.linspace(0, np.pi/2, 20)]
            pointsz = [[np.sin(th), -np.cos(th), 0] for th in np.linspace(0, 3*np.pi/4, 30)]

            points = pointsx + pointsz

            points_alpha = [np.linspace(0.8, 1, len(points))]

            points_color = [[rgb2hex(cm(kk)) for kk in np.linspace(-1,1,len(points))]]

            vectors_color = ["#777777", "#AA00FF"]

            bloch_sphere(points=points,
                         vectors=[[0, 0, 1], [1/np.sqrt(2), 1/np.sqrt(2), 0]],
                         vectors_color=vectors_color,
                         points_alpha=points_alpha,
                         points_color=points_color)
    """

    # Output figure instance
    fig = go.Figure()

    # List for vector annotations, if any
    fig_annotations = []

    idx = 0
    if points is not None:

        nest_depth = nest_level(points)
        # Take care of single point passed
        if nest_depth == 1:
            points = [[points]]
        # A single list of points passes
        elif nest_depth == 2:
            points = [points]
        # nest_depth = 3 means multiple lists passed

        if points_color is None:
            # passed a single point
            if nest_depth == 1:
                points_color = [DARK2[0]]
            elif nest_depth == 2:
                points_color = [[
                    DARK2[kk % 8] for kk in range(len(points[0]))
                ]]

            elif nest_depth == 3:
                points_color = []
                for kk, pnts in enumerate(points):
                    points_color.append(DARK2[kk % 8] * len(pnts))

        if nest_depth == 2 and nest_level(points_color) == 1:
            points_color = [points_color]

        if isinstance(points_color, str):
            points_color = [points_color]

        if points_alpha is None:
            points_alpha = [[1.0] * len(p) for p in points]

        if nest_depth == 2 and nest_level(points_alpha) == 1:
            points_alpha = [points_alpha]

        if isinstance(points_alpha, (int, float)):
            points_alpha = [[points_alpha]]

        for idx, point_collection in enumerate(points):
            x_pnts = []
            y_pnts = []
            z_pnts = []
            if isinstance(points_color[idx], str):
                _colors = [points_color[idx]] * len(point_collection)
            else:
                _colors = points_color[idx]

            if len(points_alpha[idx]) != len(point_collection):
                err_str = 'number of alpha values ({}) does not equal number of points ({})'
                raise ValueError(
                    err_str.format(len(points_alpha[idx]), len(x_pnts)))

            mcolors = []
            for kk, point in enumerate(point_collection):
                x_pnts.append(point[0])
                y_pnts.append(point[1])
                z_pnts.append(point[2])

                mcolors.append("rgba({},{},{},{})".format(
                    *hex_to_rgb(_colors[kk]), points_alpha[idx][kk]))

            fig.add_trace(
                go.Scatter3d(
                    x=x_pnts,
                    y=y_pnts,
                    z=z_pnts,
                    mode='markers',
                    marker=dict(size=7, color=mcolors),
                ))
            idx += 1

    if vectors is not None:

        if vectors.__class__.__name__ in ['Statevector'] \
                and 'qiskit' in vectors.__class__.__module__:
            vectors = bloch_components(vectors.data)

        elif not isinstance(vectors[0], (list, np.ndarray)):
            if vectors[0].__class__.__name__ not in ['Statevector']:
                vectors = [[vectors[0], vectors[1], vectors[2]]]

        new_vecs = []
        for vec in vectors:
            if vec.__class__.__name__ in [
                    'Statevector'
            ] and 'qiskit' in vec.__class__.__module__:
                # pylint: disable=no-member
                new_vecs.append(bloch_components(vec.data)[0])
            else:
                nst_lvl = nest_level(vec)
                if nst_lvl == 1:
                    new_vecs.append(vec)
                elif nst_lvl == 2:
                    new_vecs.append(vec[0])
                else:
                    raise KaleidoscopeError("Invalid vector input.")

        if vectors_color is None:
            vectors_color = [
                DARK2[kk + idx % 8] for kk in range(len(new_vecs))
            ]

        if isinstance(vectors_color, str):
            vectors_color = [vectors_color]

        if vectors_alpha is None:
            vectors_alpha = [1.0] * len(new_vecs)

        if isinstance(vectors_alpha, (int, float)):
            vectors_alpha = [vectors_alpha]

        if vectors_annotation is True:
            vectors_annotation = [True] * len(new_vecs)
        elif not vectors_annotation:
            vectors_annotation = [False] * len(new_vecs)

        eps = 1e-12

        for idx, vec in enumerate(new_vecs):
            vec = np.asarray(vec)
            if np.linalg.norm(vec) > 1.0 + eps:
                raise ValueError('Vector norm must be <= 1.')
            # So that line does not go out of arrow head
            vec_line = vec / 1.05

            color_str = "rgba({},{},{},{})".format(
                *hex_to_rgb(vectors_color[idx]), vectors_alpha[idx])

            fig.add_trace(
                go.Scatter3d(x=[0, vec_line[0]],
                             y=[0, vec_line[1]],
                             z=[0, vec_line[2]],
                             mode="lines",
                             hoverinfo=None,
                             line=dict(color=color_str, width=10)))

            fig.add_trace(
                go.Cone(x=[vec[0]],
                        y=[vec[1]],
                        z=[vec[2]],
                        u=[vec[0]],
                        v=[vec[1]],
                        w=[vec[2]],
                        sizemode="absolute",
                        showscale=False,
                        opacity=vectors_alpha[idx],
                        colorscale=[vectors_color[idx], vectors_color[idx]],
                        sizeref=0.25,
                        anchor="tip"))

            if vectors_annotation[idx]:
                fig_annotations.append(
                    dict(
                        showarrow=False,
                        x=vec[0] * 1.05,
                        y=vec[1] * 1.05,
                        z=vec[2] * 1.05,
                        text="[{},<br> {},<br> {}]".format(
                            round(vec[0], 3), round(vec[1], 3),
                            round(vec[2], 3)),
                        align='left',
                        borderpad=3,
                        xanchor='right' if vec[1] <= 0 else "left",
                        xshift=10,
                        bgcolor="#53565F",
                        font=dict(
                            size=annotation_fontsize,
                            color="#ffffff",
                            family="Courier New, monospace",
                        ),
                    ))
    # Start construction of sphere
    # Sphere
    fig.add_trace(BSPHERE())

    # latitudes
    for kk in LATS:
        fig.add_trace(kk)

    # longitudes
    for kk in LONGS:
        fig.add_trace(kk)

    # z-axis
    fig.add_trace(ZAXIS)
    # x-axis
    fig.add_trace(XAXIS)
    # y-axis
    fig.add_trace(YAXIS)

    # zaxis label
    fig.add_trace(Z0LABEL(fontsize=label_fontsize))
    fig.add_trace(Z1LABEL(fontsize=label_fontsize))
    # xaxis label
    fig.add_trace(XLABEL(fontsize=label_fontsize))
    # yaxis label
    fig.add_trace(YLABEL(fontsize=label_fontsize))

    fig.update_layout(width=figsize[0],
                      height=figsize[1],
                      autosize=False,
                      hoverdistance=50,
                      showlegend=False,
                      scene_aspectmode='cube',
                      margin=dict(r=0, b=0, l=0, t=0),
                      scene=dict(annotations=fig_annotations,
                                 xaxis=dict(showbackground=False,
                                            range=[-1.2, 1.2],
                                            showspikes=False,
                                            visible=False),
                                 yaxis=dict(showbackground=False,
                                            range=[-1.2, 1.2],
                                            showspikes=False,
                                            visible=False),
                                 zaxis=dict(showbackground=False,
                                            range=[-1.2, 1.2],
                                            showspikes=False,
                                            visible=False)),
                      scene_camera=dict(eye=dict(x=1.5, y=0.4, z=0.4)))
    if as_widget:
        return PlotlyWidget(fig)

    return PlotlyFigure(fig, modebar=True)
Esempio n. 20
0
from kaleidoscope.errors import KaleidoscopeError

# This is needed because version info is only generated
# at setup.  This should only fall back when not using
# setup.py lint or style to check.
try:
    from .version import version as __version__
except ImportError:
    __version__ = '0.0.0'

from kaleidoscope.interactive import *

try:
    from qiskit import QuantumCircuit
    from qiskit.providers.aer import Aer
    from qiskit.providers.ibmq import IBMQ
except ImportError:
    HAS_QISKIT = False
else:
    HAS_QISKIT = True

# Look for config file
has_rc, rc_file = config.has_kal_rc()
if not has_rc:
    config.generate_kal_rc()
    has_rc, rc_file = config.has_kal_rc()
    # Write open provider as default when generating new file.
    config.write_rc_key(rc_file, 'default_provider', 'ibm-q//open//main')
if not has_rc:
    raise KaleidoscopeError('Could not find or generate kalrc file.')
Esempio n. 21
0
def system_error_map(backend,
                     figsize=(800, 500),
                     show_title=True,
                     remove_badcal_edges=True,
                     background_color='white',
                     as_widget=False):
    """Plot the error map of a device.

    Args:
        backend (IBMQBackend or FakeBackend or DeviceSimulator or Properties): Plot the error map
                                                                               for a backend.
        figsize (tuple, optional): Figure size in pixels.
        show_title (bool, optional): Whether to show figure title.
        remove_badcal_edges (bool, optional): Whether to remove bad CX gate calibration data.
        background_color (str, optional): Background color, either 'white' or 'black'.
        as_widget (bool, optional): ``True`` if the figure is to be returned as a ``PlotlyWidget``.
            Otherwise the figure is to be returned as a ``PlotlyFigure``.

    Returns:
        PlotlyFigure or PlotlyWidget: The error map figure.

    Raises:
        KaleidoscopeError: Invalid input type.

    Example:
        .. jupyter-execute::

            from qiskit import *
            from kaleidoscope.qiskit.backends import system_error_map

            pro = IBMQ.load_account()
            backend = pro.backends.ibmq_vigo
            system_error_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)

    meas_text_color = '#000000'
    if background_color == 'white':
        color_map = CMAP
        text_color = '#000000'
        plotly_cmap = BMY_PLOTLY
    elif background_color == 'black':
        color_map = CMAP
        text_color = '#FFFFFF'
        plotly_cmap = BMY_PLOTLY
    else:
        raise KaleidoscopeError(
            '"{}" is not a valid background_color selection.'.format(
                background_color))

    if backend.configuration().simulator and not isinstance(
            backend, DeviceSimulator):
        raise KaleidoscopeError('Requires a device backend, not a simulator.')

    config = backend.configuration()
    n_qubits = config.n_qubits
    cmap = config.coupling_map

    if n_qubits in DEVICE_LAYOUTS.keys():
        grid_data = DEVICE_LAYOUTS[n_qubits]
    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=60, l=0, r=0, b=0))
        out = PlotlyWidget(fig)
        return out

    props = backend.properties().to_dict()

    t1s = []
    t2s = []
    for qubit_props in props['qubits']:
        count = 0
        for item in qubit_props:
            if item['name'] == 'T1':
                t1s.append(item['value'])
                count += 1
            elif item['name'] == 'T2':
                t2s.append(item['value'])
                count += 1
            if count == 2:
                break

    # U2 error rates
    single_gate_errors = [0] * n_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)
    max_1q_err = max(single_gate_errors)

    single_norm = mpl.colors.Normalize(vmin=min(single_gate_errors),
                                       vmax=max_1q_err)

    q_colors = [
        mpl.colors.rgb2hex(color_map(single_norm(err)))
        for err in single_gate_errors
    ]

    if n_qubits > 1:
        line_colors = []
        if cmap:
            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)

            # remove bad cx edges
            if remove_badcal_edges:
                cx_idx = np.where(cx_errors != 100.0)[0]
            else:
                cx_idx = np.arange(len(cx_errors))

            avg_cx_err = np.mean(cx_errors[cx_idx])

            cx_norm = mpl.colors.Normalize(vmin=min(cx_errors[cx_idx]),
                                           vmax=max(cx_errors[cx_idx]))

            for err in cx_errors:
                if err != 100.0 or not remove_badcal_edges:
                    line_colors.append(
                        mpl.colors.rgb2hex(color_map(cx_norm(err))))
                else:
                    line_colors.append("#ff0000")

    # Measurement errors
    read_err = []

    for qubit in range(n_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)

    if n_qubits < 10:
        num_left = n_qubits
        num_right = 0
    else:
        num_left = math.ceil(n_qubits / 2)
        num_right = n_qubits - num_left

    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)

    qubit_size = 32
    font_size = 14
    offset = 0
    if cmap:
        if y_max / max_dim < 0.33:
            qubit_size = 24
            font_size = 10
            offset = 1

    if n_qubits > 5:
        right_meas_title = "Readout Error (%)"
    else:
        right_meas_title = None

    if cmap:
        cx_title = "CNOT Error Rate [Avg. {}%]".format(np.round(avg_cx_err, 3))
    else:
        cx_title = None
    fig = make_subplots(
        rows=2,
        cols=11,
        row_heights=[0.95, 0.05],
        vertical_spacing=0.15,
        specs=[[{
            "colspan": 2
        }, None, {
            "colspan": 6
        }, None, None, None, None, None, {
            "colspan": 2
        }, None, None],
               [{
                   "colspan": 4
               }, None, None, None, None, None, {
                   "colspan": 4
               }, None, None, None, None]],
        subplot_titles=("Readout Error (%)", None, right_meas_title,
                        "Hadamard Error Rate [Avg. {}%]".format(
                            np.round(avg_1q_err, 3)), cx_title))

    # Add lines for couplings
    if cmap and n_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] + 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.append_trace(go.Scatter(
                x=[x_start, x_mid, x_end],
                y=[-y_start, -y_mid, -y_end],
                mode="lines",
                line=dict(width=6, color=line_colors[ind]),
                hoverinfo='text',
                hovertext='CX<sub>err</sub>{B}_{A} = {err} %'.format(
                    A=edge[0], B=edge[1], err=np.round(cx_errors[ind], 3))),
                             row=1,
                             col=3)

    # Add the qubits themselves
    qubit_text = []
    qubit_str = "<b>Qubit {}</b><br>H<sub>err</sub> = {} %"
    qubit_str += "<br>T1 = {} \u03BCs<br>T2 = {} \u03BCs"
    for kk in range(n_qubits):
        qubit_text.append(
            qubit_str.format(kk, np.round(single_gate_errors[kk], 3),
                             np.round(t1s[kk], 2), np.round(t2s[kk], 2)))

    if n_qubits > 20:
        qubit_size = 23
        font_size = 11

    if n_qubits > 50:
        qubit_size = 20
        font_size = 9

    qtext_color = []
    for ii in range(n_qubits):
        if single_gate_errors[ii] > 0.8 * max_1q_err:
            qtext_color.append('black')
        else:
            qtext_color.append('white')

    fig.append_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=q_colors,
                                                         opacity=1),
                                text=[str(ii) for ii in range(n_qubits)],
                                textposition="middle center",
                                textfont=dict(size=font_size,
                                              color=qtext_color),
                                hoverinfo="text",
                                hovertext=qubit_text),
                     row=1,
                     col=3)

    fig.update_xaxes(row=1, col=3, visible=False)
    _range = None
    if offset:
        _range = [-3.5, 0.5]
    fig.update_yaxes(row=1, col=3, visible=False, range=_range)

    # H error rate colorbar
    min_1q_err = min(single_gate_errors)
    max_1q_err = max(single_gate_errors)
    if n_qubits > 1:
        fig.append_trace(go.Heatmap(z=[
            np.linspace(min_1q_err, max_1q_err, 100),
            np.linspace(min_1q_err, max_1q_err, 100)
        ],
                                    colorscale=plotly_cmap,
                                    showscale=False,
                                    hoverinfo='none'),
                         row=2,
                         col=1)

        fig.update_yaxes(row=2, col=1, visible=False)

        fig.update_xaxes(row=2,
                         col=1,
                         tickvals=[0, 49, 99],
                         ticktext=[
                             np.round(min_1q_err, 3),
                             np.round(
                                 (max_1q_err - min_1q_err) / 2 + min_1q_err,
                                 3),
                             np.round(max_1q_err, 3)
                         ])

    # CX error rate colorbar
    if cmap and n_qubits > 1:
        min_cx_err = min(cx_errors)
        max_cx_err = max(cx_errors)
        fig.append_trace(go.Heatmap(z=[
            np.linspace(min_cx_err, max_cx_err, 100),
            np.linspace(min_cx_err, max_cx_err, 100)
        ],
                                    colorscale=plotly_cmap,
                                    showscale=False,
                                    hoverinfo='none'),
                         row=2,
                         col=7)

        fig.update_yaxes(row=2, col=7, visible=False)

        min_cx_idx_err = min(cx_errors[cx_idx])
        max_cx_idx_err = max(cx_errors[cx_idx])
        fig.update_xaxes(row=2,
                         col=7,
                         tickvals=[0, 49, 99],
                         ticktext=[
                             np.round(min_cx_idx_err, 3),
                             np.round((max_cx_idx_err - min_cx_idx_err) / 2 +
                                      min_cx_idx_err, 3),
                             np.round(max_cx_idx_err, 3)
                         ])

    hover_text = "<b>Qubit {}</b><br>M<sub>err</sub> = {} %"
    # Add the left side meas errors
    for kk in range(num_left - 1, -1, -1):
        fig.append_trace(go.Bar(
            x=[read_err[kk]],
            y=[kk],
            orientation='h',
            marker=dict(color='#c7c7c5'),
            hoverinfo="text",
            hoverlabel=dict(font=dict(color=meas_text_color)),
            hovertext=[hover_text.format(kk, np.round(read_err[kk], 3))]),
                         row=1,
                         col=1)

    fig.append_trace(go.Scatter(x=[avg_read_err, avg_read_err],
                                y=[-0.25, num_left - 1 + 0.25],
                                mode='lines',
                                hoverinfo='none',
                                line=dict(color=text_color,
                                          width=2,
                                          dash='dot')),
                     row=1,
                     col=1)

    fig.update_yaxes(row=1,
                     col=1,
                     tickvals=list(range(num_left)),
                     autorange="reversed")

    fig.update_xaxes(
        row=1,
        col=1,
        range=[0, 1.1 * max_read_err],
        tickvals=[0, np.round(avg_read_err, 2),
                  np.round(max_read_err, 2)],
        showline=True,
        linewidth=1,
        linecolor=text_color,
        tickcolor=text_color,
        ticks="outside",
        showgrid=False,
        zeroline=False)

    # Add the right side meas errors, if any
    if num_right:
        for kk in range(n_qubits - 1, num_left - 1, -1):
            fig.append_trace(go.Bar(
                x=[-read_err[kk]],
                y=[kk],
                orientation='h',
                marker=dict(color='#c7c7c5'),
                hoverinfo="text",
                hoverlabel=dict(font=dict(color=meas_text_color)),
                hovertext=[hover_text.format(kk, np.round(read_err[kk], 3))]),
                             row=1,
                             col=9)

        fig.append_trace(go.Scatter(x=[-avg_read_err, -avg_read_err],
                                    y=[num_left - 0.25, n_qubits - 1 + 0.25],
                                    mode='lines',
                                    hoverinfo='none',
                                    line=dict(color=text_color,
                                              width=2,
                                              dash='dot')),
                         row=1,
                         col=9)

        fig.update_yaxes(
            row=1,
            col=9,
            tickvals=list(range(n_qubits - 1, num_left - 1, -1)),
            side='right',
            autorange="reversed",
        )

        fig.update_xaxes(
            row=1,
            col=9,
            range=[-1.1 * max_read_err, 0],
            tickvals=[
                0, -np.round(avg_read_err, 2), -np.round(max_read_err, 2)
            ],
            ticktext=[0,
                      np.round(avg_read_err, 2),
                      np.round(max_read_err, 2)],
            showline=True,
            linewidth=1,
            linecolor=text_color,
            tickcolor=text_color,
            ticks="outside",
            showgrid=False,
            zeroline=False)

    # Makes the subplot titles smaller than the 16pt default
    for ann in fig['layout']['annotations']:
        ann['font'] = dict(size=13)

    title_text = "{} Error Map".format(backend.name()) if show_title else ''
    fig.update_layout(showlegend=False,
                      plot_bgcolor=background_color,
                      paper_bgcolor=background_color,
                      width=figsize[0],
                      height=figsize[1],
                      title=dict(text=title_text, x=0.452),
                      title_font_size=20,
                      font=dict(color=text_color),
                      margin=dict(t=60, l=0, r=40, b=0))
    if as_widget:
        return PlotlyWidget(fig)
    return PlotlyFigure(fig)
Esempio n. 22
0
def system_error_map(backend,
                     figsize=(None, None),
                     colormap=None,
                     background_color='white',
                     show_title=True,
                     remove_badcal_edges=True,
                     as_widget=False):
    """Plot the error map of a device.

    Args:
        backend (IBMQBackend or FakeBackend or DeviceSimulator or Properties): Plot the error map
                                                                               for a backend.
        figsize (tuple, optional): Figure size in pixels.
        colormap (Colormap): A matplotlib colormap.
        background_color (str, optional): Background color, either 'white' or 'black'.
        show_title (bool, optional): Whether to show figure title.
        remove_badcal_edges (bool, optional): Whether to remove bad CX gate calibration data.
        as_widget (bool, optional): ``True`` if the figure is to be returned as a ``PlotlyWidget``.
            Otherwise the figure is to be returned as a ``PlotlyFigure``.

    Returns:
        PlotlyFigure or PlotlyWidget: The error map figure.

    Raises:
        KaleidoscopeError: Invalid input type.

    Example:
        .. jupyter-execute::

            from qiskit import *
            from kaleidoscope.qiskit.backends import system_error_map

            pro = IBMQ.load_account()
            backend = pro.backends.ibmq_vigo
            system_error_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)

    CMAP = BMW
    PLOTLY_CMAP = cmap_to_plotly(CMAP)

    if colormap is not None:
        CMAP = colormap
        PLOTLY_CMAP = cmap_to_plotly(CMAP)

    meas_text_color = '#000000'
    if background_color == 'white':
        color_map = CMAP
        text_color = '#000000'
        plotly_cmap = PLOTLY_CMAP
    elif background_color == 'black':
        color_map = CMAP
        text_color = '#FFFFFF'
        plotly_cmap = PLOTLY_CMAP
    else:
        raise KaleidoscopeError(
            '"{}" is not a valid background_color selection.'.format(
                background_color))

    if backend.configuration().simulator and not isinstance(
            backend, DeviceSimulator):
        raise KaleidoscopeError('Requires a device backend, not a simulator.')

    config = backend.configuration()
    n_qubits = config.n_qubits
    cmap = config.coupling_map

    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=60, l=0, r=0, b=0))
        out = PlotlyWidget(fig)
        return out

    props = backend.properties()

    freqs = [0] * n_qubits
    t1s = [0] * n_qubits
    t2s = [0] * n_qubits
    alphas = [0] * n_qubits
    for idx, qubit_props in enumerate(props.qubits):
        for item in qubit_props:
            if item.name == 'frequency':
                freqs[idx] = item.value
            elif item.name == 'T1':
                t1s[idx] = item.value
            elif item.name == 'T2':
                t2s[idx] = item.value
            elif item.name == 'anharmonicity':
                alphas[idx] = item.value

    # U2 error rates
    single_gate_errors = [0] * n_qubits
    single_gate_times = [0] * n_qubits
    for gate in props.gates:
        if gate.gate in ['u2', 'sx']:
            _qubit = gate.qubits[0]
            for gpar in gate.parameters:
                if gpar.name == 'gate_error':
                    single_gate_errors[_qubit] = gpar.value
                elif gpar.name == 'gate_length':
                    single_gate_times[_qubit] = gpar.value

    # Convert to log10
    single_gate_errors = np.log10(np.asarray(single_gate_errors))

    avg_1q_err = np.mean(single_gate_errors)
    max_1q_err = _round_log10_exp(np.max(single_gate_errors),
                                  rnd='up',
                                  decimals=1)
    min_1q_err = _round_log10_exp(np.min(single_gate_errors),
                                  rnd='down',
                                  decimals=1)

    single_norm = mpl.colors.Normalize(vmin=min_1q_err, vmax=max_1q_err)

    q_colors = [
        mpl.colors.rgb2hex(color_map(single_norm(err)))
        for err in single_gate_errors
    ]

    if n_qubits > 1:
        line_colors = []
        if cmap:
            cx_errors = []
            cx_times = []
            for line in cmap:
                for gate in props.gates:
                    if gate.qubits == line:
                        for gpar in gate.parameters:
                            if gpar.name == 'gate_error':
                                cx_errors.append(gpar.value)
                            elif gpar.name == 'gate_length':
                                cx_times.append(gpar.value)

            # Convert to array
            cx_errors = np.log10(np.asarray(cx_errors))

            # remove bad cx edges
            if remove_badcal_edges:
                cx_idx = np.where(cx_errors != 0.0)[0]
            else:
                cx_idx = np.arange(len(cx_errors))

            avg_cx_err = np.mean(cx_errors[cx_idx])
            min_cx_err = _round_log10_exp(np.min(cx_errors[cx_idx]),
                                          rnd='down',
                                          decimals=1)
            max_cx_err = _round_log10_exp(np.max(cx_errors[cx_idx]),
                                          rnd='up',
                                          decimals=1)

            cx_norm = mpl.colors.Normalize(vmin=min_cx_err, vmax=max_cx_err)

            for err in cx_errors:
                if err != 0.0 or not remove_badcal_edges:
                    line_colors.append(
                        mpl.colors.rgb2hex(color_map(cx_norm(err))))
                else:
                    line_colors.append("#ff0000")

    # Measurement errors
    read_err = [0] * n_qubits
    p01_err = [0] * n_qubits
    p10_err = [0] * n_qubits
    for qubit in range(n_qubits):
        for item in props.qubits[qubit]:
            if item.name == 'readout_error':
                read_err[qubit] = item.value
            elif item.name == 'prob_meas0_prep1':
                p01_err[qubit] = item.value
            elif item.name == 'prob_meas1_prep0':
                p10_err[qubit] = item.value

    read_err = np.asarray(read_err)
    avg_read_err = np.mean(read_err)
    max_read_err = np.max(read_err)
    p01_err = np.asarray(p01_err)
    p10_err = np.asarray(p10_err)

    if n_qubits < 10:
        num_left = n_qubits
        num_right = 0
    else:
        num_left = math.ceil(n_qubits / 2)
        num_right = n_qubits - num_left

    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)

    qubit_size = 32
    font_size = 14
    offset = 0
    if cmap:
        if y_max / max_dim < 0.33:
            qubit_size = 24
            font_size = 10
            offset = 1

    if n_qubits > 5:
        right_meas_title = "Readout error"
    else:
        right_meas_title = None

    if cmap:
        cx_title = "CNOT error rate [Avg. {}]".format(
            '{:.2}\u22C510<sup>{}</sup>'.format(*_pow10_coeffs(avg_cx_err)))
    else:
        cx_title = None
    fig = make_subplots(
        rows=2,
        cols=11,
        row_heights=[0.95, 0.05],
        vertical_spacing=0.15,
        specs=[[{
            "colspan": 2
        }, None, {
            "colspan": 6
        }, None, None, None, None, None, {
            "colspan": 2
        }, None, None],
               [{
                   "colspan": 4
               }, None, None, None, None, None, {
                   "colspan": 4
               }, None, None, None, None]],
        subplot_titles=("Readout error", None, right_meas_title,
                        "SX error rate [Avg. {}]".format(
                            '{:.2}\u22C510<sup>{}</sup>'.format(
                                *_pow10_coeffs(avg_1q_err))), cx_title))

    # Add lines for couplings
    if cmap and n_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] + 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

            cx_str = 'cnot<sub>err</sub> = {err}'
            cx_str += '<br>&#120591;<sub>cx</sub>     = {tau} ns'
            fig.append_trace(go.Scatter(
                x=[x_start, x_mid, x_end],
                y=[-y_start, -y_mid, -y_end],
                mode="lines",
                line=dict(width=6, color=line_colors[ind]),
                hoverinfo='text',
                hovertext=cx_str.format(
                    err='{:.3}\u22C510<sup>{}</sup>'.format(
                        *_pow10_coeffs(cx_errors[ind])),
                    tau=np.round(cx_times[ind], 2))),
                             row=1,
                             col=3)

    # Add the qubits themselves
    qubit_text = []
    qubit_str = "<b>Qubit {idx}</b>"
    qubit_str += "<br>freq = {freq} GHz"
    qubit_str += "<br>T<sub>1</sub>   = {t1} \u03BCs"
    qubit_str += "<br>T<sub>2</sub>   = {t2} \u03BCs"
    qubit_str += "<br>&#945;    = {anh} GHz"
    qubit_str += "<br>sx<sub>err</sub> = {err}"
    qubit_str += "<br>&#120591;<sub>sx</sub>   = {tau} ns"
    for kk in range(n_qubits):
        qubit_text.append(
            qubit_str.format(
                idx=kk,
                freq=np.round(freqs[kk], 5),
                t1=np.round(t1s[kk], 2),
                t2=np.round(t2s[kk], 2),
                anh=np.round(alphas[kk], 3) if alphas[kk] else 'NA',
                err='{:.3}\u22C510<sup>{}</sup>'.format(
                    *_pow10_coeffs(single_gate_errors[kk])),
                tau=np.round(single_gate_times[kk], 2)))

    if n_qubits > 20:
        qubit_size = 23
        font_size = 11

    if n_qubits > 50:
        qubit_size = 20
        font_size = 9

    qtext_color = []
    for ii in range(n_qubits):
        qtext_color.append(find_text_color(q_colors[ii]))

    fig.append_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=q_colors,
                                                         opacity=1),
                                text=[str(ii) for ii in range(n_qubits)],
                                textposition="middle center",
                                textfont=dict(size=font_size,
                                              color=qtext_color),
                                hoverinfo="text",
                                hovertext=qubit_text),
                     row=1,
                     col=3)

    fig.update_xaxes(row=1, col=3, visible=False)
    _range = None
    if offset:
        _range = [-3.5, 0.5]
    fig.update_yaxes(row=1, col=3, visible=False, range=_range)

    # H error rate colorbar
    if n_qubits > 1:
        fig.append_trace(go.Heatmap(z=[
            np.linspace(min_1q_err, max_1q_err, 100),
            np.linspace(min_1q_err, max_1q_err, 100)
        ],
                                    colorscale=plotly_cmap,
                                    showscale=False,
                                    hoverinfo='none'),
                         row=2,
                         col=1)

        fig.update_yaxes(row=2, col=1, visible=False)

        mid_1q_err = _round_log10_exp(
            (max_1q_err - min_1q_err) / 2 + min_1q_err, rnd='up', decimals=1)

        fig.update_xaxes(row=2,
                         col=1,
                         tickfont=dict(size=13),
                         tickvals=[0, 49, 99],
                         ticktext=[
                             '{:.2}\u22C510<sup>{}</sup>'.format(
                                 *_pow10_coeffs(min_1q_err)),
                             '{:.2}\u22C510<sup>{}</sup>'.format(
                                 *_pow10_coeffs(mid_1q_err)),
                             '{:.2}\u22C510<sup>{}</sup>'.format(
                                 *_pow10_coeffs(max_1q_err)),
                         ])

    # CX error rate colorbar
    if cmap and n_qubits > 1:
        fig.append_trace(go.Heatmap(z=[
            np.linspace(min_cx_err, max_cx_err, 100),
            np.linspace(min_cx_err, max_cx_err, 100)
        ],
                                    colorscale=plotly_cmap,
                                    showscale=False,
                                    hoverinfo='none'),
                         row=2,
                         col=7)

        fig.update_yaxes(row=2, col=7, visible=False)

        mid_cx_err = (max_cx_err - min_cx_err) / 2 + min_cx_err
        fig.update_xaxes(
            row=2,
            col=7,
            tickfont=dict(size=13),
            tickvals=[0, 49, 99],
            ticktext=[
                '{:.2}\u22C510<sup>{}</sup>'.format(
                    *_pow10_coeffs(min_cx_err)),
                '{:.2}\u22C510<sup>{}</sup>'.format(
                    *_pow10_coeffs(mid_cx_err)),
                '{:.2}\u22C510<sup>{}</sup>'.format(*_pow10_coeffs(max_cx_err))
            ])

    hover_text = "<b>Qubit {idx}</b>"
    hover_text += "<br>M<sub>err</sub> = {err}"
    hover_text += "<br>P<sub>0|1</sub> = {p01}"
    hover_text += "<br>P<sub>1|0</sub> = {p10}"
    # Add the left side meas errors
    for kk in range(num_left - 1, -1, -1):
        fig.append_trace(go.Bar(
            x=[read_err[kk]],
            y=[kk],
            orientation='h',
            marker=dict(color='#c7c7c5'),
            hoverinfo="text",
            hoverlabel=dict(font=dict(color=meas_text_color)),
            hovertext=[
                hover_text.format(idx=kk,
                                  err=np.round(read_err[kk], 4),
                                  p01=np.round(p01_err[kk], 4),
                                  p10=np.round(p10_err[kk], 4))
            ]),
                         row=1,
                         col=1)

    fig.append_trace(go.Scatter(x=[avg_read_err, avg_read_err],
                                y=[-0.25, num_left - 1 + 0.25],
                                mode='lines',
                                hoverinfo='none',
                                line=dict(color=text_color,
                                          width=2,
                                          dash='dot')),
                     row=1,
                     col=1)

    fig.update_yaxes(row=1,
                     col=1,
                     tickvals=list(range(num_left)),
                     autorange="reversed")

    fig.update_xaxes(
        row=1,
        col=1,
        range=[0, 1.1 * max_read_err],
        tickvals=[0, np.round(avg_read_err, 2),
                  np.round(max_read_err, 2)],
        showline=True,
        linewidth=1,
        linecolor=text_color,
        tickcolor=text_color,
        ticks="outside",
        showgrid=False,
        zeroline=False)

    # Add the right side meas errors, if any
    if num_right:
        for kk in range(n_qubits - 1, num_left - 1, -1):
            fig.append_trace(go.Bar(
                x=[-read_err[kk]],
                y=[kk],
                orientation='h',
                marker=dict(color='#c7c7c5'),
                hoverinfo="text",
                hoverlabel=dict(font=dict(color=meas_text_color)),
                hovertext=[
                    hover_text.format(idx=kk,
                                      err=np.round(read_err[kk], 4),
                                      p01=np.round(p01_err[kk], 4),
                                      p10=np.round(p10_err[kk], 4))
                ]),
                             row=1,
                             col=9)

        fig.append_trace(go.Scatter(x=[-avg_read_err, -avg_read_err],
                                    y=[num_left - 0.25, n_qubits - 1 + 0.25],
                                    mode='lines',
                                    hoverinfo='none',
                                    line=dict(color=text_color,
                                              width=2,
                                              dash='dot')),
                         row=1,
                         col=9)

        fig.update_yaxes(
            row=1,
            col=9,
            tickvals=list(range(n_qubits - 1, num_left - 1, -1)),
            side='right',
            autorange="reversed",
        )

        fig.update_xaxes(
            row=1,
            col=9,
            range=[-1.1 * max_read_err, 0],
            tickvals=[
                0, -np.round(avg_read_err, 2), -np.round(max_read_err, 2)
            ],
            ticktext=[0,
                      np.round(avg_read_err, 2),
                      np.round(max_read_err, 2)],
            showline=True,
            linewidth=1,
            linecolor=text_color,
            tickcolor=text_color,
            ticks="outside",
            showgrid=False,
            zeroline=False)

    # Makes the subplot titles smaller than the 16pt default
    for ann in fig['layout']['annotations']:
        ann['font'] = dict(size=13)

    title_text = "{} error map".format(backend.name()) if show_title else ''
    fig.update_layout(showlegend=False,
                      plot_bgcolor=background_color,
                      paper_bgcolor=background_color,
                      width=figsize[0],
                      height=figsize[1],
                      title=dict(text=title_text, x=0.452),
                      title_font_size=20,
                      font=dict(color=text_color),
                      margin=dict(t=60, l=0, r=0, b=0),
                      hoverlabel=dict(font_size=14,
                                      font_family="courier,monospace",
                                      align='left'))
    if as_widget:
        return PlotlyWidget(fig)
    return PlotlyFigure(fig)
Esempio n. 23
0
    def __call__(self, name=None, hub=None, group=None, project=None):
        """Return all backends that satisfy the given criteria.

        If no criteria passed then returns all systems.

        Parameters:
            name (str or list): System name.
            hub (str or list): Specified hub.
            group (str or list): Specified group.
            project (str or list): Specified project.

        Returns:
            BackendCollection: List of specified backends.

        Raises:
            KaleidoscopeError: No matching backends.
        """
        filtered_backends = self._added_backends
        if name is not None:
            _temp = []
            if not isinstance(name, list):
                name = [name]
            for nm in name:
                _temp += [
                    back for back in self._added_backends
                    if back.name() == nm and back in filtered_backends
                ]
            filtered_backends = _temp

        if hub is not None:
            _temp = []
            if not isinstance(hub, list):
                hub = [hub]
            for hb in hub:
                _temp += [
                    back for back in self._added_backends
                    if back.hub == hb and back in filtered_backends
                ]
            filtered_backends = _temp

        if group is not None:
            _temp = []
            if not isinstance(group, list):
                group = [group]
            for gp in group:
                _temp += [
                    back for back in self._added_backends
                    if back.group == gp and back in filtered_backends
                ]
            filtered_backends = _temp

        if project is not None:
            _temp = []
            if not isinstance(project, list):
                project = [project]
            for pt in project:
                _temp += [
                    back for back in self._added_backends
                    if back.project == pt and back in filtered_backends
                ]
            filtered_backends = _temp

        if not any(filtered_backends):
            raise KaleidoscopeError('No matching systems found.')
        return BackendCollection(filtered_backends)
Esempio n. 24
0
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)