#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.)
#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")
#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
#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.
#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)))
#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)))
#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)))
#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)))
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:])
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:])
#Interestingly, using the option "worst" instead of "all" yields a better scoring fiducial set, by both the "worst"
#and "all".
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:])
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:])
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]
#We have the same scores for "all" and "worst" for measurement fiducials, even though the fiducial sets themselves
#are not quite the same.
#Lastly, let's see if we can find a minimal set of measurement fiducials (size 6), using the same input set as before.
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)))
FS.test_fiducial_list(gs_target,measFidList1_all_force6,'meas',scoreFunc='all',returnAll=True)
#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.)