def plot_bloch_vector(bloch, title="", ax=None, figsize=None):
    """Plot the Bloch sphere.

    Plot a sphere, axes, the Bloch vector, and its projections onto each axis.

    Args:
        bloch (list[double]): array of three elements where [<x>, <y>, <z>]
        title (str): a string that represents the plot title
        ax (matplotlib.Axes): An Axes to use for rendering the bloch sphere
        figsize (tuple): Figure size in inches. Has no effect is passing `ax`.

    Returns:
        Figure: A matplotlib figure instance if `ax = None`.

    Raises:
        ImportError: Requires matplotlib.
    """
    if not HAS_MATPLOTLIB:
        raise ImportError('Must have Matplotlib installed.')
    if figsize is None:
        figsize = (5, 5)
    B = Bloch(axes=ax)
    B.add_vectors(bloch)
    B.render(title=title)
    if ax is None:
        fig = B.fig
        fig.set_size_inches(figsize[0], figsize[1])
        plt.close(fig)
        return fig
    return None
Example #2
0
def plot_bloch_vector(bloch, title="", ax=None, figsize=None, coord_type="cartesian"):
    """Plot the Bloch sphere.

    Plot a sphere, axes, the Bloch vector, and its projections onto each axis.

    Args:
        bloch (list[double]): array of three elements where [<x>, <y>, <z>] (Cartesian)
            or [<r>, <theta>, <phi>] (spherical in radians)
            <theta> is inclination angle from +z direction
            <phi> is azimuth from +x direction
        title (str): a string that represents the plot title
        ax (matplotlib.axes.Axes): An Axes to use for rendering the bloch
            sphere
        figsize (tuple): Figure size in inches. Has no effect is passing ``ax``.
        coord_type (str): a string that specifies coordinate type for bloch
            (Cartesian or spherical), default is Cartesian

    Returns:
        Figure: A matplotlib figure instance if ``ax = None``.

    Raises:
        MissingOptionalLibraryError: Requires matplotlib.

    Example:
        .. jupyter-execute::

           from qiskit.visualization import plot_bloch_vector
           %matplotlib inline

           plot_bloch_vector([0,1,0], title="New Bloch Sphere")
    """
    if not HAS_MATPLOTLIB:
        raise MissingOptionalLibraryError(
            libname="Matplotlib",
            name="plot_bloch_vector",
            pip_install="pip install matplotlib",
        )
    from qiskit.visualization.bloch import Bloch
    from matplotlib import get_backend
    from matplotlib import pyplot as plt

    if figsize is None:
        figsize = (5, 5)
    B = Bloch(axes=ax)
    if coord_type == "spherical":
        r, theta, phi = bloch[0], bloch[1], bloch[2]
        bloch[0] = r * np.sin(theta) * np.cos(phi)
        bloch[1] = r * np.sin(theta) * np.sin(phi)
        bloch[2] = r * np.cos(theta)
    B.add_vectors(bloch)
    B.render(title=title)
    if ax is None:
        fig = B.fig
        fig.set_size_inches(figsize[0], figsize[1])
        if get_backend() in ["module://ipykernel.pylab.backend_inline", "nbAgg"]:
            plt.close(fig)
        return fig
    return None
Example #3
0
def plot_bloch_sphere(bloch_vectors):
    """Given a list of Bloch vectors, plot them on the Bloch sphere

    Args:
        bloch_vectors (list): list of bloch vectors
    """
    sphere = Bloch()
    sphere.add_points(np.transpose(bloch_vectors))
    sphere.show()
Example #4
0
def plot_bloch_vector(bloch, title="", ax=None, figsize=None):
    """Plot the Bloch sphere.

    Plot a sphere, axes, the Bloch vector, and its projections onto each axis.

    Args:
        bloch (list[double]): array of three elements where [<x>, <y>, <z>]
        title (str): a string that represents the plot title
        ax (matplotlib.axes.Axes): An Axes to use for rendering the bloch
            sphere
        figsize (tuple): Figure size in inches. Has no effect is passing ``ax``.

    Returns:
        Figure: A matplotlib figure instance if ``ax = None``.

    Raises:
        ImportError: Requires matplotlib.

    Example:
        .. jupyter-execute::

           from qiskit.visualization import plot_bloch_vector
           %matplotlib inline

           plot_bloch_vector([0,1,0], title="New Bloch Sphere")
    """
    if not HAS_MATPLOTLIB:
        raise ImportError('Must have Matplotlib installed. To install, run '
                          '"pip install matplotlib".')
    if figsize is None:
        figsize = (5, 5)
    B = Bloch(axes=ax)
    B.add_vectors(bloch)
    B.render(title=title)
    if ax is None:
        fig = B.fig
        fig.set_size_inches(figsize[0], figsize[1])
        if get_backend() in [
                'module://ipykernel.pylab.backend_inline', 'nbAgg'
        ]:
            plt.close(fig)
        return fig
    return None
def visualize_transition(circuit, trace=False, saveas=None, fpg=100, spg=2):
    """
    Creates animation showing transitions between states of a single
    qubit by applying quantum gates.

    Args:
        circuit (QuantumCircuit): Qiskit single-qubit QuantumCircuit. Gates supported are
            h,x, y, z, rx, ry, rz, s, sdg, t, tdg and u1.
        trace (bool): Controls whether to display tracing vectors - history of 10 past vectors
            at each step of the animation.
        saveas (str): User can choose to save the animation as a video to their filesystem.
            This argument is a string of path with filename and extension (e.g. "movie.mp4" to
            save the video in current working directory).
        fpg (int): Frames per gate. Finer control over animation smoothness and computiational
            needs to render the animation. Works well for tkinter GUI as it is, for jupyter GUI
            it might be preferable to choose fpg between 5-30.
        spg (int): Seconds per gate. How many seconds should animation of individual gate
            transitions take.

    Returns:
        IPython.core.display.HTML:
            If arg jupyter is set to True. Otherwise opens tkinter GUI and returns
            after the GUI is closed.

    Raises:
        ImportError: Must have Matplotlib (and/or IPython) installed.
        VisualizationError: Given gate(s) are not supported.

    """
    try:
        from IPython.display import HTML
        has_ipython = True
    except ImportError:
        has_ipython = False

    try:
        import matplotlib
        from matplotlib import pyplot as plt
        from matplotlib import animation
        from mpl_toolkits.mplot3d import Axes3D
        from qiskit.visualization.bloch import Bloch
        from qiskit.visualization.exceptions import VisualizationError
        has_matplotlib = True
    except ImportError:
        has_matplotlib = False

    jupyter = False
    if ('ipykernel' in sys.modules) and ('spyder' not in sys.modules):
        jupyter = True

    if not has_matplotlib:
        raise ImportError("Must have Matplotlib installed.")
    if not has_ipython and jupyter is True:
        raise ImportError("Must have IPython installed.")
    if len(circuit.qubits) != 1:
        raise VisualizationError("Only one qubit circuits are supported")

    frames_per_gate = fpg
    time_between_frames = (spg * 1000) / fpg

    # quaternions of gates which don't take parameters
    gates = dict()
    gates['x'] = ('x',
                  _Quaternion.from_axisangle(np.pi / frames_per_gate,
                                             [1, 0, 0]), '#1abc9c')
    gates['y'] = ('y',
                  _Quaternion.from_axisangle(np.pi / frames_per_gate,
                                             [0, 1, 0]), '#2ecc71')
    gates['z'] = ('z',
                  _Quaternion.from_axisangle(np.pi / frames_per_gate,
                                             [0, 0, 1]), '#3498db')
    gates['s'] = ('s',
                  _Quaternion.from_axisangle(np.pi / 2 / frames_per_gate,
                                             [0, 0, 1]), '#9b59b6')
    gates['sdg'] = ('sdg',
                    _Quaternion.from_axisangle(-np.pi / 2 / frames_per_gate,
                                               [0, 0, 1]), '#8e44ad')
    gates['h'] = ('h',
                  _Quaternion.from_axisangle(np.pi / frames_per_gate,
                                             _normalize([1, 0, 1])), '#34495e')
    gates['t'] = ('t',
                  _Quaternion.from_axisangle(np.pi / 4 / frames_per_gate,
                                             [0, 0, 1]), '#e74c3c')
    gates['tdg'] = ('tdg',
                    _Quaternion.from_axisangle(-np.pi / 4 / frames_per_gate,
                                               [0, 0, 1]), '#c0392b')

    implemented_gates = [
        'h', 'x', 'y', 'z', 'rx', 'ry', 'rz', 's', 'sdg', 't', 'tdg', 'u1'
    ]
    simple_gates = ['h', 'x', 'y', 'z', 's', 'sdg', 't', 'tdg']
    list_of_circuit_gates = []

    for gate in circuit._data:
        if gate[0].name not in implemented_gates:
            raise VisualizationError("Gate {} is not supported".format(
                gate[0].name))
        if gate[0].name in simple_gates:
            list_of_circuit_gates.append(gates[gate[0].name])
        else:
            theta = gate[0].params[0]
            rad = np.deg2rad(theta)
            if gate[0].name == 'rx':
                quaternion = _Quaternion.from_axisangle(
                    rad / frames_per_gate, [1, 0, 0])
                list_of_circuit_gates.append(
                    ('rx:' + str(theta), quaternion, '#16a085'))
            elif gate[0].name == 'ry':
                quaternion = _Quaternion.from_axisangle(
                    rad / frames_per_gate, [0, 1, 0])
                list_of_circuit_gates.append(
                    ('ry:' + str(theta), quaternion, '#27ae60'))
            elif gate[0].name == 'rz':
                quaternion = _Quaternion.from_axisangle(
                    rad / frames_per_gate, [0, 0, 1])
                list_of_circuit_gates.append(
                    ('rz:' + str(theta), quaternion, '#2980b9'))
            elif gate[0].name == 'u1':
                quaternion = _Quaternion.from_axisangle(
                    rad / frames_per_gate, [0, 0, 1])
                list_of_circuit_gates.append(
                    ('u1:' + str(theta), quaternion, '#f1c40f'))

    if len(list_of_circuit_gates) == 0:
        raise VisualizationError("Nothing to visualize.")

    starting_pos = _normalize(np.array([0, 0, 1]))

    fig = plt.figure(figsize=(5, 5))
    _ax = Axes3D(fig)
    _ax.set_xlim(-10, 10)
    _ax.set_ylim(-10, 10)
    sphere = Bloch(axes=_ax)

    class Namespace:
        """Helper class serving as scope container"""
        def __init__(self):
            self.new_vec = []
            self.last_gate = -2
            self.colors = []
            self.pnts = []

    namespace = Namespace()
    namespace.new_vec = starting_pos

    def animate(i):
        sphere.clear()

        # starting gate count from -1 which is the initial vector
        gate_counter = (i - 1) // frames_per_gate
        if gate_counter != namespace.last_gate:
            namespace.pnts.append([[], [], []])
            namespace.colors.append(list_of_circuit_gates[gate_counter][2])

        # starts with default vector [0,0,1]
        if i == 0:
            sphere.add_vectors(namespace.new_vec)
            namespace.pnts[0][0].append(namespace.new_vec[0])
            namespace.pnts[0][1].append(namespace.new_vec[1])
            namespace.pnts[0][2].append(namespace.new_vec[2])
            namespace.colors[0] = 'r'
            sphere.make_sphere()
            return _ax

        namespace.new_vec = list_of_circuit_gates[gate_counter][
            1] * namespace.new_vec

        namespace.pnts[gate_counter + 1][0].append(namespace.new_vec[0])
        namespace.pnts[gate_counter + 1][1].append(namespace.new_vec[1])
        namespace.pnts[gate_counter + 1][2].append(namespace.new_vec[2])

        sphere.add_vectors(namespace.new_vec)
        if trace:
            # sphere.add_vectors(namespace.points)
            for point_set in namespace.pnts:
                sphere.add_points([point_set[0], point_set[1], point_set[2]])

        sphere.vector_color = [list_of_circuit_gates[gate_counter][2]]
        sphere.point_color = namespace.colors
        sphere.point_marker = 'o'

        annotation_text = list_of_circuit_gates[gate_counter][0]
        annotationvector = [1.4, -0.45, 1.7]
        sphere.add_annotation(annotationvector,
                              annotation_text,
                              color=list_of_circuit_gates[gate_counter][2],
                              fontsize=30,
                              horizontalalignment='left')

        sphere.make_sphere()

        namespace.last_gate = gate_counter
        return _ax

    def init():
        sphere.vector_color = ['r']
        return _ax

    ani = animation.FuncAnimation(
        fig,
        animate,
        range(frames_per_gate * len(list_of_circuit_gates) + 1),
        init_func=init,
        blit=False,
        repeat=False,
        interval=time_between_frames)

    if saveas:
        ani.save(saveas, fps=30)
    if jupyter:
        # This is necessary to overcome matplotlib memory limit
        matplotlib.rcParams['animation.embed_limit'] = 50
        return HTML(ani.to_jshtml())
    plt.show()
    plt.close(fig)
    return None
Example #6
0
def visualize_transition(circuit, trace=False, saveas=None, fpg=100, spg=2):
    """
    Creates animation showing transitions between states of a single
    qubit by applying quantum gates.

    Args:
        circuit (QuantumCircuit): Qiskit single-qubit QuantumCircuit. Gates supported are
            h,x, y, z, rx, ry, rz, s, sdg, t, tdg and u1.
        trace (bool): Controls whether to display tracing vectors - history of 10 past vectors
            at each step of the animation.
        saveas (str): User can choose to save the animation as a video to their filesystem.
            This argument is a string of path with filename and extension (e.g. "movie.mp4" to
            save the video in current working directory).
        fpg (int): Frames per gate. Finer control over animation smoothness and computational
            needs to render the animation. Works well for tkinter GUI as it is, for jupyter GUI
            it might be preferable to choose fpg between 5-30.
        spg (int): Seconds per gate. How many seconds should animation of individual gate
            transitions take.

    Returns:
        IPython.core.display.HTML:
            If arg jupyter is set to True. Otherwise opens tkinter GUI and returns
            after the GUI is closed.

    Raises:
        MissingOptionalLibraryError: Must have Matplotlib (and/or IPython) installed.
        VisualizationError: Given gate(s) are not supported.

    """
    try:
        from IPython.display import HTML

        has_ipython = True
    except ImportError:
        has_ipython = False

    try:
        import matplotlib
        from matplotlib import pyplot as plt
        from matplotlib import animation
        from mpl_toolkits.mplot3d import Axes3D
        from qiskit.visualization.bloch import Bloch
        from qiskit.visualization.exceptions import VisualizationError

        has_matplotlib = True
    except ImportError:
        has_matplotlib = False

    jupyter = False
    if ("ipykernel" in sys.modules) and ("spyder" not in sys.modules):
        jupyter = True

    if not has_matplotlib:
        raise MissingOptionalLibraryError(
            libname="Matplotlib",
            name="visualize_transition",
            pip_install="pip install matplotlib",
        )
    if not has_ipython and jupyter is True:
        raise MissingOptionalLibraryError(
            libname="IPython",
            name="visualize_transition",
            pip_install="pip install ipython",
        )
    if len(circuit.qubits) != 1:
        raise VisualizationError("Only one qubit circuits are supported")

    frames_per_gate = fpg
    time_between_frames = (spg * 1000) / fpg

    # quaternions of gates which don't take parameters
    gates = {}
    gates["x"] = ("x", _Quaternion.from_axisangle(np.pi / frames_per_gate, [1, 0, 0]), "#1abc9c")
    gates["y"] = ("y", _Quaternion.from_axisangle(np.pi / frames_per_gate, [0, 1, 0]), "#2ecc71")
    gates["z"] = ("z", _Quaternion.from_axisangle(np.pi / frames_per_gate, [0, 0, 1]), "#3498db")
    gates["s"] = (
        "s",
        _Quaternion.from_axisangle(np.pi / 2 / frames_per_gate, [0, 0, 1]),
        "#9b59b6",
    )
    gates["sdg"] = (
        "sdg",
        _Quaternion.from_axisangle(-np.pi / 2 / frames_per_gate, [0, 0, 1]),
        "#8e44ad",
    )
    gates["h"] = (
        "h",
        _Quaternion.from_axisangle(np.pi / frames_per_gate, _normalize([1, 0, 1])),
        "#34495e",
    )
    gates["t"] = (
        "t",
        _Quaternion.from_axisangle(np.pi / 4 / frames_per_gate, [0, 0, 1]),
        "#e74c3c",
    )
    gates["tdg"] = (
        "tdg",
        _Quaternion.from_axisangle(-np.pi / 4 / frames_per_gate, [0, 0, 1]),
        "#c0392b",
    )

    implemented_gates = ["h", "x", "y", "z", "rx", "ry", "rz", "s", "sdg", "t", "tdg", "u1"]
    simple_gates = ["h", "x", "y", "z", "s", "sdg", "t", "tdg"]
    list_of_circuit_gates = []

    for gate in circuit._data:
        if gate[0].name not in implemented_gates:
            raise VisualizationError(f"Gate {gate[0].name} is not supported")
        if gate[0].name in simple_gates:
            list_of_circuit_gates.append(gates[gate[0].name])
        else:
            theta = gate[0].params[0]
            if gate[0].name == "rx":
                quaternion = _Quaternion.from_axisangle(theta / frames_per_gate, [1, 0, 0])
                list_of_circuit_gates.append(("rx:" + str(theta), quaternion, "#16a085"))
            elif gate[0].name == "ry":
                quaternion = _Quaternion.from_axisangle(theta / frames_per_gate, [0, 1, 0])
                list_of_circuit_gates.append(("ry:" + str(theta), quaternion, "#27ae60"))
            elif gate[0].name == "rz":
                quaternion = _Quaternion.from_axisangle(theta / frames_per_gate, [0, 0, 1])
                list_of_circuit_gates.append(("rz:" + str(theta), quaternion, "#2980b9"))
            elif gate[0].name == "u1":
                quaternion = _Quaternion.from_axisangle(theta / frames_per_gate, [0, 0, 1])
                list_of_circuit_gates.append(("u1:" + str(theta), quaternion, "#f1c40f"))

    if len(list_of_circuit_gates) == 0:
        raise VisualizationError("Nothing to visualize.")

    starting_pos = _normalize(np.array([0, 0, 1]))

    fig = plt.figure(figsize=(5, 5))
    if tuple(int(x) for x in matplotlib.__version__.split(".")) >= (3, 4, 0):
        _ax = Axes3D(fig, auto_add_to_figure=False)
        fig.add_axes(_ax)
    else:
        _ax = Axes3D(fig)

    _ax.set_xlim(-10, 10)
    _ax.set_ylim(-10, 10)
    sphere = Bloch(axes=_ax)

    class Namespace:
        """Helper class serving as scope container"""

        def __init__(self):
            self.new_vec = []
            self.last_gate = -2
            self.colors = []
            self.pnts = []

    namespace = Namespace()
    namespace.new_vec = starting_pos

    def animate(i):
        sphere.clear()

        # starting gate count from -1 which is the initial vector
        gate_counter = (i - 1) // frames_per_gate
        if gate_counter != namespace.last_gate:
            namespace.pnts.append([[], [], []])
            namespace.colors.append(list_of_circuit_gates[gate_counter][2])

        # starts with default vector [0,0,1]
        if i == 0:
            sphere.add_vectors(namespace.new_vec)
            namespace.pnts[0][0].append(namespace.new_vec[0])
            namespace.pnts[0][1].append(namespace.new_vec[1])
            namespace.pnts[0][2].append(namespace.new_vec[2])
            namespace.colors[0] = "r"
            sphere.make_sphere()
            return _ax

        namespace.new_vec = list_of_circuit_gates[gate_counter][1] * namespace.new_vec

        namespace.pnts[gate_counter + 1][0].append(namespace.new_vec[0])
        namespace.pnts[gate_counter + 1][1].append(namespace.new_vec[1])
        namespace.pnts[gate_counter + 1][2].append(namespace.new_vec[2])

        sphere.add_vectors(namespace.new_vec)
        if trace:
            # sphere.add_vectors(namespace.points)
            for point_set in namespace.pnts:
                sphere.add_points([point_set[0], point_set[1], point_set[2]])

        sphere.vector_color = [list_of_circuit_gates[gate_counter][2]]
        sphere.point_color = namespace.colors
        sphere.point_marker = "o"

        annotation_text = list_of_circuit_gates[gate_counter][0]
        annotationvector = [1.4, -0.45, 1.7]
        sphere.add_annotation(
            annotationvector,
            annotation_text,
            color=list_of_circuit_gates[gate_counter][2],
            fontsize=30,
            horizontalalignment="left",
        )

        sphere.make_sphere()

        namespace.last_gate = gate_counter
        return _ax

    def init():
        sphere.vector_color = ["r"]
        return _ax

    ani = animation.FuncAnimation(
        fig,
        animate,
        range(frames_per_gate * len(list_of_circuit_gates) + 1),
        init_func=init,
        blit=False,
        repeat=False,
        interval=time_between_frames,
    )

    if saveas:
        ani.save(saveas, fps=30)
    if jupyter:
        # This is necessary to overcome matplotlib memory limit
        matplotlib.rcParams["animation.embed_limit"] = 50
        return HTML(ani.to_jshtml())
    plt.show()
    plt.close(fig)
    return None