{ "cells": [ { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "# Matrix Basis Tutorial\n", "\n", "Consider the space of density matrices corresponding to a Hilbert space $\\mathcal{H}$ of dimension $d$. The basis used for this Hilbert-Schmidt space, $B(\\mathcal{H})$, can be any set of $d\\times d$ matrices which span the density matrix space. pyGSTi supports arbitrary bases by deriving from the `pygsti.tools.Basis` class, and constains built-in support for the following basis sets:\n", "\n", "- the matrix unit, or \"standard\" basis, consisting of the matrices with a single unit (1.0) element and otherwise zero. This basis is selected by passing `\"std\"` to appropriate function arguments.\n", "- the Pauli-product basis, consisting of tensor products of the four Pauli matrices {I, X, Y, Z} normalized so that $Tr(B_i B_j) = \\delta_{ij}$. All of these matrices are Hermitian, so that Hilbert-Schmidt vectors and matrices are real when this basis is used. This basis can only be used when the $d = 4^i$ for integer $i$, and is selected using the string `\"pp\"`.\n", "- the Gell-Mann basis, consisting of the normalized Gell-Mann matrices (see Wikipedia if you don't know what these are). Similar to the Pauli-product case, these matrices are also Hermitian, so that Hilbert-Schmidt vectors and matrices are real when this basis is used. Unlike the Pauli-product case, since Gell-Mann matrices are well defined in any dimension, the Gell-Mann basis is *not* restricted to cases when $d=4^i$. This basis is selected using the string `\"gm\"`.\n", "- a special basis of $3 \\times 3$ matricies designed for Qutrit systems formed by taking the symmetric subspace of a 2-qubit system. This basis is selected using the string `\"qt\"`. \n", "\n", "Numerous functions within pyGSTi require knowledge of what Hilbert-Schmidt basis is being used. The `pygsti.objects.Basis` object encapsulates a basis, and is the most flexible way of specifying a basis in pyGSTi. Alternatively, many functions also accept the short strings `\"std\"`, `\"gm\"`, `\"pp\"`, and `\"qt\"` to select one of the standard bases. In this tutorial, we'll demonstrate how to create a `Basis` object and use it and related functions to obtain and change the basis of the gate matrices and SPAM vectors stored in a `GateSet`." ] }, { "cell_type": "markdown", "metadata": { "collapsed": true, "deletable": true, "editable": true }, "source": [ "The most straightforward way to create a `Basis` object is to provide its short name and dimension:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "from pygsti import Basis\n", "pp = Basis('pp', 2)\n", "std = Basis('std', 2)\n", "gm = Basis('gm', 2)\n", "qt = Basis('qt', 3) # qt must be dim 3\n", "bases = [pp, std, gm, qt]" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Each of the `pp`, `std`, and `gm` bases created will have $4$ $2x2$ matrices each. The `qt` basis has $9$ $3x3$ matrices instead:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "pp basis (dim 2):\n", "4 elements:\n", "[[0.70710678+0.j 0. +0.j]\n", " [0. +0.j 0.70710678+0.j]]\n", "[[0. +0.j 0.70710678+0.j]\n", " [0.70710678+0.j 0. +0.j]]\n", "[[0.+0. j 0.-0.70710678j]\n", " [0.+0.70710678j 0.+0. j]]\n", "[[ 0.70710678+0.j 0. +0.j]\n", " [ 0. +0.j -0.70710678+0.j]]\n", "std basis (dim 2):\n", "4 elements:\n", "[[1.+0.j 0.+0.j]\n", " [0.+0.j 0.+0.j]]\n", "[[0.+0.j 1.+0.j]\n", " [0.+0.j 0.+0.j]]\n", "[[0.+0.j 0.+0.j]\n", " [1.+0.j 0.+0.j]]\n", "[[0.+0.j 0.+0.j]\n", " [0.+0.j 1.+0.j]]\n", "gm basis (dim 2):\n", "4 elements:\n", "[[0.70710678+0.j 0. +0.j]\n", " [0. +0.j 0.70710678+0.j]]\n", "[[0. +0.j 0.70710678+0.j]\n", " [0.70710678+0.j 0. +0.j]]\n", "[[0.+0. j 0.-0.70710678j]\n", " [0.+0.70710678j 0.+0. j]]\n", "[[ 0.70710678+0.j 0. +0.j]\n", " [ 0. +0.j -0.70710678+0.j]]\n", "qt basis (dim 3):\n", "9 elements:\n", "[[0.57735027+0.j 0. +0.j 0. +0.j]\n", " [0. +0.j 0.57735027+0.j 0. +0.j]\n", " [0. +0.j 0. +0.j 0.57735027+0.j]]\n", "[[-0.40824829+0.j 0. +0.j 0. +0.j]\n", " [ 0. +0.j 0.81649658+0.j 0. +0.j]\n", " [ 0. +0.j 0. +0.j -0.40824829+0.j]]\n", "[[0. +0.j 0. +0.j 0.70710678+0.j]\n", " [0. +0.j 0. +0.j 0. +0.j]\n", " [0.70710678+0.j 0. +0.j 0. +0.j]]\n", "[[0.+0. j 0.-0.5j 0.+0. j]\n", " [0.+0.5j 0.+0. j 0.+0.5j]\n", " [0.+0. j 0.-0.5j 0.+0. j]]\n", "[[0. +0.j 0.5+0.j 0. +0.j]\n", " [0.5+0.j 0. +0.j 0.5+0.j]\n", " [0. +0.j 0.5+0.j 0. +0.j]]\n", "[[0.+0. j 0.-0.5j 0.+0. j]\n", " [0.+0.5j 0.+0. j 0.-0.5j]\n", " [0.+0. j 0.+0.5j 0.+0. j]]\n", "[[ 0.70710678+0.j 0. +0.j 0. +0.j]\n", " [ 0. +0.j 0. +0.j 0. +0.j]\n", " [ 0. +0.j 0. +0.j -0.70710678+0.j]]\n", "[[0.+0. j 0.+0. j 0.-0.70710678j]\n", " [0.+0. j 0.+0. j 0.+0. j]\n", " [0.+0.70710678j 0.+0. j 0.+0. j]]\n", "[[ 0. +0.j 0.5+0.j 0. +0.j]\n", " [ 0.5+0.j 0. +0.j -0.5+0.j]\n", " [ 0. +0.j -0.5+0.j 0. +0.j]]\n" ] } ], "source": [ "for basis in bases:\n", " print('{} basis (dim {}):'.format(basis.name, basis.dim.dmDim))\n", " print('{} elements:'.format(len(basis)))\n", " for element in basis:\n", " print(element)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "However, custom bases can be easily created by supplying matrices:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Standard Basis : (0,0), (0,1), (1,0), (1,1)\n" ] } ], "source": [ "import numpy as np\n", "std2x2Matrices = [\n", " np.array([[1, 0],\n", " [0, 0]]),\n", " np.array([[0, 1],\n", " [0, 0]]),\n", " np.array([[0, 0],\n", " [1, 0]]),\n", " np.array([[0, 0],\n", " [0, 1]])]\n", "\n", "alt_standard = Basis(matrices=std2x2Matrices,\n", " name='std',\n", " longname='Standard')\n", "print(alt_standard)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "More complex bases can be created by chaining other bases together along the diagonal. For example, a composition of the $2x2$ `std` basis with the $1x1$ `std` basis leads to a basis with state vectors of length $5$, or $5x5$ matrices:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "std,std Basis : M(std,std)[0,0], M(std,std)[0,1], M(std,std)[0,2], M(std,std)[0,3], M(std,std)[1,0]\n", "[[1.+0.j 0.+0.j 0.+0.j]\n", " [0.+0.j 0.+0.j 0.+0.j]\n", " [0.+0.j 0.+0.j 0.+0.j]]\n", "[[0.+0.j 1.+0.j 0.+0.j]\n", " [0.+0.j 0.+0.j 0.+0.j]\n", " [0.+0.j 0.+0.j 0.+0.j]]\n", "[[0.+0.j 0.+0.j 0.+0.j]\n", " [1.+0.j 0.+0.j 0.+0.j]\n", " [0.+0.j 0.+0.j 0.+0.j]]\n", "[[0.+0.j 0.+0.j 0.+0.j]\n", " [0.+0.j 1.+0.j 0.+0.j]\n", " [0.+0.j 0.+0.j 0.+0.j]]\n", "[[0.+0.j 0.+0.j 0.+0.j]\n", " [0.+0.j 0.+0.j 0.+0.j]\n", " [0.+0.j 0.+0.j 1.+0.j]]\n" ] } ], "source": [ "comp = Basis('std', [2, 1])\n", "comp = Basis([('std', 2), ('std', 1)])\n", "comp = Basis([std, ('std', 1)])\n", "comp = Basis([Basis('std', 2), Basis('std', 1)])\n", "print(comp)\n", "for element in comp:\n", " print(element)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "### Basis usage\n", "Once created, bases are used to manipulate matrices and vectors within pygsti:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [ "array([[ 2., 0., 0., 0.],\n", " [ 0., 3., 0., 0.],\n", " [ 0., 0., -1., 0.],\n", " [ 0., 0., 0., 0.]])" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from pygsti.tools import change_basis, flexible_change_basis\n", "\n", "mx = np.array([[1, 0, 0, 1],\n", " [0, 1, 2, 0],\n", " [0, 2, 1, 0],\n", " [1, 0, 0, 1]])\n", "\n", "change_basis(mx, 'std', 'gm') # shortname lookup\n", "change_basis(mx, std, gm) # object only\n", "change_basis(mx, std, 'gm') # combination" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Composite bases can be converted between expanded and contracted forms:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[1.+0.j 2.+0.j]\n", " [3.+0.j 4.+0.j]]\n" ] } ], "source": [ "mxInStdBasis = np.array([[1,0,0,2],\n", " [0,0,0,0],\n", " [0,0,0,0],\n", " [3,0,0,4]],'d')\n", "\n", "begin = Basis('std', 2)\n", "end = Basis('std', [1,1])\n", "mxInReducedBasis = flexible_change_basis(mxInStdBasis, begin, end)\n", "print(mxInReducedBasis)\n", "original = flexible_change_basis(mxInReducedBasis, end, begin)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.5.2" } }, "nbformat": 4, "nbformat_minor": 2 }