コード例 #1
0
def test_bloch_components():
    """Tests the Bloch components function"""

    # |0> state
    state = np.array([1, 0], dtype=complex)
    comp = bloch_components(state)[0]
    assert np.allclose(comp, [0, 0, 1])

    # |1> state
    state = np.array([0, 1], dtype=complex)
    comp = bloch_components(state)[0]
    assert np.allclose(comp, [0, 0, -1])

    # (|00> + |11>)/sqrt(2)
    state = np.array([1/np.sqrt(2), 0, 0, 1/np.sqrt(2)], dtype=complex)
    comp = bloch_components(state)
    assert np.allclose(comp[0], [0.0, 0.0, 0.0])
    assert np.allclose(comp[1], [0.0, 0.0, 0.0])
コード例 #2
0
def bloch_disc(rho, figsize=None, title=None, as_widget=False):
    """Plot a Bloch disc for a single qubit.

    Parameters:
        rho (list or ndarray or Statevector or DensityMatrix): Input statevector, density matrix,
                                                               or Bloch components.
        figsize (tuple): Figure size in pixels, default=(200,275).
        title (str): Plot title.
        as_widget (bool): Return plot as a widget.

    Returns:
        PlotlyFigure: A Plotly figure instance
        PlotlyWidget : A Plotly widget if `as_widget=True`.

    Example:
        .. jupyter-execute::

            import numpy as np
            from qiskit import *
            from qiskit.quantum_info import Statevector

            from kaleidoscope.interactive import bloch_disc
            qc = QuantumCircuit(1)
            qc.ry(np.pi*np.random.random(), 0)
            qc.rz(np.pi*np.random.random(), 0)

            state = Statevector.from_instruction(qc)
            bloch_disc(state)

    """
    # A hack so I do not have to import the actual instances from Qiskit.
    if rho.__class__.__name__ in ['Statevector', 'DensityMatrix'] \
            and 'qiskit' in rho.__class__.__module__:
        rho = rho.data
    if len(rho) != 3:
        rho = np.asarray(rho, dtype=complex)
        comp = bloch_components(rho)
    else:
        comp = [rho]

    if title:
        title = [title] + ["\u2329Z\u232A"]
    else:
        title = [""] + ["\u2329Z\u232A"]

    if figsize is None:
        figsize = (200, 275)

    fig = make_subplots(rows=1, cols=2,
                        specs=[[{'type': 'domain'}]+[{'type': 'xy'}]],
                        subplot_titles=title,
                        column_widths=[0.93]+[0.07])

    fig.add_trace(bloch_sunburst(comp[0]), row=1, col=1)

    zval = comp[0][2]
    zrange = [k*np.ones(1) for k in np.linspace(-1, 1, 100)]

    idx = (np.abs(np.linspace(-1, 1, 100) - zval)).argmin()

    tickvals = np.array([0, 49, 99, idx])
    idx_sort = np.argsort(tickvals)
    tickvals = tickvals[idx_sort]

    ticktext = [-1, 0, 1, "\u25C0"+str(np.round(zval, 3))]
    if zval <= -0.95:
        ticktext[0] = ''
    elif abs(zval) <= 0.05:
        ticktext[1] = ''
    elif zval >= 0.95:
        ticktext[2] = ''

    ticktext = [ticktext[kk] for kk in idx_sort]

    fig.append_trace(go.Heatmap(z=zrange,
                                colorscale=BMY_PLOTLY,
                                showscale=False,
                                hoverinfo='none',
                                ),
                     row=1, col=2
                     )

    fig.update_yaxes(row=1, col=2, tickvals=tickvals,
                     ticktext=ticktext)

    fig.update_yaxes(row=1, col=2, side="right")
    fig.update_xaxes(row=1, col=2, visible=False)

    fig.update_layout(margin=dict(t=30, l=10, r=0, b=0),
                      height=figsize[0],
                      width=figsize[1],
                      hoverlabel=dict(font_size=16,
                                      font_family="courier,monospace",
                                      align='left'
                                      )
                      )
    for ann in fig['layout']['annotations']:
        ann['font'] = dict(size=14)

    if as_widget:
        return PlotlyWidget(fig)

    return PlotlyFigure(fig)
コード例 #3
0
ファイル: bloch3d.py プロジェクト: JanLahmann/kaleidoscope
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)
コード例 #4
0
def bloch_multi_disc(rho, figsize=None, titles=True, as_widget=False):
    """Plot Bloch discs for a multi-qubit state.

    Parameters:
        rho (list or ndarray or Statevector or DensityMatrix): Input statevector, density matrix.
        figsize (tuple): Figure size in pixels, default=(125*num_qubits, 150).
        titles (bool): Display titles.
        as_widget (bool): Return plot as a widget.

    Returns:
        PlotlyFigure: A Plotly figure instance
        PlotlyWidget : A Plotly widget if `as_widget=True`.

    Example:
        .. jupyter-execute::

            import numpy as np
            from qiskit import *
            from qiskit.quantum_info import Statevector
            from kaleidoscope.interactive import bloch_multi_disc

            N = 4
            qc = QuantumCircuit(N)
            qc.h(range(N))
            for kk in range(N):
                qc.ry(2*np.pi*np.random.random(), kk)
            for kk in range(N-1):
                qc.cx(kk,kk+1)
            for kk in range(N):
                qc.rz(2*np.pi*np.random.random(), kk)

            state = Statevector.from_instruction(qc)
            bloch_multi_disc(state)
    """
    # A hack so I do not have to import the actual instances from Qiskit.
    if rho.__class__.__name__ in ['Statevector', 'DensityMatrix'] \
            and 'qiskit' in rho.__class__.__module__:
        rho = rho.data

    rho = np.asarray(rho, dtype=complex)

    comp = bloch_components(rho)
    num = int(np.log2(rho.shape[0]))

    nrows = 1
    ncols = num

    if figsize is None:
        figsize = (ncols*125, 150)

    if titles:
        titles = ["Qubit {}".format(k) for k in range(num)] + ["\u2329Z\u232A"]
    else:
        titles = ["" for k in range(num)] + ["\u2329Z\u232A"]

    fig = make_subplots(rows=nrows, cols=ncols+1,
                        specs=[[{'type': 'domain'}]*ncols+[{'type': 'xy'}]],
                        subplot_titles=titles,
                        column_widths=[0.95/num]*num+[0.05])

    for jj in range(num):
        fig.add_trace(bloch_sunburst(comp[jj]), row=1, col=jj+1)

    zrange = [k*np.ones(1) for k in np.linspace(-1, 1, 100)]
    fig.append_trace(go.Heatmap(z=zrange,
                                colorscale=BMY_PLOTLY,
                                showscale=False,
                                hoverinfo='none',
                                ),
                     row=1, col=num+1)

    fig.update_yaxes(row=1, col=num+1, tickvals=[0, 49, 99],
                     ticktext=[-1, 0, 1])
    fig.update_yaxes(row=1, col=num+1, side="right")
    fig.update_xaxes(row=1, col=num+1, visible=False)

    fig.update_layout(margin=dict(t=50, l=0, r=15, b=30),
                      width=figsize[0],
                      height=figsize[1],
                      hoverlabel=dict(font_size=14,
                                      font_family="monospace",
                                      align='left'
                                      )
                      )
    # Makes the subplot titles smaller than the 16pt default
    for ann in fig['layout']['annotations']:
        ann['font'] = dict(size=16)

    if as_widget:
        return PlotlyWidget(fig)
    return PlotlyFigure(fig)