The purpose of this tutorial is to illustrate "germ selection". Germ selection is the process by which a complete set of germ gate sequences is constructed. The defining property which makes a set of gate sequences a "complete germ set" is the amplification of all possible gate errors. More precisely, the repetition of a complete set of germs, sandwiched between preparation and measurement fiducial sequences, will yield a sensitivity to all gate errors that scales with the number of times each germ is repeated. This completeness is relative to the set of gates under consideration, typically a set of desired or "target" gates.
In this tutorial, we find a complete germ set for the standard $X(\pi/2)$, $Y(\pi/2)$, $I$ gate set.
import pygsti from pygsti.construction import std1Q_XYI as std
The perfect target gates may contain symmetries that result in certain parameters being amplified by the same germ sequence coincidentally. We want to find a set of germs that amplifies slight deviations from the ideal gates as well, and so we find germs for a "noisy" version of the target gates, in which each ideal gate is composed with a random small unitary map.
gs_target_noisy = std.gs_target.randomize_with_unitary(0.001, seed=1234)
The germ selection algorithm works by throwing unnecessary germs away from an initial (large) list that is assumed to be complete. In this example, our initial list includes all gatestrings up to length three that are distinct up to powers and cycles. Since germ sequences are repeated and sandwiched between fiducial sequences, a germ that is a power of another germ (i.e. the other germ repeated some number of times) or that is a cyclic permutation of another germ is effectively the same as the other germ. The
list_all_gatestrings_without_powers_and_cycles function provides a convenient way to list sequences gate sequences that are distinct up to such powers and cycles.
germsToTest = pygsti.construction.list_all_gatestrings_without_powers_and_cycles( std.gs_target.gates.keys(), 3)
optimize_integer_germs_slack function thins out an initial list of germs with the goal of finding a smallest complete set. The parameter
slackFrac specifies how much of an increase in the quantity 1.0/smallest-nongauge-jacobian-eigenvalue will be tolerated when excluding a germ sequence from the final set (see the function's documentation for further details). A good value to begin with is
finalGerms = pygsti.alg.optimize_integer_germs_slack( gs_target_noisy, germsToTest, initialWeights=None, fixedSlack=0.1, slackFrac=False, returnAll=False, tol=1e-6, verbosity=4)
Starting germ set optimization. Lower score is better. Gateset has 16 gauge params. Iteration 0: score=12.0189, nGerms=14 No better neighbor. Relaxing score w/slack: 12.0189 => 12.1189 Found better neighbor: nGerms = 13 score = 12.084 Moving to better neighbor Iteration 1: score=12.084, nGerms=13 No better neighbor. Relaxing score w/slack: 12.084 => 12.184 Found better neighbor: nGerms = 12 score = 12.0849 Moving to better neighbor Iteration 2: score=12.0849, nGerms=12 No better neighbor. Relaxing score w/slack: 12.0849 => 12.1849 Found better neighbor: nGerms = 11 score = 12.0984 Moving to better neighbor Iteration 3: score=12.0984, nGerms=11 No better neighbor. Relaxing score w/slack: 12.0984 => 12.1984 Found better neighbor: nGerms = 10 score = 12.1251 Moving to better neighbor Iteration 4: score=12.1251, nGerms=10 No better neighbor. Relaxing score w/slack: 12.1251 => 12.2251 Stationary point found! score = 12.2251346425 weights = [1 1 1 1 0 0 1 1 0 1 1 0 1 1] L1(weights) = 10
And that's it! We now have a small complete germ set that can be used in later GST calculations. Typically one would save this list using
pygsti.io.write_gatestring_list, but for this tutorial we'll just print them.
print "Germs:" print "\n".join(map(str,finalGerms)) # To save to a file: # pygsti.io.write_gatestring_list("mygerms.lst",finalGerms,"List of germs from tutorial")
Germs: Gi Gx Gy GiGx GiGiGx GiGiGy GiGxGy GiGyGx GxGxGy GxGyGy