diff --git a/examples/state_and_process_plots.ipynb b/examples/state_and_process_plots.ipynb new file mode 100644 index 00000000..6dcb89d5 --- /dev/null +++ b/examples/state_and_process_plots.ipynb @@ -0,0 +1,351 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# State and Process Plots" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Some states" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# python related things\n", + "import numpy as np\n", + "from matplotlib import pyplot as plt\n", + "\n", + "# quantum related things\n", + "from pyquil.gate_matrices import X, Y, Z, H, CNOT, CZ\n", + "from forest.benchmarking.superoperator_tools import *\n", + "from forest.benchmarking.utils import n_qubit_pauli_basis\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Define some quantum states" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Single qubit quantum states" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ZERO = np.array([[1, 0], [0, 0]])\n", + "ONE = np.array([[0, 0], [0, 1]])\n", + "\n", + "plus = np.array([[1], [1]]) / np.sqrt(2)\n", + "minus = np.array([[1], [-1]]) / np.sqrt(2)\n", + "PLUS = plus @ plus.T.conj()\n", + "MINUS = minus @ minus.T.conj()\n", + "\n", + "plusy = np.array([[1], [1j]]) / np.sqrt(2)\n", + "minusy = np.array([[1], [-1j]]) / np.sqrt(2)\n", + "PLUSy = plusy @ plusy.T.conj()\n", + "MINUSy = minusy @ minusy.T.conj()\n", + "\n", + "MIXED = np.eye(2)/2\n", + "\n", + "single_qubit_states = [('0',ZERO),('1',ONE),('+',PLUS),('-',MINUS),('+i',PLUSy),('-i',MINUSy)]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Two qubit quantum states" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "P00 = np.kron(ZERO, ZERO)\n", + "P01 = np.kron(ZERO, ONE)\n", + "P10 = np.kron(ONE, ZERO)\n", + "P11 = np.kron(ONE, ONE)\n", + "\n", + "bell = 1/np.sqrt(2) * np.array([[1, 0, 0, 1]])\n", + "BELL = np.outer(bell, bell)\n", + "\n", + "two_qubit_states = [('00',P00), ('01',P01), ('10',P10), ('11',P11),('BELL',BELL)]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Two types of Pauli Representation of a quantum state" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# convert to pauli basis\n", + "n_qubits = 1\n", + "pl_basis_oneq = n_qubit_pauli_basis(n_qubits)\n", + "c2p_oneq = computational2pauli_basis_matrix(2*n_qubits)\n", + "oneq_states_pl = [ (state[0], np.real(c2p_oneq@vec(state[1]))) for state in single_qubit_states]\n", + "\n", + "n_qubits = 2\n", + "pl_basis_twoq = n_qubit_pauli_basis(n_qubits)\n", + "c2p_twoq = computational2pauli_basis_matrix(2*n_qubits)\n", + "twoq_states_pl = [ (state[0], np.real(c2p_twoq@vec(state[1]))) for state in two_qubit_states]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from forest.benchmarking.plotting.state_process import plot_pauli_rep_of_state, plot_pauli_bar_rep_of_state" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Single Qubit states" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# can plot vertically\n", + "fig, ax = plt.subplots(1)\n", + "plot_pauli_rep_of_state(oneq_states_pl[0][1], ax, pl_basis_oneq.labels, 'State is |0>')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# or can plot horizontally\n", + "for state in oneq_states_pl:\n", + " fig, ax = plt.subplots(1)\n", + " plot_pauli_rep_of_state(state[1].transpose(), ax, pl_basis_oneq.labels, 'State is |'+state[0]+'>')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for state in oneq_states_pl:\n", + " fig, ax = plt.subplots(1)\n", + " plot_pauli_bar_rep_of_state(state[1].flatten(), ax, pl_basis_oneq.labels, 'State is |'+state[0]+'>')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Two qubit states" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# can plot vertically \n", + "fig, ax = plt.subplots(1)\n", + "plot_pauli_rep_of_state(twoq_states_pl[0][1], ax, pl_basis_twoq.labels, 'State is |0>')\n", + "# can plot horizontially\n", + "fig, ax = plt.subplots(1)\n", + "plot_pauli_rep_of_state(twoq_states_pl[0][1].transpose(), ax, pl_basis_twoq.labels, 'State is |0>')\n", + "fig, ax = plt.subplots(1)\n", + "plot_pauli_rep_of_state(twoq_states_pl[-1][1].transpose(), ax, pl_basis_twoq.labels, 'State is BELL')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Also bar plots \n", + "fig, ax = plt.subplots(1)\n", + "plot_pauli_bar_rep_of_state(twoq_states_pl[-1][1].flatten(), ax, pl_basis_twoq.labels, 'State is BELL')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Plot a Quantum Process as a Pauli Transfer Matrix" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "Xpl = kraus2pauli_liouville(X)\n", + "Hpl = kraus2pauli_liouville(H)\n", + "from forest.benchmarking.plotting.state_process import plot_pauli_transfer_matrix" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "f, (ax1) = plt.subplots(1, 1, figsize=(5, 4.2))\n", + "plot_pauli_transfer_matrix(np.real(Xpl), ax1, pl_basis_oneq.labels, 'X gate')\n", + "\n", + "f, (ax1) = plt.subplots(1, 1, figsize=(5, 4.2))\n", + "plot_pauli_transfer_matrix(np.real(Hpl), ax1, pl_basis_oneq.labels, 'H gate')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "CNOTpl = kraus2pauli_liouville(CNOT)\n", + "CZpl = kraus2pauli_liouville(CZ)\n", + "\n", + "f, (ax1) = plt.subplots(1, 1, figsize=(5, 4.2))\n", + "plot_pauli_transfer_matrix(np.real(CNOTpl), ax1, pl_basis_twoq.labels, 'CNOT')\n", + "f, (ax1) = plt.subplots(1, 1, figsize=(5, 4.2))\n", + "plot_pauli_transfer_matrix(np.real(CZpl), ax1, pl_basis_twoq.labels, 'CZ')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Hinton Plots for states and processes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The warning here is the `hinton_real` function only works for plotting a real matrix so the user has to be careful. It will take the absolute value of complex numbers." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Visualize a real state in the computational basis" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from forest.benchmarking.utils import n_qubit_computational_basis\n", + "from forest.benchmarking.plotting.hinton import hinton_real\n", + "oneq = n_qubit_computational_basis(1)\n", + "oneq_latex_labels = [r'$|{}\\rangle$'.format(''.join(j)) for j in oneq.labels]\n", + "\n", + "_ = hinton_real(ZERO, max_weight=1.0, xlabels=oneq_latex_labels, ylabels=oneq_latex_labels, ax=None, title=r'$|0\\rangle$')\n", + "_ = hinton_real(MINUS, max_weight=1.0, xlabels=oneq_latex_labels, ylabels=oneq_latex_labels, ax=None, title=r'$|-\\rangle$')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Visualize a Process Pauli basis\n", + "The Pauli representation is real so we can plot any process" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "_ = hinton_real(Xpl, max_weight=1.0, xlabels=pl_basis_oneq.labels, ylabels=pl_basis_oneq.labels, ax=None, title='X gate')\n", + "_ = hinton_real(Hpl, max_weight=1.0, xlabels=pl_basis_oneq.labels, ylabels=pl_basis_oneq.labels, ax=None, title='H gate')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "So far things look the same as the `plot_pauli_transfer_matrix` but we can plot using the traditional Hinton diagram colors, now the size of the squares makes a difference." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from matplotlib import cm\n", + "_ = hinton_real(Hpl, max_weight=1.0, xlabels=pl_basis_oneq.labels, ylabels=pl_basis_oneq.labels,cmap = cm.Greys_r, ax=None, title='Good H gate')\n", + "_ = hinton_real(Hpl-0.3, max_weight=1.0, xlabels=pl_basis_oneq.labels, ylabels=pl_basis_oneq.labels, cmap = cm.Greys_r, ax=None, title='Bad H gate')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/tomography_process.ipynb b/examples/tomography_process.ipynb index 0eb40952..1cd7116e 100644 --- a/examples/tomography_process.ipynb +++ b/examples/tomography_process.ipynb @@ -130,13 +130,35 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'process_choi_ideal' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m--------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0mfig\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0max1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0max2\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mplt\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msubplots\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfigsize\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m12\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m5\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 6\u001b[0;31m \u001b[0mplot_pauli_transfer_matrix\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mchoi2pauli_liouville\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mprocess_choi_ideal\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0max1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtitle\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'Ideal'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 7\u001b[0m \u001b[0mplot_pauli_transfer_matrix\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mchoi2pauli_liouville\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mprocess_choi_est\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0max2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtitle\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'Estimate'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 8\u001b[0m \u001b[0mplt\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtight_layout\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mNameError\u001b[0m: name 'process_choi_ideal' is not defined" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "import matplotlib.pyplot as plt\n", "from forest.benchmarking.superoperator_tools import choi2pauli_liouville\n", - "from forest.benchmarking.tomography import plot_pauli_transfer_matrix\n", + "from forest.benchmarking.plotting.state_process import plot_pauli_transfer_matrix\n", "\n", "fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12,5))\n", "plot_pauli_transfer_matrix(choi2pauli_liouville(process_choi_ideal), ax1, title='Ideal')\n", diff --git a/forest/benchmarking/plotting/hinton.py b/forest/benchmarking/plotting/hinton.py index 3be293f9..d9fae280 100644 --- a/forest/benchmarking/plotting/hinton.py +++ b/forest/benchmarking/plotting/hinton.py @@ -1,11 +1,14 @@ -import matplotlib.pyplot as plt import numpy as np +from typing import List +import matplotlib.pyplot as plt from matplotlib import cm +import matplotlib as mpl from matplotlib.colors import Normalize ANGLE_MAPPER = cm.ScalarMappable(norm=Normalize(vmin=-np.pi, vmax=np.pi)) +# Modified from the SciPy Cookbook. def hinton(matrix, max_weight=1.0, ax=None): """Draw Hinton diagram for visualizing a weight matrix.""" ax = ax if ax is not None else plt.gca() @@ -30,3 +33,110 @@ def hinton(matrix, max_weight=1.0, ax=None): ax.set_ylim((-max_weight / 2, matrix.shape[1] - max_weight / 2)) ax.autoscale_view() ax.invert_yaxis() + + +# From QuTiP which in turn modified the code from the SciPy Cookbook. +def _blob(x, y, w, w_max, area, cmap=None): + """ + Draws a square-shaped blob with the given area (< 1) at the given coordinates. + """ + hs = np.sqrt(area) / 2 + xcorners = np.array([x - hs, x + hs, x + hs, x - hs]) + ycorners = np.array([y - hs, y - hs, y + hs, y + hs]) + + plt.fill(xcorners, ycorners, color=cmap) # cmap(int((w + w_max) * 256 / (2 * w_max)))) + + +# Modified from QuTip (see https://bit.ly/2LrbayH ) which in turn modified the code from the +# SciPy Cookbook. +def hinton_real(matrix: np.ndarray, + max_weight: float = None, + xlabels: List[str] = None, + ylabels: List[str] = None, + title: str = None, + ax=None, + cmap=None, + label_top: bool = True): + ''' + Draw Hinton diagram for visualizing a real valued weight matrix. + + In the traditional Hinton diagram positive and negative values are represented by white and + black squares respectively. The size of each square represents the magnitude of each value. + The traditional Hinton diagram can be recovered by setting cmap = cm.Greys_r. + + :param matrix: The matrix to be visualized. + :param max_weight: normalize size to this scalar. + :param xlabels: The labels for the operator basis. + :param ylabels: The labels for the operator basis. + :param title: The title for the plot. + :param ax: The matplotlib axes. + :param cmap: A matplotlib colormap to use when plotting. + :param label_top: If True, x-axis labels will be placed on top, otherwise they will appear + below the plot. + :return: A tuple of the matplotlib figure and axes instances used to produce the figure. + ''' + if ax is None: + fig, ax = plt.subplots(1, 1, figsize=(8, 6)) + + # Grays in increasing darkness: smokewhite, gainsboro, lightgrey, lightgray, silver + backgnd_gray = 'gainsboro' + + if cmap is None: + cmap = cm.RdBu + cneg = cmap(0) + cpos = cmap(256) + cmap = mpl.colors.ListedColormap([cneg, backgnd_gray, cpos]) + else: + cneg = cmap(0) + cpos = cmap(256) + cmap = mpl.colors.ListedColormap([cneg, backgnd_gray, cpos]) + + if title and fig: + ax.set_title(title, y=1.1, fontsize=18) + + ax.set_aspect('equal', 'box') + ax.set_frame_on(False) + + height, width = matrix.shape + if max_weight is None: + max_weight = 1.25 * max(abs(np.diag(np.matrix(matrix)))) + if max_weight <= 0.0: + max_weight = 1.0 + + bounds = [-max_weight, -0.0001, 0.0001, max_weight] + tick_loc = [-max_weight / 2, 0, max_weight / 2] + + ax.fill(np.array([0, width, width, 0]), np.array([0, 0, height, height]), color=cmap(1)) + for x in range(width): + for y in range(height): + _x = x + 1 + _y = y + 1 + if np.real(matrix[x, y]) > 0.0: + _blob(_x - 0.5, height - _y + 0.5, abs(matrix[x, y]), max_weight, + min(1, abs(matrix[x, y]) / max_weight), cmap=cmap(2)) + else: + _blob(_x - 0.5, height - _y + 0.5, -abs(matrix[x, y]), max_weight, + min(1, abs(matrix[x, y]) / max_weight), cmap=cmap(0)) + + norm = mpl.colors.BoundaryNorm(bounds, cmap.N) + cax, kw = mpl.colorbar.make_axes(ax, shrink=0.75, pad=.1) + mpl.colorbar.ColorbarBase(cax, + norm=norm, + cmap=cmap, + boundaries=bounds, + ticks=tick_loc).set_ticklabels(['$-$', '$0$', '$+$']) + cax.tick_params(labelsize=14) + # x axis + ax.xaxis.set_major_locator(plt.IndexLocator(1, 0.5)) + if xlabels: + ax.set_xticklabels(xlabels) + if label_top: + ax.xaxis.tick_top() + ax.tick_params(axis='x', labelsize=14) + # y axis + ax.yaxis.set_major_locator(plt.IndexLocator(1, 0.5)) + if ylabels: + ax.set_yticklabels(list(reversed(ylabels))) + ax.tick_params(axis='y', labelsize=14) + + return fig, ax \ No newline at end of file diff --git a/forest/benchmarking/plotting/state_process.py b/forest/benchmarking/plotting/state_process.py new file mode 100644 index 00000000..46fa600e --- /dev/null +++ b/forest/benchmarking/plotting/state_process.py @@ -0,0 +1,119 @@ +import matplotlib.pyplot as plt +import numpy as np +from matplotlib.colors import LinearSegmentedColormap + +THREE_COLOR_MAP = ['#48737F', '#FFFFFF', '#D6619E'] +rigetti_3_color_cm = LinearSegmentedColormap.from_list("Rigetti", THREE_COLOR_MAP[::-1], N=100) + + +def plot_pauli_rep_of_state(state_pl_basis, ax, labels, title): + """ + Visualize a quantum state in the Pauli-Liouville basis. + + :param numpy.ndarray state_pl_basis: The quantum state represented in the Pauli-Liouville basis. + :param ax: The matplotlib axes. + :param labels: The labels for the operator basis states. + :param title: The title for the plot. + + Examples + -------- + from forest.benchmarking.superoperator_tools import * + from forest.benchmarking.utils import n_qubit_pauli_basis + # zero state in the (Z) computational basis + rho_std_basis = np.array([[1, 0], [0, 0]]) + # change to Pauli-Liouville basis + n_qubits = 1 + pl_basis = n_qubit_pauli_basis(n_qubits) + c2p = computational2pauli_basis_matrix(2*n_qubits) + rho_pl_basis = np.real(c2p@vec(rho_std_basis)) + # plot + fig, ax = plt.subplots(1) + plot_pauli_rep_of_state(rho_pl_basis, ax, pl_basis.labels, 'Zero state |0>') + """ + if len(state_pl_basis.shape) == 1: + raise ValueError("You must pass in a (N by 1) or a (1 by N) numpy.ndarray") + if np.iscomplexobj(state_pl_basis): + raise ValueError("You must pass in a real vector") + + im = ax.imshow(state_pl_basis, interpolation="nearest", cmap="RdBu", vmin=-1 / 2, vmax=1 / 2) + dim = len(labels) + # make the colorbar ticks look pretty + rows, cols = state_pl_basis.shape + if rows > cols: + cb = plt.colorbar(im, ax=ax, ticks=[-1 / 2, -1 / 4, 0, 1 / 4, 1 / 2]) + ticklabs = cb.ax.get_yticklabels() + cb.ax.set_yticklabels(ticklabs, ha='right') + cb.ax.yaxis.set_tick_params(pad=35) + # axis labels etc + ax.set_xlabel("Coefficient") + ax.set_xticks([]) + ax.set_yticks(range(dim)) + ax.set_ylabel("Pauli Operator") + ax.set_yticklabels(labels) + else: + cb = plt.colorbar(im, ax=ax, ticks=[-1 / 2, -1 / 4, 0, 1 / 4, 1 / 2], + orientation="horizontal", + pad=0.22) + ax.set_ylabel("Coefficient") + ax.set_yticks([]) + ax.set_xticks(range(dim)) + ax.set_xlabel("Pauli Operator") + ax.set_xticklabels(labels) + ax.set_title(title) + ax.grid(False) + + +def plot_pauli_bar_rep_of_state(state_pl_basis, ax, labels, title): + """ + Visualize a quantum state in the Pauli-Liouville basis. The magnitude of the operator + coeffiences are represent by the height of a bar in the bargraph. + + :param numpy.ndarray state_pl_basis: The quantum state represented in the Pauli-Liouville basis. + :param ax: The matplotlib axes. + :param labels: The labels for the operator basis states. + :param title: The title for the plot. + """ + dim = len(labels) + im = ax.bar(np.arange(dim) - .4, np.real(state_pl_basis), width=.8) + ax.set_xticks(range(dim)) + ax.set_xlabel("Pauli Operator") + ax.set_ylabel("Coefficient") + ax.set_title(title) + ax.set_xticklabels(labels, rotation=45) + ax.grid(False) + + +def plot_pauli_transfer_matrix(ptransfermatrix, ax, labels=None, title='', fontsizes: int = 16): + """ + Visualize a quantum process using the Pauli-Liouville representation (aka the Pauli Transfer + Matrix) of the process. + + :param numpy.ndarray ptransfermatrix: The Pauli Transfer Matrix + :param ax: The matplotlib axes. + :param labels: The labels for the operator basis states. + :param title: The title for the plot + :param fontsizes: Font size for axis labels + :return: The modified axis object. + :rtype: AxesSubplot + """ + im = ax.imshow(ptransfermatrix, interpolation="nearest", cmap="RdBu", vmin=-1, vmax=1) + if labels is None: + dim_squared = ptransfermatrix.shape[0] + num_qubits = np.int(np.log2(np.sqrt(dim_squared))) + labels = [''.join(x) for x in itertools.product('IXYZ', repeat=num_qubits)] + else: + dim_squared = len(labels) + + cb = plt.colorbar(im, ax=ax, ticks=[-1, -3 / 4, -1 / 2, -1 / 4, 0, 1 / 4, 1 / 2, 3 / 4, 1]) + ticklabs = cb.ax.get_yticklabels() + cb.ax.set_yticklabels(ticklabs, ha='right') + cb.ax.yaxis.set_tick_params(pad=35) + ax.set_xticks(range(dim_squared)) + ax.set_xlabel("Input Pauli Operator", fontsize=fontsizes) + ax.set_yticks(range(dim_squared)) + ax.set_ylabel("Output Pauli Operator", fontsize=fontsizes) + ax.set_title(title, fontsize= int(np.floor(1.2*fontsizes))) + ax.set_xticklabels(labels, rotation=45, fontsize=int(np.floor(0.7*fontsizes))) + ax.set_yticklabels(labels, fontsize=int(np.floor(0.7*fontsizes))) + ax.grid(False) + return ax diff --git a/forest/benchmarking/tomography.py b/forest/benchmarking/tomography.py index 2e81f7b6..093bb6cf 100644 --- a/forest/benchmarking/tomography.py +++ b/forest/benchmarking/tomography.py @@ -4,9 +4,7 @@ from operator import mul from typing import Callable, Tuple, List, Optional, Union, Sequence -import matplotlib.pyplot as plt import numpy as np -from matplotlib.colors import LinearSegmentedColormap from scipy.linalg import logm, pinv, eigh import forest.benchmarking.distance_measures as dm @@ -801,33 +799,3 @@ def estimate_variance(results: List[ExperimentResult], sample_estimate.append(np.real(functional(target_state, rho))) return np.mean(sample_estimate), np.var(sample_estimate) - - -THREE_COLOR_MAP = ['#48737F', '#FFFFFF', '#D6619E'] -rigetti_3_color_cm = LinearSegmentedColormap.from_list("Rigetti", THREE_COLOR_MAP[::-1], N=100) - - -def plot_pauli_transfer_matrix(ptransfermatrix, ax, title = ''): - """ - Visualize the Pauli Transfer Matrix of a process. - :param numpy.ndarray ptransfermatrix: The Pauli Transfer Matrix - :param ax: The matplotlib axes. - :param labels: The labels for the operator basis states. - :param title: The title for the plot - :return: The modified axis object. - :rtype: AxesSubplot - """ - im = ax.imshow(np.real(ptransfermatrix), interpolation="nearest", cmap=rigetti_3_color_cm, vmin=-1,vmax=1) - dim_squared = ptransfermatrix.shape[0] - num_qubits = np.int(np.log2(np.sqrt(dim_squared))) - labels = [''.join(x) for x in itertools.product('IXYZ', repeat=num_qubits)] - plt.colorbar(im, ax=ax) - ax.set_xticks(range(dim_squared)) - ax.set_xlabel("Input Pauli Operator", fontsize=20) - ax.set_yticks(range(dim_squared)) - ax.set_ylabel("Output Pauli Operator", fontsize=20) - ax.set_title(title, fontsize=25) - ax.set_xticklabels(labels, rotation=45) - ax.set_yticklabels(labels) - ax.grid(False) - return ax diff --git a/forest/benchmarking/utils.py b/forest/benchmarking/utils.py index 60a211d2..dbbbc594 100644 --- a/forest/benchmarking/utils.py +++ b/forest/benchmarking/utils.py @@ -432,32 +432,50 @@ def __repr__(self): pauli_label_ops = [('I', np.eye(2)), ('X', X), ('Y', Y), ('Z', Z)] +PAULI_BASIS = OperatorBasis(pauli_label_ops) -def pauli_basis_measurements(qubit): + +def n_qubit_pauli_basis(n): """ - Generates the Programs required to measure the expectation values of the pauli operators. + Construct the tensor product operator basis of `n` PAULI_BASIS's. - :param qubit: Required argument (so that the caller has a reference). + :param int n: The number of qubits. + :return: The product Pauli operator basis of `n` qubits + :rtype: OperatorBasis """ - pauli_label_meas_progs = [Program(), Program(RY(-np.pi / 2, qubit)), Program(RX(-np.pi / 2, qubit)), Program()] - return pauli_label_meas_progs + if n >= 1: + return PAULI_BASIS ** n + else: + raise ValueError("n = {} should be at least 1.".format(n)) -PAULI_BASIS = OperatorBasis(pauli_label_ops) +computational_label_ops = [('0', np.array([[1], [0]])), ('1', np.array([[0], [1]]))] +COMPUTATIONAL_BASIS = OperatorBasis(computational_label_ops) -def n_qubit_pauli_basis(n): + +def n_qubit_computational_basis(n): """ - Construct the tensor product operator basis of `n` PAULI_BASIS's. + Construct the tensor product operator basis of `n` COMPUTATIONAL_BASIS's. :param int n: The number of qubits. :return: The product Pauli operator basis of `n` qubits :rtype: OperatorBasis """ if n >= 1: - return PAULI_BASIS ** n + return COMPUTATIONAL_BASIS ** n else: raise ValueError("n = {} should be at least 1.".format(n)) + + +def pauli_basis_measurements(qubit): + """ + Generates the Programs required to measure the expectation values of the pauli operators. + + :param qubit: Required argument (so that the caller has a reference). + """ + pauli_label_meas_progs = [Program(), Program(RY(-np.pi / 2, qubit)), Program(RX(-np.pi / 2, qubit)), Program()] + return pauli_label_meas_progs def transform_pauli_moments_to_bit(mean_p, var_p):