This notebook contains a list of frequently asked questions and their answers. If the answer is short, example code is given directly in this notebook; if not, then the reader is referred to other pyGSTi tutorials and examples.
"Gate Set Tomography" (GST) is a protocol that attempts to infer the quantum operations a device is performing by analyzing data generated by it. The device is viewed as a black box, so that physics-level details of its construction and operation are not needed. GST characterizes quantum gate operations, state preparations, and measurement operations simultaneously, avoiding the chicken-and-egg problem of state and process tomography, which has been shown to be problematic. For more information about the algorithms and theory of GST, please see Demonstration of qubit operations below a rigorous fault tolerance threshold with gate set tomography, Nature Communications 8 (2017)
PyGSTi is the name of (this) software, which implements the various parts of the GST protocol(s). It is written (almost) entirely in Python, and is released as an open-source software under the GPL license. "pyGSTi" stands for "python GST implementation".
Using pyGSTi, running GST is fairly simple. Single-qubit GST is demonstrated in full in the [first tutorial](Tutorials/00 Getting Started.ipynb), and 2-qubit GST (though very similar to 1-qubit GST) is separately demonstrated in [this 2Q-GST example](Examples/2Q-GST: running it.ipynb). The core GST algorithm is run by calling pygsti.do_long_sequence_gst
or pygsti.do_stdpractice_gst
.
Constraint on the gates (and SPAM operations) in pyGSTi are imposed via the "parameterization" of GateSet
objects. Each GateSet
essentially knows how to map some vector of (real-valued) "parameters" to a full set of gate matrices and SPAM vectors - and whether a given set of matrices & vectors can be reached depends on whether there exists a set of parameters that maps onto it. The parameterization used by a GateSet
object can be changed among commonly used parameterizations via the set_all_parameterizations
member function. To constrain gates and SPAM operations to be trace preserving, simply call
my_target_gateset.set_all_parameterizations("TP")
before calling do_long_sequence_gst
or do_stdpractice_gst
with my_target_gateset
.
Similar to the above question, you simply set the parameterization of your target GateSet
to "CPTP" before calling do_long_sequence_gst
or do_stdpractice_gst
. Note that currenlty this only ensures that the gates are CPTP - not the SPAM operations. (Attempts to parameterize the SPAM operations as such have resulted in poor performance and are considered an experimental feature.)
my_target_gateset.set_all_parameterizations("CPTP")
A "gauge transformation" is a special type of mapping from one gate set to another which preserves all predicted physical outcomes (hence the name "gauge"). Thus, gauge transformations map between physically equivalent gate sets, and the set of all gauge transformations partitions the space of gate sets into physically-distinct equivalence classes. Gauge optimization refers to the process by which one finds the gate set within an equivalence class which optimizes some metric - typically the frobenius distance between the gate set and some "target gate set". In pyGSTi, gauge optimization is invoked using the pygsti.gaugeopt_to_target
method (which minimizes the distance between a GateSet
and a target GateSet
) or the pygsti.gaugeopt_custom
method (which accepts a user-defined objective function).
Specifying the "details" of gauge optimization is essentially specifying the objective function. The arguments of gaugeopt_to_target
(detailed in its docstring and pyGSTi's online docs) describe how to change which distance metric is used (the frobenius distance, process fidelity, or the Jamiolkowski trace distance) when comparing gates, and how to put different weighting factors on individual gates (via the itemWeights
argument). In higher-level functions, gauge-optimization details are specified by simply creating a dictionary of gauge_opt_to_target
's arguments. Adding a new gauge-optimization to an existing pygsti.objects.Results
object is demonstrated in the ["adding new gauge optimizations" example](Examples/GOpt: adding new gauge optimizations.ipynb). One particularly powerful way to control gauge optimization is by specifying an imperfect target GateSet
which includes the errors you expect to see in the gates. This is simple to do, and outlined in the ["non-ideal gauge optimization targets" example](Examples/GOpt: non-ideal gauge optimization targets.ipynb).
There are two primary ways of speeding up the GST analysis within pyGSTi: 1) using more/multiple processors and 2) reducing the number of gate sequences being analyzed. The first option is achieved by passing the core pyGSTi routines (e.g. do_long_sequence_gst
) a mpi4py.MPI.Comm
object (and often a per-core memory limit too), and is demonstrated in an [example](Examples/MPI: running GST in parallel.ipynb). The second option involves more of a tradeoff, as decreasing the number of sequences with reduce the accuracy of GST and/or its robustness. Restricting GST to shorter sequences (reducing the "max-lengths" used) will result in less accurate estimates, i.e. larger error bars. The use of "fiducial pair reduction" techniques, outlined in [this tutorial](Tutorials/10 Fiducial Pair Reduction.ipynb), retains the accuracy of GST while eliminating sequences. This, however, results is less robustness and sensitivity to out-of-model errors.
Because their computation can be time-consuming, the process of computing error bars on report quantities has been split into more or less three pieces in pyGSTi:
None
confidenceLevel
argument.In previous pyGSTi versions, simply doing step 3 would automatically trigger steps 1 and 2, but this is no longer the case. The reason for this is that steps 1 and 2 (especially 1) can take a long time, and one may want to run them on a separate machine with more processing power. As demonstrated in the [2Q-GST error bars example](Examples/2Q-GST: generating error bars.ipynb), you must first add a ConfidenceRegionFactory
object to your results, then call compute_hessian
and project_hessian
(perhaps on a large multiprocessor machine). After this, you can use create_standard_report
with confidenceLevel=95
, for instance, to create a report with 95% confidence interval error bars.
A note about Hessian projection:
After computing a Hessian you must specify how the Hessian is projected onto a space orthogonal to the manifold of gauge degrees of freedom. This is done via ConfidenceRegionFactory.project_hessian(...)
. The basic idea here is that there is a choice, similar to the choice of which metric to use for gauge optimization, which defines the notion of "orthogonality" and thereby how error bars are constructed for the non-gauge degrees of freedom. There are several ways pyGSTi can do this, and you specify which way you want by the projection_type
argument to project_hessian
. One, "optimal gate CIs"
, is to optimize this metric so as to make the error bars as small as possible - the but this can sometimes take a long time. For faster run times, one can use the "std"
(standard) option which takes almost no time but just chooses an arbitrary gauge metric. A third "intrinsic error"
type attempts to balance speed with small confidence intervals, but is currently just experimental. Using either of the latter two options is fine, but may result in artificially large error bars. So if you use "std"
or "intrinsic error"
and get error bars you're happy with, then great. If the error bars seem too large, it's probably worth setting the parameter to "optimal gate CIs"
and getting some coffee.
Currently there aren't many options for speeding up the core computation required to generate a report (using, e.g. pygsti.report.create_standard_report
. One can, however, take advantage of the caching built into the pyGSTi Results
and Workspace
objects that can effectively speedup report-generation times.
create_standard_report
returns a Workspace
object that caches the various tables and plots within a report. This Workspace
is can be stored and given as the ws
argument to a subsequent call to create_standard_report
, and this latter call with utilize the cache within that Workspace
. This is useful if you want to construct two version of the same, or similar, reports. For instance, you might want to generate one "full" report (with brevity=0
, the default) and one "brief" report from the same results. Furthermore, note that specifying None
as the filename
argument to create_standard_report
results in no output files but does construct a Workspace
full of all the would-be report's items. This functionality can be used to generate a Workspace
on a large and fast multi-processor machine (which ran the main GST analysis). For example, using a workspace as shown below would dramatically speed up the 2nd and 3rd create_standard_report
calls.
#On large & fast computer
results = pygsti.do_long_sequence_gst(..., comm=my_comm)
crfact = results.estimates['default'].add_confidence_region_factory('go0', 'final')
crfact.compute_hessian(comm=comm) # use multiple processors for hessian calc
crfact.project_hessian('intrinsic error') # see above
ws = pygsti.report.create_standard_report(results, None, "Dummy Title", confidenceLevel=95)
# --> no output produced, just to create ws
pickle.dump( (results, ws), open("my_saved_results.pkl","wb") )
#On small laptop
results, ws = pickle.load( open("my_saved_results.pkl","rb") )
pygsti.report.create_standard_report(results, "full_report.html", "My Full Report",
ws=ws, confidenceLevel=95) # FAST!
pygsti.report.create_standard_report(results, "brief_report.html", "My Brief Report",
ws=ws, confidenceLevel=95, brief=True) # FAST!