From de2934fa84bac74b802a2261482b3ef7e087bea8 Mon Sep 17 00:00:00 2001 From: Joshua Combes Date: Tue, 18 Jun 2019 19:38:36 +1000 Subject: [PATCH 01/11] WIP, using some content from grove tomography docs. --- examples/figs/bloch.png | Bin 0 -> 59705 bytes examples/tomography_state.ipynb | 290 ++++++++++++++++++++++++++++---- 2 files changed, 259 insertions(+), 31 deletions(-) create mode 100644 examples/figs/bloch.png diff --git a/examples/figs/bloch.png b/examples/figs/bloch.png new file mode 100644 index 0000000000000000000000000000000000000000..59d650f23d99878cfe66d43d2b95fa42c4b8cb82 GIT binary patch literal 59705 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

%G*PT7^teWXeRPCSgX^QmS3q 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 literal 0 HcmV?d00001 diff --git a/examples/tomography_state.ipynb b/examples/tomography_state.ipynb index a1f2df6c..decf2318 100644 --- a/examples/tomography_state.ipynb +++ b/examples/tomography_state.ipynb @@ -5,12 +5,108 @@ "metadata": {}, "source": [ "# State tomography\n", - "State tomography involves measuring a quantum state repeatedly in the bases given by `itertools.product(['X', 'Y', 'Z], repeat=n_qubits)`. From these measurements, we can reconstruct a density matrix $\\rho$." + "\n", + "**Classical tomography** \n", + "The simplest classical analogy to estimating a quantum state using tomography is estimating the bias of a coin. The bias, denoted bias by $p$, is analogous to the quantum state in a way that will explained shortly.\n", + "\n", + "If we have access to $n_{\\rm Tot}$ independent experiements (or measurements) and observe $n_{\\rm H}$ heads then maximum likelihood estimate for the bias of the coin is\n", + "\n", + "$$ p_{\\rm Max-Like} = \\frac{n_H}{n_{\\rm Tot}},$$\n", + "\n", + "and the variance of this estimator is $ {\\rm Var}[p_{\\rm Max-Like}] = p(1-p)/n_{\\rm Tot}$.\n", + "\n", + "The things to learn from this example are:\n", + "* it takes many measurements to estiamte $p$, it can't be done in a single shot\n", + "* $p_{\\rm Max-Like}$ is an estimator, there are other choices of estimators see e.g. [Beta distribution](https://en.wikipedia.org/wiki/Beta_distribution#Bayesian_inference) and [Bayes estimator](https://en.wikipedia.org/wiki/Bayes_estimator)\n", + "\n", + "\n", + "Let's take the analogy a little further. Lets define a \"quantum\" state \n", + "\n", + "$$\\begin{align}\n", + "\\rho \n", + "&= \\begin{pmatrix} p & 0\\\\ 0 & 1-p\\end{pmatrix} \\\\\n", + "&= \\frac{1}{2} (I +z Z)\\\\\n", + "&=\\frac{1}{2} \\begin{pmatrix} 1+z & 0\\\\ 0 & 1-z\\end{pmatrix},\n", + "\\end{align}\n", + "$$ \n", + "where $I$ and $Z$ are the identity and the Pauli-z matrix. This parameterizes the states along the z-axis of the Bloch sphere\n", + "\n", + "\n", + "![alt txt](figs/bloch.png)\n", + "\n", + "\n", + "The relationship between the $Z$ expectation value and the coin bias is\n", + "\n", + "$$z:= \\langle Z \\rangle = {\\rm Tr}[Z \\rho] = 2 p -1.$$\n", + "\n", + "In this analogy the pure states $|0\\rangle$ and $|1\\rangle$ corespond to the coin biases $p=0$ and $p=1$ respectively, all other (mixed) states are convex mixtures of these extremal points." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Quantum tomography of a single qubit** \n", + "\n", + "The simplest quantum system to tomograph is a single qubit. Like before we parameterize the state with respect to a set of operators \n", + "$$\\begin{align}\n", + "\\rho \n", + "&= \\frac{1}{2} (I+x X+ y Y +z Z)\\\\\n", + "&=\\frac{1}{2} \\begin{pmatrix} 1+z & x+iy\\\\ x-iy & 1-z\\end{pmatrix},\n", + "\\end{align}\n", + "$$ \n", + "where $x = \\langle X \\rangle$, $y = \\langle Y \\rangle$, and $z = \\langle Z \\rangle$. In the language of our classical coin we have three parameters we need to estimate that are constrained in the following way\n", + "\n", + "$$\n", + "0\\le x \\le 1\\\\\n", + "0\\le y \\le 1\\\\ \n", + "0\\le z \\le 1\\\\\n", + "x^2 + y^2 +z^2 \\le 1.\n", + "$$\n", + "\n", + "The physics of our system means that our default our measurement gives us the Z basis statistics. We already constructed an estimator to go from the coin flip statistics to the Z expectation: $2p -1$. \n", + "\n", + "\n", + "Now we need to, measure the statistics of the operators X and Y. Essentially this means we must rotate our state after we prepare it but before it is measured (or equivalently rotate our measurement basis). If we rotate the state as $\\rho\\mapsto U\\rho U^\\dagger$ and then do our usual Z-basis measurement, then this is equivalent to rotating the measured observable as $Z \\mapsto U^\\dagger Z U$ and keeping our state $\\rho$ unchanged. This is the disticntion between the [Heisenberg and Schrödinger pictures](https://en.wikipedia.org/wiki/Heisenberg_picture#Summary_comparison_of_evolution_in_all_pictures). The Heisenberg picture point of view then allows us to see that if we apply a rotation such as $U=R_y(\\pi/2)$ then this rotates the observable as $R_y(-\\pi/2)ZR_y(+\\pi/2)=\\cos(\\pi/2) Z - \\sin(\\pi/2) X = -X$. Similarly, we could rotate by $U=R_x(\\pi/2)$ to measure the Y observable. \n", + "\n", + " \n", + "\n", + "\n", + "**Quantum state tomography in general** \n", + "Involves measuring all the expectation value of all the operators given by `itertools.product(['X', 'Y', 'Z], repeat=n_qubits)` many times. From these measurements, we can reconstruct a density matrix $\\rho$ on `n_qubits`." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**More information** \n", + "See the following references:\n", + "\n", + "[Quantum tomography wikipedia page](https://en.wikipedia.org/wiki/Quantum_tomography)\n", + "\n", + "*Initialization and characterization of open quantum systems* \n", + "Christopher Wood, \n", + "Chapter 3, PhD Thesis, University of Waterloo (2015) \n", + "http://hdl.handle.net/10012/9557 \n", + "\n", + "\n", + "Introduction to Quantum Gate Set Tomography \n", + "Daniel Greenbaum, \n", + "arXiv:1509.02921 (2015) \n", + "https://arxiv.org/abs/1509.02921 " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Some imports" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -23,22 +119,66 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Construct a state with a `Program`\n", - "We'll construct a two-qubit graph state by Hadamarding all qubits and then applying a controlled-Z operation across edges of our graph. In the two-qubit case, there's only one edge. " + "## Prepare a state with a `Program`\n", + "We'll construct a two-qubit graph state by Hadamarding all qubits and then applying a controlled-Z operation across edges of our graph. In the two-qubit case, there's only one edge. The vector we end up preparing is\n", + "\n", + "$$ |\\Psi\\rangle = \\frac{1}{2}\\begin{pmatrix} 1\\\\ 1 \\\\ 1\\\\ -1\\end{pmatrix}= {\\rm CZ}(0,1){\\rm H}(1){\\rm H}(0)|0,0\\rangle,$$\n", + "\n", + "which corresponds to the state matrix\n", + "\n", + "$$ \\rho_{\\rm true} = |\\Psi\\rangle\\langle \\Psi| = \\frac{1}{4}\\begin{pmatrix} 1 & 1 & 1 &-1\\\\ 1 & 1 & 1 &-1 \\\\ 1 & 1 & 1 &-1\\\\ -1 & -1 & -1 & 1\\end{pmatrix}.$$" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[ 0.25, 0.25, 0.25, -0.25],\n", + " [ 0.25, 0.25, 0.25, -0.25],\n", + " [ 0.25, 0.25, 0.25, -0.25],\n", + " [-0.25, -0.25, -0.25, 0.25]])" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# numerical representation of the true state\n", + "Psi = (1/2) * np.array([1, 1, 1, -1])\n", + "rho_true = np.outer(Psi, Psi.T.conj())\n", + "\n", + "rho_true" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "H 0\n", + "H 1\n", + "CZ 0 1\n", + "\n" + ] + } + ], "source": [ "qubits = [0, 1]\n", - "program = Program()\n", + "state_prep_prog = Program()\n", "for qubit in qubits:\n", - " program += H(qubit)\n", - "program += CZ(qubits[0], qubits[1])\n", - "print(program)" + " state_prep_prog += H(qubit)\n", + "state_prep_prog += CZ(qubits[0], qubits[1])\n", + "print(state_prep_prog)" ] }, { @@ -51,12 +191,35 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "H 0; H 1; CZ 0 1\n", + "0: Z0_0 * Z0_1→(1+0j)*X1\n", + "1: Z0_0 * Z0_1→(1+0j)*Y1\n", + "2: Z0_0 * Z0_1→(1+0j)*Z1\n", + "3: Z0_0 * Z0_1→(1+0j)*X0\n", + "4: Z0_0 * Z0_1→(1+0j)*X0X1\n", + "5: Z0_0 * Z0_1→(1+0j)*X0Y1\n", + "6: Z0_0 * Z0_1→(1+0j)*X0Z1\n", + "7: Z0_0 * Z0_1→(1+0j)*Y0\n", + "8: Z0_0 * Z0_1→(1+0j)*Y0X1\n", + "9: Z0_0 * Z0_1→(1+0j)*Y0Y1\n", + "10: Z0_0 * Z0_1→(1+0j)*Y0Z1\n", + "11: Z0_0 * Z0_1→(1+0j)*Z0\n", + "12: Z0_0 * Z0_1→(1+0j)*Z0X1\n", + "13: Z0_0 * Z0_1→(1+0j)*Z0Y1\n", + "14: Z0_0 * Z0_1→(1+0j)*Z0Z1\n" + ] + } + ], "source": [ "from forest.benchmarking.tomography import generate_state_tomography_experiment\n", - "experiment = generate_state_tomography_experiment(program=program, qubits=qubits)\n", + "experiment = generate_state_tomography_experiment(program=state_prep_prog, qubits=qubits)\n", "print(experiment)" ] }, @@ -70,9 +233,26 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "H 0; H 1; CZ 0 1\n", + "0: Z0_0 * Z0_1→(1+0j)*X1, Z0_0 * Z0_1→(1+0j)*X0, Z0_0 * Z0_1→(1+0j)*X0X1\n", + "1: Z0_0 * Z0_1→(1+0j)*Y1, Z0_0 * Z0_1→(1+0j)*X0Y1\n", + "2: Z0_0 * Z0_1→(1+0j)*Z1, Z0_0 * Z0_1→(1+0j)*X0Z1\n", + "3: Z0_0 * Z0_1→(1+0j)*Y0, Z0_0 * Z0_1→(1+0j)*Y0X1\n", + "4: Z0_0 * Z0_1→(1+0j)*Y0Y1\n", + "5: Z0_0 * Z0_1→(1+0j)*Y0Z1\n", + "6: Z0_0 * Z0_1→(1+0j)*Z0, Z0_0 * Z0_1→(1+0j)*Z0X1\n", + "7: Z0_0 * Z0_1→(1+0j)*Z0Y1\n", + "8: Z0_0 * Z0_1→(1+0j)*Z0Z1\n" + ] + } + ], "source": [ "from forest.benchmarking.observable_estimation import group_settings\n", "print(group_settings(experiment))" @@ -87,9 +267,34 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[ExperimentResult[Z0_0 * Z0_1→(1+0j)*X1: -0.088 +- 0.04454786190155483],\n", + " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Y1: 0.008 +- 0.04471992844359213],\n", + " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Z1: 0.024 +- 0.04470847794322683],\n", + " ExperimentResult[Z0_0 * Z0_1→(1+0j)*X0: 0.024 +- 0.04470847794322683],\n", + " ExperimentResult[Z0_0 * Z0_1→(1+0j)*X0X1: -0.032 +- 0.04469845634918503],\n", + " ExperimentResult[Z0_0 * Z0_1→(1+0j)*X0Y1: 0.028 +- 0.04470382533967311],\n", + " ExperimentResult[Z0_0 * Z0_1→(1+0j)*X0Z1: 1.0 +- 0.0],\n", + " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Y0: -0.032 +- 0.04469845634918503],\n", + " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Y0X1: -0.044 +- 0.0446780483011512],\n", + " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Y0Y1: 1.0 +- 0.0],\n", + " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Y0Z1: -0.036 +- 0.044692370713579295],\n", + " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Z0: 0.032 +- 0.04469845634918503],\n", + " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Z0X1: 1.0 +- 0.0],\n", + " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Z0Y1: -0.016 +- 0.04471563484956912],\n", + " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Z0Z1: -0.076 +- 0.04459201722281691]]" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "from forest.benchmarking.observable_estimation import estimate_observables\n", "\n", @@ -114,9 +319,23 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[ 0.245-0.j , 0.228+0.002j, 0.256+0.017j, -0.258+0.004j],\n", + " [ 0.228-0.002j, 0.271+0.j , 0.242+0.018j, -0.244-0.001j],\n", + " [ 0.256-0.017j, 0.242-0.018j, 0.267-0.j , -0.272-0.006j],\n", + " [-0.258-0.004j, -0.244+0.001j, -0.272+0.006j, 0.217-0.j ]])" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "from forest.benchmarking.tomography import linear_inv_state_estimate\n", "rho = linear_inv_state_estimate(results, qubits=qubits)\n", @@ -128,11 +347,7 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": [ - "psi = (1/2) * np.array([1, 1, 1, -1])\n", - "rho_true = np.outer(psi, psi.T.conj())\n", - "rho_true" - ] + "source": [] }, { "cell_type": "markdown", @@ -143,7 +358,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": {}, "outputs": [], "source": [ @@ -370,9 +585,22 @@ } ], "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", - "pygments_lexer": "ipython3" + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3" } }, "nbformat": 4, From cbd81ee7c1f5d83f7b95a7c68fd4f24095cde9a9 Mon Sep 17 00:00:00 2001 From: Joshua Combes Date: Wed, 19 Jun 2019 11:37:44 +1000 Subject: [PATCH 02/11] small addition to superoperator examples --- examples/superoperator_tools.ipynb | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/examples/superoperator_tools.ipynb b/examples/superoperator_tools.ipynb index 9d965d75..7e030f1e 100644 --- a/examples/superoperator_tools.ipynb +++ b/examples/superoperator_tools.ipynb @@ -601,6 +601,34 @@ "print(choi_is_cptp(AD_choi))" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Project an unphysical state to the closest physical state" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from forest.benchmarking.operator_tools.project_state_matrix import project_state_matrix_to_physical\n", + "from forest.benchmarking.plotting import hinton\n", + "\n", + "rho_unphys = np.random.uniform(-1, 1, (2, 2)) \\\n", + " * np.exp(1.j * np.random.uniform(-np.pi, np.pi, (2, 2)))\n", + "rho_phys = project_state_matrix_to_physical(rho_unphys)\n", + "\n", + "fig, (ax1, ax2) = plt.subplots(1, 2)\n", + "hinton(rho_unphys, ax=ax1)\n", + "hinton(rho_phys, ax=ax2)\n", + "ax1.set_title('Unphysical')\n", + "ax2.set_title('Physical projection')\n", + "fig.tight_layout()" + ] + }, { "cell_type": "markdown", "metadata": {}, From 283f124270e4484a14d0f258bcd25124ee6c130f Mon Sep 17 00:00:00 2001 From: Joshua Combes Date: Wed, 19 Jun 2019 13:24:25 +1000 Subject: [PATCH 03/11] rename the file --- docs/superoperator_representations.md | 601 ++++++++++++++++++++++++++ 1 file changed, 601 insertions(+) create mode 100644 docs/superoperator_representations.md diff --git a/docs/superoperator_representations.md b/docs/superoperator_representations.md new file mode 100644 index 00000000..0eb18fd0 --- /dev/null +++ b/docs/superoperator_representations.md @@ -0,0 +1,601 @@ +# Superoperator representations + +This document summarizes our conventions for the different superoperator representations. We show how to apply the channels to states in these represenations and how to convert channels between a subset of representations. By combining these conversion methods you can convert between any of the channel representations. + +This document is **not** intended to be a tutorial or a comprehensive review. At the bottom of the document there is a list of references with more information. This document was influenced by [IGST] and we recomend reading [GRAPTN] to gain deeper understading. (The references are listed at the bottom of this document.) Additionally these references explain, for example how to determine if a channel is unital or completely postive in the different representations. + + +## `vec` and `unvec` +Consider an $m\times m$ matrix +$$ A = [a_{ij}] = \begin{pmatrix} +a_{11} & a_{12} & \ldots & a_{1m} \\\\ +a_{21} & a_{22} & \ldots & a_{2m}\\\\ +\vdots & & \ddots & \vdots\\\\ +a_{m1} & a_{m2} & \ldots & a_{mm} +\end{pmatrix}$$ +where $i$ is a row and $j$ is a column index. + +We define `vec` to be column stacking + +$$ |A\rangle \rangle :={\rm vec}(A) = (a_{11},a_{21},\ldots,a_{m1},a_{12},\ldots,a_{mm})^T \quad (1) $$ + +were $T$ denotes a transpose. Clearly an inverse operation, `unvec` can be defined so that + +$$ {\rm unvec}\big ( {\rm vec}(A) \big ) = A.$$ + +Of course `unvec()` generally depends on the dimensions of $A$, which are not recoverable from `vec(A)`. We often focus on square A, but for generality, we require the dimensions for $A$, defaulting to the square root of the dimension of `vec(A)`. Column stacking corresponds to how matrices are stored in memory for column major storage conventions. + +Similarly we can define a row vectorization to be row stacking $ {\rm vec_r}(A) = (a_{11}, a_{12}, \ldots, a_{1m}, a_{21},\ldots, a_{mm})^T$. Note that ${\rm vec}(A) = {\rm vec_r}(A^T)$. In any case we will **not** use this row convention. + +### Matrix multiplication in vectorized form + +For matricies $A,B,C$ + +$$\begin{align} +{\rm vec}(ABC) = (C^T\otimes A) {\rm vec}(B), \quad (2) +\end{align}$$ +which is sometimes called Roth's lemma. + +Eq. 2 is useful in representing quantum operations on mixed quantum states. For example consider +$$ \rho' = U \rho U^\dagger.$$ +We can use Eq. 1 to write this as + +$$ {\rm vec}(\rho') = \{(U^\dagger)^T \otimes U \} {\rm vec}(\rho) += (U^*\otimes U) |\rho\rangle\rangle$$ +so +$$ |\rho'\rangle \rangle = \mathcal U |\rho\rangle\rangle, +$$ +where $\mathcal U = U^*\otimes U$. The nice thing about this is the operator (the state) has become a vector and the superoperator (the left right action of $U$) has become an operator. + +Some other useful results related to vectorization are + +$ {\rm vec}([A,X])= (I\otimes A - A^T\otimes I) {\rm vec}(X)$ + +${\rm vec}(ABC) = (I\otimes AB) {\rm vec}( C ) = (C^T B^T\otimes I) {\rm vec}(A)$ + +${\rm vec}(AB) = (I\otimes A) {\rm vec}(B) = (B^T\otimes I) {\rm vec}(A)$. + + +## Matrix operations on Bipartite matrices: Reshuffling, SWAP, and tranposition + +This section is based on the Wood et al. presentation in [GRAPTN]. + +As motivation for this section consider the Kraus representation theorem. It shows that a quantum channel can be represented as a partial trace over a unitary operation on a larger Hilbert space. Actually the unitary is on a bipartite Hilbert space. + + +When representing quantum channels one insight is used may times. + +Consider two Hilbert spaces $\mathbb H_A$ and $\mathbb H_B$ with dimensions $d_A$ and $d_B$ respectively. An abstract quantum process matrix $\mathcal Q$ lives in the combined (bipartite) space of $\mathbb H_A \otimes \mathbb H_B$ so $\mathcal Q$ is a $d_A^2\times d_B^2$ matrix. + +We can represent the process as a tensor with components + +$$\mathcal Q_{m,\mu;n,\nu} = \langle m, \mu |\mathcal Q |n,\nu \rangle $$ +where $|n,\nu\rangle = |n\rangle \otimes |\nu\rangle$, $m,n\in \{0,\ldots, d_A-1\}$, $\mu,\nu\in \{0,\ldots, d_B-1\}$ and all vectors are in the standard basis. + +With respect to these indicies some useful operations are [GRAPTN]: + +Transpose $T$: $\mathcal Q_{m,\mu;n,\nu} \mapsto \mathcal Q_{n,\nu;m,\mu},$ +SWAP: $\mathcal Q_{m,\mu;n,\nu} \mapsto \mathcal Q_{\mu,m;\nu,n},$ +Row-reshuffling $R_r$: $\mathcal Q_{m,\mu;n,\nu} \mapsto \mathcal Q_{m,n;\mu,\nu},$ +Col-reshuffling $R$: $\mathcal Q_{m,\mu;n,\nu} \mapsto \mathcal Q_{\nu,\mu;n,m}.$ + +The importance of understanding reshuffling can be understood as understanding the relationship between +$${\rm vec}(G)\otimes {\rm vec}(\Gamma) \quad {\rm and} \quad {\rm vec}(G\otimes\Gamma)$$ +where $G$ and $\Gamma$ are matrices that act on $\mathbb H_A$ and $\mathbb H_B$ respectively, as explained in [VECQO]. + +### A note on numerical implementations +Most linear algebra (or tensor) libraries have the ablity to `reshape` a matrix and `swapaxes` (or sometimes it is called `permute_dims`). + +If you are trying to reshuffle indicies usually the first job is to write your matrix in tensor form. This requires reshaping a $d_A^2\times d_B^2$ matrix into a $d_A\times d_A\times d_B \times d_B$ tensor. Next you `permute_dims` or `swapaxes`. Often $d_A = d_B$ so we `reshape` to a Matrix that has the same dimensions as the orignal $d_A^2\times d_A^2$ matix. + + +## The $n$-qubit Pauli basis + The $n$-qubit Pauli basis is denoted $\mathcal P^{\otimes n} $ where $\mathcal P = \{ I, X, Y, Z \}$ are the usual Pauli matricies. It is an operator basis for the $d = 2^n$ dimensional Hilbert space and there are $d^2 = 4^n$ operators in $\mathcal P^{\otimes n} $. If one divides all the operators by $\sqrt{d}$ the basis is orthonormal with respect to the Hilbert-Schmidt inner product. + +It is often convenient to index the $d^2$ operators with a single label, e.g. $P_1=I^{\otimes n},\, \ldots,\, P_{d^2}= Z^{\otimes n}$ (or $P_0=I^{\otimes n}$ if you like zero indexing). In anycase, as these operators are Hermitian and unitary they obey $P_i^2=I^{\otimes n}$. + +To be explicit, for two qubits $d=4$ and we have 16 operators e.g. $\{II, IX, IY, IZ, XI, XX, XY, ..., ZZ\}$ were $II$ should be interpreted as $I\otimes I$ etc. The single index would be $\{P_1, P_2, P_3, P_4, P_5, P_6, P_7, ..., P_{16}\}$. + +## Quantum channels in the Kraus decomposition (or operator-sum representation) +A completely positive map on the state $\rho$ can be written using a set of Kraus operators $\{ M_k \}$ as + + +$$\rho' =\mathcal E (\rho) = \sum_{k=1}^N M_k \rho M_k^\dagger, $$ +where $\rho'$ is the state at the output of the channel. + +If $\sum_k M_k^\dagger M_k= I $ the map is trace preserving. It turns out that $N\le d^2$ where $d$ is the Hilbert space dimension e.g. $d=2^n$ for $n$ qubits. Kraus operators are not necessarily unique, sometimes there is a unitary degree of freedom in the Kraus representation. + +## Kraus to $\chi$ matrix (aka chi or process matrix) +We choose to represent the $\chi$ matrix in the Pauli basis. So we expand each of the Kraus operators in the $n$ qubit Pauli basis + +$M_k = \sum^{d^2}_{j=1}c_{kj}\,P_j$ + +where $\mathcal P_j \in \mathcal P ^{\otimes n}$. + +Now the channel $\mathcal E$ can be written as + +$\mathcal E (\rho) = \sum_{i,j=1}^{d^2} \chi_{i,j} P_i\rho P_j ,$ + +where + +$$\chi_{i,j} = \sum_k c_{k,i} c_{k,j}^*$$ + +is an element of the process matrix $\chi$ of size $d^2 \times d^2$. If the channel is CP the $\chi$ matrix is a Hermitian and positive semidefinite. + +The $\chi$ matrix can be related to the (yet to be defined) Choi matrix via a change of basis. Typically the Choi matrix is defined in the computational basis, while the $\chi$ matrix uses the Pauli basis. Moreover, they may have different normalization conventions. + +In this light, after reviewing the Kraus to Choi conversion it is simple to see that the above is equivalent to first defining + +$$ +|c_{k}\rangle\rangle = U_{c2p}{\rm vec}(M_k) +$$ +then +$$ +\chi = \sum_k |c_{k}\rangle\rangle \langle\langle c_k|. +$$ + +## Kraus to Pauli-Liouville matrix (Pauli transfer matrix) + +We begin by defining the Pauli vector representation of the state $\rho$ + +$$ |\rho \rangle \rangle = \sum_j c_j |P_j\rangle \rangle$$ + +where $P_j \in \mathcal P^{\otimes n}$ and $c_j = (1/d) \langle\langle P_j|\rho \rangle\rangle$. + +The Pauli-Liouville or Pauli transfer matrix representation of the channel $\mathcal E$ is denoted by $R_{\mathcal E}$. The matrix elements are + +$$(R_{\mathcal E})_{i,j} = \frac 1 d {\rm Tr}[P_i \mathcal E(P_j)].$$ + +Trace preservation implies $(R_{\mathcal E})_{0,j} = \delta_{0,j}$, i.e. the first row is one and all zeros. Unitality implies $(R_{\mathcal E})_{i,0} = \delta_{i,0}$, the first column is one and all zeros. + +In this representation the channel is applied to the state by multiplication + +$$|\rho' \rangle \rangle = R_{\mathcal E} |\rho \rangle \rangle.$$ + + +## Kraus to Superoperator (Liouville) +We already saw an example of this in the setion on `vec`-ing. There we re-packaged conjugation by unitary evolution into the action of a matrix on a vec'd density operator. Unitary evolution is simply the case of a single Kraus operator, so we generalize this by taking a sum over all Kraus operators. + +Consider the set of Kraus operators $\{ M_k \}$. The corresponding quantum operation is $\mathcal E (\rho) = \sum_k M_k \rho M_k^\dagger $. + +Using the vec operator (see Eq. 1) this implies a superoperator + +$$\mathcal E = \sum_k (M_k^\dagger)^T \otimes M_k = \sum_k M_k^* \otimes M_k,$$ +which acts as $\mathcal E |\rho\rangle \rangle$ using Equation 2. + +**Note** In quantum information a superoperator is an abstract concept. The object above is a concrete representation of the abstract concept in a particular basis. In the NMR community this particular construction is called the Liouville representation. The Pauli-Liouville representation is attained from Liouville representation by a change of basis, so the similarity in naming makes sense. + +## Kraus to Choi + +Define $ | \eta \rangle = \frac{1}{\sqrt{d}}\sum_{i=0}^{d-1}|i,i \rangle $ + +One can show that + +$|A\rangle \rangle = {\rm vec}(A) = \sqrt{d} (I\otimes A) |\eta\rangle$. + +The Choi state is + +$$\begin{align} +\mathcal C &= I\otimes \mathcal E (|\eta \rangle \langle \eta|) \\\\ +&=\sum_i (I \otimes M_i) |\eta \rangle \langle \eta | ( I \otimes M_i^\dagger)\\\\ +& = \frac{1}{d} \sum_i {\rm vec}(M_i) {\rm vec} (M_i) ^\dagger \\\\ +& = \frac{1}{d} \sum_i |M_i\rangle \rangle \langle\langle M_i |. +\end{align}$$ + +An often quoted equivalent expression is + +$\begin{align} +\mathcal C &= I\otimes \mathcal E (|\eta \rangle \langle \eta|) \\\\ +&=\sum_{ij} |i\rangle \langle j| \otimes \mathcal E (|i \rangle \langle j | ). +\end{align}$ + +## $\chi$ matrix to Pauli-Liouville matrix +$$(R_{\mathcal E})_{i,j} = \frac 1 d \sum_{k,l}\chi_{k,l} {\rm Tr}[ P_i P_k P_j P_l].$$ + +## Superoperator to Pauli-Liouville matrix +The standard basis on $n$ qubits is called the computational basis. It is essentially all the strings $|c_1\rangle=|0..0\rangle$ through to $|c_{\rm max}\rangle = |1...1\rangle$. To convert between a superoperator and the Pauli-Liouville matrix representation we need to do a change of basis from the computational basis to the Pauli basis. This is acheived by the unitary + +$$ U_{c2p}= \sum_{k=1}|c_k\rangle\langle\langle P_k|.$$ + +The we have + +$$ R_{\mathcal E} = U_{c2p} \mathcal E U_{c2p}^\dagger.$$ + + +## Superoperator to Choi +The conversion from the superoperator to a Choi matrix $\mathcal C$ is simply a (column) reshuffling operation + +$$ \mathcal C = R(\mathcal E).$$ + +It turns out that $ \mathcal E = R(\mathcal C)$ which means that $\mathcal E= R(R(\mathcal E))$. + +## Pauli-Liouville matrix to Superoperator +To convert between the Pauli-Liouville matrix and the superoperator representation we need to to a change of basis from the Pauli basis to the computational basis. This is acheived by the unitary + +$$ U_{p2c}= \sum_{k=1}|P_k\rangle\rangle \langle k|,$$ +which is simply $U_{c2p}^\dagger$. + +The we have + +$$\mathcal E = U_{p2c}R_{\mathcal E}U_{p2c}^\dagger.$$ + + +## Pauli-Liouville to Choi +We obtain the normalized Choi matrix using the expression + +$$ \rho_{\mathcal E} = \frac{1}{d^2}\sum_{i,j=1}^{d^2} (R_{\mathcal E})_{i,j} \, P_j^T \otimes P_i.$$ + + + +## Choi to Kraus +This is simply the reverse of the Kraus to Choi procedure. + +Given the Choi matrix $\mathcal C$ we find it's eigenvalues $\{\lambda_i\}$ and vectors $\{|M_i\rangle\rangle \}$. Then the Kraus operators are + +$$ M_i = \sqrt{\lambda_i}\, {\rm unvec}\big (|M_i\rangle\rangle\big),$$ + +For numerical implementation one usually puts a threshold on the eigenvalues, say $\lambda> 10^{-10}$, to prevent numerical instablities. + +## Choi to Pauli-Liouville +First we normalize the Choi representation + +$$\begin{align} +\rho_{\mathcal E}=\frac 1 d \mathcal C = \frac 1 d \sum_{ij} |i\rangle \langle j| \otimes \mathcal E (|i \rangle \langle j | ) +\end{align}$$ + +Then the matrix elements of the Pauli-Liouville matrix representation of the channel can be obtained from the Choi state using + +$$(R_{\mathcal E})_{i,j} ={\rm Tr}[ \rho_{\mathcal E} \, P_j^T \otimes P_i].$$ + +## Choi to Superoperator +The conversion from a Choi matrix $\mathcal C$ to a superoperator is simply a (column) reshuffling operation + +$$ \mathcal E = R(\mathcal C).$$ + +It turns out that $ \mathcal C = R(\mathcal E)$ which means that $\mathcal C= R(R(\mathcal C))$. + + + +## Examples: One qubit channels +Some observations: + +* The Choi matrix of a unitary process always has rank 1. +* The superoperator / Liouville representation of a unitary process is always full rank. +* The eigenvalues of a Choi matrix give you an upper bound to the probability a particular (canonical) Kraus operator will occur (generally that probability depends on the state). This is helpful when sampling Kraus operators (you can test for which occurred accoridng to the order of these eigenvalues). +* The $\chi$ matrix (in the Pauli basis) is very convenient for computing the result of Pauli twirling or Clifford twirling the corresponding process. + +### Unitary Channels or Gates +As an example we look at two single qubit channels $R_z(\theta) = \exp(-i \theta Z/2)$ and $H$. The Hadamard is is a nice channel to examine as it transforms $X$ and $Z$ to each other +$$\begin{align} +H Z H^\dagger &=X\\\\ +H X H^\dagger &= Z +\end{align}$$ +which can be easily seen in some of the channel representations. + +**Kraus** + +As the channel is unitary there is only one Kraus operator used in the operator sum representation. However we express them in the Pauli basis to make some of the below manipulations easier +$$\begin{align} +R_z(\theta) &= \cos(\theta/2) I - i \sin(\theta/2) Z\\\\ +&= \begin{pmatrix} +e^{-i\theta/2} & 0 \\\\ +0 & e^{i\theta /2} +\end{pmatrix} +\\\\ +H &= \frac{1}{\sqrt{2}} (X+Z)\\\\ +&=\frac{1}{\sqrt{2}} + \begin{pmatrix} +1 & 1 \\\\ +1 & -1 +\end{pmatrix} +\end{align}$$ + +**$\chi$ matrix (process)** + +$$ \chi(R_z) = [\chi_{ij}] = \frac 1 2\begin{pmatrix} +1+\cos(\theta) & 0 & 0 & i \sin(\theta) \\\\ +0 & 0 & 0 & 0\\\\ +0 & 0 & 0 & 0\\\\ +-i\sin(\theta) & 0 & 0 & 1-\cos(\theta) +\end{pmatrix}$$ + +$$ \chi(H) = [\chi_{ij}] = \frac 1 2\begin{pmatrix} +0 & 0 & 0 & 0 \\\\ +0 & 1 & 0 & 1\\\\ +0 & 0 & 0 & 0\\\\ +0 & 1 & 0 & 1 +\end{pmatrix}$$ + +**Pauli-Liouville matrix** +$$ +R_{R_z(\theta)}= [(R_{R_z(\theta)})_{i,j}] = +\begin{pmatrix} +1 & 0 & 0 & 0 \\\\ +0 & \cos(\theta) & -\sin(\theta) & 0 \\\\ +0 & \sin(\theta) & \cos(\theta) & 0 \\\\ +0 & 0 & 0 & 1 +\end{pmatrix}$$ + +$$ +R_{H}= [(R_{H})_{i,j}] = +\frac 1 2\begin{pmatrix} +1 & 0 & 0 & 0 \\\\ +0 & 0 & 0 & 1 \\\\ +0 & 0 & -1 & 0 \\\\ +0 & 1 & 0 & 0 +\end{pmatrix}$$ + +**Superoperator** + +$$ \mathcal R_z(\theta) = R_z(\theta)^*\otimes R_z(\theta)= +\begin{pmatrix} +1 & 0 & 0 & 0 \\\\ +0 & e^{i\theta} & 0 & 0\\\\ +0 & 0 & e^{-i\theta} & 0\\\\ +0 & 0 & 0 & 1 +\end{pmatrix} +$$ + +$$ \mathcal H = H^*\otimes H=\frac 1 2 +\begin{pmatrix} +1 & 1 & 1 & 1 \\\\ +1 & -1 & 1 & -1\\\\ +1 & 1 & -1 &-1\\\\ +1 & -1 & -1 & 1 +\end{pmatrix} +$$ + +**Choi** + +$$\begin{align} +\mathcal C_{R_z} &= \frac 1 2 |R_z(\theta)\rangle\rangle\langle\langle R_z(\theta)|\\\\ +&=\frac 1 2 +\begin{pmatrix} +1 & 0 & 0 & e^{-i\theta} \\\\ +0 & 0 & 0 & 0\\\\ +0 & 0 & 0 & 0\\\\ +e^{i\theta} & 0 & 0 & 1 +\end{pmatrix} +\end{align}$$ + +$$\begin{align} +\mathcal C_H &= \frac 1 2 |H\rangle\rangle\langle\langle H|\\\\ +&=\frac 1 2 +\begin{pmatrix} +1 & 1 & 1 & -1 \\\\ +1 & 1 & 1 & -1\\\\ +1 & 1 & 1 & -1\\\\ +-1 & -1 & -1 & 1 +\end{pmatrix} +\end{align}$$ + + + +### Pauli Channels +Pauli channels are nice because they are diagonal in two representations and they have the *depolarlizing channel* as a speical case. + +In the operator sum representation a single qubit Pauli channel is defined as +$$\mathcal E(\rho) = (1-p_x-p_y-p_z) I \rho I + p_x X\rho X + p_y Y \rho Y + p_z Z \rho Z$$ +where $p_x,p_y,p_z\ge 0$ and $p_x+p_y+p_z\le 1$. + +If we define $p' = p_x+p_y+p_z$ then + +$$\mathcal E(\rho) = (1-p') I \rho I + p_x X\rho X + p_y Y \rho Y + p_z Z \rho Z.$$ + +The Pauli channel specializes to the depolarizing channel when +$$ p' = \frac 3 4 p \quad {\rm and}\quad p_x=p_y=p_z = p +$$ +for $0\le p \le 1$. + +**Kraus** + +The Kraus operators used in the operator sum representation are +$$\begin{align} +M_0 &= \sqrt{1-p'}I \\\\ +M_1 &= \sqrt{p_x}X \\\\ +M_2 &= \sqrt{p_y}Y \\\\ +M_3 &= \sqrt{p_z}Z. +\end{align}$$ + +**$\chi$ matrix (process)** + +$$ \chi = [\chi_{ij}] = \begin{pmatrix} +(1-p') & 0 & 0 & 0 \\\\ +0 & p_x & 0 & 0\\\\ +0 & 0 & p_y & 0\\\\ +0 & 0 & 0 & p_z +\end{pmatrix}$$ + +**Pauli-Liouville matrix** +$$ +R_{\mathcal E}= [(R_{\mathcal E})_{i,j}] = +\begin{pmatrix} +1 & 0 & 0 & 0 \\\\ +0 & 1-2(p_y+p_z) & 0 & 0 \\\\ +0 & 0 & 1-2(p_x+p_z) & 0 \\\\ +0 & 0 & 0 & 1-2(p_x+p_y) +\end{pmatrix}$$ + +**Superoperator** +$$(1-p') +\begin{pmatrix} +1 & 0 & 0 & 0 \\\\ +0 & 1 & 0 & 0\\\\ +0 & 0 & 1 & 0\\\\ +0 & 0 & 0 & 1 +\end{pmatrix} + +p_x +\begin{pmatrix} +0 & 0 & 0 & 1\\\\ +0 & 0 & 1 & 0\\\\ +0 & 1 & 0 & 0\\\\ +1 & 0 & 0 & 0 +\end{pmatrix}+ +p_y +\begin{pmatrix} +0 & 0 & 0 & 1\\\\ +0 & 0 & -1 & 0\\\\ +0 & -1 & 0 & 0\\\\ +1 & 0 & 0 & 0 +\end{pmatrix}+ +p_z +\begin{pmatrix} +1 & 0 & 0 & 0\\\\ +0 & -1 & 0 & 0\\\\ +0 & 0 & -1 & 0\\\\ +0 & 0 & 0 & 1 +\end{pmatrix} +$$ +So +$$ +\begin{pmatrix} +(1-p')+p_z & 0 & 0 & p_x+p_y \\\\ +0 & (1-p')-p_z & p_x-p_y & 0\\\\ +0 & p_x-p_y & (1-p')-p_z & 0\\\\ +p_x +p_y & 0 & 0 & (1-p')+p_z +\end{pmatrix} $$ + +**Choi** + +$$\begin{align} +\mathcal C &= \frac 1 2 ( |M_0\rangle\rangle\langle\langle M_0|+|M_1\rangle\rangle\langle\langle M_1|+|M_2\rangle\rangle\langle\langle M_2|+|M_3\rangle\rangle\langle\langle M_3|)\\\\ +&= \frac 1 2 +\begin{pmatrix} +(1-p')+p_z & 0 & 0 & (1-p')-p_z \\\\ +0 & p_x+p_y & p_x-p_y & 0\\\\ +0 & p_x-p_y & p_x+p_y & 0\\\\ +(1-p')-p_z & 0 & 0 & (1-p')+p_z +\end{pmatrix} +\end{align}$$ + +### Amplitude Damping or the $T_1$ channel +Amplitude damping is an energy dissipation (or relaxation) process. If a qubit it in it's excited state $|1\rangle$ it may emit energy, a photon, and transition to the ground state $|0\rangle$. In device physics an experiment that measures the decay over some time $t$, with functional form $\exp(-\Gamma t)$, is known as a $T_1$ experiment (where $T_1 = 1/\Gamma$). + +From the perspective of quantum channels the amplitude damping channel is interesting as is an example of a non-unital channel i.e. one that does not have the identity matrix as a fixed point $\mathcal E_{AD} (I) \neq I$. + +**Kraus** + +The Kraus operators are +$$\begin{align} +M_0 &= \sqrt{I - \gamma \sigma_+\sigma_-} += \begin{pmatrix} +1 & 0 \\\\ +0 & \sqrt{1-\gamma} +\end{pmatrix} +\\\\ +M_1&=\sqrt{\gamma}\sigma_- +=\begin{pmatrix} +0 & \sqrt{\gamma} \\\\ +0 & 0 +\end{pmatrix} +\end{align}$$ +where $\sigma_- = (\sigma_+)^\dagger= \frac 1 2 (X +i Y) =|0\rangle \langle 1| $. To relate this channel to a $T_1$ process we make the decay rate time dependant $\gamma(t) = \exp(-\Gamma t)$. + +**$\chi$ matrix (process)** + +$$ \chi(AD) = [\chi_{ij}] = \frac 1 4\begin{pmatrix} +(1+\sqrt{1-\gamma})^2 & 0 & 0 & \gamma \\\\ +0 & \gamma & -i\gamma & 0\\\\ +0 & i\gamma & \gamma & 0\\\\ +\gamma & 0 & 0 & (-1+\sqrt{1-\gamma})^2 +\end{pmatrix}$$ + +**Pauli-Liouville matrix** +$$ +R_{AD}= [(R_{AD})_{i,j}] = +\begin{pmatrix} +1 & 0 & 0 & 0 \\\\ +0 & \sqrt{1-\gamma} & 0 & 0 \\\\ +0 & 0 & \sqrt{1-\gamma} & 0 \\\\ +\gamma & 0 & 0 & 1-\gamma +\end{pmatrix}$$ + +**Superoperator** +$$ +\begin{pmatrix} +1 & 0 & 0 & \gamma \\\\ +0 & \sqrt{1-\gamma} & 0 & 0\\\\ +0 & 0 & \sqrt{1-\gamma} & 0\\\\ +0 & 0 & 0 & 1-\gamma +\end{pmatrix} +$$ + + +**Choi** + +$$\begin{align} +\mathcal C &= \frac 1 2 ( |M_0\rangle\rangle\langle\langle M_0|+|M_1\rangle\rangle\langle\langle M_1|)\\\\ +&=\frac 1 2 +\begin{pmatrix} +1 & 0 & 0 & \sqrt{1-\gamma} \\\\ +0 & 0 & 0 & 0\\\\ +0 & 0 & \gamma & 0\\\\ +\sqrt{1-\gamma} & 0 & 0 & 1-\gamma +\end{pmatrix} +\end{align}$$ + +## Examples: Two qubit channels +This section will not be as comprehensive we only consider two channels and two representations the operator sum representation (Kraus) and the superoperator representation. + +**Kraus** +The two channels we consider are: + +(1) A unitary channel on one qubit +$$\mathcal U_{IZ}(\rho) = U_{IZ} \rho U_{IZ}^\dagger $$ +with Kraus operator $U_{IZ} = I\otimes Z = IZ$. + +(2) A dephasing channel on one qubit +$$ \mathcal E_{IZ}(\rho) = (1-p)II \rho II + p IZ \rho IZ,$$ +with Kraus operators $M_0=\sqrt{1-p}II$ and $M_1= \sqrt{p}IZ$. + +**Superoperator** +The superoperator representations for both channels are +$$\mathcal U_{IZ} = U_{IZ}^* \otimes U_{IZ} = +{\rm diag}(1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1) +$$ + +and +$$\begin{align} +\mathcal E_{IZ} &= +(1-p)\,{\rm diag}(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)+ \\\\ +&\quad p \,{\rm diag}(1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1). +\end{align}$$ + +## References + +[IGST] Introduction to Quantum Gate Set Tomography +Greenbaum, +arXiv:1509.02921, (2015) +https://arxiv.org/abs/1509.02921 + +[QN] Quantum Nescimus. Improving the characterization of quantum systems from limited information +Harper, +PhD thesis University of Sydney, 2018 +https://ses.library.usyd.edu.au/handle/2123/17896 + +[GRAPTN] Tensor networks and graphical calculus for open quantum systems +Wood et al., +Quant. Inf. Comp. 15, 0579-0811 (2015) +https://arxiv.org/abs/1111.6950 + +[SVDMAT] Singular value decomposition and matrix reorderings in quantum information theory +Miszczak, +Int. J. Mod. Phys. C 22, No. 9, 897 (2011) +https://dx.doi.org/10.1142/S0129183111016683 +https://arxiv.org/abs/1011.1585 + +[VECQO] Vectorization of quantum operations and its use +Gilchrist et al., +arXiv:0911.2539, (2009) +https://arxiv.org/abs/0911.2539 + +[MATQO] On the Matrix Representation of Quantum Operations +Nambu et al., +arXiv: 0504091 (2005) +https://arxiv.org/abs/quant-ph/0504091 + +[DUAL] On duality between quantum maps and quantum states +Zyczkowski et al., +Open Syst. Inf. Dyn. 11, 3 (2004) +https://dx.doi.org/10.1023/B:OPSY.0000024753.05661.c2 +https://arxiv.org/abs/quant-ph/0401119 From ca40437f4ee72d8348fbb728bf91d8981af39fdc Mon Sep 17 00:00:00 2001 From: Joshua Combes Date: Wed, 19 Jun 2019 13:24:49 +1000 Subject: [PATCH 04/11] remove file and partial progress --- docs/Superoperator representations.md | 601 -------------------------- examples/tomography_state.ipynb | 582 ++++++++++++++++++++----- 2 files changed, 466 insertions(+), 717 deletions(-) delete mode 100644 docs/Superoperator representations.md diff --git a/docs/Superoperator representations.md b/docs/Superoperator representations.md deleted file mode 100644 index 0eb18fd0..00000000 --- a/docs/Superoperator representations.md +++ /dev/null @@ -1,601 +0,0 @@ -# Superoperator representations - -This document summarizes our conventions for the different superoperator representations. We show how to apply the channels to states in these represenations and how to convert channels between a subset of representations. By combining these conversion methods you can convert between any of the channel representations. - -This document is **not** intended to be a tutorial or a comprehensive review. At the bottom of the document there is a list of references with more information. This document was influenced by [IGST] and we recomend reading [GRAPTN] to gain deeper understading. (The references are listed at the bottom of this document.) Additionally these references explain, for example how to determine if a channel is unital or completely postive in the different representations. - - -## `vec` and `unvec` -Consider an $m\times m$ matrix -$$ A = [a_{ij}] = \begin{pmatrix} -a_{11} & a_{12} & \ldots & a_{1m} \\\\ -a_{21} & a_{22} & \ldots & a_{2m}\\\\ -\vdots & & \ddots & \vdots\\\\ -a_{m1} & a_{m2} & \ldots & a_{mm} -\end{pmatrix}$$ -where $i$ is a row and $j$ is a column index. - -We define `vec` to be column stacking - -$$ |A\rangle \rangle :={\rm vec}(A) = (a_{11},a_{21},\ldots,a_{m1},a_{12},\ldots,a_{mm})^T \quad (1) $$ - -were $T$ denotes a transpose. Clearly an inverse operation, `unvec` can be defined so that - -$$ {\rm unvec}\big ( {\rm vec}(A) \big ) = A.$$ - -Of course `unvec()` generally depends on the dimensions of $A$, which are not recoverable from `vec(A)`. We often focus on square A, but for generality, we require the dimensions for $A$, defaulting to the square root of the dimension of `vec(A)`. Column stacking corresponds to how matrices are stored in memory for column major storage conventions. - -Similarly we can define a row vectorization to be row stacking $ {\rm vec_r}(A) = (a_{11}, a_{12}, \ldots, a_{1m}, a_{21},\ldots, a_{mm})^T$. Note that ${\rm vec}(A) = {\rm vec_r}(A^T)$. In any case we will **not** use this row convention. - -### Matrix multiplication in vectorized form - -For matricies $A,B,C$ - -$$\begin{align} -{\rm vec}(ABC) = (C^T\otimes A) {\rm vec}(B), \quad (2) -\end{align}$$ -which is sometimes called Roth's lemma. - -Eq. 2 is useful in representing quantum operations on mixed quantum states. For example consider -$$ \rho' = U \rho U^\dagger.$$ -We can use Eq. 1 to write this as - -$$ {\rm vec}(\rho') = \{(U^\dagger)^T \otimes U \} {\rm vec}(\rho) -= (U^*\otimes U) |\rho\rangle\rangle$$ -so -$$ |\rho'\rangle \rangle = \mathcal U |\rho\rangle\rangle, -$$ -where $\mathcal U = U^*\otimes U$. The nice thing about this is the operator (the state) has become a vector and the superoperator (the left right action of $U$) has become an operator. - -Some other useful results related to vectorization are - -$ {\rm vec}([A,X])= (I\otimes A - A^T\otimes I) {\rm vec}(X)$ - -${\rm vec}(ABC) = (I\otimes AB) {\rm vec}( C ) = (C^T B^T\otimes I) {\rm vec}(A)$ - -${\rm vec}(AB) = (I\otimes A) {\rm vec}(B) = (B^T\otimes I) {\rm vec}(A)$. - - -## Matrix operations on Bipartite matrices: Reshuffling, SWAP, and tranposition - -This section is based on the Wood et al. presentation in [GRAPTN]. - -As motivation for this section consider the Kraus representation theorem. It shows that a quantum channel can be represented as a partial trace over a unitary operation on a larger Hilbert space. Actually the unitary is on a bipartite Hilbert space. - - -When representing quantum channels one insight is used may times. - -Consider two Hilbert spaces $\mathbb H_A$ and $\mathbb H_B$ with dimensions $d_A$ and $d_B$ respectively. An abstract quantum process matrix $\mathcal Q$ lives in the combined (bipartite) space of $\mathbb H_A \otimes \mathbb H_B$ so $\mathcal Q$ is a $d_A^2\times d_B^2$ matrix. - -We can represent the process as a tensor with components - -$$\mathcal Q_{m,\mu;n,\nu} = \langle m, \mu |\mathcal Q |n,\nu \rangle $$ -where $|n,\nu\rangle = |n\rangle \otimes |\nu\rangle$, $m,n\in \{0,\ldots, d_A-1\}$, $\mu,\nu\in \{0,\ldots, d_B-1\}$ and all vectors are in the standard basis. - -With respect to these indicies some useful operations are [GRAPTN]: - -Transpose $T$: $\mathcal Q_{m,\mu;n,\nu} \mapsto \mathcal Q_{n,\nu;m,\mu},$ -SWAP: $\mathcal Q_{m,\mu;n,\nu} \mapsto \mathcal Q_{\mu,m;\nu,n},$ -Row-reshuffling $R_r$: $\mathcal Q_{m,\mu;n,\nu} \mapsto \mathcal Q_{m,n;\mu,\nu},$ -Col-reshuffling $R$: $\mathcal Q_{m,\mu;n,\nu} \mapsto \mathcal Q_{\nu,\mu;n,m}.$ - -The importance of understanding reshuffling can be understood as understanding the relationship between -$${\rm vec}(G)\otimes {\rm vec}(\Gamma) \quad {\rm and} \quad {\rm vec}(G\otimes\Gamma)$$ -where $G$ and $\Gamma$ are matrices that act on $\mathbb H_A$ and $\mathbb H_B$ respectively, as explained in [VECQO]. - -### A note on numerical implementations -Most linear algebra (or tensor) libraries have the ablity to `reshape` a matrix and `swapaxes` (or sometimes it is called `permute_dims`). - -If you are trying to reshuffle indicies usually the first job is to write your matrix in tensor form. This requires reshaping a $d_A^2\times d_B^2$ matrix into a $d_A\times d_A\times d_B \times d_B$ tensor. Next you `permute_dims` or `swapaxes`. Often $d_A = d_B$ so we `reshape` to a Matrix that has the same dimensions as the orignal $d_A^2\times d_A^2$ matix. - - -## The $n$-qubit Pauli basis - The $n$-qubit Pauli basis is denoted $\mathcal P^{\otimes n} $ where $\mathcal P = \{ I, X, Y, Z \}$ are the usual Pauli matricies. It is an operator basis for the $d = 2^n$ dimensional Hilbert space and there are $d^2 = 4^n$ operators in $\mathcal P^{\otimes n} $. If one divides all the operators by $\sqrt{d}$ the basis is orthonormal with respect to the Hilbert-Schmidt inner product. - -It is often convenient to index the $d^2$ operators with a single label, e.g. $P_1=I^{\otimes n},\, \ldots,\, P_{d^2}= Z^{\otimes n}$ (or $P_0=I^{\otimes n}$ if you like zero indexing). In anycase, as these operators are Hermitian and unitary they obey $P_i^2=I^{\otimes n}$. - -To be explicit, for two qubits $d=4$ and we have 16 operators e.g. $\{II, IX, IY, IZ, XI, XX, XY, ..., ZZ\}$ were $II$ should be interpreted as $I\otimes I$ etc. The single index would be $\{P_1, P_2, P_3, P_4, P_5, P_6, P_7, ..., P_{16}\}$. - -## Quantum channels in the Kraus decomposition (or operator-sum representation) -A completely positive map on the state $\rho$ can be written using a set of Kraus operators $\{ M_k \}$ as - - -$$\rho' =\mathcal E (\rho) = \sum_{k=1}^N M_k \rho M_k^\dagger, $$ -where $\rho'$ is the state at the output of the channel. - -If $\sum_k M_k^\dagger M_k= I $ the map is trace preserving. It turns out that $N\le d^2$ where $d$ is the Hilbert space dimension e.g. $d=2^n$ for $n$ qubits. Kraus operators are not necessarily unique, sometimes there is a unitary degree of freedom in the Kraus representation. - -## Kraus to $\chi$ matrix (aka chi or process matrix) -We choose to represent the $\chi$ matrix in the Pauli basis. So we expand each of the Kraus operators in the $n$ qubit Pauli basis - -$M_k = \sum^{d^2}_{j=1}c_{kj}\,P_j$ - -where $\mathcal P_j \in \mathcal P ^{\otimes n}$. - -Now the channel $\mathcal E$ can be written as - -$\mathcal E (\rho) = \sum_{i,j=1}^{d^2} \chi_{i,j} P_i\rho P_j ,$ - -where - -$$\chi_{i,j} = \sum_k c_{k,i} c_{k,j}^*$$ - -is an element of the process matrix $\chi$ of size $d^2 \times d^2$. If the channel is CP the $\chi$ matrix is a Hermitian and positive semidefinite. - -The $\chi$ matrix can be related to the (yet to be defined) Choi matrix via a change of basis. Typically the Choi matrix is defined in the computational basis, while the $\chi$ matrix uses the Pauli basis. Moreover, they may have different normalization conventions. - -In this light, after reviewing the Kraus to Choi conversion it is simple to see that the above is equivalent to first defining - -$$ -|c_{k}\rangle\rangle = U_{c2p}{\rm vec}(M_k) -$$ -then -$$ -\chi = \sum_k |c_{k}\rangle\rangle \langle\langle c_k|. -$$ - -## Kraus to Pauli-Liouville matrix (Pauli transfer matrix) - -We begin by defining the Pauli vector representation of the state $\rho$ - -$$ |\rho \rangle \rangle = \sum_j c_j |P_j\rangle \rangle$$ - -where $P_j \in \mathcal P^{\otimes n}$ and $c_j = (1/d) \langle\langle P_j|\rho \rangle\rangle$. - -The Pauli-Liouville or Pauli transfer matrix representation of the channel $\mathcal E$ is denoted by $R_{\mathcal E}$. The matrix elements are - -$$(R_{\mathcal E})_{i,j} = \frac 1 d {\rm Tr}[P_i \mathcal E(P_j)].$$ - -Trace preservation implies $(R_{\mathcal E})_{0,j} = \delta_{0,j}$, i.e. the first row is one and all zeros. Unitality implies $(R_{\mathcal E})_{i,0} = \delta_{i,0}$, the first column is one and all zeros. - -In this representation the channel is applied to the state by multiplication - -$$|\rho' \rangle \rangle = R_{\mathcal E} |\rho \rangle \rangle.$$ - - -## Kraus to Superoperator (Liouville) -We already saw an example of this in the setion on `vec`-ing. There we re-packaged conjugation by unitary evolution into the action of a matrix on a vec'd density operator. Unitary evolution is simply the case of a single Kraus operator, so we generalize this by taking a sum over all Kraus operators. - -Consider the set of Kraus operators $\{ M_k \}$. The corresponding quantum operation is $\mathcal E (\rho) = \sum_k M_k \rho M_k^\dagger $. - -Using the vec operator (see Eq. 1) this implies a superoperator - -$$\mathcal E = \sum_k (M_k^\dagger)^T \otimes M_k = \sum_k M_k^* \otimes M_k,$$ -which acts as $\mathcal E |\rho\rangle \rangle$ using Equation 2. - -**Note** In quantum information a superoperator is an abstract concept. The object above is a concrete representation of the abstract concept in a particular basis. In the NMR community this particular construction is called the Liouville representation. The Pauli-Liouville representation is attained from Liouville representation by a change of basis, so the similarity in naming makes sense. - -## Kraus to Choi - -Define $ | \eta \rangle = \frac{1}{\sqrt{d}}\sum_{i=0}^{d-1}|i,i \rangle $ - -One can show that - -$|A\rangle \rangle = {\rm vec}(A) = \sqrt{d} (I\otimes A) |\eta\rangle$. - -The Choi state is - -$$\begin{align} -\mathcal C &= I\otimes \mathcal E (|\eta \rangle \langle \eta|) \\\\ -&=\sum_i (I \otimes M_i) |\eta \rangle \langle \eta | ( I \otimes M_i^\dagger)\\\\ -& = \frac{1}{d} \sum_i {\rm vec}(M_i) {\rm vec} (M_i) ^\dagger \\\\ -& = \frac{1}{d} \sum_i |M_i\rangle \rangle \langle\langle M_i |. -\end{align}$$ - -An often quoted equivalent expression is - -$\begin{align} -\mathcal C &= I\otimes \mathcal E (|\eta \rangle \langle \eta|) \\\\ -&=\sum_{ij} |i\rangle \langle j| \otimes \mathcal E (|i \rangle \langle j | ). -\end{align}$ - -## $\chi$ matrix to Pauli-Liouville matrix -$$(R_{\mathcal E})_{i,j} = \frac 1 d \sum_{k,l}\chi_{k,l} {\rm Tr}[ P_i P_k P_j P_l].$$ - -## Superoperator to Pauli-Liouville matrix -The standard basis on $n$ qubits is called the computational basis. It is essentially all the strings $|c_1\rangle=|0..0\rangle$ through to $|c_{\rm max}\rangle = |1...1\rangle$. To convert between a superoperator and the Pauli-Liouville matrix representation we need to do a change of basis from the computational basis to the Pauli basis. This is acheived by the unitary - -$$ U_{c2p}= \sum_{k=1}|c_k\rangle\langle\langle P_k|.$$ - -The we have - -$$ R_{\mathcal E} = U_{c2p} \mathcal E U_{c2p}^\dagger.$$ - - -## Superoperator to Choi -The conversion from the superoperator to a Choi matrix $\mathcal C$ is simply a (column) reshuffling operation - -$$ \mathcal C = R(\mathcal E).$$ - -It turns out that $ \mathcal E = R(\mathcal C)$ which means that $\mathcal E= R(R(\mathcal E))$. - -## Pauli-Liouville matrix to Superoperator -To convert between the Pauli-Liouville matrix and the superoperator representation we need to to a change of basis from the Pauli basis to the computational basis. This is acheived by the unitary - -$$ U_{p2c}= \sum_{k=1}|P_k\rangle\rangle \langle k|,$$ -which is simply $U_{c2p}^\dagger$. - -The we have - -$$\mathcal E = U_{p2c}R_{\mathcal E}U_{p2c}^\dagger.$$ - - -## Pauli-Liouville to Choi -We obtain the normalized Choi matrix using the expression - -$$ \rho_{\mathcal E} = \frac{1}{d^2}\sum_{i,j=1}^{d^2} (R_{\mathcal E})_{i,j} \, P_j^T \otimes P_i.$$ - - - -## Choi to Kraus -This is simply the reverse of the Kraus to Choi procedure. - -Given the Choi matrix $\mathcal C$ we find it's eigenvalues $\{\lambda_i\}$ and vectors $\{|M_i\rangle\rangle \}$. Then the Kraus operators are - -$$ M_i = \sqrt{\lambda_i}\, {\rm unvec}\big (|M_i\rangle\rangle\big),$$ - -For numerical implementation one usually puts a threshold on the eigenvalues, say $\lambda> 10^{-10}$, to prevent numerical instablities. - -## Choi to Pauli-Liouville -First we normalize the Choi representation - -$$\begin{align} -\rho_{\mathcal E}=\frac 1 d \mathcal C = \frac 1 d \sum_{ij} |i\rangle \langle j| \otimes \mathcal E (|i \rangle \langle j | ) -\end{align}$$ - -Then the matrix elements of the Pauli-Liouville matrix representation of the channel can be obtained from the Choi state using - -$$(R_{\mathcal E})_{i,j} ={\rm Tr}[ \rho_{\mathcal E} \, P_j^T \otimes P_i].$$ - -## Choi to Superoperator -The conversion from a Choi matrix $\mathcal C$ to a superoperator is simply a (column) reshuffling operation - -$$ \mathcal E = R(\mathcal C).$$ - -It turns out that $ \mathcal C = R(\mathcal E)$ which means that $\mathcal C= R(R(\mathcal C))$. - - - -## Examples: One qubit channels -Some observations: - -* The Choi matrix of a unitary process always has rank 1. -* The superoperator / Liouville representation of a unitary process is always full rank. -* The eigenvalues of a Choi matrix give you an upper bound to the probability a particular (canonical) Kraus operator will occur (generally that probability depends on the state). This is helpful when sampling Kraus operators (you can test for which occurred accoridng to the order of these eigenvalues). -* The $\chi$ matrix (in the Pauli basis) is very convenient for computing the result of Pauli twirling or Clifford twirling the corresponding process. - -### Unitary Channels or Gates -As an example we look at two single qubit channels $R_z(\theta) = \exp(-i \theta Z/2)$ and $H$. The Hadamard is is a nice channel to examine as it transforms $X$ and $Z$ to each other -$$\begin{align} -H Z H^\dagger &=X\\\\ -H X H^\dagger &= Z -\end{align}$$ -which can be easily seen in some of the channel representations. - -**Kraus** - -As the channel is unitary there is only one Kraus operator used in the operator sum representation. However we express them in the Pauli basis to make some of the below manipulations easier -$$\begin{align} -R_z(\theta) &= \cos(\theta/2) I - i \sin(\theta/2) Z\\\\ -&= \begin{pmatrix} -e^{-i\theta/2} & 0 \\\\ -0 & e^{i\theta /2} -\end{pmatrix} -\\\\ -H &= \frac{1}{\sqrt{2}} (X+Z)\\\\ -&=\frac{1}{\sqrt{2}} - \begin{pmatrix} -1 & 1 \\\\ -1 & -1 -\end{pmatrix} -\end{align}$$ - -**$\chi$ matrix (process)** - -$$ \chi(R_z) = [\chi_{ij}] = \frac 1 2\begin{pmatrix} -1+\cos(\theta) & 0 & 0 & i \sin(\theta) \\\\ -0 & 0 & 0 & 0\\\\ -0 & 0 & 0 & 0\\\\ --i\sin(\theta) & 0 & 0 & 1-\cos(\theta) -\end{pmatrix}$$ - -$$ \chi(H) = [\chi_{ij}] = \frac 1 2\begin{pmatrix} -0 & 0 & 0 & 0 \\\\ -0 & 1 & 0 & 1\\\\ -0 & 0 & 0 & 0\\\\ -0 & 1 & 0 & 1 -\end{pmatrix}$$ - -**Pauli-Liouville matrix** -$$ -R_{R_z(\theta)}= [(R_{R_z(\theta)})_{i,j}] = -\begin{pmatrix} -1 & 0 & 0 & 0 \\\\ -0 & \cos(\theta) & -\sin(\theta) & 0 \\\\ -0 & \sin(\theta) & \cos(\theta) & 0 \\\\ -0 & 0 & 0 & 1 -\end{pmatrix}$$ - -$$ -R_{H}= [(R_{H})_{i,j}] = -\frac 1 2\begin{pmatrix} -1 & 0 & 0 & 0 \\\\ -0 & 0 & 0 & 1 \\\\ -0 & 0 & -1 & 0 \\\\ -0 & 1 & 0 & 0 -\end{pmatrix}$$ - -**Superoperator** - -$$ \mathcal R_z(\theta) = R_z(\theta)^*\otimes R_z(\theta)= -\begin{pmatrix} -1 & 0 & 0 & 0 \\\\ -0 & e^{i\theta} & 0 & 0\\\\ -0 & 0 & e^{-i\theta} & 0\\\\ -0 & 0 & 0 & 1 -\end{pmatrix} -$$ - -$$ \mathcal H = H^*\otimes H=\frac 1 2 -\begin{pmatrix} -1 & 1 & 1 & 1 \\\\ -1 & -1 & 1 & -1\\\\ -1 & 1 & -1 &-1\\\\ -1 & -1 & -1 & 1 -\end{pmatrix} -$$ - -**Choi** - -$$\begin{align} -\mathcal C_{R_z} &= \frac 1 2 |R_z(\theta)\rangle\rangle\langle\langle R_z(\theta)|\\\\ -&=\frac 1 2 -\begin{pmatrix} -1 & 0 & 0 & e^{-i\theta} \\\\ -0 & 0 & 0 & 0\\\\ -0 & 0 & 0 & 0\\\\ -e^{i\theta} & 0 & 0 & 1 -\end{pmatrix} -\end{align}$$ - -$$\begin{align} -\mathcal C_H &= \frac 1 2 |H\rangle\rangle\langle\langle H|\\\\ -&=\frac 1 2 -\begin{pmatrix} -1 & 1 & 1 & -1 \\\\ -1 & 1 & 1 & -1\\\\ -1 & 1 & 1 & -1\\\\ --1 & -1 & -1 & 1 -\end{pmatrix} -\end{align}$$ - - - -### Pauli Channels -Pauli channels are nice because they are diagonal in two representations and they have the *depolarlizing channel* as a speical case. - -In the operator sum representation a single qubit Pauli channel is defined as -$$\mathcal E(\rho) = (1-p_x-p_y-p_z) I \rho I + p_x X\rho X + p_y Y \rho Y + p_z Z \rho Z$$ -where $p_x,p_y,p_z\ge 0$ and $p_x+p_y+p_z\le 1$. - -If we define $p' = p_x+p_y+p_z$ then - -$$\mathcal E(\rho) = (1-p') I \rho I + p_x X\rho X + p_y Y \rho Y + p_z Z \rho Z.$$ - -The Pauli channel specializes to the depolarizing channel when -$$ p' = \frac 3 4 p \quad {\rm and}\quad p_x=p_y=p_z = p -$$ -for $0\le p \le 1$. - -**Kraus** - -The Kraus operators used in the operator sum representation are -$$\begin{align} -M_0 &= \sqrt{1-p'}I \\\\ -M_1 &= \sqrt{p_x}X \\\\ -M_2 &= \sqrt{p_y}Y \\\\ -M_3 &= \sqrt{p_z}Z. -\end{align}$$ - -**$\chi$ matrix (process)** - -$$ \chi = [\chi_{ij}] = \begin{pmatrix} -(1-p') & 0 & 0 & 0 \\\\ -0 & p_x & 0 & 0\\\\ -0 & 0 & p_y & 0\\\\ -0 & 0 & 0 & p_z -\end{pmatrix}$$ - -**Pauli-Liouville matrix** -$$ -R_{\mathcal E}= [(R_{\mathcal E})_{i,j}] = -\begin{pmatrix} -1 & 0 & 0 & 0 \\\\ -0 & 1-2(p_y+p_z) & 0 & 0 \\\\ -0 & 0 & 1-2(p_x+p_z) & 0 \\\\ -0 & 0 & 0 & 1-2(p_x+p_y) -\end{pmatrix}$$ - -**Superoperator** -$$(1-p') -\begin{pmatrix} -1 & 0 & 0 & 0 \\\\ -0 & 1 & 0 & 0\\\\ -0 & 0 & 1 & 0\\\\ -0 & 0 & 0 & 1 -\end{pmatrix} + -p_x -\begin{pmatrix} -0 & 0 & 0 & 1\\\\ -0 & 0 & 1 & 0\\\\ -0 & 1 & 0 & 0\\\\ -1 & 0 & 0 & 0 -\end{pmatrix}+ -p_y -\begin{pmatrix} -0 & 0 & 0 & 1\\\\ -0 & 0 & -1 & 0\\\\ -0 & -1 & 0 & 0\\\\ -1 & 0 & 0 & 0 -\end{pmatrix}+ -p_z -\begin{pmatrix} -1 & 0 & 0 & 0\\\\ -0 & -1 & 0 & 0\\\\ -0 & 0 & -1 & 0\\\\ -0 & 0 & 0 & 1 -\end{pmatrix} -$$ -So -$$ -\begin{pmatrix} -(1-p')+p_z & 0 & 0 & p_x+p_y \\\\ -0 & (1-p')-p_z & p_x-p_y & 0\\\\ -0 & p_x-p_y & (1-p')-p_z & 0\\\\ -p_x +p_y & 0 & 0 & (1-p')+p_z -\end{pmatrix} $$ - -**Choi** - -$$\begin{align} -\mathcal C &= \frac 1 2 ( |M_0\rangle\rangle\langle\langle M_0|+|M_1\rangle\rangle\langle\langle M_1|+|M_2\rangle\rangle\langle\langle M_2|+|M_3\rangle\rangle\langle\langle M_3|)\\\\ -&= \frac 1 2 -\begin{pmatrix} -(1-p')+p_z & 0 & 0 & (1-p')-p_z \\\\ -0 & p_x+p_y & p_x-p_y & 0\\\\ -0 & p_x-p_y & p_x+p_y & 0\\\\ -(1-p')-p_z & 0 & 0 & (1-p')+p_z -\end{pmatrix} -\end{align}$$ - -### Amplitude Damping or the $T_1$ channel -Amplitude damping is an energy dissipation (or relaxation) process. If a qubit it in it's excited state $|1\rangle$ it may emit energy, a photon, and transition to the ground state $|0\rangle$. In device physics an experiment that measures the decay over some time $t$, with functional form $\exp(-\Gamma t)$, is known as a $T_1$ experiment (where $T_1 = 1/\Gamma$). - -From the perspective of quantum channels the amplitude damping channel is interesting as is an example of a non-unital channel i.e. one that does not have the identity matrix as a fixed point $\mathcal E_{AD} (I) \neq I$. - -**Kraus** - -The Kraus operators are -$$\begin{align} -M_0 &= \sqrt{I - \gamma \sigma_+\sigma_-} -= \begin{pmatrix} -1 & 0 \\\\ -0 & \sqrt{1-\gamma} -\end{pmatrix} -\\\\ -M_1&=\sqrt{\gamma}\sigma_- -=\begin{pmatrix} -0 & \sqrt{\gamma} \\\\ -0 & 0 -\end{pmatrix} -\end{align}$$ -where $\sigma_- = (\sigma_+)^\dagger= \frac 1 2 (X +i Y) =|0\rangle \langle 1| $. To relate this channel to a $T_1$ process we make the decay rate time dependant $\gamma(t) = \exp(-\Gamma t)$. - -**$\chi$ matrix (process)** - -$$ \chi(AD) = [\chi_{ij}] = \frac 1 4\begin{pmatrix} -(1+\sqrt{1-\gamma})^2 & 0 & 0 & \gamma \\\\ -0 & \gamma & -i\gamma & 0\\\\ -0 & i\gamma & \gamma & 0\\\\ -\gamma & 0 & 0 & (-1+\sqrt{1-\gamma})^2 -\end{pmatrix}$$ - -**Pauli-Liouville matrix** -$$ -R_{AD}= [(R_{AD})_{i,j}] = -\begin{pmatrix} -1 & 0 & 0 & 0 \\\\ -0 & \sqrt{1-\gamma} & 0 & 0 \\\\ -0 & 0 & \sqrt{1-\gamma} & 0 \\\\ -\gamma & 0 & 0 & 1-\gamma -\end{pmatrix}$$ - -**Superoperator** -$$ -\begin{pmatrix} -1 & 0 & 0 & \gamma \\\\ -0 & \sqrt{1-\gamma} & 0 & 0\\\\ -0 & 0 & \sqrt{1-\gamma} & 0\\\\ -0 & 0 & 0 & 1-\gamma -\end{pmatrix} -$$ - - -**Choi** - -$$\begin{align} -\mathcal C &= \frac 1 2 ( |M_0\rangle\rangle\langle\langle M_0|+|M_1\rangle\rangle\langle\langle M_1|)\\\\ -&=\frac 1 2 -\begin{pmatrix} -1 & 0 & 0 & \sqrt{1-\gamma} \\\\ -0 & 0 & 0 & 0\\\\ -0 & 0 & \gamma & 0\\\\ -\sqrt{1-\gamma} & 0 & 0 & 1-\gamma -\end{pmatrix} -\end{align}$$ - -## Examples: Two qubit channels -This section will not be as comprehensive we only consider two channels and two representations the operator sum representation (Kraus) and the superoperator representation. - -**Kraus** -The two channels we consider are: - -(1) A unitary channel on one qubit -$$\mathcal U_{IZ}(\rho) = U_{IZ} \rho U_{IZ}^\dagger $$ -with Kraus operator $U_{IZ} = I\otimes Z = IZ$. - -(2) A dephasing channel on one qubit -$$ \mathcal E_{IZ}(\rho) = (1-p)II \rho II + p IZ \rho IZ,$$ -with Kraus operators $M_0=\sqrt{1-p}II$ and $M_1= \sqrt{p}IZ$. - -**Superoperator** -The superoperator representations for both channels are -$$\mathcal U_{IZ} = U_{IZ}^* \otimes U_{IZ} = -{\rm diag}(1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1) -$$ - -and -$$\begin{align} -\mathcal E_{IZ} &= -(1-p)\,{\rm diag}(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)+ \\\\ -&\quad p \,{\rm diag}(1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1). -\end{align}$$ - -## References - -[IGST] Introduction to Quantum Gate Set Tomography -Greenbaum, -arXiv:1509.02921, (2015) -https://arxiv.org/abs/1509.02921 - -[QN] Quantum Nescimus. Improving the characterization of quantum systems from limited information -Harper, -PhD thesis University of Sydney, 2018 -https://ses.library.usyd.edu.au/handle/2123/17896 - -[GRAPTN] Tensor networks and graphical calculus for open quantum systems -Wood et al., -Quant. Inf. Comp. 15, 0579-0811 (2015) -https://arxiv.org/abs/1111.6950 - -[SVDMAT] Singular value decomposition and matrix reorderings in quantum information theory -Miszczak, -Int. J. Mod. Phys. C 22, No. 9, 897 (2011) -https://dx.doi.org/10.1142/S0129183111016683 -https://arxiv.org/abs/1011.1585 - -[VECQO] Vectorization of quantum operations and its use -Gilchrist et al., -arXiv:0911.2539, (2009) -https://arxiv.org/abs/0911.2539 - -[MATQO] On the Matrix Representation of Quantum Operations -Nambu et al., -arXiv: 0504091 (2005) -https://arxiv.org/abs/quant-ph/0504091 - -[DUAL] On duality between quantum maps and quantum states -Zyczkowski et al., -Open Syst. Inf. Dyn. 11, 3 (2004) -https://dx.doi.org/10.1023/B:OPSY.0000024753.05661.c2 -https://arxiv.org/abs/quant-ph/0401119 diff --git a/examples/tomography_state.ipynb b/examples/tomography_state.ipynb index decf2318..54506e32 100644 --- a/examples/tomography_state.ipynb +++ b/examples/tomography_state.ipynb @@ -6,8 +6,8 @@ "source": [ "# State tomography\n", "\n", - "**Classical tomography** \n", - "The simplest classical analogy to estimating a quantum state using tomography is estimating the bias of a coin. The bias, denoted bias by $p$, is analogous to the quantum state in a way that will explained shortly.\n", + "### Classical tomography \n", + "The simplest classical analogy to estimating a quantum state using tomography is estimating the bias of a coin. The bias, denoted bias by $p$, is analogous to the quantum state in a way that will be explained shortly.\n", "\n", "If we have access to $n_{\\rm Tot}$ independent experiements (or measurements) and observe $n_{\\rm H}$ heads then maximum likelihood estimate for the bias of the coin is\n", "\n", @@ -32,21 +32,26 @@ "where $I$ and $Z$ are the identity and the Pauli-z matrix. This parameterizes the states along the z-axis of the Bloch sphere\n", "\n", "\n", - "![alt txt](figs/bloch.png)\n", + "\"Drawing\"\n", + "\n", "\n", "\n", "The relationship between the $Z$ expectation value and the coin bias is\n", "\n", "$$z:= \\langle Z \\rangle = {\\rm Tr}[Z \\rho] = 2 p -1.$$\n", "\n", - "In this analogy the pure states $|0\\rangle$ and $|1\\rangle$ corespond to the coin biases $p=0$ and $p=1$ respectively, all other (mixed) states are convex mixtures of these extremal points." + "In this analogy the pure states $|0\\rangle$ and $|1\\rangle$ corespond to the coin biases $p=1$, $p=0$ and z expectation values $z=+1$, $z=-1$ respectively. All other (mixed) states are convex mixtures of these extremal points e.g. the fair coin, i.e. $p=1/2$, corresponds to $z = 0$ and the state \n", + "$$\n", + "\\rho \n", + "= \\begin{pmatrix} 0.5 & 0\\\\ 0 & 0.5\\end{pmatrix}. \n", + "$$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "**Quantum tomography of a single qubit** \n", + "### Quantum tomography of a single qubit\n", "\n", "The simplest quantum system to tomograph is a single qubit. Like before we parameterize the state with respect to a set of operators \n", "$$\\begin{align}\n", @@ -67,13 +72,35 @@ "The physics of our system means that our default our measurement gives us the Z basis statistics. We already constructed an estimator to go from the coin flip statistics to the Z expectation: $2p -1$. \n", "\n", "\n", - "Now we need to, measure the statistics of the operators X and Y. Essentially this means we must rotate our state after we prepare it but before it is measured (or equivalently rotate our measurement basis). If we rotate the state as $\\rho\\mapsto U\\rho U^\\dagger$ and then do our usual Z-basis measurement, then this is equivalent to rotating the measured observable as $Z \\mapsto U^\\dagger Z U$ and keeping our state $\\rho$ unchanged. This is the disticntion between the [Heisenberg and Schrödinger pictures](https://en.wikipedia.org/wiki/Heisenberg_picture#Summary_comparison_of_evolution_in_all_pictures). The Heisenberg picture point of view then allows us to see that if we apply a rotation such as $U=R_y(\\pi/2)$ then this rotates the observable as $R_y(-\\pi/2)ZR_y(+\\pi/2)=\\cos(\\pi/2) Z - \\sin(\\pi/2) X = -X$. Similarly, we could rotate by $U=R_x(\\pi/2)$ to measure the Y observable. \n", + "Now we need to, measure the statistics of the operators X and Y. Essentially this means we must rotate our state after we prepare it but before it is measured (or equivalently rotate our measurement basis). If we rotate the state as $\\rho\\mapsto U\\rho U^\\dagger$ and then do our usual Z-basis measurement, then this is equivalent to rotating the measured observable as $Z \\mapsto U^\\dagger Z U$ and keeping our state $\\rho$ unchanged. This is the disticntion between the [Heisenberg and Schrödinger pictures](https://en.wikipedia.org/wiki/Heisenberg_picture#Summary_comparison_of_evolution_in_all_pictures). The Heisenberg picture point of view then allows us to see that if we apply a rotation such as $R_y(\\alpha) = \\exp(-i \\alpha Y /2)$ for $\\alpha = -\\pi/2$ then this rotates the observable as $R_y(\\pi/2)ZR_y(-\\pi/2)=\\cos(\\pi/2) Z + \\sin(\\pi/2) X = X$. Similarly, we could rotate by $U=R_x(\\pi/2)$ to measure the Y observable. \n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Quantum state tomography in general \n", + "In this section we closely follow the reference [PBT]. \n", + "\n", + "When thinking about tomography it is useful to introduce the notation of \"super kets\" $|O\\rangle \\rangle = {\\rm vec}(O)$ for an operator $O$.\n", + "The dual vector is the corresponding \"super bra\" $\\langle\\langle O|$ and represents $O^\\dagger$. This vector space has is equiped with the Hilbert-Schmidt inner product $\\langle\\langle A | B \\rangle\\rangle = {\\rm Tr}[A^\\dagger B]$. For more information see [vec and unvec in superoperator_representations.md](../.././forest-benchmarking/docs/superoperator_representations.md) and the [superoperator_tools ipython notebook](superoperator_tools.ipynb).\n", + "\n", + "A quantum state matrix on $n$ qubits, a $D =2^n$ dimensional Hilbert\n", + "space, can be represented by \n", + "$$\n", + " \\rho = \\frac{1}{D} I + \\sum_{\\alpha=1}^{D^2-1}x_\\alpha B_\\alpha\n", + "$$\n", + "where the coefficents $x_\\alpha$ are defined by $x_\\alpha = \\langle\\langle B_\\alpha | \\rho \\rangle\\rangle$ for a basis of Hermitian operators\n", + "$\\{ B_\\alpha \\}$ that is orthonormal under the Hilbert-Schmidt inner product\n", + "$\\langle\\langle B_\\alpha | B_\\beta\\rangle\\rangle =\\delta_{\\alpha,\\beta}$.\n", + "\n", + "For many qubits, tensor products of Pauli matrices \n", + "matrices are the natural Hermitian basis. For two qubits define $B_5 = X \\otimes X$ and $B_6 = X \\otimes Y$ then $\\langle\\langle B_5 | B_6\\rangle\\rangle =0$. It is typical to choose $B_0 = I / \\sqrt {D}$ to be the only traceful element.\n", "\n", - " \n", + "State tomography involves estimating or measuring the expectation values of all the operators $\\{ B_\\alpha \\}$. If you can reconstruct all the operators $\\{ B_\\alpha \\}$ then your measurement is said to be **tomographically complete**. The operators that need to be estimatated are programatically given by `itertools.product(['I', 'X', 'Y', 'Z'], repeat=n_qubits)`. From these measurements, we can reconstruct a density matrix $\\rho$ on `n_qubits`.\n", "\n", "\n", - "**Quantum state tomography in general** \n", - "Involves measuring all the expectation value of all the operators given by `itertools.product(['X', 'Y', 'Z], repeat=n_qubits)` many times. From these measurements, we can reconstruct a density matrix $\\rho$ on `n_qubits`." + "Most research in quantum state tomography is to do with finding estimators with desirable properties, e.g. [Minimax tomography](https://arxiv.org/abs/1503.03100), although experiment design is also considered e.g. [adaptive quantum state tomography](https://arxiv.org/abs/1303.0436). \n" ] }, { @@ -83,43 +110,55 @@ "**More information** \n", "See the following references:\n", "\n", - "[Quantum tomography wikipedia page](https://en.wikipedia.org/wiki/Quantum_tomography)\n", + "[QTW] [Quantum tomography wikipedia page](https://en.wikipedia.org/wiki/Quantum_tomography)\n", "\n", - "*Initialization and characterization of open quantum systems* \n", + "[CWPHD] *Initialization and characterization of open quantum systems* \n", "Christopher Wood, \n", "Chapter 3, PhD Thesis, University of Waterloo (2015) \n", "http://hdl.handle.net/10012/9557 \n", "\n", "\n", - "Introduction to Quantum Gate Set Tomography \n", + "[IGST] *Introduction to Quantum Gate Set Tomography* \n", "Daniel Greenbaum, \n", "arXiv:1509.02921 (2015) \n", - "https://arxiv.org/abs/1509.02921 " + "https://arxiv.org/abs/1509.02921 \n", + "\n", + "\n", + "[PBT] *Practical Bayesian Tomography* \n", + "Christopher Granade et al. \n", + "New J. Phys. 18, 033024 (2016) \n", + "https://dx.doi.org/10.1088/1367-2630/18/3/033024 \n", + "https://arxiv.org/abs/1509.03770" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Some imports" + "## Quantum state tomography in `forest.benchmarking`" ] }, { - "cell_type": "code", - "execution_count": 1, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "import numpy as np\n", - "from pyquil import Program, get_qc\n", - "from pyquil.gates import *" + "The basic workflow is:\n", + "\n", + "1. prepare a state by specifying a pyQuil program\n", + "2. construct a list of observables that are needed to estimate the state; we collect this into an object called an `ObservablesExperiment`.\n", + "3. Aquire the data by running the program on a QVM or QPU.\n", + "4. Apply an estimator to the data to obtain an estimate of the state\n", + "5. Compare the estimated state to the true state by a distance measure or visualization\n", + "\n", + "\n", + "Below we break these steps down in to all their gastly glory, before providing a packaged function." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Prepare a state with a `Program`\n", + "## Step 1. Prepare a state with a `Program`\n", "We'll construct a two-qubit graph state by Hadamarding all qubits and then applying a controlled-Z operation across edges of our graph. In the two-qubit case, there's only one edge. The vector we end up preparing is\n", "\n", "$$ |\\Psi\\rangle = \\frac{1}{2}\\begin{pmatrix} 1\\\\ 1 \\\\ 1\\\\ -1\\end{pmatrix}= {\\rm CZ}(0,1){\\rm H}(1){\\rm H}(0)|0,0\\rangle,$$\n", @@ -131,7 +170,18 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "from pyquil import Program\n", + "from pyquil.gates import *" + ] + }, + { + "cell_type": "code", + "execution_count": 2, "metadata": {}, "outputs": [ { @@ -143,7 +193,7 @@ " [-0.25, -0.25, -0.25, 0.25]])" ] }, - "execution_count": 3, + "execution_count": 2, "metadata": {}, "output_type": "execute_result" } @@ -158,7 +208,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "metadata": {}, "outputs": [ { @@ -173,11 +223,16 @@ } ], "source": [ + "# construct the state preparation program\n", + "\n", "qubits = [0, 1]\n", "state_prep_prog = Program()\n", + "\n", "for qubit in qubits:\n", " state_prep_prog += H(qubit)\n", + " \n", "state_prep_prog += CZ(qubits[0], qubits[1])\n", + "\n", "print(state_prep_prog)" ] }, @@ -185,13 +240,16 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Construct a `ObservablesExperiment` for state tomography\n", - "We can print this out to see the 16 measurements we will perform." + "## Step 2. Construct a `ObservablesExperiment` for state tomography\n", + "\n", + "We use the helper function `generate_state_tomography_experiment` to construct a tomographically complete set of measurements.\n", + "\n", + "We can print this out to see the 16 observables or operator measurements we will perform." ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 4, "metadata": {}, "outputs": [ { @@ -218,17 +276,66 @@ } ], "source": [ + "# import the generate_state_tomography_experiment function \n", "from forest.benchmarking.tomography import generate_state_tomography_experiment\n", + "\n", "experiment = generate_state_tomography_experiment(program=state_prep_prog, qubits=qubits)\n", + "\n", "print(experiment)" ] }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The object \"experiment\" is a:\n", + " \n", + "\n", + "It has a program attribute:\n", + "H 0\n", + "H 1\n", + "CZ 0 1\n", + "\n", + "It also has a list of observables that need to be estimated:\n", + "0: Z0_0 * Z0_1→(1+0j)*X1\n", + "1: Z0_0 * Z0_1→(1+0j)*Y1\n", + "2: Z0_0 * Z0_1→(1+0j)*Z1\n", + "3: Z0_0 * Z0_1→(1+0j)*X0\n", + "4: Z0_0 * Z0_1→(1+0j)*X0X1\n", + "5: Z0_0 * Z0_1→(1+0j)*X0Y1\n", + "6: Z0_0 * Z0_1→(1+0j)*X0Z1\n", + "7: Z0_0 * Z0_1→(1+0j)*Y0\n", + "8: Z0_0 * Z0_1→(1+0j)*Y0X1\n", + "9: Z0_0 * Z0_1→(1+0j)*Y0Y1\n", + "10: Z0_0 * Z0_1→(1+0j)*Y0Z1\n", + "11: Z0_0 * Z0_1→(1+0j)*Z0\n", + "12: Z0_0 * Z0_1→(1+0j)*Z0X1\n", + "13: Z0_0 * Z0_1→(1+0j)*Z0Y1\n", + "14: Z0_0 * Z0_1→(1+0j)*Z0Z1\n" + ] + } + ], + "source": [ + "# lets peek into the object\n", + "print('The object \"experiment\" is a:')\n", + "print(type(experiment),'\\n')\n", + "print('It has a program attribute:')\n", + "print(experiment.program)\n", + "print('It also has a list of observables that need to be estimated:')\n", + "print(experiment.settings_string())" + ] + }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Optional grouping\n", - "We can simultaneously estimate some of these observables" + "We can simultaneously estimate some of these observables, this saves on run time." ] }, { @@ -262,35 +369,82 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## PyQuil will run the tomography programs" + "## Step 3. Aquire the data\n", + "\n", + "PyQuil will run the tomography programs.\n", + "\n", + "We will use the QVM but at this point you can use a QPU." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, + "outputs": [], + "source": [ + "from pyquil import get_qc\n", + "qc = get_qc('2q-qvm')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The next step is to over-write full `quilc` compilation with a much more simple version that *only* substitutes gates to Rigetti-native gates.\n", + "\n", + "We do this because, we don't want to accidentally compile away our tomography circuit or map to different qubits." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "from forest.benchmarking.compilation import basic_compile\n", + "qc.compiler.quil_to_native_quil = basic_compile" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now get the data!" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ExperimentResult[(input operators)→(output operator): \"mean\" +- \"standard error\"]\n" + ] + }, { "data": { "text/plain": [ - "[ExperimentResult[Z0_0 * Z0_1→(1+0j)*X1: -0.088 +- 0.04454786190155483],\n", - " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Y1: 0.008 +- 0.04471992844359213],\n", - " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Z1: 0.024 +- 0.04470847794322683],\n", - " ExperimentResult[Z0_0 * Z0_1→(1+0j)*X0: 0.024 +- 0.04470847794322683],\n", - " ExperimentResult[Z0_0 * Z0_1→(1+0j)*X0X1: -0.032 +- 0.04469845634918503],\n", + "[ExperimentResult[Z0_0 * Z0_1→(1+0j)*X1: -0.008 +- 0.04471992844359213],\n", + " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Y1: 0.016 +- 0.04471563484956912],\n", + " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Z1: -0.02 +- 0.04471241438347967],\n", + " ExperimentResult[Z0_0 * Z0_1→(1+0j)*X0: 0.056 +- 0.044651181395344956],\n", + " ExperimentResult[Z0_0 * Z0_1→(1+0j)*X0X1: -0.036 +- 0.044692370713579295],\n", " ExperimentResult[Z0_0 * Z0_1→(1+0j)*X0Y1: 0.028 +- 0.04470382533967311],\n", " ExperimentResult[Z0_0 * Z0_1→(1+0j)*X0Z1: 1.0 +- 0.0],\n", - " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Y0: -0.032 +- 0.04469845634918503],\n", - " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Y0X1: -0.044 +- 0.0446780483011512],\n", + " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Y0: -0.044 +- 0.0446780483011512],\n", + " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Y0X1: 0.004 +- 0.04472100177768829],\n", " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Y0Y1: 1.0 +- 0.0],\n", - " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Y0Z1: -0.036 +- 0.044692370713579295],\n", - " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Z0: 0.032 +- 0.04469845634918503],\n", + " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Y0Z1: 0.036 +- 0.044692370713579295],\n", + " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Z0: 0.064 +- 0.044629676225578875],\n", " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Z0X1: 1.0 +- 0.0],\n", - " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Z0Y1: -0.016 +- 0.04471563484956912],\n", - " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Z0Z1: -0.076 +- 0.04459201722281691]]" + " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Z0Y1: 0.004 +- 0.04472100177768829],\n", + " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Z0Z1: -0.028 +- 0.04470382533967311]]" ] }, - "execution_count": 7, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } @@ -298,15 +452,9 @@ "source": [ "from forest.benchmarking.observable_estimation import estimate_observables\n", "\n", - "qc = get_qc('2q-qvm')\n", - "# Over-write full quilc compilation with a much more simple\n", - "# version that *only* substitutes gates to Rigetti-native gates.\n", - "# We don't want to accidentally compile away our tomography circuit\n", - "# or map to different qubits.\n", - "from forest.benchmarking.compilation import basic_compile\n", - "qc.compiler.quil_to_native_quil = basic_compile\n", - "\n", "results = list(estimate_observables(qc, experiment))\n", + "\n", + "print('ExperimentResult[(input operators)→(output operator): \"mean\" +- \"standard error\"]')\n", "results" ] }, @@ -314,106 +462,248 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### We can look at a bunch of numbers..." + "## Step 4. Apply some estimators to the data \"do tomography\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Linear inversion estimator" ] }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 10, "metadata": {}, "outputs": [ { - "data": { - "text/plain": [ - "array([[ 0.245-0.j , 0.228+0.002j, 0.256+0.017j, -0.258+0.004j],\n", - " [ 0.228-0.002j, 0.271+0.j , 0.242+0.018j, -0.244-0.001j],\n", - " [ 0.256-0.017j, 0.242-0.018j, 0.267-0.j , -0.272-0.006j],\n", - " [-0.258-0.004j, -0.244+0.001j, -0.272+0.006j, 0.217-0.j ]])" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" + "name": "stdout", + "output_type": "stream", + "text": [ + "[[ 0.254-0.j 0.248-0.005j 0.264+0.002j -0.259-0.008j]\n", + " [ 0.248+0.005j 0.278+0.j 0.241+0.006j -0.236+0.02j ]\n", + " [ 0.264-0.002j 0.241-0.006j 0.236-0.j -0.252-0.003j]\n", + " [-0.259+0.008j -0.236-0.02j -0.252+0.003j 0.232-0.j ]]\n" + ] } ], "source": [ "from forest.benchmarking.tomography import linear_inv_state_estimate\n", - "rho = linear_inv_state_estimate(results, qubits=qubits)\n", - "np.round(rho, 3)" + "\n", + "rho_est_linv = linear_inv_state_estimate(results, qubits=qubits)\n", + "\n", + "print(np.round(rho_est_linv, 3))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Linear inversion projected to closest physical state" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "metadata": {}, - "outputs": [], - "source": [] + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[ 0.259+0.j 0.246+0.001j 0.251+0.003j -0.246-0.002j]\n", + " [ 0.246-0.001j 0.26 +0.j 0.239+0.001j -0.235+0.009j]\n", + " [ 0.251-0.003j 0.239-0.001j 0.243+0.j -0.239+0.001j]\n", + " [-0.246+0.002j -0.235-0.009j -0.239-0.001j 0.238-0.j ]]\n" + ] + } + ], + "source": [ + "from forest.benchmarking.operator_tools.project_state_matrix import project_state_matrix_to_physical\n", + "\n", + "rho_phys = project_state_matrix_to_physical(rho_est_linv)\n", + "\n", + "print(np.round(rho_phys, 3))" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### Or visualize using Hinton plots" + "### Maximum Liklihood Estimate (MLE) via diluted iterative method" ] }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 12, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[ 0.258-0.j 0.255+0.002j 0.253+0.002j -0.251+0.001j]\n", + " [ 0.255-0.002j 0.251-0.j 0.249-0.001j -0.247+0.003j]\n", + " [ 0.253-0.002j 0.249+0.001j 0.248+0.j -0.245+0.002j]\n", + " [-0.251-0.001j -0.247-0.003j -0.245-0.002j 0.243+0.j ]]\n" + ] + } + ], "source": [ - "from matplotlib import pyplot as plt\n", - "from forest.benchmarking.plotting import hinton\n", - "fig, (ax1, ax2) = plt.subplots(1, 2)\n", - "hinton(rho_true, ax=ax1)\n", - "hinton(rho, ax=ax2)\n", - "ax1.set_title('Analytical')\n", - "ax2.set_title('Estimated')\n", - "fig.tight_layout()" + "from forest.benchmarking.tomography import iterative_mle_state_estimate\n", + "\n", + "rho_mle = iterative_mle_state_estimate(results=results, qubits=qubits)\n", + "\n", + "print(np.around(rho_mle, 3))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### Matrix norm between true and estimated is low" + "### MLE with Max Entropy constraint" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[ 0.256+0.j 0.206+0.j 0.209+0.001j -0.206-0.001j]\n", + " [ 0.206-0.j 0.256+0.j 0.202+0.001j -0.199+0.006j]\n", + " [ 0.209-0.001j 0.202-0.001j 0.246-0.j -0.202+0.001j]\n", + " [-0.206+0.001j -0.199-0.006j -0.202-0.001j 0.242+0.j ]]\n" + ] + } + ], "source": [ - "np.linalg.norm(rho - rho_true)" + "rho_mle_maxent = iterative_mle_state_estimate(results=results, qubits=qubits, epsilon=0.05, entropy_penalty=0.05)\n", + "\n", + "print(np.around(rho_mle_maxent, 3))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Linear inversion estimate" + "### MLE with Hedging parameter" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[ 0.258+0.j 0.254+0.002j 0.252+0.002j -0.25 +0.001j]\n", + " [ 0.254-0.002j 0.251-0.j 0.249-0.001j -0.246+0.003j]\n", + " [ 0.252-0.002j 0.249+0.001j 0.248-0.j -0.245+0.002j]\n", + " [-0.25 -0.001j -0.246-0.003j -0.245-0.002j 0.243+0.j ]]\n" + ] + } + ], "source": [ - "from forest.benchmarking.tomography import linear_inv_state_estimate\n", - "rho = linear_inv_state_estimate(results, qubits=qubits)\n", + "rho_mle_hedge = iterative_mle_state_estimate(results=results, qubits=qubits, epsilon=.001, beta=.61)\n", "\n", - "print(np.round(rho, 4))\n", - "print('Purity =', np.trace(rho @ rho))\n", - "hinton(rho)" + "print(np.around(rho_mle_hedge, 3))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Maximum Liklihood Estimate (MLE) via diluted iterative method" + "## Step 5. Compare estimated state to the true state" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Or visualize using Hinton plots" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Compare purities of estimates" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "estimates = {\n", + " 'True State': rho_true,\n", + " 'Linear Inv': rho_est_linv,\n", + " 'Proj Linear Inv': rho_phys,\n", + " 'MLE': rho_mle,\n", + " 'MLE + MaxEnt': rho_mle_maxent,\n", + " 'MLE + Hedge': rho_mle_hedge}" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "from forest.benchmarking.distance_measures import purity" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "purity" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True State estimates a purity of 1.0.\n", + "Linear Inv estimates a purity of (1.004+0j).\n", + "Proj Linear Inv estimates a purity of (0.958-0j).\n", + "MLE estimates a purity of (1+0j).\n", + "MLE + MaxEnt estimates a purity of (0.749+0j).\n", + "MLE + Hedge estimates a purity of (0.996+0j).\n" + ] + } + ], + "source": [ + "\n", + "for key, rho_e in estimates.items():\n", + " p = np.round(purity(rho_e),3)\n", + " print(f\"{key} estimates a purity of {p}.\")" ] }, { @@ -421,19 +711,29 @@ "execution_count": null, "metadata": {}, "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 79, + "metadata": {}, + "outputs": [], "source": [ - "from forest.benchmarking.tomography import iterative_mle_state_estimate\n", - "rho = iterative_mle_state_estimate(results=results, qubits=qubits)\n", - "print(np.around(rho, decimals=4))\n", - "print('Purity =', np.trace(rho @ rho))\n", - "hinton(rho)" + "from matplotlib import pyplot as plt\n", + "from forest.benchmarking.plotting import hinton\n", + "fig, (ax1, ax2) = plt.subplots(1, 2)\n", + "hinton(rho_true, ax=ax1)\n", + "hinton(rho, ax=ax2)\n", + "ax1.set_title('Analytical')\n", + "ax2.set_title('Estimated')\n", + "fig.tight_layout()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## MLE with Max Entropy constraint" + "### Matrix norm between true and estimated is low" ] }, { @@ -442,17 +742,14 @@ "metadata": {}, "outputs": [], "source": [ - "rho = iterative_mle_state_estimate(results=results, qubits=qubits, epsilon=0.5, entropy_penalty=0.005)\n", - "print(np.around(rho, decimals=4))\n", - "print('Purity =', np.trace(rho @ rho))\n", - "hinton(rho)" + "np.linalg.norm(rho - rho_true)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## MLE with Hedging parameter" + "## Linear inversion estimate" ] }, { @@ -461,9 +758,11 @@ "metadata": {}, "outputs": [], "source": [ - "rho = iterative_mle_state_estimate(results=results, qubits=qubits, epsilon=.0001, beta=.61)\n", - "print(np.around(rho, decimals=4))\n", - "print('Purity = ', np.trace(rho @ rho))\n", + "from forest.benchmarking.tomography import linear_inv_state_estimate\n", + "rho = linear_inv_state_estimate(results, qubits=qubits)\n", + "\n", + "print(np.round(rho, 4))\n", + "print('Purity =', np.trace(rho @ rho))\n", "hinton(rho)" ] }, @@ -471,18 +770,28 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Project an unphysical state to the closest physical state" + "## Project Linear inversion estimate to the closest physical state" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 80, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "

" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "from forest.benchmarking.operator_tools.project_state_matrix import project_state_matrix_to_physical\n", - "rho_unphys = np.random.uniform(-1, 1, (2, 2)) \\\n", - " * np.exp(1.j * np.random.uniform(-np.pi, np.pi, (2, 2)))\n", + "\n", "rho_phys = project_state_matrix_to_physical(rho_unphys)\n", "\n", "fig, (ax1, ax2) = plt.subplots(1, 2)\n", @@ -516,7 +825,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 91, "metadata": {}, "outputs": [], "source": [ @@ -526,7 +835,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 92, "metadata": {}, "outputs": [], "source": [ @@ -543,9 +852,18 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 93, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(0.976366671390057, 8.096610769504756e-06)\n", + "(0.9551345210316053, 0.00013453288014556413)\n" + ] + } + ], "source": [ "mle_est = estimate_variance(results, qubits, fast_tomo_est, dm.purity,\n", " n_resamples=40, project_to_physical=True)\n", @@ -564,9 +882,34 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 95, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Failed to find a square root.\n", + "Failed to find a square root.\n" + ] + }, + { + "ename": "ValueError", + "evalue": "array must not contain infs or NaNs", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\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 1\u001b[0m mle_est = estimate_variance(results, qubits, fast_tomo_est, dm.fidelity,\n\u001b[0;32m----> 2\u001b[0;31m target_state=rho_true, n_resamples=40, project_to_physical=True)\n\u001b[0m\u001b[1;32m 3\u001b[0m lin_inv_est = estimate_variance(results, qubits, linear_inv_state_estimate, dm.fidelity,\n\u001b[1;32m 4\u001b[0m target_state=rho_true, n_resamples=40, project_to_physical=True)\n\u001b[1;32m 5\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmle_est\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/forest-benchmarking/forest/benchmarking/tomography.py\u001b[0m in \u001b[0;36mestimate_variance\u001b[0;34m(results, qubits, tomo_estimator, functional, target_state, n_resamples, project_to_physical)\u001b[0m\n\u001b[1;32m 426\u001b[0m \u001b[0msample_estimate\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mreal\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdm\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpurity\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrho\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdim_renorm\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 427\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 428\u001b[0;31m \u001b[0msample_estimate\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mreal\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfunctional\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtarget_state\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrho\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 429\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 430\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmean\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msample_estimate\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvar\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msample_estimate\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/forest-benchmarking/forest/benchmarking/distance_measures.py\u001b[0m in \u001b[0;36mfidelity\u001b[0;34m(rho, sigma)\u001b[0m\n\u001b[1;32m 50\u001b[0m \u001b[0;34m:\u001b[0m\u001b[0;32mreturn\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mFidelity\u001b[0m \u001b[0mwhich\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0ma\u001b[0m \u001b[0mscalar\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 51\u001b[0m \"\"\"\n\u001b[0;32m---> 52\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtrace\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msqrtm\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmatmul\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmatmul\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msqrtm\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrho\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0msigma\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0msqrtm\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrho\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m**\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 53\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 54\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/anaconda3/lib/python3.7/site-packages/scipy/linalg/_matfuncs_sqrtm.py\u001b[0m in \u001b[0;36msqrtm\u001b[0;34m(A, disp, blocksize)\u001b[0m\n\u001b[1;32m 161\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 162\u001b[0m \"\"\"\n\u001b[0;32m--> 163\u001b[0;31m \u001b[0mA\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_asarray_validated\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mA\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcheck_finite\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mas_inexact\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 164\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mA\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshape\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 165\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Non-matrix input to matrix function.\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/anaconda3/lib/python3.7/site-packages/scipy/_lib/_util.py\u001b[0m in \u001b[0;36m_asarray_validated\u001b[0;34m(a, check_finite, sparse_ok, objects_ok, mask_ok, as_inexact)\u001b[0m\n\u001b[1;32m 237\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'masked arrays are not supported'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 238\u001b[0m \u001b[0mtoarray\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0masarray_chkfinite\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mcheck_finite\u001b[0m \u001b[0;32melse\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0masarray\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 239\u001b[0;31m \u001b[0ma\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtoarray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 240\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mobjects_ok\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 241\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0ma\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdtype\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdtype\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'O'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/anaconda3/lib/python3.7/site-packages/numpy/lib/function_base.py\u001b[0m in \u001b[0;36masarray_chkfinite\u001b[0;34m(a, dtype, order)\u001b[0m\n\u001b[1;32m 496\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0ma\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdtype\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mchar\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mtypecodes\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'AllFloat'\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0misfinite\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mall\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 497\u001b[0m raise ValueError(\n\u001b[0;32m--> 498\u001b[0;31m \"array must not contain infs or NaNs\")\n\u001b[0m\u001b[1;32m 499\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0ma\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 500\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mValueError\u001b[0m: array must not contain infs or NaNs" + ] + } + ], "source": [ "mle_est = estimate_variance(results, qubits, fast_tomo_est, dm.fidelity,\n", " target_state=rho_true, n_resamples=40, project_to_physical=True)\n", @@ -576,6 +919,13 @@ "print(lin_inv_est)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Advanced topics" + ] + }, { "cell_type": "code", "execution_count": null, From 2cdb39eca259450360d5860a467e990141c18d8c Mon Sep 17 00:00:00 2001 From: Joshua Combes Date: Wed, 19 Jun 2019 14:27:19 +1000 Subject: [PATCH 05/11] make fidelity calculation more robust --- forest/benchmarking/distance_measures.py | 4 +++- .../operator_tools/calculational.py | 20 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/forest/benchmarking/distance_measures.py b/forest/benchmarking/distance_measures.py index 7b2e9736..b6055e58 100644 --- a/forest/benchmarking/distance_measures.py +++ b/forest/benchmarking/distance_measures.py @@ -5,6 +5,7 @@ from scipy.linalg import sqrtm from scipy.linalg import fractional_matrix_power from scipy.optimize import minimize_scalar +from forest.benchmarking.operator_tools.calculational import sqrtm_psd # =================================================================================================== @@ -74,7 +75,8 @@ def fidelity(rho: np.ndarray, sigma: np.ndarray, tol: float = 1000) -> float: :param tol: Tolerance in machine epsilons for np.real_if_close. :return: Fidelity which is a scalar. """ - fid = (np.trace(sqrtm(np.matmul(np.matmul(sqrtm(rho), sigma), sqrtm(rho))))) ** 2 + sqrt_rho = sqrtm_psd(rho) + fid = (np.trace(sqrtm_psd(np.matmul(np.matmul(sqrt_rho, sigma), sqrt_rho)))) ** 2 return np.ndarray.item(np.real_if_close(fid, tol)) diff --git a/forest/benchmarking/operator_tools/calculational.py b/forest/benchmarking/operator_tools/calculational.py index 325eaa15..f58229fb 100644 --- a/forest/benchmarking/operator_tools/calculational.py +++ b/forest/benchmarking/operator_tools/calculational.py @@ -1,4 +1,5 @@ import numpy as np +from scipy.linalg import eigh def partial_trace(rho, keep, dims, optimize=False): @@ -64,3 +65,22 @@ def inner_product(bra1: np.ndarray, bra2: np.ndarray) -> complex: if not (cols1 == cols2 == 1 and rows1 > 1 and rows2 > 1): raise ValueError("The vectors do not have the correct dimensions.") return np.transpose(bra1.conj()) @ bra2 + + +# code from https://github.com/scipy/scipy/pull/4775/files +# Algorithm 9.1.1. in Gene H. Golub, Charles F. van Loan, Matrix Computations 4th ed. +def sqrtm_psd(matrix: np.ndarray, check_finite: bool =True) -> np.ndarray: + """ + Calculates the square root of a matrix that is positive semidefinite. + + :param matrix: the matrix to square root + :param check_finite: Whether to check that the input matrices contain only finite numbers. + :return: sqrt(matrix) + """ + w, v = eigh(matrix, check_finite=check_finite) + # As we further know that your matrix is positive semidefinite, + # we can guard against precision errors by doing + w = np.maximum(w, 0) + w = np.sqrt(w) + matrix_sqrt = (v * w).dot(v.conj().T) + return matrix_sqrt From 042ede09beaa925e5444b227d42ee9b5b5afa427 Mon Sep 17 00:00:00 2001 From: Joshua Combes Date: Wed, 19 Jun 2019 14:29:39 +1000 Subject: [PATCH 06/11] make code more readable --- forest/benchmarking/distance_measures.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forest/benchmarking/distance_measures.py b/forest/benchmarking/distance_measures.py index b6055e58..965c8301 100644 --- a/forest/benchmarking/distance_measures.py +++ b/forest/benchmarking/distance_measures.py @@ -76,7 +76,7 @@ def fidelity(rho: np.ndarray, sigma: np.ndarray, tol: float = 1000) -> float: :return: Fidelity which is a scalar. """ sqrt_rho = sqrtm_psd(rho) - fid = (np.trace(sqrtm_psd(np.matmul(np.matmul(sqrt_rho, sigma), sqrt_rho)))) ** 2 + fid = (np.trace(sqrtm_psd(sqrt_rho @ sigma @ sqrt_rho))) ** 2 return np.ndarray.item(np.real_if_close(fid, tol)) From 19fd18beef000780fadcf4954cf073474468943b Mon Sep 17 00:00:00 2001 From: Joshua Combes Date: Wed, 19 Jun 2019 15:59:01 +1000 Subject: [PATCH 07/11] move the example from tomo notebook --- examples/superoperator_tools.ipynb | 35 +++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/examples/superoperator_tools.ipynb b/examples/superoperator_tools.ipynb index 7e030f1e..5c987266 100644 --- a/examples/superoperator_tools.ipynb +++ b/examples/superoperator_tools.ipynb @@ -614,7 +614,40 @@ "metadata": {}, "outputs": [], "source": [ - "from forest.benchmarking.operator_tools.project_state_matrix import project_state_matrix_to_physical\n", + "from forest.benchmarking.operator_tools.project_state_matrix import project_state_matrix_to_physical" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Test the method. Example from fig 1 of maximum likelihood minimum effort \n", + "# https://doi.org/10.1103/PhysRevLett.108.070502\n", + "\n", + "eigs = np.diag(np.array(list(reversed([3.0/5, 1.0/2, 7.0/20, 1.0/10, -11.0/20]))))\n", + "phys = project_state_matrix_to_physical(eigs)\n", + "np.allclose(phys, np.diag([0, 0, 1.0/5, 7.0/20, 9.0/20]))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ "from forest.benchmarking.plotting import hinton\n", "\n", "rho_unphys = np.random.uniform(-1, 1, (2, 2)) \\\n", From 207d33d9d24c1d6561c1afa85ff12044a34db9e1 Mon Sep 17 00:00:00 2001 From: Joshua Combes Date: Wed, 19 Jun 2019 15:59:23 +1000 Subject: [PATCH 08/11] tomo notebook first cut --- examples/tomography_state.ipynb | 514 +++++++++++++++++++++----------- 1 file changed, 342 insertions(+), 172 deletions(-) diff --git a/examples/tomography_state.ipynb b/examples/tomography_state.ipynb index 54506e32..c620e4fe 100644 --- a/examples/tomography_state.ipynb +++ b/examples/tomography_state.ipynb @@ -151,7 +151,25 @@ "5. Compare the estimated state to the true state by a distance measure or visualization\n", "\n", "\n", - "Below we break these steps down in to all their gastly glory, before providing a packaged function." + "Below we break these steps down in to all their gastly glory. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### A pre-packaged function\n", + "\n", + "We start by " + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "#TODO" ] }, { @@ -170,7 +188,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -181,7 +199,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": {}, "outputs": [ { @@ -193,7 +211,7 @@ " [-0.25, -0.25, -0.25, 0.25]])" ] }, - "execution_count": 2, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } @@ -208,7 +226,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "metadata": {}, "outputs": [ { @@ -249,7 +267,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": {}, "outputs": [ { @@ -286,7 +304,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -340,7 +358,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "metadata": {}, "outputs": [ { @@ -378,7 +396,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "metadata": {}, "outputs": [], "source": [ @@ -397,7 +415,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "metadata": {}, "outputs": [], "source": [ @@ -414,7 +432,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "metadata": {}, "outputs": [ { @@ -427,24 +445,24 @@ { "data": { "text/plain": [ - "[ExperimentResult[Z0_0 * Z0_1→(1+0j)*X1: -0.008 +- 0.04471992844359213],\n", - " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Y1: 0.016 +- 0.04471563484956912],\n", - " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Z1: -0.02 +- 0.04471241438347967],\n", - " ExperimentResult[Z0_0 * Z0_1→(1+0j)*X0: 0.056 +- 0.044651181395344956],\n", - " ExperimentResult[Z0_0 * Z0_1→(1+0j)*X0X1: -0.036 +- 0.044692370713579295],\n", - " ExperimentResult[Z0_0 * Z0_1→(1+0j)*X0Y1: 0.028 +- 0.04470382533967311],\n", + "[ExperimentResult[Z0_0 * Z0_1→(1+0j)*X1: -0.06 +- 0.04464078852350168],\n", + " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Y1: 0.02 +- 0.04471241438347967],\n", + " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Z1: 0.016 +- 0.04471563484956912],\n", + " ExperimentResult[Z0_0 * Z0_1→(1+0j)*X0: -0.024 +- 0.04470847794322683],\n", + " ExperimentResult[Z0_0 * Z0_1→(1+0j)*X0X1: 0.008 +- 0.04471992844359213],\n", + " ExperimentResult[Z0_0 * Z0_1→(1+0j)*X0Y1: 0.008 +- 0.04471992844359213],\n", " ExperimentResult[Z0_0 * Z0_1→(1+0j)*X0Z1: 1.0 +- 0.0],\n", - " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Y0: -0.044 +- 0.0446780483011512],\n", - " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Y0X1: 0.004 +- 0.04472100177768829],\n", + " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Y0: 0.008 +- 0.04471992844359213],\n", + " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Y0X1: -0.024 +- 0.04470847794322683],\n", " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Y0Y1: 1.0 +- 0.0],\n", - " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Y0Z1: 0.036 +- 0.044692370713579295],\n", - " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Z0: 0.064 +- 0.044629676225578875],\n", + " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Y0Z1: 0.02 +- 0.04471241438347967],\n", + " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Z0: -0.1 +- 0.04449719092257399],\n", " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Z0X1: 1.0 +- 0.0],\n", - " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Z0Y1: 0.004 +- 0.04472100177768829],\n", - " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Z0Z1: -0.028 +- 0.04470382533967311]]" + " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Z0Y1: -0.056 +- 0.044651181395344956],\n", + " ExperimentResult[Z0_0 * Z0_1→(1+0j)*Z0Z1: -0.036 +- 0.044692370713579295]]" ] }, - "execution_count": 9, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -474,17 +492,17 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "[[ 0.254-0.j 0.248-0.005j 0.264+0.002j -0.259-0.008j]\n", - " [ 0.248+0.005j 0.278+0.j 0.241+0.006j -0.236+0.02j ]\n", - " [ 0.264-0.002j 0.241-0.006j 0.236-0.j -0.252-0.003j]\n", - " [-0.259+0.008j -0.236-0.02j -0.252+0.003j 0.232-0.j ]]\n" + "[[ 0.22 +0.j 0.235+0.009j 0.244-0.007j -0.248+0.004j]\n", + " [ 0.235-0.009j 0.23 +0.j 0.252+0.008j -0.256+0.003j]\n", + " [ 0.244+0.007j 0.252-0.008j 0.288-0.j -0.265-0.019j]\n", + " [-0.248-0.004j -0.256-0.003j -0.265+0.019j 0.262-0.j ]]\n" ] } ], @@ -505,17 +523,17 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "[[ 0.259+0.j 0.246+0.001j 0.251+0.003j -0.246-0.002j]\n", - " [ 0.246-0.001j 0.26 +0.j 0.239+0.001j -0.235+0.009j]\n", - " [ 0.251-0.003j 0.239-0.001j 0.243+0.j -0.239+0.001j]\n", - " [-0.246+0.002j -0.235-0.009j -0.239-0.001j 0.238-0.j ]]\n" + "[[ 0.222+0.j 0.228+0.002j 0.242-0.005j -0.242-0.001j]\n", + " [ 0.228-0.002j 0.235+0.j 0.249-0.002j -0.246-0.j ]\n", + " [ 0.242+0.005j 0.249+0.002j 0.279-0.j -0.264-0.011j]\n", + " [-0.242+0.001j -0.246+0.j -0.264+0.011j 0.264+0.j ]]\n" ] } ], @@ -536,17 +554,17 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "[[ 0.258-0.j 0.255+0.002j 0.253+0.002j -0.251+0.001j]\n", - " [ 0.255-0.002j 0.251-0.j 0.249-0.001j -0.247+0.003j]\n", - " [ 0.253-0.002j 0.249+0.001j 0.248+0.j -0.245+0.002j]\n", - " [-0.251-0.001j -0.247-0.003j -0.245-0.002j 0.243+0.j ]]\n" + "[[ 0.232+0.j 0.237+0.j 0.249-0.003j -0.246-0.002j]\n", + " [ 0.237-0.j 0.241-0.j 0.253-0.004j -0.25 -0.002j]\n", + " [ 0.249+0.003j 0.253+0.004j 0.267-0.j -0.263-0.005j]\n", + " [-0.246+0.002j -0.25 +0.002j -0.263+0.005j 0.26 +0.j ]]\n" ] } ], @@ -567,22 +585,22 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "[[ 0.256+0.j 0.206+0.j 0.209+0.001j -0.206-0.001j]\n", - " [ 0.206-0.j 0.256+0.j 0.202+0.001j -0.199+0.006j]\n", - " [ 0.209-0.001j 0.202-0.001j 0.246-0.j -0.202+0.001j]\n", - " [-0.206+0.001j -0.199-0.006j -0.202-0.001j 0.242+0.j ]]\n" + "[[ 0.233+0.j 0.193+0.002j 0.202-0.003j -0.201-0.j ]\n", + " [ 0.193-0.002j 0.241+0.j 0.207-0.001j -0.205-0.j ]\n", + " [ 0.202+0.003j 0.207+0.001j 0.268-0.j -0.215-0.007j]\n", + " [-0.201+0.j -0.205+0.j -0.215+0.007j 0.258-0.j ]]\n" ] } ], "source": [ - "rho_mle_maxent = iterative_mle_state_estimate(results=results, qubits=qubits, epsilon=0.05, entropy_penalty=0.05)\n", + "rho_mle_maxent = iterative_mle_state_estimate(results=results, qubits=qubits, epsilon=0.1, entropy_penalty=0.05)\n", "\n", "print(np.around(rho_mle_maxent, 3))" ] @@ -596,17 +614,17 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "[[ 0.258+0.j 0.254+0.002j 0.252+0.002j -0.25 +0.001j]\n", - " [ 0.254-0.002j 0.251-0.j 0.249-0.001j -0.246+0.003j]\n", - " [ 0.252-0.002j 0.249+0.001j 0.248-0.j -0.245+0.002j]\n", - " [-0.25 -0.001j -0.246-0.003j -0.245-0.002j 0.243+0.j ]]\n" + "[[ 0.232+0.j 0.236+0.j 0.248-0.003j -0.245-0.002j]\n", + " [ 0.236-0.j 0.241+0.j 0.253-0.004j -0.25 -0.001j]\n", + " [ 0.248+0.003j 0.253+0.004j 0.267-0.j -0.263-0.005j]\n", + " [-0.245+0.002j -0.25 +0.001j -0.263+0.005j 0.26 -0.j ]]\n" ] } ], @@ -623,42 +641,26 @@ "## Step 5. Compare estimated state to the true state" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Or visualize using Hinton plots" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Compare purities of estimates" - ] - }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "estimates = {\n", " 'True State': rho_true,\n", " 'Linear Inv': rho_est_linv,\n", - " 'Proj Linear Inv': rho_phys,\n", - " 'MLE': rho_mle,\n", - " 'MLE + MaxEnt': rho_mle_maxent,\n", - " 'MLE + Hedge': rho_mle_hedge}" + " 'ProjLinInv': rho_phys,\n", + " 'plain MLE': rho_mle,\n", + " 'MLE MaxEnt': rho_mle_maxent,\n", + " 'MLE Hedge': rho_mle_hedge}" ] }, { - "cell_type": "code", - "execution_count": 16, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "from forest.benchmarking.distance_measures import purity" + "### Compare fidelity and Trace distance to the true state" ] }, { @@ -667,165 +669,202 @@ "metadata": {}, "outputs": [ { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" + "name": "stdout", + "output_type": "stream", + "text": [ + "Fidelity(True State, True State) = 1.0\n", + "Fidelity(True State, Linear Inv) = 1.0\n", + "Fidelity(True State, ProjLinInv) = 0.985\n", + "Fidelity(True State, plain MLE) = 0.999\n", + "Fidelity(True State, MLE MaxEnt) = 0.862\n", + "Fidelity(True State, MLE Hedge) = 0.997\n" + ] } ], "source": [ - "purity" + "from forest.benchmarking.distance_measures import fidelity, trace_distance\n", + "\n", + "for key, rho_e in estimates.items():\n", + " fid = np.round(fidelity(rho_true, rho_e), 3)\n", + " print(f\"Fidelity(True State, {key}) = {fid}\")" ] }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "True State estimates a purity of 1.0.\n", - "Linear Inv estimates a purity of (1.004+0j).\n", - "Proj Linear Inv estimates a purity of (0.958-0j).\n", - "MLE estimates a purity of (1+0j).\n", - "MLE + MaxEnt estimates a purity of (0.749+0j).\n", - "MLE + Hedge estimates a purity of (0.996+0j).\n" + "Tr_dist(True State, True State) = 0.0\n", + "Tr_dist(True State, Linear Inv) = 0.04\n", + "Tr_dist(True State, ProjLinInv) = 0.034\n", + "Tr_dist(True State, plain MLE) = 0.02\n", + "Tr_dist(True State, MLE MaxEnt) = 0.085\n", + "Tr_dist(True State, MLE Hedge) = 0.02\n" ] } ], "source": [ - "\n", "for key, rho_e in estimates.items():\n", - " p = np.round(purity(rho_e),3)\n", - " print(f\"{key} estimates a purity of {p}.\")" + " fid = np.round(trace_distance(rho_true, rho_e), 3)\n", + " print(f\"Tr_dist(True State, {key}) = {fid}\")" ] }, { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": 79, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "from matplotlib import pyplot as plt\n", - "from forest.benchmarking.plotting import hinton\n", - "fig, (ax1, ax2) = plt.subplots(1, 2)\n", - "hinton(rho_true, ax=ax1)\n", - "hinton(rho, ax=ax2)\n", - "ax1.set_title('Analytical')\n", - "ax2.set_title('Estimated')\n", - "fig.tight_layout()" + "### Compare purities of estimates\n", + "\n", + "Notice how the Maximum entropy has a lower purity." ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": 19, "metadata": {}, + "outputs": [], "source": [ - "### Matrix norm between true and estimated is low" + "from forest.benchmarking.distance_measures import purity" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 20, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True State estimates a purity of 1.0\n", + "Linear Inv estimates a purity of 1.005\n", + "ProjLinInv estimates a purity of 0.974\n", + "plain MLE estimates a purity of 1.0\n", + "MLE MaxEnt estimates a purity of 0.751\n", + "MLE Hedge estimates a purity of 0.996\n" + ] + } + ], "source": [ - "np.linalg.norm(rho - rho_true)" + "for key, rho_e in estimates.items():\n", + " p = np.round(purity(rho_e),3)\n", + " print(f\"{key} estimates a purity of {p}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Linear inversion estimate" + "### Plot\n", + "\n", + "There are many different ways to visualize states and processes in forest.benchmarking, see [state_and_process_plots.ipynb](state_and_process_plots.ipynb) for more options." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 22, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ - "from forest.benchmarking.tomography import linear_inv_state_estimate\n", - "rho = linear_inv_state_estimate(results, qubits=qubits)\n", + "import matplotlib.pyplot as plt\n", + "from forest.benchmarking.plotting.hinton import hinton\n", "\n", - "print(np.round(rho, 4))\n", - "print('Purity =', np.trace(rho @ rho))\n", - "hinton(rho)" + "fig, (ax1, ax2) = plt.subplots(1, 2)\n", + "hinton(rho_true, ax=ax1)\n", + "hinton(rho_mle_maxent, ax=ax2)\n", + "ax1.set_title('True')\n", + "ax2.set_title('Estimated via MLE MaxEnt')\n", + "fig.tight_layout()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Project Linear inversion estimate to the closest physical state" + "Above we can't really see any difference. \n", + "\n", + "So lets try a more informative plot" ] }, { "cell_type": "code", - "execution_count": 80, + "execution_count": 23, "metadata": {}, "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Now we see a clear difference:\n" + ] + }, { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAagAAADiCAYAAAAbBlN+AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4zLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvnQurowAADfBJREFUeJzt3X+QXeVdx/H3Nw2bZPMTDFSDIZQGdQwpCq30D2wQMtIyLVQHcbA0E+yPODClIz+k00GbKVjG0srYMYzBpgaotFAcbbQ/pD8Eq9aq1Y5T21GgJYQfBgQCSTcEgcc/nmftze1ustvs5n7v3vdrZmfOveec537PyXnu55znnM1GKQVJkrKZ1esCJEkaiwElSUrJgJIkpWRASZJSMqAkSSkZUJKklAyoRCKiRMTKKW7zPyLijENsY2NEfHyKSlKfi4h7IuLtU9zmH0XEbx9iG2dExMNTVdNBPuu4iNgTES/rh3b7lQE1CWMFSPYv71LKqlLKPb2uQ/0lIh6MiL3ty3JnRPxJRCyYrs8rpfxGKeXa6Wp/qpVSHiqlLCilvHgo7bT9vHaq250pDChJ43lTKWUBcArwGuCaHtdz2ETE7F7XIANqSo0OMUTEFRHxeEQ8FhEXd8zf2oYyvhARuyPi3ohY0dXM2oi4LyKejohNUc2JiKciYnVHW8e0M9yjI2JpRPxVROxqy30lIma15f7/DC0iXhYR742IB9rnfz0ilrd5fxAROyLi2fb+zx+GXaY+UEp5BPgccFLH2ysi4u/bcXR3RCwFiIjPRMS7OtePiH+PiDe3Y/nG1jeeae+f1JbZGhHXdaxzXkR8ox2PD0TE69v7F0fEt9vnficiNkx0O9oIyGVtvf+JiBs6+sn6tj03RsRTwMaImBUR10TE9lbzrRGxuC1/fGtvdnu9OCK2tD7/SERc1zlMFxHv6Kj7WxFxSkTcBhwH/GW7Uv2tMdpdFhHbWr++PyLe0dHmxoi4s9W1O+pw/qsnuj/6gQE19X4UWAwcC7wN2BQRR3bMfwtwLbAU+Abwp13rv5F6tnoycAFwdillH/BJ4KKO5S4EvlhKeQK4AngYOBp4OfBeYKz/w+rytt45wCLg14GRNu+fgZ8BjgJuBz4VEXMnue2agdpJzDnAv3W8/WvAxcAxwBBwZXv/FjqO04g4mdoXPgv8IvA64CeAJcCvAk+O8Xk/B9wKXNWWex3wYJv9OLWPLGqff2NEnDKJzfkl4NXUq8LzqH1g1GnAd9o2/S6wvv38AnACsAD4w3HavQV4AVgJ/Gzb1re37fkVYCOwrtV9LvBkKeWtwEO0K9VSygfHaPcT1L69DDgf+EBEnNUx/1zqd8MSYNsB6utPpRR/JvhD/dJf2fXeRuDjbfoMYC8wu2P+48Br2/RW4JMd8xYALwLLO9o/vWP+ncB72vRpwA5gVnv9L8AFbfr9wKe7a2vzHgTWtun/BM6b4LY+DZzcvY3+DMZPO272ALuA7cBNwLw27x7gmo5lLwE+36bnAE8BJ7bXHwJuatNnAv8FvHb0OO5oYytwXZveDNw4wTr/Anh3mz4DePgAyxbg9V11f6lNrwce6lr+S8AlHa9/EvhfYDZwfGtvNvWkcN/o/mnLXgj8TZv+69Eax9nPazted7a7vH0/LOyYfz2wtU1vpJ6kjs77aWBvr4+dqfzxCmpyXgSO6HrvCOpBO+rJUsoLHa9HqEE0asfoRCllD7UzL+uY/99jrVtK+RrwPWBNRPwU9UxtW1vuBuB+4O42fPGecepfDjww1oyow5LfbkMvu6hXgUvHaUeD4c2llCWllBWllEtKKXs75o13nO6jnlhd1IbPLgRua/O+TD3D3wTsjIibI2LRGJ97oOP0DRHxj23Iaxf1ym4yx+mOjunt7N/3dnQtu6wt07n8aCB1WkH9HnisDbPvoobsMQfbnoNYBjxVStndVcOxHa+7/x3mxgy6f2ZATc5D1DOcTq9g/4P4YJaPTkR9Kuoo4NEJrjs6fPJW4K5SynMApZTdpZQrSiknAG8CLu8aBhi1A3hl95vtftPV1CHFI0spS4BngJjwVknfdwt1KPssYKSU8tXRGaWUj5RSTgVWUYf6rhpj/fGO0znAn1Gvyl7ejtPPMrnjdHnH9HHs3/e6h8UfpYZP5/IvADvHqHcfsLQF+pJSyqJSyqoDbc84n9n9+UdFxMKuGh45wDozigE1OXcA10TEj7cbqGupgXDXJNo4JyJOj4gh6r2or5VSus/cxnMbdQz9IuoYPQAR8caIWBkRATxLvdIb6zHVjwLXRsSJ7Yb1qyLiR4CF1I73BDA7In6HOlYuTVoLpJeAD9OungAi4jURcVpEHEEdDXiOsY/TLcDFEXFW62fHtlGDIeoQ4hPACxHxBuq9nsm4KiKObPfV3k3t0+P5BPCbEfGKdjL5AeCOrhESSimPAXcDH46IRa3mV0bEmrbIR4ErI+LU1u9WxvcfjtpJvb/1A9r3wj8A10fE3Ih4FfW+dvd96xnLgJqc91MPmL+j3qP5IPCWUso3J9HG7cD7qEN7p1LPNCeklPIw8K/Us66vdMw6Efgi9Z7BV6lj/veM0cTvU4df7qYG2RZgHnWM/HPU+wPbqV8cEw1NaSy3AquBzt8RXAT8MbXvbKc+IPGh7hVLKf9EewCCeiV/L7CiDXVdRj2Gn6Y+qLGte/2D+DTwdeoDSp+h9oHxfIwasH8LfJfaL941zrLrqAH6rVbbXcCPte35FPWhi9uB3dT7Zke19a6nnvTuiogruxulDpEeT72a+nPgfaWUL0xgO2eEaDfXdBhExFbqTdwf+vdJIuJjwKOH0oY03SJiHfDOUsrpva5lVEQU6sMb909BWycA91EfiPJLdJrMmJtpgyAijgd+mfoYq5RSRAxTn5C7qde1TKOTgAcNp+nlEF+fiIhrgW8CN5RSvtvreqSxRMTZ1HtEO6lDWjNORFwO3AyM97SspohDfJKklLyCkiSlNKmAiojPT1chUj+Yij5gP9Kgm2gfmNRDEvPnzz971apVjglqkD17qA3Yj6SJ9aNJBdSKFSu4444D/V6bNLOtXr36vkNtw36kQTfRfuQ9KElSSgaUJCklA0qSlJL/k0Sf23DnvTzz3PO9LmPGWTx3iM0XrDn4gpKmjVdQfc5wmh7uV6n3DChJUkoGlCQpJQNKkpSSASVJSsmAkiSlZEBJklIyoCRJKfmLupI0Qb/37Fb2lL29LiONBTGPqxetn7b2DSipz2wa2cwII70uo6eGGebS4Q2H/XMNp/1N9/5wiE/qM4MeTuA+GBQGlCQpJQNKkpSSASVJSsmAkiSlZEBJklJK8Zj5O++aWX90b/HcIW4+3z92J0mHIsUV1EwKJ5h52yNJvZAioCRJ6mZASZJSMqAkSSkZUJKklAwoSVJKBpQkKSUDSpKUkgElSUrJgJIkpWRASZJSMqAkSSkZUJKklAwoSVJKBpQkKSUDSpKUkgElSUrJgJIkpWRASZJSMqAkSSkZUJKklAwoSVJKBpQkKSUDSpKUkgElSUrJgJIkpWRASZJSMqAkSSkZUJKklAwoSVJKBpQkKSUDSpKUkgElSUrJgJIkpWRASZJSMqAkSSkZUJKklAwoSVJKBpQkKSUDSpKUkgElSUrJgJIkpWRASZJSMqAkSSkZUJKklAwoSVJKBpQkKSUDSpKUkgElSUrJgJIkpWRASZJSShFQi+cO9bqEKTXTtkeSemF2rwsAuPn8Nb0uQZKUTIorKEmSuhlQkqSUDChJUkoGlCQpJQNKkpSSASX1mWGGe11Cz7kPBkOKx8wlTdylwxt6XcLAWhDz2FP29rqMNBbEvGlt34CSpAm6etH6XpcwUBzikySlZEBJklIyoCRJKRlQkqSUDChJUkoGlCQpJQNKkpSSAdXn/OOI08P9KvWev6jb5zZf4B97lDQzeQUlSUrJgJIkpWRASZJSMqAkSSkZUJKklAwoSVJKBpQkKSUDSpKUkgElSUrJgJIkpWRASZJSMqAkSSlN+X8W++VZG3k+dk91szPeUFnImS9t7HUZkpTGlF9BGU4/HPebJO3PIT5JUkoGlCQpJf9goSRNwKaRzYww0usy0hlmmEuHN0xL2waU1Cduff4j7OV7vS4jlXnMZ93QZYflswynsU3nfnGIT+oThtMPcp/MbAaUJCklA0qSlJL3oAbQ27bdyzP7nu91GYfV4jlDbDl3Ta/LkDQJXkENoEELJxjMbZb6nQElSUrJgJIkpWRASZJSMqAkSSkZUJKklAwoSVJKBpQkKSUDSpKUkgElSUrJgJIkpWRASZJSMqAkSSkZUJKklAwoSVJKBpQkKSUDSpKUkgElSUrJgJIkpWRASZJSMqAkSSkZUJKklAwoSVJKBpQkKSUDSpKUkgElSUrJgJIkpWRASZJSMqAkSSkZUJKklAwoSVJKBpQkKSUDSpKUkgElSUrJgJIkpWRASZJSMqAkSSkZUJKklAwoSVJKBpQkKSUDSpKUkgElSUrJgJIkpWRASZJSMqAkSSkZUJKklAwoSVJKBpQkKSUDSpKUkgElSUrJgJIkpWRASZJSMqAkSSkZUJKklAwoSVJKBpQkKSUDSpKUkgElSUrJgJIkpWRADaDFc4Z6XcJhN4jbLPW72b0uQIfflnPX9LoESToor6AkSSkZUJKklAwoqU/MY36vS0jHfTKzeQ9K6hPrhi7rdQkDbZhhRhjpdRnpDDM8bW0bUJI0AZcOb+h1CQPHIT5JUkoGlCQppSkPqKGycKqbHAjuN0na35TfgzrzpY1T3aQkaQA5xCdJSsmAkiSlZEBJklIyoCRJKRlQkqSUDChJUkoGlCQppSilTHzhiCeA7dNXjpTeilLK0YfSgP1Imlg/mlRASZJ0uDjEJ0lKyYCSJKVkQEmSUjKgJEkpGVCSpJQMKElSSgaUJCklA0qSlJIBJUlK6f8AbfyWAAJYZiwAAAAASUVORK5CYII=\n", + "image/png": "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\n", "text/plain": [ - "
" + "
" ] }, - "metadata": {}, + "metadata": { + "needs_background": "light" + }, "output_type": "display_data" } ], "source": [ - "from forest.benchmarking.operator_tools.project_state_matrix import project_state_matrix_to_physical\n", + "from forest.benchmarking.utils import n_qubit_pauli_basis\n", + "from forest.benchmarking.operator_tools.superoperator_transformations import vec, computational2pauli_basis_matrix\n", + "from forest.benchmarking.plotting.state_process import plot_pauli_rep_of_state, plot_pauli_bar_rep_of_state\n", "\n", - "rho_phys = project_state_matrix_to_physical(rho_unphys)\n", + "# convert to pauli representation\n", + "n_qubits = 2\n", + "pl_basis = n_qubit_pauli_basis(n_qubits)\n", + "c2p = computational2pauli_basis_matrix(2*n_qubits)\n", "\n", - "fig, (ax1, ax2) = plt.subplots(1, 2)\n", - "hinton(rho_unphys, ax=ax1)\n", - "hinton(rho_phys, ax=ax2)\n", - "ax1.set_title('Unphysical')\n", - "ax2.set_title('Physical projection')\n", - "fig.tight_layout()" + "\n", + "rho_true_pauli = np.real(c2p @ vec(rho_true))\n", + "\n", + "rho_mle_maxent_pauli = np.real(c2p @ vec(rho_mle_maxent)) \n", + "\n", + "fig1, (ax3, ax4) = plt.subplots(1, 2, figsize=(10,5))\n", + "plot_pauli_bar_rep_of_state(rho_true_pauli.flatten(), ax=ax3, labels=pl_basis.labels, title='True State')\n", + "plot_pauli_bar_rep_of_state(rho_mle_maxent_pauli.flatten(), ax=ax4, labels=pl_basis.labels, title='Estimated via MLE MaxEnt')\n", + "fig1.tight_layout()\n", + "print('Now we see a clear difference:')" ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "# Test the wizard method. Example from fig 1 of maximum likelihood minimum effort \n", - "# https://doi.org/10.1103/PhysRevLett.108.070502\n", - "\n", - "eigs = np.diag(np.array(list(reversed([3.0/5, 1.0/2, 7.0/20, 1.0/10, -11.0/20]))))\n", - "phys = project_state_matrix_to_physical(eigs)\n", - "np.allclose(phys, np.diag([0, 0, 1.0/5, 7.0/20, 9.0/20]))" + "## Advanced topics" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "# Lightweight Bootstrap for functionals of the state" + "### Lightweight Bootstrap for functionals of the state" ] }, { "cell_type": "code", - "execution_count": 91, + "execution_count": 24, "metadata": {}, "outputs": [], "source": [ @@ -835,12 +874,12 @@ }, { "cell_type": "code", - "execution_count": 92, + "execution_count": 25, "metadata": {}, "outputs": [], "source": [ "from functools import partial\n", - "fast_tomo_est = partial(iterative_mle_state_estimate, epsilon=.0001, beta=.5, tol=1e-3)" + "fast_tomo_est = partial(iterative_mle_state_estimate, epsilon=.0005, beta=.5, tol=1e-3)" ] }, { @@ -852,15 +891,16 @@ }, { "cell_type": "code", - "execution_count": 93, + "execution_count": 26, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "(0.976366671390057, 8.096610769504756e-06)\n", - "(0.9551345210316053, 0.00013453288014556413)\n" + "(mean, standard error)\n", + "(0.9921854927040691, 4.630904963784856e-06)\n", + "(0.956466918646775, 0.00019415365210126724)\n" ] } ], @@ -869,6 +909,7 @@ " n_resamples=40, project_to_physical=True)\n", "lin_inv_est = estimate_variance(results, qubits, linear_inv_state_estimate, dm.purity,\n", " n_resamples=40, project_to_physical=True)\n", + "print(\"(mean, standard error)\")\n", "print(mle_est)\n", "print(lin_inv_est)" ] @@ -882,31 +923,16 @@ }, { "cell_type": "code", - "execution_count": 95, + "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Failed to find a square root.\n", - "Failed to find a square root.\n" - ] - }, - { - "ename": "ValueError", - "evalue": "array must not contain infs or NaNs", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mValueError\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 1\u001b[0m mle_est = estimate_variance(results, qubits, fast_tomo_est, dm.fidelity,\n\u001b[0;32m----> 2\u001b[0;31m target_state=rho_true, n_resamples=40, project_to_physical=True)\n\u001b[0m\u001b[1;32m 3\u001b[0m lin_inv_est = estimate_variance(results, qubits, linear_inv_state_estimate, dm.fidelity,\n\u001b[1;32m 4\u001b[0m target_state=rho_true, n_resamples=40, project_to_physical=True)\n\u001b[1;32m 5\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmle_est\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/forest-benchmarking/forest/benchmarking/tomography.py\u001b[0m in \u001b[0;36mestimate_variance\u001b[0;34m(results, qubits, tomo_estimator, functional, target_state, n_resamples, project_to_physical)\u001b[0m\n\u001b[1;32m 426\u001b[0m \u001b[0msample_estimate\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mreal\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdm\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpurity\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrho\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdim_renorm\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 427\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 428\u001b[0;31m \u001b[0msample_estimate\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mreal\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfunctional\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtarget_state\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrho\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 429\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 430\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmean\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msample_estimate\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvar\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msample_estimate\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/forest-benchmarking/forest/benchmarking/distance_measures.py\u001b[0m in \u001b[0;36mfidelity\u001b[0;34m(rho, sigma)\u001b[0m\n\u001b[1;32m 50\u001b[0m \u001b[0;34m:\u001b[0m\u001b[0;32mreturn\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mFidelity\u001b[0m \u001b[0mwhich\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0ma\u001b[0m \u001b[0mscalar\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 51\u001b[0m \"\"\"\n\u001b[0;32m---> 52\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtrace\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msqrtm\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmatmul\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmatmul\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msqrtm\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrho\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0msigma\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0msqrtm\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrho\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m**\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 53\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 54\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/anaconda3/lib/python3.7/site-packages/scipy/linalg/_matfuncs_sqrtm.py\u001b[0m in \u001b[0;36msqrtm\u001b[0;34m(A, disp, blocksize)\u001b[0m\n\u001b[1;32m 161\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 162\u001b[0m \"\"\"\n\u001b[0;32m--> 163\u001b[0;31m \u001b[0mA\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_asarray_validated\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mA\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcheck_finite\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mas_inexact\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 164\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mA\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshape\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 165\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Non-matrix input to matrix function.\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/anaconda3/lib/python3.7/site-packages/scipy/_lib/_util.py\u001b[0m in \u001b[0;36m_asarray_validated\u001b[0;34m(a, check_finite, sparse_ok, objects_ok, mask_ok, as_inexact)\u001b[0m\n\u001b[1;32m 237\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'masked arrays are not supported'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 238\u001b[0m \u001b[0mtoarray\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0masarray_chkfinite\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mcheck_finite\u001b[0m \u001b[0;32melse\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0masarray\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 239\u001b[0;31m \u001b[0ma\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtoarray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 240\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mobjects_ok\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 241\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0ma\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdtype\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdtype\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'O'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/anaconda3/lib/python3.7/site-packages/numpy/lib/function_base.py\u001b[0m in \u001b[0;36masarray_chkfinite\u001b[0;34m(a, dtype, order)\u001b[0m\n\u001b[1;32m 496\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0ma\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdtype\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mchar\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mtypecodes\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'AllFloat'\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0misfinite\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mall\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 497\u001b[0m raise ValueError(\n\u001b[0;32m--> 498\u001b[0;31m \"array must not contain infs or NaNs\")\n\u001b[0m\u001b[1;32m 499\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0ma\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 500\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mValueError\u001b[0m: array must not contain infs or NaNs" + "(mean, standard error)\n", + "(0.9933553002948612, 2.7690620039996715e-06)\n", + "(0.9729268273350122, 5.1585557474299336e-05)\n" ] } ], @@ -915,6 +941,8 @@ " target_state=rho_true, n_resamples=40, project_to_physical=True)\n", "lin_inv_est = estimate_variance(results, qubits, linear_inv_state_estimate, dm.fidelity,\n", " target_state=rho_true, n_resamples=40, project_to_physical=True)\n", + "\n", + "print(\"(mean, standard error)\")\n", "print(mle_est)\n", "print(lin_inv_est)" ] @@ -923,7 +951,149 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Advanced topics" + "### Estimator accuracy for mixed state tomography\n", + "\n", + "As soon as [GH-920](https://github.com/rigetti/pyquil/pull/920) gets merged the cells below will work.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [], + "source": [ + "# make an abstract compiler\n", + "from pyquil.api._qac import AbstractCompiler\n", + "\n", + "class DummyCompiler(AbstractCompiler):\n", + " def get_version_info(self):\n", + " return {}\n", + " def quil_to_native_quil(self, program: Program):\n", + " return program\n", + " def native_quil_to_executable(self, nq_program: Program):\n", + " return nq_program" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [], + "source": [ + "#make a quantum computer object\n", + "import networkx as nx\n", + "from pyquil.device import NxDevice\n", + "from pyquil.api import QVM, QuantumComputer\n", + "from pyquil.pyqvm import PyQVM\n", + "from pyquil.reference_simulator import ReferenceDensitySimulator\n", + "\n", + "device = NxDevice(nx.complete_graph(1))\n", + "qc = QuantumComputer(name='testy!',\n", + " qam=PyQVM(n_qubits=1,quantum_simulator_type=ReferenceDensitySimulator),\n", + " device=device,\n", + " compiler=DummyCompiler())" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [], + "source": [ + "n_shots_max = [400,1000,4000,16000,64000]\n", + "number_of_states = 30" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "I 0\n", + "0: Z0_0→(1+0j)*X0\n", + "1: Z0_0→(1+0j)*Y0\n", + "2: Z0_0→(1+0j)*Z0\n" + ] + } + ], + "source": [ + "program = Program(I(0))\n", + "qubits = [0]\n", + "experiment = generate_state_tomography_experiment(program=program, qubits=qubits)\n", + "print(experiment)" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [], + "source": [ + "# NBVAL_SKIP\n", + "\n", + "import forest.benchmarking.operator_tools.random_operators as rand_ops\n", + "from forest.benchmarking.distance_measures import infidelity\n", + "infidn =[]\n", + "trdn =[]\n", + "for nshots in n_shots_max:\n", + " infid = []\n", + " trd = []\n", + " for _ in range(0,number_of_states):\n", + " # set the inital state of the simulator\n", + " rho_true = rand_ops.bures_measure_state_matrix(2)\n", + " qc.qam.wf_simulator.set_initial_state(rho_true).reset()\n", + " # gather data\n", + " resultsy = list(estimate_observables(qc=qc, obs_expt=experiment, num_shots=nshots))\n", + " # estimate\n", + " rho_est = iterative_mle_state_estimate(results=resultsy, qubits=[0],maxiter=100_000)\n", + " infid.append(infidelity(rho_true, rho_est))\n", + " trd.append(trace_distance(rho_true, rho_est))\n", + " infidn.append({'mean': np.mean(np.real(infid)), 'std': np.std(np.real_if_close(infid))})\n", + " trdn.append({'mean': np.mean(np.real(trd)), 'std': np.std(np.real_if_close(trd))})" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# NBVAL_SKIP\n", + "\n", + "import pandas as pd\n", + "import matplotlib.pyplot as plt\n", + "\n", + "df = pd.DataFrame(infidn)\n", + "dt = pd.DataFrame(trdn)\n", + "plt.scatter(n_shots_max,df['mean'],label='1-Fidelity')\n", + "plt.scatter(n_shots_max,dt['mean'],label='Trace Dist')\n", + "plt.plot(n_shots_max,1/np.sqrt(n_shots_max),label='1/sqrt(N)')\n", + "plt.yscale('log')\n", + "plt.xscale('log')\n", + "plt.ylim([0.0000051,0.1])\n", + "plt.ylabel('Error')\n", + "plt.xlabel('Number of Shots (N)')\n", + "plt.title('Avg. error in estimating one Qubit states drawn from Bures measure')\n", + "plt.legend()\n", + "plt.show()" ] }, { From 0a8c03817682f19fe80fed631ebaaa71627f8b9a Mon Sep 17 00:00:00 2001 From: Joshua Combes Date: Fri, 21 Jun 2019 15:50:51 +1000 Subject: [PATCH 09/11] spelling, improvements and including the figures from NikT's grove docs --- examples/figs/process-tomo.png | Bin 0 -> 19643 bytes examples/figs/state-tomo.png | Bin 0 -> 27282 bytes examples/tomography_process.ipynb | 194 ++++++++++++++++++++++++++++-- examples/tomography_state.ipynb | 77 ++++++++---- 4 files changed, 240 insertions(+), 31 deletions(-) create mode 100644 examples/figs/process-tomo.png create mode 100644 examples/figs/state-tomo.png diff --git a/examples/figs/process-tomo.png b/examples/figs/process-tomo.png new file mode 100644 index 0000000000000000000000000000000000000000..e8c1ea10a6fda92fe0bde26e2d8f8482d7ec118e GIT binary patch literal 19643 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%0A{(o2os3tv9Gf@KdOX92$NIGGW-R?R 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 literal 0 HcmV?d00001 diff --git a/examples/figs/state-tomo.png b/examples/figs/state-tomo.png new file mode 100644 index 0000000000000000000000000000000000000000..2634bd75d18f264e9232651a266dd0a00222e9c3 GIT binary patch literal 27282 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

8ho@zuDy=WjCJTEe9keh4_MCAB#N-2rElI@o z4=yzH4)jd^u>9BfLdlp9S`0X~2BFS!AyQQY0o2^m@Uf!verk{rzVw#LxT{UvNN_Is zEFfl~h_wn_!wjUF+dtu!aZDMhvGV$Q*MLRLh;)=8(J9;r1@eC^kbCa+Lgf^BWe|QvGa{v83CsKuw<%tU zd4W;)4S4=s2SG4LRxboYVu~nY#Z+tY^y3AZU0b#!!JM}bSrby^%`13Umj9nT)!O7X zKtXTb)uG*MzMXw%wkmg4;uIpNuM$1EtqCWwlUA3HCyHJ3es1NqRvGxp@4F4Q3m8yy z9f?_#TzOCtI`J#-UWzw}Dz!VVsrPGvw7d#I!q<166|YS-3XDgaB^Jc8oe0wfVB9aa6Af&_nQ)*NCCmyrfCd*r zc2TVOJP7lUCAoe9d5l8K8?2qK!n!6!u&$XU1g5ST7XM<+Ty>yjEcSJ}N(GCQEMxQuinIy&QROWN`bK*N570NL4_@mNJE(8Hg} z01q`#voV%pJT*oO1$B>LbbQcaj4H4iN-BlU|2P55J3C#pfeg6iaz5k@A1k1xwg4nj zqmlCs+lB4NXLkWm!u5alr=AuVjJ-!GZM05MvjGPu0*c+g~{Br4w$b0iEfgSJVy5K|D19KfauQ8@8zt|$|9cq%FghQv@ za}_Bv5QFr_2%&wEEd=I5;VZIuk*b!!z!a-AZ$g2cUk285_~Sjbs|ceSC`T~T1MOKz zQ*;r8<_xSUBsZAkgCY<#j&9eRH;=|!q2?3G>+n4YZF86;*!tbKs}C3?(Jglf1)w$V zQStFh8~;L@Y-U8a_*F7jXxkNy5cp{~eDHp9zH=7()2b{_Y8|}c@bpsZ-W>^ zb+-~coHp3BU56(!sJ-C>emiKwN1TWB8`lXe8_jNb*t%s>YX;hlBsP6^U_Q0M3$DTA zNFEqkj}!M?P10s*y{=Vs3+4-st_Hz+u(ojD=o^qB4HL97*$-o|3+-a4K-2OkoVFUD zPnSal_(wo_FeEB!q-%ym-T;%rNpHyVqA`Gq=9a^j2}^h5D$P8)VcJ%*We0AB@NkKa z$A0oH&L=hAjMS(M%JlBGbMX)l`4iL_rkD(KE18K2{_~EWC_W?z+pV9^`uD$?L#_ih zZqdqp@z2tOMQHjrSE{f2pHzo79RA@jLkT1kiR3$9fk`0eQ~MEFsgPJm3AjXsmz$se zd%t9aJPyS3QTkV9>}3Iqoryxw-oN*gVuJUhJ&pHY9}t$7DD>uE3O2-34&INSmPEk! z-v|D$dhS1;AP~+H{7Nl|{(ayl3h>MwZ95E9fd2Wyv|u0%nsN\n", + " \"Drawing\"\n", + "

Figure 1. For process tomography, rotations must be prepended and appended to fully resolve the action of V on arbitrary initial states.
\n", + "
\n", + " \n", + " \n", + "The process is kept fixed, while the experimental settings (the preparation and measurement) are varied using pre and post rotations, see Figure 1. To estimate a quantum process matrix on $n$ qubits requires estimating $D^4-D^2$ parameters where $D=2^n$ is the dimension of the Hilbert space.\n", + "\n", + "\n", "\n", - "For input states, we choose the SIC basis comprised of four states, and wee measure in the Pauli basis. The scalling w.r.t. number of qubits is therefore $4^n 3^n$, which is very exponential. If you use the $\\pm$ eigenstates of the pauli operators, it scales as $6^n 3^n$." + "Programmatically ((prep, measure) tuples) are varied. You first choose a suitable set of input states and measurement operators, and then run every `itertools.product` combination of settings.\n", + "\n", + "There are two choices of tomographically complete input states, *SIC* states and *Pauli* states.\n", + "\n", + "The SIC states are the states corresponding to the directions of a [SIC POVM](https://en.wikipedia.org/wiki/SIC-POVM). In this case there are only four states, but we still have to measure in the Pauli basis. The scaling of the number of experiments with respect to number of qubits is therefore $4^n 3^n$.\n", + "\n", + "The alternative is to use $\\pm$ eigenstates of the Pauli operators as our tomographically complete input states. In this case there are six input states, and we still have to measure in the Pauli basis. The scaling of the number of experiments with respect to number of qubits is therefore $6^n 3^n$." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**More information** \n", + "\n", + "\n", + "When thinking about process tomography it is necessary to understand superoperators. For more information see [superoperator_representations.md](../.././forest-benchmarking/docs/superoperator_representations.md) and the [superoperator_tools ipython notebook](superoperator_tools.ipynb).\n", + "\n", + "Also see the following references:\n", + "\n", + "[CWPHD] *Initialization and characterization of open quantum systems* \n", + "Christopher Wood, \n", + "Chapter 3, PhD Thesis, University of Waterloo (2015) \n", + "http://hdl.handle.net/10012/9557 \n", + "\n", + "\n", + "[IGST] *Introduction to Quantum Gate Set Tomography* \n", + "Daniel Greenbaum, \n", + "arXiv:1509.02921 (2015) \n", + "https://arxiv.org/abs/1509.02921 \n", + "\n", + "\n", + "[PBT] *Practical Bayesian Tomography* \n", + "Christopher Granade et al. \n", + "New J. Phys. 18, 033024 (2016) \n", + "https://dx.doi.org/10.1088/1367-2630/18/3/033024 \n", + "https://arxiv.org/abs/1509.03770\n", + "\n", + "\n", + "[SCQPT] Self-Consistent Quantum Process Tomography \n", + "Seth T. Merkel et al. \n", + "Phys. Rev. A 87, 062119 (2013) \n", + "https://dx.doi.org/10.1103/PhysRevA.87.062119 \n", + "https://arxiv.org/abs/1211.0322 " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Quantum process tomography in `forest.benchmarking`\n", + "\n", + "Before reading this section make sure you are familiar with the [state tomography ipython notebook](tomography_state.ipynb)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The basic workflow is:\n", + "\n", + "1. Prepare a process that you wish to estiamte by specifying a pyQuil program.\n", + "2. Construct a list of input and output observables that are needed to estimate the state; we collect this into an object called an `ObservablesExperiment`.\n", + "3. Acquire the data by running the program on a QVM or QPU.\n", + "4. Apply an estimator to the data to obtain an estimate of the process.\n", + "5. Compare the estimated state to the true state by a distance measure or visualization.\n", + "\n", + "\n", + "Below we break these steps down in to all their ghastly glory. " ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": {}, "outputs": [], "source": [ @@ -31,7 +198,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Construct a process\n", + "### Step 1. Construct a process\n", "Which is represented as a pyQuil `Program`" ] }, @@ -278,9 +445,22 @@ } ], "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", - "pygments_lexer": "ipython3" + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3" } }, "nbformat": 4, diff --git a/examples/tomography_state.ipynb b/examples/tomography_state.ipynb index c620e4fe..8dee3a3c 100644 --- a/examples/tomography_state.ipynb +++ b/examples/tomography_state.ipynb @@ -6,21 +6,33 @@ "source": [ "# State tomography\n", "\n", - "### Classical tomography \n", + "It is not possible to learn (or estimate or learn) a quantum state in a single experiment, due to the [no cloning theorem](https://en.wikipedia.org/wiki/No-cloning_theorem). In general one needs to re-prepare the state and measure it many times in [different bases](https://quantumcomputing.stackexchange.com/questions/1870/what-does-measurement-in-a-certain-basis-mean)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Classical \"state\" tomography \n", "The simplest classical analogy to estimating a quantum state using tomography is estimating the bias of a coin. The bias, denoted bias by $p$, is analogous to the quantum state in a way that will be explained shortly.\n", "\n", - "If we have access to $n_{\\rm Tot}$ independent experiements (or measurements) and observe $n_{\\rm H}$ heads then maximum likelihood estimate for the bias of the coin is\n", + "The coin toss is a random variable $R$ with outcome Heads (denoted by $1$) and tails (denoted by $0$). Given the bias $p$ probability distribution for the random variable $R$ is\n", + "$$\n", + "\\Pr(R|p) = p^R(1-p)^{1-R}.\n", + "$$\n", + "\n", + "If we have access to $n_{\\rm Tot}$ independent experiments (or measurements) and observe $n_{\\rm H}$ heads then [maximum likelihood estimate](http://mathworld.wolfram.com/MaximumLikelihood.html) for the bias of the coin is\n", "\n", "$$ p_{\\rm Max-Like} = \\frac{n_H}{n_{\\rm Tot}},$$\n", "\n", "and the variance of this estimator is $ {\\rm Var}[p_{\\rm Max-Like}] = p(1-p)/n_{\\rm Tot}$.\n", "\n", "The things to learn from this example are:\n", - "* it takes many measurements to estiamte $p$, it can't be done in a single shot\n", + "* it takes many measurements to estimate $p$, it can't be done in a single shot because of the [classical no-cloning theorem](https://doi.org/10.1103/PhysRevLett.88.210601)\n", "* $p_{\\rm Max-Like}$ is an estimator, there are other choices of estimators see e.g. [Beta distribution](https://en.wikipedia.org/wiki/Beta_distribution#Bayesian_inference) and [Bayes estimator](https://en.wikipedia.org/wiki/Bayes_estimator)\n", "\n", "\n", - "Let's take the analogy a little further. Lets define a \"quantum\" state \n", + "Let's take the analogy a little further by defining a \"quantum\" state \n", "\n", "$$\\begin{align}\n", "\\rho \n", @@ -29,12 +41,23 @@ "&=\\frac{1}{2} \\begin{pmatrix} 1+z & 0\\\\ 0 & 1-z\\end{pmatrix},\n", "\\end{align}\n", "$$ \n", - "where $I$ and $Z$ are the identity and the Pauli-z matrix. This parameterizes the states along the z-axis of the Bloch sphere\n", + "where $I$ and $Z$ are the identity and the Pauli-z matrix. This parameterizes the states along the z-axis of the Bloch sphere, see Figure 1.\n", + "
\n", + " \"Drawing\"\n", + "
Figure 1. A cross section through the Bloch sphere. The states along the z-axis are equivalent to the allowed states (biases) of a coin.
\n", + "
\n", "\n", "\n", - "\"Drawing\"\n", "\n", "\n", + "Given the state $\\rho$ the probability of measuring zero and one are\n", + "$$\n", + "\\begin{align}\n", + "\\Pr(0|\\rho) &= {\\rm Tr}[\\rho \\Pi_0]\\\\\n", + "\\Pr(1|\\rho) &= {\\rm Tr}[\\rho \\Pi_1]\n", + "\\end{align}\n", + "$$\n", + "where the measurement operators $\\Pi_i$ are defined by $\\Pi_i = |i\\rangle \\langle i|$ for $i \\in \\{0, 1 \\}$.\n", "\n", "The relationship between the $Z$ expectation value and the coin bias is\n", "\n", @@ -51,7 +74,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Quantum tomography of a single qubit\n", + "### Quantum state tomography of a single qubit\n", "\n", "The simplest quantum system to tomograph is a single qubit. Like before we parameterize the state with respect to a set of operators \n", "$$\\begin{align}\n", @@ -63,16 +86,16 @@ "where $x = \\langle X \\rangle$, $y = \\langle Y \\rangle$, and $z = \\langle Z \\rangle$. In the language of our classical coin we have three parameters we need to estimate that are constrained in the following way\n", "\n", "$$\n", - "0\\le x \\le 1\\\\\n", - "0\\le y \\le 1\\\\ \n", - "0\\le z \\le 1\\\\\n", + "0\\le x \\le 1,\\\\\n", + "0\\le y \\le 1,\\\\ \n", + "0\\le z \\le 1,\\\\\n", "x^2 + y^2 +z^2 \\le 1.\n", "$$\n", "\n", - "The physics of our system means that our default our measurement gives us the Z basis statistics. We already constructed an estimator to go from the coin flip statistics to the Z expectation: $2p -1$. \n", + "The physics of our system means that our default measurement gives us the Z basis statistics. We already constructed an estimator to go from the coin flip statistics to the Z expectation: $2p -1$. \n", "\n", "\n", - "Now we need to, measure the statistics of the operators X and Y. Essentially this means we must rotate our state after we prepare it but before it is measured (or equivalently rotate our measurement basis). If we rotate the state as $\\rho\\mapsto U\\rho U^\\dagger$ and then do our usual Z-basis measurement, then this is equivalent to rotating the measured observable as $Z \\mapsto U^\\dagger Z U$ and keeping our state $\\rho$ unchanged. This is the disticntion between the [Heisenberg and Schrödinger pictures](https://en.wikipedia.org/wiki/Heisenberg_picture#Summary_comparison_of_evolution_in_all_pictures). The Heisenberg picture point of view then allows us to see that if we apply a rotation such as $R_y(\\alpha) = \\exp(-i \\alpha Y /2)$ for $\\alpha = -\\pi/2$ then this rotates the observable as $R_y(\\pi/2)ZR_y(-\\pi/2)=\\cos(\\pi/2) Z + \\sin(\\pi/2) X = X$. Similarly, we could rotate by $U=R_x(\\pi/2)$ to measure the Y observable. \n" + "Now we need to measure the statistics of the operators X and Y. Essentially this means we must rotate our state after we prepare it but before it is measured (or equivalently rotate our measurement basis). If we rotate the state as $\\rho\\mapsto U\\rho U^\\dagger$ and then do our usual Z-basis measurement, then this is equivalent to rotating the measured observable as $Z \\mapsto U^\\dagger Z U$ and keeping our state $\\rho$ unchanged. This is the distinction between the [Heisenberg and Schrödinger pictures](https://en.wikipedia.org/wiki/Heisenberg_picture#Summary_comparison_of_evolution_in_all_pictures). The Heisenberg picture point of view then allows us to see that if we apply a rotation such as $R_y(\\alpha) = \\exp(-i \\alpha Y /2)$ for $\\alpha = -\\pi/2$ then this rotates the observable as $R_y(\\pi/2)ZR_y(-\\pi/2)=\\cos(\\pi/2) Z + \\sin(\\pi/2) X = X$. Similarly, we could rotate by $U=R_x(\\pi/2)$ to measure the Y observable. \n" ] }, { @@ -83,7 +106,7 @@ "In this section we closely follow the reference [PBT]. \n", "\n", "When thinking about tomography it is useful to introduce the notation of \"super kets\" $|O\\rangle \\rangle = {\\rm vec}(O)$ for an operator $O$.\n", - "The dual vector is the corresponding \"super bra\" $\\langle\\langle O|$ and represents $O^\\dagger$. This vector space has is equiped with the Hilbert-Schmidt inner product $\\langle\\langle A | B \\rangle\\rangle = {\\rm Tr}[A^\\dagger B]$. For more information see [vec and unvec in superoperator_representations.md](../.././forest-benchmarking/docs/superoperator_representations.md) and the [superoperator_tools ipython notebook](superoperator_tools.ipynb).\n", + "The dual vector is the corresponding \"super bra\" $\\langle\\langle O|$ and represents $O^\\dagger$. This vector space has is equipped with the Hilbert-Schmidt inner product $\\langle\\langle A | B \\rangle\\rangle = {\\rm Tr}[A^\\dagger B]$. For more information see [vec and unvec in superoperator_representations.md](../.././forest-benchmarking/docs/superoperator_representations.md) and the [superoperator_tools ipython notebook](superoperator_tools.ipynb).\n", "\n", "A quantum state matrix on $n$ qubits, a $D =2^n$ dimensional Hilbert\n", "space, can be represented by \n", @@ -94,10 +117,16 @@ "$\\{ B_\\alpha \\}$ that is orthonormal under the Hilbert-Schmidt inner product\n", "$\\langle\\langle B_\\alpha | B_\\beta\\rangle\\rangle =\\delta_{\\alpha,\\beta}$.\n", "\n", - "For many qubits, tensor products of Pauli matrices \n", - "matrices are the natural Hermitian basis. For two qubits define $B_5 = X \\otimes X$ and $B_6 = X \\otimes Y$ then $\\langle\\langle B_5 | B_6\\rangle\\rangle =0$. It is typical to choose $B_0 = I / \\sqrt {D}$ to be the only traceful element.\n", + "For many qubits, tensor products of Pauli matrices are the natural Hermitian basis. For two qubits define $B_5 = X \\otimes X$ and $B_6 = X \\otimes Y$ then $\\langle\\langle B_5 | B_6\\rangle\\rangle =0$. It is typical to choose $B_0 = I / \\sqrt {D}$ to be the only traceful element, where $I$ is the identity on $n$ qubits.\n", + "\n", + "State tomography involves estimating or measuring the expectation values of all the operators $\\{ B_\\alpha \\}$. If you can reconstruct all the operators $\\{ B_\\alpha \\}$ then your measurement is said to be **tomographically complete**. To measure these operators we need to do rotations, like in the single qubit case, on many qubits. This is depicted in Figure 2.\n", + "
\n", + " \"Drawing\"\n", + "
Figure 2. This upper half of this diagram shows a simple 2-qubit quantum program consisting of both qubits initialized in the ∣0⟩ state, then transformed to some other state via a process V and finally measured in the natural qubit basis.
\n", + "
\n", + "\n", "\n", - "State tomography involves estimating or measuring the expectation values of all the operators $\\{ B_\\alpha \\}$. If you can reconstruct all the operators $\\{ B_\\alpha \\}$ then your measurement is said to be **tomographically complete**. The operators that need to be estimatated are programatically given by `itertools.product(['I', 'X', 'Y', 'Z'], repeat=n_qubits)`. From these measurements, we can reconstruct a density matrix $\\rho$ on `n_qubits`.\n", + "The operators that need to be estimated are programatically given by `itertools.product(['I', 'X', 'Y', 'Z'], repeat=n_qubits)`. From these measurements, we can reconstruct a density matrix $\\rho$ on `n_qubits`.\n", "\n", "\n", "Most research in quantum state tomography is to do with finding estimators with desirable properties, e.g. [Minimax tomography](https://arxiv.org/abs/1503.03100), although experiment design is also considered e.g. [adaptive quantum state tomography](https://arxiv.org/abs/1303.0436). \n" @@ -144,14 +173,14 @@ "source": [ "The basic workflow is:\n", "\n", - "1. prepare a state by specifying a pyQuil program\n", - "2. construct a list of observables that are needed to estimate the state; we collect this into an object called an `ObservablesExperiment`.\n", - "3. Aquire the data by running the program on a QVM or QPU.\n", - "4. Apply an estimator to the data to obtain an estimate of the state\n", - "5. Compare the estimated state to the true state by a distance measure or visualization\n", + "1. Prepare a state by specifying a pyQuil program.\n", + "2. Construct a list of observables that are needed to estimate the state; we collect this into an object called an `ObservablesExperiment`.\n", + "3. Acquire the data by running the program on a QVM or QPU.\n", + "4. Apply an estimator to the data to obtain an estimate of the state.\n", + "5. Compare the estimated state to the true state by a distance measure or visualization.\n", "\n", "\n", - "Below we break these steps down in to all their gastly glory. " + "Below we break these steps down in to all their ghastly glory. " ] }, { @@ -177,7 +206,7 @@ "metadata": {}, "source": [ "## Step 1. Prepare a state with a `Program`\n", - "We'll construct a two-qubit graph state by Hadamarding all qubits and then applying a controlled-Z operation across edges of our graph. In the two-qubit case, there's only one edge. The vector we end up preparing is\n", + "We'll construct a two-qubit graph state by Hadamarding all qubits and then applying a controlled-Z operation across the edges of our graph. In the two-qubit case, there's only one edge. The vector we end up preparing is\n", "\n", "$$ |\\Psi\\rangle = \\frac{1}{2}\\begin{pmatrix} 1\\\\ 1 \\\\ 1\\\\ -1\\end{pmatrix}= {\\rm CZ}(0,1){\\rm H}(1){\\rm H}(0)|0,0\\rangle,$$\n", "\n", @@ -387,7 +416,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Step 3. Aquire the data\n", + "## Step 3. Acquire the data\n", "\n", "PyQuil will run the tomography programs.\n", "\n", From 01a031e83bf1f021ae46829f1bf15193fedc8c42 Mon Sep 17 00:00:00 2001 From: Joshua Combes Date: Fri, 21 Jun 2019 17:01:36 +1000 Subject: [PATCH 10/11] notebook updates --- examples/tomography_process.ipynb | 480 ++++++++++++++++++++++++++---- examples/tomography_state.ipynb | 34 +-- 2 files changed, 439 insertions(+), 75 deletions(-) diff --git a/examples/tomography_process.ipynb b/examples/tomography_process.ipynb index 1c77f535..db5d7327 100644 --- a/examples/tomography_process.ipynb +++ b/examples/tomography_process.ipynb @@ -182,12 +182,34 @@ "Below we break these steps down in to all their ghastly glory. " ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Step 1. Construct a process\n", + "\n", + "We choose an $RX(\\pi/2)$ which is represented as a pyQuil `Program`.\n", + "\n", + "The true process is \n", + "\n", + "$$\n", + "RX(\\pi) \n", + "= \\exp[-i \\pi X /2] \n", + "= \\begin{pmatrix}\n", + "0 & -i\\\\\n", + "-i & 0\n", + "\\end{pmatrix}.\n", + "$$\n", + "which is $X$ upto an irrelevant global phase." + ] + }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ + "#some imports\n", "import numpy as np\n", "from pyquil import Program, get_qc\n", "from pyquil.gates import *\n", @@ -195,19 +217,66 @@ ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": 2, "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The Kraus representation is:\n", + " [[0.+0.j 0.-1.j]\n", + " [0.-1.j 0.+0.j]] \n", + "\n", + "The Choi representation is:\n", + " [[0. 0. 0. 0.]\n", + " [0. 1. 1. 0.]\n", + " [0. 1. 1. 0.]\n", + " [0. 0. 0. 0.]]\n", + "\n", + " The X gate choi matrix is:\n", + " [[0. 0. 0. 0.]\n", + " [0. 1. 1. 0.]\n", + " [0. 1. 1. 0.]\n", + " [0. 0. 0. 0.]]\n" + ] + } + ], "source": [ - "### Step 1. Construct a process\n", - "Which is represented as a pyQuil `Program`" + "# numerical representation of the true process\n", + "\n", + "from pyquil.gate_matrices import RX as RX_matrix\n", + "from forest.benchmarking.operator_tools import kraus2choi\n", + "\n", + "kraus_true = RX_matrix(np.pi)\n", + "print('The Kraus representation is:\\n', np.round(kraus_true, 2),'\\n')\n", + "\n", + "choi_true = kraus2choi(kraus_true)\n", + "print('The Choi representation is:\\n', np.real_if_close(np.round(choi_true, 2)))\n", + "\n", + "from pyquil.gate_matrices import X as X_matrix\n", + "choi_x_gate = kraus2choi(X_matrix)\n", + "print('\\n The X gate choi matrix is:\\n', np.real_if_close(np.round(choi_x_gate)))" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "RX(pi) 0\n", + "\n" + ] + } + ], "source": [ + "# construct the process program\n", + "\n", "qubits = [0]\n", "process = Program(RX(np.pi, qubits[0]))\n", "print(process)" @@ -217,17 +286,45 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Construct a `TomographyExperiment` for process tomography\n", - "The `I` basis measurements are redundant, and can be grouped with other terms (see below)." + "## Step 2. Construct a `ObservablesExperiment` for process tomography\n", + "\n", + "Note: The `I` basis measurements are redundant, and can be grouped with other terms (see below)." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "RX(pi) 0\n", + "0: X0_0→(1+0j)*X0\n", + "1: X0_0→(1+0j)*Y0\n", + "2: X0_0→(1+0j)*Z0\n", + "3: X1_0→(1+0j)*X0\n", + "4: X1_0→(1+0j)*Y0\n", + "5: X1_0→(1+0j)*Z0\n", + "6: Y0_0→(1+0j)*X0\n", + "7: Y0_0→(1+0j)*Y0\n", + "8: Y0_0→(1+0j)*Z0\n", + "9: Y1_0→(1+0j)*X0\n", + "10: Y1_0→(1+0j)*Y0\n", + "11: Y1_0→(1+0j)*Z0\n", + "12: Z0_0→(1+0j)*X0\n", + "13: Z0_0→(1+0j)*Y0\n", + "14: Z0_0→(1+0j)*Z0\n", + "15: Z1_0→(1+0j)*X0\n", + "16: Z1_0→(1+0j)*Y0\n", + "17: Z1_0→(1+0j)*Z0\n" + ] + } + ], "source": [ "from forest.benchmarking.tomography import generate_process_tomography_experiment\n", + "\n", "experiment = generate_process_tomography_experiment(process, qubits)\n", "print(experiment)" ] @@ -236,14 +333,46 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## PyQuil will run the tomography programs" + "## Step 3. Acquire the data\n", + "\n", + "PyQuil will run the tomography programs.\n", + "\n", + "We will use the QVM but at this point you can use a QPU." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "[ExperimentResult[X0_0→(1+0j)*X0: 1.0 +- 0.0],\n", + " ExperimentResult[X0_0→(1+0j)*Y0: 0.028 +- 0.04470382533967311],\n", + " ExperimentResult[X0_0→(1+0j)*Z0: 0.024 +- 0.04470847794322683],\n", + " ExperimentResult[X1_0→(1+0j)*X0: -1.0 +- 0.0],\n", + " ExperimentResult[X1_0→(1+0j)*Y0: 0.04 +- 0.044685568140060604],\n", + " ExperimentResult[X1_0→(1+0j)*Z0: -0.012 +- 0.04471813949618208],\n", + " ExperimentResult[Y0_0→(1+0j)*X0: 0.004 +- 0.04472100177768829],\n", + " ExperimentResult[Y0_0→(1+0j)*Y0: -1.0 +- 0.0],\n", + " ExperimentResult[Y0_0→(1+0j)*Z0: 0.0 +- 0.044721359549995794],\n", + " ExperimentResult[Y1_0→(1+0j)*X0: -0.044 +- 0.0446780483011512],\n", + " ExperimentResult[Y1_0→(1+0j)*Y0: 1.0 +- 0.0],\n", + " ExperimentResult[Y1_0→(1+0j)*Z0: 0.108 +- 0.044459779576601605],\n", + " ExperimentResult[Z0_0→(1+0j)*X0: -0.024 +- 0.04470847794322683],\n", + " ExperimentResult[Z0_0→(1+0j)*Y0: -0.016 +- 0.04471563484956912],\n", + " ExperimentResult[Z0_0→(1+0j)*Z0: -1.0 +- 0.0],\n", + " ExperimentResult[Z1_0→(1+0j)*X0: -0.084 +- 0.04456330328869259],\n", + " ExperimentResult[Z1_0→(1+0j)*Y0: 0.064 +- 0.044629676225578875],\n", + " ExperimentResult[Z1_0→(1+0j)*Z0: 1.0 +- 0.0]]" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "from forest.benchmarking.observable_estimation import estimate_observables\n", "results = list(estimate_observables(qc, experiment))\n", @@ -254,31 +383,40 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Linear Inversion Estimate\n", + "## Step 4. Apply some estimators to the data \"do tomography\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Linear Inversion Estimate\n", "\n", "Sometimes the Linear Inversion Estimates can be unphysical. But we can use `proj_choi_to_physical` to force it to be physical." ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "[[-0.03-0.j -0.01-0.j -0.01+0.j -0. +0.02j]\n", - " [-0.01+0.j 1.03-0.j 1. +0.j 0.01-0.01j]\n", - " [-0. -0.01j 1. -0.j 0.97-0.j 0.02+0.02j]\n", - " [ 0. -0.02j 0. +0.01j 0.02-0.02j 0.03-0.j ]]\n", + "Linear inversion estimate:\n", + "\n", + "[[ 0.01-0.j 0. +0.01j 0.01-0.03j -0. +0.02j]\n", + " [ 0. -0.01j 0.99-0.j 1. +0.01j -0.01+0.03j]\n", + " [ 0.01+0.03j 1. -0.01j 1.01-0.j -0.03-0.03j]\n", + " [ 0. -0.02j -0.01-0.03j -0.03+0.03j -0.01-0.j ]]\n", "\n", " Project the above estimate to a physical estimate:\n", "\n", - "[[-0. +0.j -0.01+0.j -0.01+0.j -0. +0.01j]\n", - " [-0.01-0.j 1. -0.j 0.99+0.j 0.01-0.j ]\n", - " [-0.01-0.j 0.99-0.j 0.97+0.j 0.02+0.01j]\n", - " [-0. -0.01j 0.01+0.j 0.02-0.01j 0.03-0.j ]]\n" + "[[ 0.01-0.j 0.01+0.j 0.01-0.01j -0.01+0.j ]\n", + " [ 0.01-0.j 0.99+0.j 0.98+0.01j -0.01+0.01j]\n", + " [ 0.01+0.01j 0.98-0.01j 0.99-0.j -0.02-0.j ]\n", + " [-0.01-0.j -0.01-0.01j -0.02+0.j 0.01+0.j ]]\n" ] } ], @@ -286,49 +424,137 @@ "from forest.benchmarking.tomography import linear_inv_process_estimate\n", "from forest.benchmarking.superoperator_tools import proj_choi_to_physical\n", "\n", - "process_choi_est_lin_inv = linear_inv_process_estimate(results, qubits)\n", - "print(np.real_if_close(np.round(process_choi_est_lin_inv, 2)))\n", - "\n", + "print('Linear inversion estimate:\\n')\n", + "choi_lin_inv_est = linear_inv_process_estimate(results, qubits)\n", + "print(np.real_if_close(np.round(choi_lin_inv_est, 2)))\n", "\n", "print('\\n Project the above estimate to a physical estimate:\\n')\n", - "print(np.real_if_close(np.round(proj_choi_to_physical(process_choi_est_lin_inv), 2)))" + "choi_lin_inv_proj_phys_est = proj_choi_to_physical(choi_lin_inv_est)\n", + "print(np.real_if_close(np.round(choi_lin_inv_proj_phys_est, 2)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## PGDB Estimate" + "### Maximum likelihood Estimate \n", + "\n", + "Using the [PGDB algorithm](https://arxiv.org/abs/1803.10062)." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "array([[-0. +0.j , 0.01-0.j , 0.01-0.j , -0. +0.j ],\n", + " [ 0.01+0.j , 1. -0.j , 1.01+0.01j, -0.01+0.j ],\n", + " [ 0.01+0.j , 1.01-0.01j, 1. -0.j , -0.01+0.j ],\n", + " [-0. -0.j , -0.01-0.j , -0.01-0.j , -0. +0.j ]])" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "from forest.benchmarking.tomography import pgdb_process_estimate\n", - "process_choi_est = pgdb_process_estimate(results, qubits)\n", - "np.real_if_close(np.round(process_choi_est, 2))" + "\n", + "choi_mle_est = pgdb_process_estimate(results, qubits)\n", + "np.real_if_close(np.round(choi_mle_est, 2))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Ideal Choi Matrix" + "## Step 5. Compare estimated process to the true process" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": {}, "outputs": [], "source": [ - "from forest.benchmarking.superoperator_tools import kraus2choi\n", - "from pyquil.gate_matrices import X as X_matrix\n", - "process_choi_ideal = kraus2choi(X_matrix)\n", - "np.real_if_close(np.round(process_choi_ideal))" + "choi_estimates = {\n", + " 'True Process': choi_true,\n", + " 'Linear Inv': choi_lin_inv_est,\n", + " 'ProjLinInv': choi_lin_inv_proj_phys_est,\n", + " 'Plain MLE': choi_mle_est\n", + " }" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Process fidelity**" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Fidelity(True Process, True Process) = 1.0\n", + "Fidelity(True Process, Linear Inv) = 1.0\n", + "Fidelity(True Process, ProjLinInv) = 0.992\n", + "Fidelity(True Process, Plain MLE) = 1.003\n" + ] + } + ], + "source": [ + "from forest.benchmarking.operator_tools import choi2pauli_liouville\n", + "from forest.benchmarking.distance_measures import process_fidelity\n", + "\n", + "# process_fidelity uses pauli liouville rep\n", + "pl_true = choi2pauli_liouville(choi_true)\n", + "\n", + "for key, choi_e in choi_estimates.items():\n", + " pl_e = choi2pauli_liouville(choi_e)\n", + " fid = np.round(process_fidelity(pl_true, pl_e), 3)\n", + " print(f\"Fidelity(True Process, {key}) = {fid}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Diamond norm distance**" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Diamond_norm_dist(True Process, True Process) = -0.0\n", + "Diamond_norm_dist(True Process, Linear Inv) = 0.099\n", + "Diamond_norm_dist(True Process, ProjLinInv) = 0.05\n", + "Diamond_norm_dist(True Process, Plain MLE) = 0.022\n" + ] + } + ], + "source": [ + "from forest.benchmarking.distance_measures import diamond_norm_distance\n", + "\n", + "# diamond_norm_distance takes the choi rep\n", + "for key, choi_e in choi_estimates.items():\n", + " fid = np.round(diamond_norm_distance(choi_true, choi_e), 3)\n", + " print(f\"Diamond_norm_dist(True Process, {key}) = {fid}\")" ] }, { @@ -340,19 +566,31 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], "source": [ "import matplotlib.pyplot as plt\n", - "from forest.benchmarking.superoperator_tools import choi2pauli_liouville\n", "from forest.benchmarking.plotting.state_process import plot_pauli_transfer_matrix\n", "\n", - "fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(12,5))\n", - "plot_pauli_transfer_matrix(np.real(choi2pauli_liouville(process_choi_ideal)), ax1, title='Ideal')\n", - "plot_pauli_transfer_matrix(np.real(choi2pauli_liouville(process_choi_est_lin_inv)), ax2, title='Lin Inv Estimate')\n", - "plot_pauli_transfer_matrix(np.real(choi2pauli_liouville(process_choi_est)), ax3, title='PGDB Estimate')\n", - "plt.tight_layout()" + "fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(12,4))\n", + "plot_pauli_transfer_matrix(np.real(choi2pauli_liouville(choi_true)), ax1, title='Ideal')\n", + "plot_pauli_transfer_matrix(np.real(choi2pauli_liouville(choi_lin_inv_est)), ax2, title='Lin Inv Estimate')\n", + "plot_pauli_transfer_matrix(np.real(choi2pauli_liouville(choi_mle_est)), ax3, title='MLE Estimate')\n", + "plt.tight_layout()\n" ] }, { @@ -364,21 +602,74 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CNOT 0 1\n", + "0: SIC0_0 * SIC0_1→(1+0j)*X1\n", + "1: SIC0_0 * SIC0_1→(1+0j)*Y1\n", + "2: SIC0_0 * SIC0_1→(1+0j)*Z1\n", + "3: SIC0_0 * SIC0_1→(1+0j)*X0\n", + "4: SIC0_0 * SIC0_1→(1+0j)*X0X1\n", + "5: SIC0_0 * SIC0_1→(1+0j)*X0Y1\n", + "6: SIC0_0 * SIC0_1→(1+0j)*X0Z1\n", + "7: SIC0_0 * SIC0_1→(1+0j)*Y0\n", + "8: SIC0_0 * SIC0_1→(1+0j)*Y0X1\n", + "9: SIC0_0 * SIC0_1→(1+0j)*Y0Y1\n", + "... 220 not shown ...\n", + "... use e.settings_string() for all ...\n", + "230: SIC3_0 * SIC3_1→(1+0j)*X0Y1\n", + "231: SIC3_0 * SIC3_1→(1+0j)*X0Z1\n", + "232: SIC3_0 * SIC3_1→(1+0j)*Y0\n", + "233: SIC3_0 * SIC3_1→(1+0j)*Y0X1\n", + "234: SIC3_0 * SIC3_1→(1+0j)*Y0Y1\n", + "235: SIC3_0 * SIC3_1→(1+0j)*Y0Z1\n", + "236: SIC3_0 * SIC3_1→(1+0j)*Z0\n", + "237: SIC3_0 * SIC3_1→(1+0j)*Z0X1\n", + "238: SIC3_0 * SIC3_1→(1+0j)*Z0Y1\n", + "239: SIC3_0 * SIC3_1→(1+0j)*Z0Z1\n" + ] + } + ], "source": [ + "# the process\n", "qubits = [0, 1]\n", "process = Program(CNOT(qubits[0], qubits[1]))\n", + "\n", + "# the experiment object?\n", "experiment = generate_process_tomography_experiment(process, qubits, in_basis='sic')\n", "print(experiment)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "[ExperimentResult[SIC0_0 * SIC0_1→(1+0j)*X1: -0.036 +- 0.044692370713579295],\n", + " ExperimentResult[SIC0_0 * SIC0_1→(1+0j)*Y1: 0.024 +- 0.04470847794322683],\n", + " ExperimentResult[SIC0_0 * SIC0_1→(1+0j)*Z1: 1.0 +- 0.0],\n", + " ExperimentResult[SIC0_0 * SIC0_1→(1+0j)*X0: -0.02 +- 0.04471241438347967],\n", + " ExperimentResult[SIC0_0 * SIC0_1→(1+0j)*X0X1: -0.032 +- 0.04469845634918503],\n", + " ExperimentResult[SIC0_0 * SIC0_1→(1+0j)*X0Y1: 0.028 +- 0.04470382533967311],\n", + " ExperimentResult[SIC0_0 * SIC0_1→(1+0j)*X0Z1: -0.048 +- 0.04466981083461179],\n", + " ExperimentResult[SIC0_0 * SIC0_1→(1+0j)*Y0: 0.032 +- 0.04469845634918503],\n", + " ExperimentResult[SIC0_0 * SIC0_1→(1+0j)*Y0X1: 0.052 +- 0.0446608553433541],\n", + " ExperimentResult[SIC0_0 * SIC0_1→(1+0j)*Y0Y1: -0.104 +- 0.04447884890596878]]" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "results = list(estimate_observables(qc, experiment))\n", "results[:10]" @@ -386,7 +677,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "metadata": {}, "outputs": [], "source": [ @@ -403,9 +694,32 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 17, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1.0 . . . . 1.0 . . . . . 1.0 . . 1.0 . \n", + " . . . . . . . . . . . . . . . . \n", + " . . . . . . . . . . . . . . . . \n", + " . . . . . . . . . . . . . . . . \n", + " . . . . . . . . . . . . . . . . \n", + "1.0 . . . . 1.0 . . . . . 1.0 0.0 . 1.0 . \n", + " . . . . . . . . . . . . . . . . \n", + " . . . . . . . . . . . . . . . . \n", + " . . . . . . . . . . . . . . . . \n", + " . . . . . . . . . . . . . . . . \n", + " . . . . . . . . . . . . . . . . \n", + "1.0 . . . . 1.0 . . . . . 1.0 . . 1.0 . \n", + " . . . . . 0.0 . . . . . . . . 0.0 . \n", + " . . . . . . . . . . . . . . . . \n", + "1.0 . . . . 1.0 . . . . . 1.0 0.0 . 1.0 . \n", + " . . . . . . . . . . . . . . . . \n" + ] + } + ], "source": [ "process_choi_est = pgdb_process_estimate(results, qubits)\n", "_print_big_matrix(process_choi_est)" @@ -413,9 +727,32 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 18, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1.0 . . . . 1.0 . . . . . 1.0 . . 1.0 . \n", + " . . . . . . . . . . . . . . . . \n", + " . . . . . . . . . . . . . . . . \n", + " . . . . . . . . . . . . . . . . \n", + " . . . . . . . . . . . . . . . . \n", + "1.0 . . . . 1.0 . . . . . 1.0 . . 1.0 . \n", + " . . . . . . . . . . . . . . . . \n", + " . . . . . . . . . . . . . . . . \n", + " . . . . . . . . . . . . . . . . \n", + " . . . . . . . . . . . . . . . . \n", + " . . . . . . . . . . . . . . . . \n", + "1.0 . . . . 1.0 . . . . . 1.0 . . 1.0 . \n", + " . . . . . . . . . . . . . . . . \n", + " . . . . . . . . . . . . . . . . \n", + "1.0 . . . . 1.0 . . . . . 1.0 . . 1.0 . \n", + " . . . . . . . . . . . . . . . . \n" + ] + } + ], "source": [ "from pyquil.gate_matrices import CNOT as CNOT_matrix\n", "process_choi_ideal = kraus2choi(CNOT_matrix)\n", @@ -424,9 +761,22 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 19, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], "source": [ "fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12,5))\n", "ideal_ptm = choi2pauli_liouville(process_choi_ideal)\n", @@ -436,6 +786,22 @@ "plt.tight_layout()" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Advanced topics: parallel process estimation" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [], + "source": [ + "#TODO" + ] + }, { "cell_type": "code", "execution_count": null, diff --git a/examples/tomography_state.ipynb b/examples/tomography_state.ipynb index 8dee3a3c..5aa78cdc 100644 --- a/examples/tomography_state.ipynb +++ b/examples/tomography_state.ipynb @@ -183,24 +183,6 @@ "Below we break these steps down in to all their ghastly glory. " ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### A pre-packaged function\n", - "\n", - "We start by " - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "#TODO" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -884,6 +866,22 @@ "## Advanced topics" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Parallel state tomography" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "#TODO" + ] + }, { "cell_type": "markdown", "metadata": {}, From 689f39996000ed55b8893b52492cd321bf7788ca Mon Sep 17 00:00:00 2001 From: Kyle Gulshen <41916921+kylegulshen@users.noreply.github.com> Date: Mon, 24 Jun 2019 15:38:24 -0400 Subject: [PATCH 11/11] Apply suggestions from code review --- examples/tomography_process.ipynb | 14 +++++++------- examples/tomography_state.ipynb | 18 +++++++++--------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/examples/tomography_process.ipynb b/examples/tomography_process.ipynb index db5d7327..4d58f82f 100644 --- a/examples/tomography_process.ipynb +++ b/examples/tomography_process.ipynb @@ -16,9 +16,9 @@ "### Classical \"process\" tomography \n", "\n", "On a single bit there are two processes (or gates or operations) one can perform, `identity` and `not`, which we will denote as $I$ and $X$. The `identity` operation behaves as\n", - "$I 0 = 0$ and $I 1 = 1$ while `not` behaves as $X 0 = 1$ and $X 1 = 0$, these are usually called truth tables. Thus to do classical process tomography we simply need to input a $0$ and $1$ into the circuit and compare the output to the truth table.\n", + "$I 0 = 0$ and $I 1 = 1$ while `not` behaves as $X 0 = 1$ and $X 1 = 0$. To do classical process tomography we simply need to input a $0$ and $1$ into the circuit implementing a particular operation and compare the output to what we ideally expect. \n", "\n", - "However if logic gates can be faulty the situation becomes more complicated. The exact operation of the faulty gate can be captured by the probability of all output strings $j$ given all possible input strings $i$, i.e. $\\Pr({\\rm output\\ } j| {\\rm input\\ }i)$. It is convenient to collect these probabilites into a matrix which is called a [confusion matrix](https://en.wikipedia.org/wiki/Confusion_matrix). For a gate $G$ on single bit $ i,j \\in \\{0, 1 \\}$ it is\n", + "The operation of a faulty classical gate can be captured by the probability of all output strings $j$ given all possible input strings $i$, i.e. $\\Pr({\\rm output\\ } j| {\\rm input\\ }i)$. It is convenient to collect these probabilities into a matrix which is called a [confusion matrix](https://en.wikipedia.org/wiki/Confusion_matrix). For a gate $G$ on single bit $ i,j \\in \\{0, 1 \\}$ it is\n", "\n", "$$\n", "C(G) =\n", @@ -40,7 +40,7 @@ "\n", "We would like to distinguish the following quantum processes\n", "$$\n", - "H = \\frac{1}{2}\n", + "H = \\frac{1}{\\sqrt{2}}\n", "\\begin{pmatrix}\n", "1 & 1\\\\\n", "1 & -1\n", @@ -60,7 +60,7 @@ "\n", "where $\\Pi_j= |j\\rangle \\langle j|$ is a measurement operator with $j\\in\\{ 0,1 \\}$, $\\rho_i=|i\\rangle \\langle i|$ is the input state with $i\\in\\{ 0,1 \\}$, and $G$ is the quantum process ie $H$ or $R_Y$. \n", "\n", - "Using the expression for $\\Pr(j|G, \\rho_i)$ we can construct the confusion matrices for each process. Unfortunately confusion matrices are identical\n", + "Using the expression for $\\Pr(j|G, \\rho_i)$ we can construct the confusion matrices for each process. Unfortunately the two confusion matrices are identical\n", "$$\n", "C(H)= C\\big(R_Y(\\pi/2)\\big) = \\frac 1 2\n", "\\begin{pmatrix}\n", @@ -179,7 +179,7 @@ "5. Compare the estimated state to the true state by a distance measure or visualization.\n", "\n", "\n", - "Below we break these steps down in to all their ghastly glory. " + "Below we break these steps down into all their ghastly glory. " ] }, { @@ -288,7 +288,7 @@ "source": [ "## Step 2. Construct a `ObservablesExperiment` for process tomography\n", "\n", - "Note: The `I` basis measurements are redundant, and can be grouped with other terms (see below)." + "Note: An `I` measurement, though possible, is 'trivial' in the sense that we know the outcome is always 1; therefore, we omit the settings where I is 'measured'. Our estimators add in the contribution of this I term automatically, so be mindful of this if you are making your own settings. " ] }, { @@ -640,7 +640,7 @@ "qubits = [0, 1]\n", "process = Program(CNOT(qubits[0], qubits[1]))\n", "\n", - "# the experiment object?\n", + "# the experiment object\n", "experiment = generate_process_tomography_experiment(process, qubits, in_basis='sic')\n", "print(experiment)" ] diff --git a/examples/tomography_state.ipynb b/examples/tomography_state.ipynb index 5aa78cdc..4a5c3cda 100644 --- a/examples/tomography_state.ipynb +++ b/examples/tomography_state.ipynb @@ -6,7 +6,7 @@ "source": [ "# State tomography\n", "\n", - "It is not possible to learn (or estimate or learn) a quantum state in a single experiment, due to the [no cloning theorem](https://en.wikipedia.org/wiki/No-cloning_theorem). In general one needs to re-prepare the state and measure it many times in [different bases](https://quantumcomputing.stackexchange.com/questions/1870/what-does-measurement-in-a-certain-basis-mean)." + "It is not possible to learn (or estimate) a quantum state in a single experiment due to the [no cloning theorem](https://en.wikipedia.org/wiki/No-cloning_theorem). In general one needs to re-prepare the state and measure it many times in [different bases](https://quantumcomputing.stackexchange.com/questions/1870/what-does-measurement-in-a-certain-basis-mean)." ] }, { @@ -14,14 +14,14 @@ "metadata": {}, "source": [ "### Classical \"state\" tomography \n", - "The simplest classical analogy to estimating a quantum state using tomography is estimating the bias of a coin. The bias, denoted bias by $p$, is analogous to the quantum state in a way that will be explained shortly.\n", + "The simplest classical analogy to estimating a quantum state using tomography is estimating the bias of a coin. The bias, denoted by $p$, is analogous to the quantum state in a way that will be explained shortly.\n", "\n", - "The coin toss is a random variable $R$ with outcome Heads (denoted by $1$) and tails (denoted by $0$). Given the bias $p$ probability distribution for the random variable $R$ is\n", + "The coin toss is a random variable $R$ with outcome Heads (denoted by $1$) and tails (denoted by $0$). Given the bias $p$, the probability distribution for the random variable $R$ is\n", "$$\n", "\\Pr(R|p) = p^R(1-p)^{1-R}.\n", "$$\n", "\n", - "If we have access to $n_{\\rm Tot}$ independent experiments (or measurements) and observe $n_{\\rm H}$ heads then [maximum likelihood estimate](http://mathworld.wolfram.com/MaximumLikelihood.html) for the bias of the coin is\n", + "If we have access to $n_{\\rm Tot}$ independent experiments (or measurements) and observe $n_{\\rm H}$ heads then the [maximum likelihood estimate](http://mathworld.wolfram.com/MaximumLikelihood.html) for the bias of the coin is\n", "\n", "$$ p_{\\rm Max-Like} = \\frac{n_H}{n_{\\rm Tot}},$$\n", "\n", @@ -63,7 +63,7 @@ "\n", "$$z:= \\langle Z \\rangle = {\\rm Tr}[Z \\rho] = 2 p -1.$$\n", "\n", - "In this analogy the pure states $|0\\rangle$ and $|1\\rangle$ corespond to the coin biases $p=1$, $p=0$ and z expectation values $z=+1$, $z=-1$ respectively. All other (mixed) states are convex mixtures of these extremal points e.g. the fair coin, i.e. $p=1/2$, corresponds to $z = 0$ and the state \n", + "In this analogy the pure states $|0\\rangle$ and $|1\\rangle$ correspond to the coin biases $p=1$, $p=0$ and z expectation values $z=+1$, $z=-1$ respectively. All other (mixed) states are convex mixtures of these extremal points e.g. the fair coin, i.e. $p=1/2$, corresponds to $z = 0$ and the state \n", "$$\n", "\\rho \n", "= \\begin{pmatrix} 0.5 & 0\\\\ 0 & 0.5\\end{pmatrix}. \n", @@ -106,7 +106,7 @@ "In this section we closely follow the reference [PBT]. \n", "\n", "When thinking about tomography it is useful to introduce the notation of \"super kets\" $|O\\rangle \\rangle = {\\rm vec}(O)$ for an operator $O$.\n", - "The dual vector is the corresponding \"super bra\" $\\langle\\langle O|$ and represents $O^\\dagger$. This vector space has is equipped with the Hilbert-Schmidt inner product $\\langle\\langle A | B \\rangle\\rangle = {\\rm Tr}[A^\\dagger B]$. For more information see [vec and unvec in superoperator_representations.md](../.././forest-benchmarking/docs/superoperator_representations.md) and the [superoperator_tools ipython notebook](superoperator_tools.ipynb).\n", + "The dual vector is the corresponding \"super bra\" $\\langle\\langle O|$ and represents $O^\\dagger$. This vector space is equipped with the Hilbert-Schmidt inner product $\\langle\\langle A | B \\rangle\\rangle = {\\rm Tr}[A^\\dagger B]$. For more information see [vec and unvec in superoperator_representations.md](../.././forest-benchmarking/docs/superoperator_representations.md) and the [superoperator_tools ipython notebook](superoperator_tools.ipynb).\n", "\n", "A quantum state matrix on $n$ qubits, a $D =2^n$ dimensional Hilbert\n", "space, can be represented by \n", @@ -180,7 +180,7 @@ "5. Compare the estimated state to the true state by a distance measure or visualization.\n", "\n", "\n", - "Below we break these steps down in to all their ghastly glory. " + "Below we break these steps down into all their ghastly glory. " ] }, { @@ -273,7 +273,7 @@ "\n", "We use the helper function `generate_state_tomography_experiment` to construct a tomographically complete set of measurements.\n", "\n", - "We can print this out to see the 16 observables or operator measurements we will perform." + "We can print this out to see the 15 observables or operator measurements we will perform. Note that we could have included an additional observable `I0I1`, but since this trivially gives an expectation of 1 we instead omit this observable in experiment generation and include its contribution by hand in the estimation methods. Be mindful of this if generating your own settings." ] }, { @@ -421,7 +421,7 @@ "source": [ "The next step is to over-write full `quilc` compilation with a much more simple version that *only* substitutes gates to Rigetti-native gates.\n", "\n", - "We do this because, we don't want to accidentally compile away our tomography circuit or map to different qubits." + "We do this because we don't want to accidentally compile away our tomography circuit or map to different qubits." ] }, {