{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "In this notebook, we'll demonstrate how to select preparation and measurement fiducials for the standard single-qubit $X, Y, I$ (or $X, Y$) gate set. The results are very straightforward to generalize for a non $X, Y, I$ single-qubit gateset or a multiqubit gate set.\n", "\n", "Fiducial selection is not quite as much of a \"dark art\" as germ selection is, but there are nonetheless equally valid choices one can make in terms of inputs to the fiducial selection function. At present, we demonstrate only a subset of the functionality, but we endeavour to explain the remaining functionality as well." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false }, "outputs": [], "source": [ "#Import relevant modules.\n", "\n", "import pygsti\n", "import numpy as _np\n", "\n", "from pygsti.algorithms import fiducialselection as FS\n", "\n", "from pygsti.construction import std1Q_XYI\n", "from pygsti.construction import std1Q_XY\n", "\n", "import matplotlib.pyplot as plt\n", "%matplotlib inline\n", "\n", "import time" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Different target gatesets require different fiducials. Thus, we must first define the\n", "target gateset. \n", "\n", "It's worth noting that unlike with germ selection, we will use perfect gates. (In fact, imperfect gates for fiducial selection can introduce errors that we don't want.)" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [], "source": [ "#Define the target gate set we will select fiducials for.\n", "#Here, it is the standard X pi/2, Y pi/2, I gate set.\n", "\n", "gs_target = std1Q_XYI.gs_target" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's now try to actually pick out a fiducial set. The fiducial selection output will strongly depend on several different inputs to the function `optimize_integer_fiducials_slack`. These inputs include:\n", "\n", "* `prepOrMeas`: Whether we are attempting to compute preparation fiducials or measurement fiducials.\n", "\n", "\n", "\n", "* `fiducialList` : The list of candidate germs from which the fiducials set will be chosen.\n", "\n", "\n", "* `initialWeights` : The initial subset of candidate fiducials which the optimizer tests. The default here is `None`, meaning that all candidate fiducials are included in the first fiducial set test.\n", "\n", "\n", "* `fixedSlack` : The absolute score a fiducial set is allowed to achieve\n", "\n", "\n", "* `slackFrac` : The relative score a fiducial set is allowed to achieve\n", "\n", "\n", "Note: **Only one** of `fixedSlack` or `slackFrac` may be set. Typically we will use `fixedSlack`, and we find that `fixedSlack` ~1 is sufficient. These arguments determine the relaxation scheme used to reduce the fiducial list size.\n", "\n", "\n", "* `forceEmpty`: Whether or not the fiducial set *must* contain the empty string.\n", " \n", " \n", "* `fixedNum` : Whether or not we are forcing the fiducial set to be a fixed size\n", "\n", "\n", "* `scoreFunc` : Whether the objective function only tries to minimize how insensitive we are for our most insensitive direction in Hilbert-Schmidt space, or if it tries to make us as sensitive as possible to all directions in Hilbert-Schmidt space\n", "\n", "\n", "\n", "Here we demonstrate particular choices for the above inputs. By parameter counting, one can see that these particular instances yield \"optimal\" results (as there are four elements of a state or measurement effect, and we choose four fiducials). \n", "\n", "** However, we make no claims of optimality for these choices in general (particularly when 2 or more qubits are considered).**\n", "\n", "End users are encouraged to experiment themselves with these inputs. They are also welcome to contact the `pygsti` development team at pygsti@sandia.gov." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": true }, "outputs": [], "source": [ "#Let's try to pick out a fiducial set. \n", "\n", "#First, we generate a candidate set which we'll attempt to prune.\n", "#Here, we're looking at all gate string sequences of maximum length 2.\n", "\n", "max_length = 2\n", "gates = ['Gx','Gy']#We omit any identity operations here, as we don't want them in our fiducials.\n", "\n", "#Important for the minlength arg to equal 0, so we include the empty string.\n", "testFidList = pygsti.construction.list_all_gatestrings(gates,0,max_length)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "Don't worry if the `optimize_integer_fiducials_slack` function below throws a divide by zero warning;\n", "this just means one of the tested cases was *really* bad." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Starting fiducial set optimization. Lower score is better.\n", "Iteration 0: score=35, nFids=7\n", "Moving to better neighbor\n", "Iteration 1: score=36, nFids=6\n", "Moving to better neighbor\n", "Iteration 2: score=35, nFids=5\n", "Moving to better neighbor\n", "Iteration 3: score=32, nFids=4\n", "Stationary point found!\n", "score = 64.0\n", "weights = [1 0 0 0 1 1 1]\n", "L1(weights) = 4\n", "\n", "Fiducial selection completed in 0.0117061 seconds.\n", "[GateString({}), GateString(GxGy), GateString(GyGx), GateString(GyGy)]\n" ] } ], "source": [ "#Compute the preparation fiducials\n", "\n", "start = time.time()\n", "prepFidList1 = FS.optimize_integer_fiducials_slack(gs_target,testFidList,prepOrMeas='prep',\\\n", " initialWeights=None,slackFrac=1)\n", "end = time.time()\n", "print\n", "print \"Fiducial selection completed in {0} seconds.\".format(round(end-start, 7))\n", "print prepFidList1" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Starting fiducial set optimization. Lower score is better.\n", "Iteration 0: score=35, nFids=7\n", "Moving to better neighbor\n", "Iteration 1: score=36, nFids=6\n", "Moving to better neighbor\n", "Iteration 2: score=35, nFids=5\n", "Moving to better neighbor\n", "Iteration 3: score=32, nFids=4\n", "Stationary point found!\n", "score = 64.0\n", "weights = [1 0 0 0 1 1 1]\n", "L1(weights) = 4\n", "\n", "Fiducial selection completed in 0.0108709 seconds.\n", "[GateString({}), GateString(GxGy), GateString(GyGx), GateString(GyGy)]\n" ] } ], "source": [ "# Compute the measurement fiducials \n", "\n", "start = time.time()\n", "measFidList1 = FS.optimize_integer_fiducials_slack(gs_target,testFidList,prepOrMeas='meas',\\\n", " initialWeights=None,slackFrac=1)\n", "end = time.time()\n", "print\n", "print \"Fiducial selection completed in {0} seconds.\".format(round(end-start, 7))\n", "print measFidList1" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "We have selected our preparation fiducials to be:\n", "\t{}\n", "\tGxGy\n", "\tGyGx\n", "\tGyGy\n" ] } ], "source": [ "print \"We have selected our preparation fiducials to be:\"\n", "for fid in prepFidList1:\n", " print '\\t',fid" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "We have selected our measurement fiducials to be:\n", "\t{}\n", "\tGxGy\n", "\tGyGx\n", "\tGyGy\n" ] } ], "source": [ "print \"We have selected our measurement fiducials to be:\"\n", "for fid in measFidList1:\n", " print '\\t',fid" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The key property we wish for our fiducials to have is _informational completeness_. Below, we test whether our selected preparation and measurement fiducuials are in fact so." ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "(True,\n", " array([ 0.21922359, 0.5 , 1. , 2.28077641]),\n", " 32.000000000000007)" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "FS.test_fiducial_list(gs_target,prepFidList1,'prep',returnAll=True)" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "(True,\n", " array([ 0.21922359, 0.5 , 1. , 2.28077641]),\n", " 32.000000000000007)" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "FS.test_fiducial_list(gs_target,measFidList1,'meas',returnAll=True)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "Note that in practice, we use a set of six fiducials both for prep and measure (which can be created using `std1Q_XYI.fiducials`).\n", "This is for greater numerical stability; for single-qubit GST, we recommend 6 preparation and 6 measurement fiducials, as the added cost is not too great, and this provides prep and measure fiducials corresponding to all 6 antipodal points on the Bloch sphere, providing a nice degree of symmetry.\n", "\n", "However, for multiqubit GST, experimental resource constraints become more relevant, and we recommend simply directly using the outputs of the fiducial selection code.\n", "\n", "That said, one can, for one or more quibits, force optimize_integer_fiducials_slack to return a fiducial set of\n", "fixed size. Instead of running an integer program over fiducial sets of different sizes, we can instead score\n", "all fiducial sets of a fixed size (that are subsets of the input set) and select the best one. \n", "This can become expensive quickly, but it is very feasible for at least single-qubit gate sets, as exhibited below.\n", "\n", "To turn this functionality on, set the fixedNum keyword argument to be equal to the fiducial set size you want.\n", "\n", "Also, a warning: **If there does not exist an informationally complete fiducial set of the desired size, you may still receive an output from `optimize_integer_fiducials_slack`**, so it is important to check the score of the fiducial set (either via the `returnAll` keyword arg, or the `function test_fiducial_list`.)" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": true }, "outputs": [], "source": [ "#Again, we'll try to pick out a fiducial set, but now we will insist that the set be of size 6.\n", "#We'll look at all gate string sequences of maximum length 3.\n", "\n", "max_length = 3\n", "gates = ['Gx','Gy']\n", "\n", "testFidList_force6 = pygsti.construction.list_all_gatestrings(gates,0,max_length)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Starting fiducial set optimization. Lower score is better.\n", "Output set is required to be of size 6\n", "Total number of fiducial sets to be checked is 2002.0\n", "If this is very large, you may wish to abort.\n", "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Fiducial selection completed in 0.860805 seconds.\n", "[GateString({}), GateString(Gx), GateString(Gy), GateString(GxGx), GateString(GxGxGx), GateString(GxGxGy)]\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "/home/enielse/research/pyGSTi/packages/pygsti/algorithms/fiducialselection.py:355: RuntimeWarning: divide by zero encountered in divide\n", " return sum(1./_np.abs(input_array))\n" ] } ], "source": [ "#Let's again forceEmpty to be True, and see what we get for preparation fiducials.\n", "start = time.time()\n", "prepFidList1_force6 = FS.optimize_integer_fiducials_slack(gs_target,testFidList_force6,prepOrMeas='prep',\\\n", " initialWeights=None,slackFrac=1,fixedNum=6,\\\n", " forceEmpty=True)\n", "end = time.time()\n", "print\n", "print \"Fiducial selection completed in {0} seconds.\".format(round(end-start, 7))\n", "print prepFidList1_force6" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Starting fiducial set optimization. Lower score is better.\n", "Output set is required to be of size 6\n", "Total number of fiducial sets to be checked is 5005.0\n", "If this is very large, you may wish to abort.\n", "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Fiducial selection completed in 1.701298 seconds.\n", "[GateString({}), GateString(Gx), GateString(Gy), GateString(GxGx), GateString(GxGxGx), GateString(GxGxGy)]\n" ] } ], "source": [ "#Let's set forceEmpty = False\n", "start = time.time()\n", "prepFidList1_force6 = FS.optimize_integer_fiducials_slack(gs_target,testFidList_force6,prepOrMeas='prep',\\\n", " initialWeights=None,slackFrac=1,fixedNum=6,\\\n", " forceEmpty=False)\n", "end = time.time()\n", "print\n", "print \"Fiducial selection completed in {0} seconds.\".format(round(end-start, 7))\n", "print prepFidList1_force6\n", "#Conveniently, we get the same results as above!" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Starting fiducial set optimization. Lower score is better.\n", "Output set is required to be of size 6\n", "Total number of fiducial sets to be checked is 2002.0\n", "If this is very large, you may wish to abort.\n", "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Fiducial selection completed in 0.8509941 seconds.\n", "[GateString({}), GateString(Gx), GateString(Gy), GateString(GxGx), GateString(GxGxGx), GateString(GyGxGx)]\n" ] } ], "source": [ "#Now let's make a measurement fiducial set with forceEmpty = True\n", "start = time.time()\n", "measFidList1_force6 = FS.optimize_integer_fiducials_slack(gs_target,testFidList_force6,prepOrMeas='meas',\\\n", " initialWeights=None,slackFrac=1,fixedNum=6,\\\n", " forceEmpty=True)\n", "end = time.time()\n", "print\n", "print \"Fiducial selection completed in {0} seconds.\".format(round(end-start, 7))\n", "print measFidList1_force6" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Starting fiducial set optimization. Lower score is better.\n", "Output set is required to be of size 6\n", "Total number of fiducial sets to be checked is 5005.0\n", "If this is very large, you may wish to abort.\n", "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Fiducial selection completed in 1.6874199 seconds.\n", "[GateString({}), GateString(Gx), GateString(Gy), GateString(GxGx), GateString(GxGxGx), GateString(GyGxGx)]\n" ] } ], "source": [ "#Now let's make a measurement fiducial set with forceEmpty = False\n", "start = time.time()\n", "measFidList1_force6 = FS.optimize_integer_fiducials_slack(gs_target,testFidList_force6,prepOrMeas='meas',\\\n", " initialWeights=None,slackFrac=1,fixedNum=6,\\\n", " forceEmpty=False)\n", "end = time.time()\n", "print\n", "print \"Fiducial selection completed in {0} seconds.\".format(round(end-start, 7))\n", "print measFidList1_force6" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "We have selected our size-6 preparation fiducials to be:\n", "\t{}\n", "\tGx\n", "\tGy\n", "\tGxGx\n", "\tGxGxGx\n", "\tGxGxGy\n" ] } ], "source": [ "print \"We have selected our size-6 preparation fiducials to be:\"\n", "for fid in prepFidList1_force6:\n", " print '\\t',fid" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "We have selected our size-6 measurement fiducials to be:\n", "\t{}\n", "\tGx\n", "\tGy\n", "\tGxGx\n", "\tGxGxGx\n", "\tGyGxGx\n" ] } ], "source": [ "print \"We have selected our size-6 measurement fiducials to be:\"\n", "for fid in measFidList1_force6:\n", " print '\\t',fid" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "(True, array([ 1., 1., 1., 3.]), 20.0)" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "FS.test_fiducial_list(gs_target,prepFidList1_force6,'prep',returnAll=True)" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "(True, array([ 1., 1., 1., 3.]), 20.0)" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "FS.test_fiducial_list(gs_target,measFidList1_force6,'meas',returnAll=True)" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "std1Q_XYI.fiducials = [GateString({}), GateString(Gx), GateString(Gy), GateString(GxGx), GateString(GxGxGx), GateString(GyGyGy)]\n", "(True, array([ 1., 1., 1., 3.]), 20.0)\n", "(True, array([ 1., 1., 1., 3.]), 20.0)\n" ] } ], "source": [ "#Lastly, let's compare to the \"standard\" 6-fiducial set we use as our default:\n", "print \"std1Q_XYI.fiducials =\", std1Q_XYI.fiducials\n", "print FS.test_fiducial_list(gs_target,std1Q_XYI.fiducials,'prep',returnAll=True)\n", "print FS.test_fiducial_list(gs_target,std1Q_XYI.fiducials,'meas',returnAll=True)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "The \"standard\" fiducials are very similar to the automatically selected ones, and score the same!\n", "The notable difference is that prep and measurement fiducials are different when automatically selected;\n", "our default sets are the same for both prep and measure.\n", "This is because each \"standard\" fiducial is symmetric; the automated fiducials reverse gate order between\n", "preparation and measure." ] } ], "metadata": { "kernelspec": { "display_name": "Python 2", "language": "python", "name": "python2" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.9" } }, "nbformat": 4, "nbformat_minor": 0 }