In [1]:
#Import relevant modules.

import pygsti
import numpy as _np

from pygsti.algorithms import fiducialselection as FS

import matplotlib.pyplot as plt
%matplotlib inline

import time

In this notebook, we'll demonstrate how to select preparation and measurement fiducials for a standard two-qubit gate set. By "standard", we mean that a) measurements are made in the computational (Z) basis (and state prep is |00>), and b) gate set consists of independent X pi/2 and Y pi/2 gates on each qubit. Presumably there will be additional entangling gates available; however, we do not want (or need) such gates in our fiducial gate strings. (Two-qubit operations will typically be of lower fidelity, so it is "safer" to use single-qubit operations for fiducials.)

In [2]:
#Build the gate set.  As mentioned above, no entangling operation is included; these results will be general for
#any two-qubit gate set that has access to the Gix, Giy, Gxi, and Gyi gates 
#(and prepares in the state |00> and performs measurements in the computational basis).
gs_target = pygsti.construction.build_gateset( [4], [('Q0','Q1')],['Gix','Giy','Gxi','Gyi'], 
                                            ["X(pi/2,Q1)", "Y(pi/2,Q1)", "X(pi/2,Q0)", "Y(pi/2,Q0)"], 
                                            prepLabels = ["rho0"], prepExpressions = ["0"], 
                                            effectLabels = ["E0","E1","E2"], effectExpressions = ["0","1","2"], 
                                            spamdefs={'upup': (0,0), 'updn': (0,1), 'dnup': (0,2), 'dndn': (0,-1) },
                                            basis="pp")
In [3]:
#Let's try to pick out a fiducial set.  

#First, we generate a candidate set which we'll attempt to prune.
#We could look at all gate strings of up to a fixed length (using pygsti.construction.list_all_gatestrings),
#but that grows quite rapidly.
#Instead, we'll look at the tensor product of the standard 1-qubit fiducial set with itself.
#This product set we define below.

#{} x 1q fid list
emptyList = pygsti.construction.gatestring_list([
        (),
        ('Gix',),
        ('Gix','Gix'),
        ('Gix','Gix','Gix'),
        ('Giy',),
        ('Giy','Giy','Giy')
    ])

#Gx x 1q fid list
XList = pygsti.construction.gatestring_list([
        ('Gxi',),
        ('Gxi','Gix',),
        ('Gxi','Gix','Gix'),
        ('Gxi','Gix','Gix','Gix'),
        ('Gxi','Giy',),
        ('Gxi','Giy','Giy','Giy')
    ])

#GxGx x 1q fid list
XXList = pygsti.construction.gatestring_list([
        ('Gxi','Gxi'),
        ('Gxi','Gxi','Gix',),
        ('Gxi','Gxi','Gix','Gix'),
        ('Gxi','Gxi','Gix','Gix','Gix'),
        ('Gxi','Gxi','Giy',),
        ('Gxi','Gxi','Giy','Giy','Giy')
    ])

#GxGxGx x 1q fid list
XXXList = pygsti.construction.gatestring_list([
        ('Gxi','Gxi','Gxi'),
        ('Gxi','Gxi','Gxi','Gix',),
        ('Gxi','Gxi','Gxi','Gix','Gix'),
        ('Gxi','Gxi','Gxi','Gix','Gix','Gix'),
        ('Gxi','Gxi','Gxi','Giy',),
        ('Gxi','Gxi','Gxi','Giy','Giy','Giy')
    ])

#Gy x 1q fid list
YList = pygsti.construction.gatestring_list([
        ('Gyi',),
        ('Gyi','Gix',),
        ('Gyi','Gix','Gix'),
        ('Gyi','Gix','Gix','Gix'),
        ('Gyi','Giy',),
        ('Gyi','Giy','Giy','Giy')
    ])

#Gy x 1q fid list
YYYList = pygsti.construction.gatestring_list([
        ('Gyi','Gyi'),
        ('Gyi','Gyi','Gyi','Gix',),
        ('Gyi','Gyi','Gyi','Gix','Gix'),
        ('Gyi','Gyi','Gyi','Gix','Gix','Gix'),
        ('Gyi','Gyi','Gyi','Giy',),
        ('Gyi','Gyi','Gyi','Giy','Giy','Giy')
    ])

testFidList = emptyList + XList + XXList + XXXList + YList + YYYList
In [4]:
#Don't worry if the optimize_integer_fiducials_slack function below throws a divide by zero warning;
#this just means one of the tested cases was *really* bad.
In [5]:
#We know that we should be able to find a prep fiducial set that has no more than 16 elements,
#so if we are finding sets that are larger than that, we can always increase slackFrac or fixedSlack
start = time.time()
prepFidList1_all = FS.optimize_integer_fiducials_slack(gs_target,testFidList,prepOrMeas='prep',initialWeights=None,
                                                       scoreFunc='all',slackFrac=.275)
end = time.time()
print
print "Fiducial selection completed in", end-start, "seconds."
print "\n".join(map(str,sorted(prepFidList1_all,key=len)))
Starting fiducial set optimization. Lower score is better.
Iteration 0: score=411.818, nFids=36
Moving to better neighbor
Iteration 1: score=408.333, nFids=35
Moving to better neighbor
Iteration 2: score=415.669, nFids=34
Moving to better neighbor
Iteration 3: score=424.621, nFids=33
Moving to better neighbor
Iteration 4: score=449.913, nFids=32
Moving to better neighbor
Iteration 5: score=460.238, nFids=31
Moving to better neighbor
Iteration 6: score=481.522, nFids=30
Moving to better neighbor
Iteration 7: score=484.676, nFids=29
Moving to better neighbor
Iteration 8: score=494.598, nFids=28
Moving to better neighbor
Iteration 9: score=525.857, nFids=27
Moving to better neighbor
Iteration 10: score=564.806, nFids=26
Moving to better neighbor
Iteration 11: score=578.853, nFids=25
Moving to better neighbor
Iteration 12: score=578.211, nFids=24
Moving to better neighbor
Iteration 13: score=660.513, nFids=23
Moving to better neighbor
Iteration 14: score=660, nFids=22
Moving to better neighbor
Iteration 15: score=699.391, nFids=21
Moving to better neighbor
Iteration 16: score=766.667, nFids=20
Moving to better neighbor
Iteration 17: score=842.333, nFids=19
Moving to better neighbor
Iteration 18: score=874.286, nFids=18
Moving to better neighbor
Iteration 19: score=1020, nFids=17
Moving to better neighbor
Iteration 20: score=1088, nFids=16
Stationary point found!
score =  1387.2
weights =  [1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 1 1 1 1 0 0 0 0 1 1 1 1 0 1 1 1 1]
L1(weights) =  16

Fiducial selection completed in 0.41614484787 seconds.
{}
GyiGiy
GyiGyi
GxiGxiGiy
GxiGxiGxiGix
GxiGxiGxiGiy
GyiGixGixGix
GyiGiyGiyGiy
GyiGyiGyiGiy
GxiGxiGixGixGix
GxiGxiGiyGiyGiy
GxiGxiGxiGixGix
GyiGyiGyiGixGix
GxiGxiGxiGixGixGix
GyiGyiGyiGixGixGix
GyiGyiGyiGiyGiyGiy
In [6]:
#We know that we should be able to find a prep fiducial set that has no more than 16 elements,
#so if we are finding sets that are larger than that, we can always increase slackFrac or fixedSlack
start = time.time()
prepFidList1_worst = FS.optimize_integer_fiducials_slack(gs_target,testFidList,prepOrMeas='prep',initialWeights=None,
                                                         scoreFunc='worst',slackFrac=.275)
end = time.time()
print
print "Fiducial selection completed in", end-start, "seconds."
print "\n".join(map(str,sorted(prepFidList1_worst,key=len)))
Starting fiducial set optimization. Lower score is better.
Iteration 0: score=53.4923, nFids=36
Moving to better neighbor
Iteration 1: score=53.3249, nFids=35
Moving to better neighbor
Iteration 2: score=53.1718, nFids=34
Moving to better neighbor
Iteration 3: score=52.0526, nFids=33
Moving to better neighbor
Iteration 4: score=50.4752, nFids=32
Moving to better neighbor
Iteration 5: score=59.4355, nFids=31
Moving to better neighbor
Iteration 6: score=57.9586, nFids=30
Moving to better neighbor
Iteration 7: score=57.7735, nFids=29
Moving to better neighbor
Iteration 8: score=57.7451, nFids=28
Moving to better neighbor
Iteration 9: score=55.7134, nFids=27
Moving to better neighbor
Iteration 10: score=66.2138, nFids=26
Moving to better neighbor
Iteration 11: score=68.2051, nFids=25
Moving to better neighbor
Iteration 12: score=83.4132, nFids=24
Moving to better neighbor
Iteration 13: score=81.0626, nFids=23
Moving to better neighbor
Iteration 14: score=78.1512, nFids=22
Moving to better neighbor
Iteration 15: score=88.4591, nFids=21
Moving to better neighbor
Iteration 16: score=100.819, nFids=20
Moving to better neighbor
Iteration 17: score=118.296, nFids=19
Moving to better neighbor
Iteration 18: score=148.25, nFids=18
Moving to better neighbor
Iteration 19: score=167.026, nFids=17
Moving to better neighbor
Iteration 20: score=195.295, nFids=16
Stationary point found!
score =  249.001323854
weights =  [1 0 0 1 1 0 0 0 0 0 0 0 0 1 0 0 0 1 1 0 1 1 0 1 0 0 1 1 0 1 1 1 1 0 1 0]
L1(weights) =  16

Fiducial selection completed in 0.37730717659 seconds.
{}
Giy
GyiGyi
GixGixGix
GxiGxiGix
GxiGxiGxi
GyiGixGix
GyiGixGixGix
GyiGiyGiyGiy
GyiGyiGyiGix
GyiGyiGyiGiy
GxiGxiGiyGiyGiy
GxiGxiGxiGixGix
GyiGyiGyiGixGix
GxiGxiGxiGixGixGix
GxiGxiGxiGiyGiyGiy
In [7]:
#We know that there might exist a fiducial measurement set with as few as 6 elements (as 6*3=18>16).
#However, repeated attempts to find one to date have failed.  We can reliably identify fiducial measurement sets
#with only 9 elements, so 9 should be considered an upper bound.  (If you do find a set with fewer than 9 elements,
#the pyGSTi team would love to hear from you!)
start = time.time()
measFidList1_all = FS.optimize_integer_fiducials_slack(gs_target,testFidList,prepOrMeas='meas',initialWeights=None,
                                                       scoreFunc='all',slackFrac=1)
end = time.time()
print
print "Fiducial selection completed in", end-start, "seconds."
print "\n".join(map(str,sorted(measFidList1_all,key=len)))
Starting fiducial set optimization. Lower score is better.
Iteration 0: score=135.206, nFids=36
Moving to better neighbor
Iteration 1: score=134.74, nFids=35
Moving to better neighbor
Iteration 2: score=135.569, nFids=34
Moving to better neighbor
Iteration 3: score=140.249, nFids=33
Moving to better neighbor
Iteration 4: score=140.606, nFids=32
Moving to better neighbor
Iteration 5: score=140.565, nFids=31
Moving to better neighbor
Iteration 6: score=140.471, nFids=30
Moving to better neighbor
Iteration 7: score=140.035, nFids=29
Moving to better neighbor
Iteration 8: score=139.165, nFids=28
Moving to better neighbor
Iteration 9: score=138.355, nFids=27
Moving to better neighbor
Iteration 10: score=137.143, nFids=26
Moving to better neighbor
Iteration 11: score=139.083, nFids=25
Moving to better neighbor
Iteration 12: score=140.314, nFids=24
Moving to better neighbor
Iteration 13: score=141.459, nFids=23
Moving to better neighbor
Iteration 14: score=141.435, nFids=22
Moving to better neighbor
Iteration 15: score=141.134, nFids=21
Moving to better neighbor
Iteration 16: score=140.906, nFids=20
Moving to better neighbor
Iteration 17: score=140.137, nFids=19
Moving to better neighbor
Iteration 18: score=138.753, nFids=18
Moving to better neighbor
Iteration 19: score=146.204, nFids=17
Moving to better neighbor
Iteration 20: score=151.585, nFids=16
Moving to better neighbor
Iteration 21: score=156.817, nFids=15
Moving to better neighbor
Iteration 22: score=159.181, nFids=14
Moving to better neighbor
Iteration 23: score=163.76, nFids=13
Moving to better neighbor
Iteration 24: score=163.266, nFids=12
Moving to better neighbor
Iteration 25: score=161.512, nFids=11
Moving to better neighbor
Iteration 26: score=160.547, nFids=10
Moving to better neighbor
Iteration 27: score=158.065, nFids=9
Stationary point found!
score =  316.130180659
weights =  [1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 1 1 1 0 0 0 0 0 0 0 0 1 1 0 0 1]
L1(weights) =  9

Fiducial selection completed in 0.639625072479 seconds.
{}
GxiGxiGxiGiy
GyiGyiGyiGix
GxiGxiGixGixGix
GxiGxiGiyGiyGiy
GxiGxiGxiGixGix
GyiGyiGyiGixGix
GxiGxiGxiGixGixGix
GyiGyiGyiGiyGiyGiy
/home/enielse/research/pyGSTi/packages/pygsti/algorithms/fiducialselection.py:355: RuntimeWarning: divide by zero encountered in divide
  return sum(1./_np.abs(input_array))
In [8]:
#Let's try the same as above, but with "worst" instead of "all" as the scoreFunc.
start = time.time()
measFidList1_worst = FS.optimize_integer_fiducials_slack(gs_target,testFidList,prepOrMeas='meas',initialWeights=None,
                                                       scoreFunc='worst',slackFrac=1)
end = time.time()
print
print "Fiducial selection completed in", end-start, "seconds."
print "\n".join(map(str,sorted(measFidList1_worst,key=len)))
Starting fiducial set optimization. Lower score is better.
Iteration 0: score=16.153, nFids=36
Moving to better neighbor
Iteration 1: score=15.7166, nFids=35
Moving to better neighbor
Iteration 2: score=15.2778, nFids=34
Moving to better neighbor
Iteration 3: score=14.9137, nFids=33
Moving to better neighbor
Iteration 4: score=14.4871, nFids=32
Moving to better neighbor
Iteration 5: score=14.0945, nFids=31
Moving to better neighbor
Iteration 6: score=13.7221, nFids=30
Moving to better neighbor
Iteration 7: score=13.2827, nFids=29
Moving to better neighbor
Iteration 8: score=12.861, nFids=28
Moving to better neighbor
Iteration 9: score=12.4406, nFids=27
Moving to better neighbor
Iteration 10: score=18.0183, nFids=26
Moving to better neighbor
Iteration 11: score=17.3281, nFids=25
Moving to better neighbor
Iteration 12: score=16.6354, nFids=24
Moving to better neighbor
Iteration 13: score=16.2301, nFids=23
Moving to better neighbor
Iteration 14: score=16.0761, nFids=22
Moving to better neighbor
Iteration 15: score=15.3486, nFids=21
Moving to better neighbor
Iteration 16: score=14.6218, nFids=20
Moving to better neighbor
Iteration 17: score=14.1724, nFids=19
Moving to better neighbor
Iteration 18: score=13.7001, nFids=18
Moving to better neighbor
Iteration 19: score=24.8079, nFids=17
Moving to better neighbor
Iteration 20: score=23.7956, nFids=16
Moving to better neighbor
Iteration 21: score=23.5748, nFids=15
Moving to better neighbor
Iteration 22: score=22.6821, nFids=14
Moving to better neighbor
Iteration 23: score=21.7602, nFids=13
Moving to better neighbor
Iteration 24: score=20.9816, nFids=12
Moving to better neighbor
Iteration 25: score=23.093, nFids=11
Moving to better neighbor
Iteration 26: score=22.7489, nFids=10
Moving to better neighbor
Iteration 27: score=24.2287, nFids=9
Stationary point found!
score =  48.4574110103
weights =  [1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0 0 1 1 1 0]
L1(weights) =  9

Fiducial selection completed in 0.607774972916 seconds.
{}
GxiGxiGxiGix
GyiGyiGyiGiy
GxiGxiGixGixGix
GxiGxiGiyGiyGiy
GxiGxiGxiGixGix
GyiGyiGyiGixGix
GxiGxiGxiGiyGiyGiy
GyiGyiGyiGixGixGix
In [9]:
print "prep fid_all spectrum:\n", FS.test_fiducial_list(gs_target,prepFidList1_all,'prep',returnAll=True)[1]
print "prep fid_all 'all-score':", sum(FS.test_fiducial_list(gs_target,prepFidList1_all,'prep',
                                                             scoreFunc='all',returnAll=True)[2:])
print "prep fid_all 'worst-score':", sum(FS.test_fiducial_list(gs_target,prepFidList1_all,'prep',
                                                             scoreFunc='worst',returnAll=True)[2:])
prep fid_all spectrum:
[ 0.04601333  0.08804562  0.11197634  0.18885363  0.19098301  0.27531678
  0.33869376  0.35895543  0.6341986   1.          1.14021158  1.30901699
  1.52707531  1.99774087  2.02250994  4.77040881]
prep fid_all 'all-score': 1088.0
prep fid_all 'worst-score': 347.725298007
In [10]:
print "prep fid_worst spectrum:\n", FS.test_fiducial_list(gs_target,prepFidList1_worst,'prep',returnAll=True)[1]
print "prep fid_worst 'all-score':", sum(FS.test_fiducial_list(gs_target,prepFidList1_worst,'prep',
                                                             scoreFunc='all',returnAll=True)[2:])
print "prep fid_worst 'worst-score':", sum(FS.test_fiducial_list(gs_target,prepFidList1_worst,'prep',
                                                             scoreFunc='worst',returnAll=True)[2:])
prep fid_worst spectrum:
[ 0.08192728  0.11388855  0.13201528  0.19518522  0.27205661  0.29289322
  0.5         0.5         0.5         0.65555661  0.9189264   1.11499364
  1.70710678  2.18411013  2.19512844  4.63621184]
prep fid_worst 'all-score': 832.0
prep fid_worst 'worst-score': 195.295155964
In [11]:
#Interestingly, using the option "worst" instead of "all" yields a better scoring fiducial set, by both the "worst"
#and "all".
In [12]:
print "prep meas_all spectrum:\n", FS.test_fiducial_list(gs_target,measFidList1_all,'meas',returnAll=True)[1]
print "prep meas_all 'all-score':", sum(FS.test_fiducial_list(gs_target,measFidList1_all,'meas',
                                                             scoreFunc='all',returnAll=True)[2:])
print "prep meas_all 'worst-score':", sum(FS.test_fiducial_list(gs_target,measFidList1_all,'meas',
                                                             scoreFunc='worst',returnAll=True)[2:])
prep meas_all spectrum:
[ 0.37146021  0.5         0.56368584  0.64534973  0.71248175  0.71922359
  0.74410254  0.75        0.75        1.91668037  2.          2.16101916
  2.52091388  2.77107311  2.78077641  7.0932334 ]
prep meas_all 'all-score': 158.065090329
prep meas_all 'worst-score': 24.2287055051
In [13]:
print "prep meas_worst spectrum:\n", FS.test_fiducial_list(gs_target,measFidList1_worst,'meas',returnAll=True)[1]
print "prep meas_worst 'all-score':", sum(FS.test_fiducial_list(gs_target,measFidList1_worst,'meas',
                                                             scoreFunc='all',returnAll=True)[2:])
print "prep meas_worst 'worst-score':", sum(FS.test_fiducial_list(gs_target,measFidList1_worst,'meas',
                                                             scoreFunc='worst',returnAll=True)[2:])
prep meas_worst spectrum:
[ 0.37146021  0.5         0.56368584  0.64534973  0.71248175  0.71922359
  0.74410254  0.75        0.75        1.91668037  2.          2.16101916
  2.52091388  2.77107311  2.78077641  7.0932334 ]
prep meas_worst 'all-score': 158.065090329
prep meas_worst 'worst-score': 24.2287055051
In [14]:
for i in xrange(len(measFidList1_all)):
    print sorted(measFidList1_all,key=len)[i], '\t', sorted(measFidList1_worst,key=len)[i], '\t', sorted(measFidList1_all,key=len)[i] == sorted(measFidList1_worst,key=len)[i]
{} 	{} 	True
GxiGxiGxiGiy 	GxiGxiGxiGix 	False
GyiGyiGyiGix 	GyiGyiGyiGiy 	False
GxiGxiGixGixGix 	GxiGxiGixGixGix 	True
GxiGxiGiyGiyGiy 	GxiGxiGiyGiyGiy 	True
GxiGxiGxiGixGix 	GxiGxiGxiGixGix 	True
GyiGyiGyiGixGix 	GyiGyiGyiGixGix 	True
GxiGxiGxiGixGixGix 	GxiGxiGxiGiyGiyGiy 	False
GyiGyiGyiGiyGiyGiy 	GyiGyiGyiGixGixGix 	False
In [15]:
#We have the same scores for "all" and "worst" for measurement fiducials, even though the fiducial sets themselves
#are not quite the same.
In [16]:
#Lastly, let's see if we can find a minimal set of measurement fiducials (size 6), using the same input set as before.
In [17]:
start = time.time()
measFidList1_all_force6 = FS.optimize_integer_fiducials_slack(gs_target,testFidList,prepOrMeas='meas',initialWeights=None,fixedNum=6,
                                                       scoreFunc='all',slackFrac=1)
end = time.time()
print
print "Fiducial selection completed in", end-start, "seconds."
print "\n".join(map(str,sorted(measFidList1_worst,key=len)))
Starting fiducial set optimization. Lower score is better.
Output set is required to be of size 6
Total number of fiducial sets to be checked is 324632.0
If this is very large, you may wish to abort.
Switching!
Switching!
Switching!

Fiducial selection completed in 151.725115061 seconds.
{}
GxiGxiGxiGix
GyiGyiGyiGiy
GxiGxiGixGixGix
GxiGxiGiyGiyGiy
GxiGxiGxiGixGix
GyiGyiGyiGixGix
GxiGxiGxiGiyGiyGiy
GyiGyiGyiGixGixGix
In [18]:
FS.test_fiducial_list(gs_target,measFidList1_all_force6,'meas',scoreFunc='all',returnAll=True)
/home/enielse/research/pyGSTi/packages/pygsti/algorithms/fiducialselection.py:164: RuntimeWarning: divide by zero encountered in divide
  return sum(1./input_array)
Out[18]:
(False, array([ -1.59973447e-17,   0.00000000e+00,   6.42205571e-17,
          1.05661853e-16,   3.39941429e-16,   6.51889291e-16,
          3.03557616e-01,   4.38772336e-01,   5.00000000e-01,
          1.00000000e+00,   1.00000000e+00,   1.00000000e+00,
          2.15905500e+00,   2.95730073e+00,   3.46274430e+00,
          5.17857002e+00]), inf)
In [19]:
#Sadly, this did not work!  However, one could try different input sets (or increasing fixedNum to 7 or 8, which would
#still be better than 9.)
In [20]: