Fiducials, Germs, and Max-Lengths (oh my!)

While pyGSTi allows one to create arbitrary lists of gate strings, the GST algorithms have been designed to work well with gate sequences that have a particular structure. At the beginning and the end of each string are "preparation fiducial" and "measurement fiducial" sequences, respectively, whose purpose is to extend the native preparation and measurment operations to informationally complete sets. In between the fiducial sequences is a "germ" sequence, or just "germ", that is repeated some number of times. The purpose of the repeated-germ sequence is to amplify one or more particular types of errors. By considering an entire set of germs (called an "amplificationally complete" set), all possible types of errors are amplified, giving the GST algorithms high sensitivity to all errors. The longer the sequences, that is, the more repetitions of the germs, the higher the sensitivity.

While this may seem to imply that one should just to incredibly long sequences, there are several caveats. 1) Because the gates are imperfect, there is some practical length (possibly germ-dependent) at which the initial state is so depolarized that it cannot be distinguished from the maximally-mixed state. This sets an upper bound on the length of useful gate sequences. 2) Because GST's numerical algorithms use local gradient-based optimization methods, starting with seqeunces of maximal length would often result in getting trapped in a local minima of the function being optimized (often the likelihood). The GST algorithms iterate through multiple gate string lists, using the result of the previous iteration to seed the next one. When gate sequences lists are chosen well they are able guide the GST optimization to a global (or near-global) maximum by gradually making the objective function sharper.

In practice, well-chosen lists of gate sequences can be formed as follows. First, we defne an increasing sequence of maximum-lengths, usually powers of 2, e.g. [1,2,4,8,16,...], which terminates with the longest useful sequence length. Secondly, we select preparation- and measurement-fiducial GateString lists, and a list of germ sequences. These lists are chosen such that the fiducial sequences result in informationally complete preparations and measurements, and the germs are amplificationally complete. For each maximum-length $L$, the set of all

preparation_fiducial + repeated_germ + measurement_fiducial

sequences, where preparation_fiducial ranges over all preparation fiducials, measurement_fiducial ranges over all measurement fiducials, and repeated_germ ranges over all the germs repeated such that the length of repeated_germ does not exceed $L$. To further increase the robustness of the numerics, the gate string list corresponding to $L$ will also contain all of the sequences from earlier (lower) values of $L$. This procedure thus creates a list of gate strings for each $L$ that are designed for use by pyGSTi's "long-sequence" GST algorithms.

The fiducial and germ lists are obtained by pyGSTi's "fiducial selection" and "germ selection" algorithms, as detailed in a later tutorial. This this tutorial we'll be using one of pyGSTi's "standard" gate sets, for which fiducial and germ sequences are pre-computed:

In [1]:
import pygsti
from pygsti.construction import std1Q_XY #import the standard X(pi/2), Y(pi/2) gate set info

prep_fiducials = std1Q_XY.prepStrs
meas_fiducials = std1Q_XY.effectStrs
germs = std1Q_XY.germs

print("Prep fiducials:\n", prep_fiducials)
print("Meas fiducials:\n", meas_fiducials)
print("Germs:\n",germs)
Prep fiducials:
 [GateString({}), GateString(Gx), GateString(Gy), GateString(GxGx), GateString(GxGxGx), GateString(GyGyGy)]
Meas fiducials:
 [GateString({}), GateString(Gx), GateString(Gy), GateString(GxGx), GateString(GxGxGx), GateString(GyGyGy)]
Germs:
 [GateString(Gx), GateString(Gy), GateString(GxGy), GateString(GxGxGy), GateString(GxGyGy), GateString(GxGxGyGxGyGy)]

We can now construct a the lists of sequences used by a long-sequence GST algorithm by defining a list of maximum lenghts and calling make_lsgst_lists:

In [2]:
maxLengths = [1,2,4]
lsgst_lists = pygsti.construction.make_lsgst_lists(['Gx','Gy'], prep_fiducials, meas_fiducials, germs, maxLengths)

#Print the result.  Note that larger L lists also contain all the elements of lower-L lists.  
# Note also that germs which are length 4 only show up in the L=4 list, and there are only "repeated" once.
for i,lst in enumerate(lsgst_lists):
    print("\nList %d (max-length L=%d): %d GateStrings" % (i,maxLengths[i],len(lst)))
    print('\n'.join([str(s) for s in lst]))
List 0 (max-length L=1): 56 GateStrings
{}
Gx
Gy
GxGx
GxGxGx
GyGyGy
GxGy
GxGxGxGx
GxGyGyGy
GyGx
GyGy
GyGxGx
GyGxGxGx
GyGyGyGy
GxGxGy
GxGxGxGxGx
GxGxGyGyGy
GxGxGxGy
GxGxGxGxGxGx
GxGxGxGyGyGy
GyGyGyGx
GyGyGyGxGx
GyGyGyGxGxGx
GyGyGyGyGyGy
Gy(Gx)Gy
Gy(Gx)GxGxGx
Gy(Gx)GyGyGy
GxGxGx(Gx)Gy
GxGxGx(Gx)GxGxGx
GxGxGx(Gx)GyGyGy
GyGyGy(Gx)Gy
GyGyGy(Gx)GxGxGx
GyGyGy(Gx)GyGyGy
Gx(Gy)Gx
Gx(Gy)Gy
Gx(Gy)GxGx
Gx(Gy)GxGxGx
Gx(Gy)GyGyGy
Gy(Gy)Gx
Gy(Gy)GxGx
Gy(Gy)GxGxGx
Gy(Gy)GyGyGy
GxGx(Gy)Gx
GxGx(Gy)Gy
GxGx(Gy)GxGx
GxGx(Gy)GxGxGx
GxGx(Gy)GyGyGy
GxGxGx(Gy)Gx
GxGxGx(Gy)Gy
GxGxGx(Gy)GxGx
GxGxGx(Gy)GxGxGx
GxGxGx(Gy)GyGyGy
GyGyGy(Gy)Gx
GyGyGy(Gy)GxGx
GyGyGy(Gy)GxGxGx
GyGyGy(Gy)GyGyGy

List 1 (max-length L=2): 96 GateStrings
{}
Gx
Gy
GxGx
GxGxGx
GyGyGy
GxGy
GxGxGxGx
GxGyGyGy
GyGx
GyGy
GyGxGx
GyGxGxGx
GyGyGyGy
GxGxGy
GxGxGxGxGx
GxGxGyGyGy
GxGxGxGy
GxGxGxGxGxGx
GxGxGxGyGyGy
GyGyGyGx
GyGyGyGxGx
GyGyGyGxGxGx
GyGyGyGyGyGy
Gy(Gx)Gy
Gy(Gx)GxGxGx
Gy(Gx)GyGyGy
GxGxGx(Gx)Gy
GxGxGx(Gx)GxGxGx
GxGxGx(Gx)GyGyGy
GyGyGy(Gx)Gy
GyGyGy(Gx)GxGxGx
GyGyGy(Gx)GyGyGy
Gx(Gy)Gx
Gx(Gy)Gy
Gx(Gy)GxGx
Gx(Gy)GxGxGx
Gx(Gy)GyGyGy
Gy(Gy)Gx
Gy(Gy)GxGx
Gy(Gy)GxGxGx
Gy(Gy)GyGyGy
GxGx(Gy)Gx
GxGx(Gy)Gy
GxGx(Gy)GxGx
GxGx(Gy)GxGxGx
GxGx(Gy)GyGyGy
GxGxGx(Gy)Gx
GxGxGx(Gy)Gy
GxGxGx(Gy)GxGx
GxGxGx(Gy)GxGxGx
GxGxGx(Gy)GyGyGy
GyGyGy(Gy)Gx
GyGyGy(Gy)GxGx
GyGyGy(Gy)GxGxGx
GyGyGy(Gy)GyGyGy
Gy(Gx)^2Gy
Gy(Gx)^2GxGxGx
Gy(Gx)^2GyGyGy
GxGxGx(Gx)^2Gy
GxGxGx(Gx)^2GxGxGx
GxGxGx(Gx)^2GyGyGy
GyGyGy(Gx)^2Gy
GyGyGy(Gx)^2GxGxGx
GyGyGy(Gx)^2GyGyGy
Gx(Gy)^2Gx
Gx(Gy)^2GxGx
Gx(Gy)^2GxGxGx
Gx(Gy)^2GyGyGy
GxGx(Gy)^2Gx
GxGx(Gy)^2GxGx
GxGx(Gy)^2GxGxGx
GxGx(Gy)^2GyGyGy
GxGxGx(Gy)^2Gx
GxGxGx(Gy)^2GxGx
GxGxGx(Gy)^2GxGxGx
GxGxGx(Gy)^2GyGyGy
GyGyGy(Gy)^2Gx
GyGyGy(Gy)^2GxGx
GyGyGy(Gy)^2GxGxGx
GyGyGy(Gy)^2GyGyGy
Gy(GxGy)Gx
Gy(GxGy)Gy
Gy(GxGy)GxGx
Gy(GxGy)GxGxGx
Gy(GxGy)GyGyGy
GxGxGx(GxGy)Gx
GxGxGx(GxGy)Gy
GxGxGx(GxGy)GxGx
GxGxGx(GxGy)GxGxGx
GxGxGx(GxGy)GyGyGy
GyGyGy(GxGy)Gx
GyGyGy(GxGy)Gy
GyGyGy(GxGy)GxGx
GyGyGy(GxGy)GxGxGx
GyGyGy(GxGy)GyGyGy

List 2 (max-length L=4): 189 GateStrings
{}
Gx
Gy
GxGx
GxGxGx
GyGyGy
GxGy
GxGxGxGx
GxGyGyGy
GyGx
GyGy
GyGxGx
GyGxGxGx
GyGyGyGy
GxGxGy
GxGxGxGxGx
GxGxGyGyGy
GxGxGxGy
GxGxGxGxGxGx
GxGxGxGyGyGy
GyGyGyGx
GyGyGyGxGx
GyGyGyGxGxGx
GyGyGyGyGyGy
Gy(Gx)Gy
Gy(Gx)GxGxGx
Gy(Gx)GyGyGy
GxGxGx(Gx)Gy
GxGxGx(Gx)GxGxGx
GxGxGx(Gx)GyGyGy
GyGyGy(Gx)Gy
GyGyGy(Gx)GxGxGx
GyGyGy(Gx)GyGyGy
Gx(Gy)Gx
Gx(Gy)Gy
Gx(Gy)GxGx
Gx(Gy)GxGxGx
Gx(Gy)GyGyGy
Gy(Gy)Gx
Gy(Gy)GxGx
Gy(Gy)GxGxGx
Gy(Gy)GyGyGy
GxGx(Gy)Gx
GxGx(Gy)Gy
GxGx(Gy)GxGx
GxGx(Gy)GxGxGx
GxGx(Gy)GyGyGy
GxGxGx(Gy)Gx
GxGxGx(Gy)Gy
GxGxGx(Gy)GxGx
GxGxGx(Gy)GxGxGx
GxGxGx(Gy)GyGyGy
GyGyGy(Gy)Gx
GyGyGy(Gy)GxGx
GyGyGy(Gy)GxGxGx
GyGyGy(Gy)GyGyGy
Gy(Gx)^2Gy
Gy(Gx)^2GxGxGx
Gy(Gx)^2GyGyGy
GxGxGx(Gx)^2Gy
GxGxGx(Gx)^2GxGxGx
GxGxGx(Gx)^2GyGyGy
GyGyGy(Gx)^2Gy
GyGyGy(Gx)^2GxGxGx
GyGyGy(Gx)^2GyGyGy
Gx(Gy)^2Gx
Gx(Gy)^2GxGx
Gx(Gy)^2GxGxGx
Gx(Gy)^2GyGyGy
GxGx(Gy)^2Gx
GxGx(Gy)^2GxGx
GxGx(Gy)^2GxGxGx
GxGx(Gy)^2GyGyGy
GxGxGx(Gy)^2Gx
GxGxGx(Gy)^2GxGx
GxGxGx(Gy)^2GxGxGx
GxGxGx(Gy)^2GyGyGy
GyGyGy(Gy)^2Gx
GyGyGy(Gy)^2GxGx
GyGyGy(Gy)^2GxGxGx
GyGyGy(Gy)^2GyGyGy
Gy(GxGy)Gx
Gy(GxGy)Gy
Gy(GxGy)GxGx
Gy(GxGy)GxGxGx
Gy(GxGy)GyGyGy
GxGxGx(GxGy)Gx
GxGxGx(GxGy)Gy
GxGxGx(GxGy)GxGx
GxGxGx(GxGy)GxGxGx
GxGxGx(GxGy)GyGyGy
GyGyGy(GxGy)Gx
GyGyGy(GxGy)Gy
GyGyGy(GxGy)GxGx
GyGyGy(GxGy)GxGxGx
GyGyGy(GxGy)GyGyGy
Gy(Gx)^4Gy
Gy(Gx)^4GxGx
Gy(Gx)^4GxGxGx
Gy(Gx)^4GyGyGy
GxGx(Gx)^4Gy
GxGx(Gx)^4GxGxGx
GxGx(Gx)^4GyGyGy
GxGxGx(Gx)^4Gy
GxGxGx(Gx)^4GxGxGx
GxGxGx(Gx)^4GyGyGy
GyGyGy(Gx)^4Gy
GyGyGy(Gx)^4GxGx
GyGyGy(Gx)^4GxGxGx
GyGyGy(Gx)^4GyGyGy
Gx(Gy)^4Gx
Gx(Gy)^4GxGx
Gx(Gy)^4GxGxGx
Gx(Gy)^4GyGyGy
GxGx(Gy)^4Gx
GxGx(Gy)^4GxGx
GxGx(Gy)^4GxGxGx
GxGx(Gy)^4GyGyGy
GxGxGx(Gy)^4Gx
GxGxGx(Gy)^4GxGx
GxGxGx(Gy)^4GxGxGx
GxGxGx(Gy)^4GyGyGy
GyGyGy(Gy)^4Gx
GyGyGy(Gy)^4GxGx
GyGyGy(Gy)^4GxGxGx
GyGyGy(Gy)^4GyGyGy
(GxGy)^2
(GxGy)^2Gx
(GxGy)^2Gy
(GxGy)^2GxGx
(GxGy)^2GxGxGx
(GxGy)^2GyGyGy
Gx(GxGy)^2
Gx(GxGy)^2Gx
Gx(GxGy)^2Gy
Gx(GxGy)^2GxGx
Gx(GxGy)^2GxGxGx
Gx(GxGy)^2GyGyGy
Gy(GxGy)^2
Gy(GxGy)^2Gx
Gy(GxGy)^2Gy
Gy(GxGy)^2GxGx
Gy(GxGy)^2GxGxGx
Gy(GxGy)^2GyGyGy
GxGx(GxGy)^2
GxGx(GxGy)^2Gx
GxGx(GxGy)^2Gy
GxGx(GxGy)^2GxGx
GxGx(GxGy)^2GxGxGx
GxGx(GxGy)^2GyGyGy
GxGxGx(GxGy)^2
GxGxGx(GxGy)^2Gx
GxGxGx(GxGy)^2Gy
GxGxGx(GxGy)^2GxGx
GxGxGx(GxGy)^2GxGxGx
GxGxGx(GxGy)^2GyGyGy
GyGyGy(GxGy)^2
GyGyGy(GxGy)^2Gx
GyGyGy(GxGy)^2Gy
GyGyGy(GxGy)^2GxGx
GyGyGy(GxGy)^2GxGxGx
GyGyGy(GxGy)^2GyGyGy
Gy(GxGxGy)Gx
Gy(GxGxGy)Gy
Gy(GxGxGy)GxGx
Gy(GxGxGy)GxGxGx
Gy(GxGxGy)GyGyGy
GxGxGx(GxGxGy)Gx
GxGxGx(GxGxGy)Gy
GxGxGx(GxGxGy)GxGx
GxGxGx(GxGxGy)GxGxGx
GxGxGx(GxGxGy)GyGyGy
GyGyGy(GxGxGy)Gx
GyGyGy(GxGxGy)Gy
GyGyGy(GxGxGy)GxGx
GyGyGy(GxGxGy)GxGxGx
GyGyGy(GxGxGy)GyGyGy
Gy(GxGyGy)Gx
Gy(GxGyGy)GxGx
Gy(GxGyGy)GxGxGx
Gy(GxGyGy)GyGyGy
GxGxGx(GxGyGy)Gx
GxGxGx(GxGyGy)GxGx
GxGxGx(GxGyGy)GxGxGx
GxGxGx(GxGyGy)GyGyGy
GyGyGy(GxGyGy)Gx
GyGyGy(GxGyGy)GxGx
GyGyGy(GxGyGy)GxGxGx
GyGyGy(GxGyGy)GyGyGy

Why settle for lists, when you can have structures?

While a list-of-lists such as lsgst_lists is all that is needed by the core long-sequence GST algorithms, one can also construct, in similar fashion, a list of pygsti.objects.GateStringStructure objects. These objects mimic a list of GateStrings in many ways, but retain the structure of each sequence so that per-gate-sequence quantities may later be plotted according to their decomposition into fiducials, germ, and $L$. The allstrs member of a GateStringStructure allows access to the underlying list of GateString objects. We'll demonstrate this when we get to plotting. For now, just think of this as a slightly richer way to generate the sequences needed by a GST algorithm that facilitates post-processing and analysis.

In [3]:
#Note: same arguments as make_lsgst_lists
lsgst_structs = pygsti.construction.make_lsgst_structs(['Gx','Gy'], prep_fiducials, meas_fiducials, germs, maxLengths)
print(type(lsgst_structs[0]))
for i,struct in enumerate(lsgst_structs):
    print("Struct %d (L=%d) has %d strings" % (i,maxLengths[i],len(struct.allstrs)))
<class 'pygsti.objects.gatestringstructure.LsGermsStructure'>
Struct 0 (L=1) has 56 strings
Struct 1 (L=2) has 96 strings
Struct 2 (L=4) has 189 strings

List of experiments

If you're taking data, not running a GST algorithm, then you just want a single list of all the sequences that the GST algorithm will need. Since most of the time the lists are nested, that is, all of the lower-$L$ sequences appear in the higher-$L$ sequences, the final element of lsgst_lists is often the list of required experiments. However, in advanced usages this is not always the case, and so there is a dedicated function, make_lsgst_experiment_list which performs this constrution:

In [4]:
#Note: same arguments as make_lsgst_lists
lsgst_experiment_list = pygsti.construction.make_lsgst_experiment_list(['Gx','Gy'], prep_fiducials,
                                                                      meas_fiducials, germs, maxLengths)
print("%d experiments to do..." % len(lsgst_experiment_list))
189 experiments to do...

Example: generating LSGST sequences by hand

As a final full-fledged example we demonstrate the use of pyGSTi's more generate GateString creation and processing functions to create the lists of LSGST sequences. The following example functions are very similar to pygsti.construction.make_lsgst_lists except we assume that the preparation and measurement fiducial sequences are the same.

In [5]:
import pygsti.construction as pc

def my_make_lsgst_lists(gateLabels, fiducialList, germList, maxLengthList):
    singleGates = pc.gatestring_list([(g,) for g in gateLabels])
    lgstStrings = pc.list_lgst_gatestrings(fiducialList, fiducialList, gateLabels)
    lsgst_list = pc.gatestring_list([ () ]) #running list of all strings so far
    
    if maxLengthList[0] == 0:
        lsgst_listOfLists = [ lgstStrings ]
        maxLengthList = maxLengthList[1:]
    else: lsgst_listOfLists = [ ]
        
    for maxLen in maxLengthList:
        lsgst_list += pc.create_gatestring_list("f0+R(germ,N)+f1", f0=fiducialList,
                                           f1=fiducialList, germ=germList, N=maxLen,
                                           R=pc.repeat_with_max_length,
                                           order=('germ','f0','f1'))
        lsgst_listOfLists.append( pygsti.remove_duplicates(lgstStrings + lsgst_list) )

    print("%d LSGST sets w/lengths" % len(lsgst_listOfLists), map(len,lsgst_listOfLists))
    return lsgst_listOfLists

my_lsgst_lists = my_make_lsgst_lists(['Gx','Gy'], prep_fiducials, germs, maxLengths)    
print('\n'.join(['%d strings' % len(l) for l in my_lsgst_lists]))
3 LSGST sets w/lengths <map object at 0x10bef6d30>
56 strings
96 strings
189 strings
In [ ]: