#!/usr/bin/env python # coding: utf-8 # # Report Generation Tutorial # # PyGSTi is able to construct polished report documents, which provide high-level summaries as well as detailed analyses of results (Gate Set Tomography (GST) and model-testing results in particular). Reports are intended to be quick and easy way of analyzing `Model`-type estimates, and pyGSTi's report generation functions are specifically designed to interact with the `Results` object (producted by several high-level algorithm functions - see, for example, the [GST overview tutorial](../algorithms/GST-Overview.ipynb) and [GST functions tutorial](../algorithms/GST-Drivers.ipynb).). The report generation functions in pyGSTi takes one or more results (often `Results`-type) objects as input and produces an HTML file as output. The HTML format allows the reports to include **interactive plots** and **switches** (see the [workspace switchboard tutorial](advanced/WorkspaceSwitchboards.ipynb), making it easy to compare different types of analysis or data sets. # # PyGSTi's reports are stand-alone HTML documents which cannot run Python. Thus, all the results displayed in a report must be pre-computed (in Python). If you find yourself wanting to fiddle with things and feel that these reports are too static, please consider using a `Workspace` object (see the [Workspace tutorial](Workspace.ipynb)) within a Jupyter notebook, where you can intermix report tables/plots and Python. Internally, functions like `create_standard_report` (see below) are just canned routines which use a `WorkSpace` object to generate various tables and plots and then insert them into a HTML template. # # **Note to veteran users:** PyGSTi has for some time now transitioned to producing HTML (rather than LaTeX/PDF) reports. The way to generate such reports is largely unchanged, with one important exception. Previously, the `Results` object had various report-generation methods included within it. We've found this is too restrictive, as we'd sometimes like to generate a report which utilizes the results from multiple runs of GST (to compare them, for instance). Thus, the `Results` class is now just a container for a `DataSet` and its related `Model`s, `CircuitStructure`s, etc. All of the report-generation capability is now housed in within separate report functions, which we now demonstrate. # # # ### Get some `Results` # We start by performing GST using `do_long_sequence_gst`, as usual, to create a `Results` object (we could also have just loaded one from file). See the [GST functions tutorial](../algorithms/GST-Drivers.ipynb) for more details. # In[1]: import pygsti from pygsti.construction import std1Q_XYI target_model = std1Q_XYI.target_model() fiducials = std1Q_XYI.fiducials germs = std1Q_XYI.germs maxLengths = [1,2,4,8,16] ds = pygsti.io.load_dataset("../tutorial_files/Example_Dataset.txt", cache=True) #Run GST target_model.set_all_parameterizations("TP") #TP-constrained results = pygsti.do_long_sequence_gst(ds, target_model, fiducials, fiducials, germs, maxLengths, verbosity=3) # ### Make a report # Now that we have `results`, we use the `create_standard_report` method within `pygsti.report` to generate a report. # `pygsti.report.create_standard_report` is the most commonly used report generation function in pyGSTi, as it is appropriate for smaller models (1- and 2-qubit) which have *operations that are or can be represeted as dense matrices and/or vectors*. # # If the given filename ends in "`.pdf`" then a PDF-format report is generated; otherwise the file name specifies a folder that will be filled with HTML pages. To open a HTML-format report, you open the `main.html` file directly inside the report's folder. Setting `auto_open=True` makes the finished report open in your web browser automatically. # In[2]: #HTML pygsti.report.create_standard_report(results, "../tutorial_files/exampleReport", title="GST Example Report", verbosity=1, auto_open=True) print("\n") #PDF pygsti.report.create_standard_report(results, "../tutorial_files/exampleReport.pdf", title="GST Example Report", verbosity=1, auto_open=True) # There are several remarks about these reports worth noting: # 1. The **HTML reports are the primary report type in pyGSTi**, and are much more flexible. The PDF reports are more limited (they can only display a *single* estimate and gauge optimization), and essentially contain a subset of the information and descriptive text of a HTML report. So, if you can, use the HTML reports. The PDF report's strength is its portability: PDFs are easily displayed by many devices, and they embed all that they need neatly into a single file. **If you need to generate a PDF report** from `Results` objects that have multiple estimates and/or gauge optimizations, consider using the `Results` object's `view` method to single out the estimate and gauge optimization you're after. # 2. It's best to use **Firefox** when opening the HTML reports. (If there's a problem with your brower's capabilities it will be shown on the screen when you try to load the report.) # 3. You'll need **`pdflatex`** on your system to compile PDF reports. # 4. To familiarize yourself with the layout of an HTML report, click on the gray **"Help" link** on the black sidebar. # ### Multiple estimates in a single report # Next, let's analyze the same data two different ways: with and without the TP-constraint (i.e. whether the gates *must* be trace-preserving) and furthermore gauge optmimize each case using several different SPAM-weights. In each case we'll call `do_long_sequence_gst` with `gaugeOptParams=False`, so that no gauge optimization is done, and then perform several gauge optimizations separately and add these to the `Results` object via its `add_gaugeoptimized` function. # In[3]: #Case1: TP-constrained GST tpTarget = target_model.copy() tpTarget.set_all_parameterizations("TP") results_tp = pygsti.do_long_sequence_gst(ds, tpTarget, fiducials, fiducials, germs, maxLengths, gaugeOptParams=False, verbosity=1) #Gauge optimize est = results_tp.estimates['default'] mdlFinal = est.models['final iteration estimate'] mdlTarget = est.models['target'] for spamWt in [1e-4,1e-2,1.0]: mdl = pygsti.gaugeopt_to_target(mdlFinal,mdlTarget,{'gates':1, 'spam':spamWt}) est.add_gaugeoptimized({'itemWeights': {'gates':1, 'spam':spamWt}}, mdl, "Spam %g" % spamWt) # In[4]: #Case2: "Full" GST fullTarget = target_model.copy() fullTarget.set_all_parameterizations("full") results_full = pygsti.do_long_sequence_gst(ds, fullTarget, fiducials, fiducials, germs, maxLengths, gaugeOptParams=False, verbosity=1) #Gauge optimize est = results_full.estimates['default'] mdlFinal = est.models['final iteration estimate'] mdlTarget = est.models['target'] for spamWt in [1e-4,1e-2,1.0]: mdl = pygsti.gaugeopt_to_target(mdlFinal,mdlTarget,{'gates':1, 'spam':spamWt}) est.add_gaugeoptimized({'itemWeights': {'gates':1, 'spam':spamWt}}, mdl, "Spam %g" % spamWt) # We'll now call the *same* `create_standard_report` function but this time instead of passing a single `Results` object as the first argument we'll pass a *dictionary* of them. This will result in a **HTML report that includes switches** to select which case ("TP" or "Full") as well as which gauge optimization to display output quantities for. PDF reports cannot support this interactivity, and so **if you try to generate a PDF report you'll get an error**. # In[5]: ws = pygsti.report.create_standard_report({'TP': results_tp, "Full": results_full}, "../tutorial_files/exampleMultiEstimateReport", title="Example Multi-Estimate Report", verbosity=2, auto_open=True) # In the above call we capture the return value in the variable `ws` - a `Workspace` object. PyGSTi's `Workspace` objects function as both a factory for figures and tables as well as a smart cache for computed values. Within `create_standard_report` a `Workspace` object is created and used to create all the figures in the report. As an intended side effect, each of these figures is cached, along with some of the intermediate results used to create it. As we'll see below, a `Workspace` can also be specified as input to `create_standard_report`, allowing it to utilize previously cached quantities. # # **Another way**: Because both `results_tp` and `results_full` above used the same dataset and operation sequences, we could have combined them as two estimates in a single `Results` object (see the previous tutorial on pyGSTi's `Results` object). This can be done by renaming at least one of the `"default"`-named estimates in `results_tp` or `results_full` (below we rename both) and then adding the estimate within `results_full` to the estimates already contained in `results_tp`: # In[6]: results_tp.rename_estimate('default','TP') results_full.rename_estimate('default','Full') results_both = results_tp.copy() #copy just for neatness results_both.add_estimates(results_full, estimatesToAdd=['Full']) # Creating a report using `results_both` will result in the same report we just generated. We'll demonstrate this anyway, but in addition we'll supply `create_standard_report` a `ws` argument, which tells it to use any cached values contained in a given *input* `Workspace` to expedite report generation. Since our workspace object has the exact quantities we need cached in it, you'll notice a significant speedup. Finally, note that even though there's just a single `Results` object, you **still can't generate a PDF report** from it because it contains multiple estimates. # In[7]: pygsti.report.create_standard_report(results_both, "../tutorial_files/exampleMultiEstimateReport2", title="Example Multi-Estimate Report (v2)", verbosity=2, auto_open=True, ws=ws) # ### Multiple estimates and `do_stdpractice_gst` # It's no coincidence that a `Results` object containing multiple estimates using the same data is precisely what's returned from `do_stdpractice_gst` (see docstring for information on its arguments, and see the [GST functions tutorial](../algorithms/GST-Drivers.ipynb)). This allows one to run GST multiple times, creating several different "standard" estimates and gauge optimizations, and plot them all in a single (HTML) report. # In[8]: results_std = pygsti.do_stdpractice_gst(ds, target_model, fiducials, fiducials, germs, maxLengths, verbosity=4, modes="TP,CPTP,Target", gaugeOptSuite=('single','toggleValidSpam')) # Generate a report with "TP", "CPTP", and "Target" estimates pygsti.report.create_standard_report(results_std, "../tutorial_files/exampleStdReport", title="Post StdPractice Report", auto_open=True, verbosity=1) # ### Reports with confidence regions # To display confidence intervals for reported quantities, you must do two things: # # 1. you must specify the `confidenceLevel` argument to `create_standard_report`. # 2. the estimate(s) being reported must have a valid confidence-region-factory. # # Constructing a factory often means computing a Hessian, which can be time consuming, and so this is *not* done automatically. Here we demonstrate how to construct a valid factory for the "Spam 0.001" gauge-optimization of the "CPTP" estimate by computing and then projecting the Hessian of the likelihood function. # In[9]: #Construct and initialize a "confidence region factory" for the CPTP estimate crfact = results_std.estimates["CPTP"].add_confidence_region_factory('Spam 0.001', 'final') crfact.compute_hessian(comm=None) #we could use more processors crfact.project_hessian('intrinsic error') pygsti.report.create_standard_report(results_std, "../tutorial_files/exampleStdReport2", title="Post StdPractice Report (w/CIs on CPTP)", confidenceLevel=95, auto_open=True, verbosity=1) # ### Reports with multiple *different* data sets # We've already seen above that `create_standard_report` can be given a dictionary of `Results` objects instead of a single one. This allows the creation of reports containing estimates for different `DataSet`s (each `Results` object only holds estimates for a single `DataSet`). Furthermore, when the data sets have the same operation sequences, they will be compared within a tab of the HTML report. # # Below, we generate a new data set with the same sequences as the one loaded at the beginning of this tutorial, proceed to run standard-practice GST on that dataset, and create a report of the results along with those of the original dataset. Look at the **"Data Comparison" tab** within the gauge-invariant error metrics category. # In[10]: #Make another dataset & estimates depol_gateset = target_model.depolarize(op_noise=0.1) datagen_gateset = depol_gateset.rotate((0.05,0,0.03)) #Compute the sequences needed to perform Long Sequence GST on # this Model with sequences up to lenth 512 circuit_list = pygsti.construction.make_lsgst_experiment_list( std1Q_XYI.target_model(), std1Q_XYI.prepStrs, std1Q_XYI.effectStrs, std1Q_XYI.germs, [1,2,4,8,16,32,64,128,256,512]) ds2 = pygsti.construction.generate_fake_data(datagen_gateset, circuit_list, nSamples=1000, sampleError='binomial', seed=2018) results_std2 = pygsti.do_stdpractice_gst(ds2, target_model, fiducials, fiducials, germs, maxLengths, verbosity=3, modes="TP,CPTP,Target", gaugeOptSuite=('single','toggleValidSpam')) pygsti.report.create_standard_report({'DS1': results_std, 'DS2': results_std2}, "../tutorial_files/exampleMultiDataSetReport", title="Example Multi-Dataset Report", auto_open=True, verbosity=1) # ### Other cool `create_standard_report` options # Finally, let us highlight a few of the additional arguments one can supply to `create_standard_report` that allows further control over what gets reported. # # - Setting the `link_to` argument to a tuple of `'pkl'`, `'tex'`, and/or `'pdf'` will create hyperlinks within the plots or below the tables of the HTML linking to Python pickle, LaTeX source, and PDF versions of the content, respectively. The Python pickle files for tables contain pickled pandas `DataFrame` objects, wheras those of plots contain ordinary Python dictionaries of the data that is plotted. Applies to HTML reports only. # # - Setting the `brevity` argument to an integer higher than $0$ (the default) will reduce the amount of information included in the report (for details on what is included for each value, see the doc string). Using `brevity > 0` will reduce the time required to create, and later load, the report, as well as the output file/folder size. This applies to both HTML and PDF reports. # # Below, we demonstrate both of these options in very brief (`brevity=4`) report with links to pickle and PDF files. Note that to generate the PDF files you must have `pdflatex` installed. # In[11]: pygsti.report.create_standard_report(results_std, "../tutorial_files/exampleBriefReport", title="Example Brief Report", auto_open=True, verbosity=1, brevity=4, link_to=('pkl','pdf')) # ## Advanced Reports: `create_report_notebook` # In addition to the standard HTML-page reports demonstrated above, pyGSTi is able to generate a Jupyter notebook containing the Python commands to create the figures and tables within a general report. This is facilitated # by `Workspace` objects, which are factories for figures and tables (see previous tutorials). By calling `create_report_notebook`, all of the relevant `Workspace` initialization and calls are dumped to a new notebook file, which can be run (either fully or partially) by the user at their convenience. Creating such "report notebooks" has the advantage that the user may insert Python code amidst the figure and table generation calls to inspect or modify what is display in a highly customizable fashion. The chief disadvantages of report notebooks is that they require the user to 1) have a Jupyter server up and running and 2) to run the notebook before any figures are displayed. # # The line below demonstrates how to create a report notebook using `create_report_notebook`. Note that the argument list is very similar to `create_general_report`. # In[12]: pygsti.report.create_report_notebook(results, "../tutorial_files/exampleReport.ipynb", title="GST Example Report Notebook", confidenceLevel=None, auto_open=True, connected=False, verbosity=3) # ## Multi-qubit reports # The dimension of the density matrix space with with more than 2 qubits starts to become quite large, and Models for 3+ qubits rarely allow every element of the operation process matrices to vary independently. As such, many of the figures generated by `create_standard_report` are both too unwieldy (displaying a $64 \times 64$ grid of colored boxes for each operation) and not very helpful (you don't often care about what each element of an operation matrix is). For this purpose, we are developing a report that doesn't just dump out and analyze operation matrices as a whole, but looks at a `Model`'s structure to determine how best to report quantities. This "n-qubit report" is invoked using `pygsti.report.create_nqnoise_report`, and has similar arguments to `create_standard_report`. It is, however still under development, and while you're welcome to try it out, it may crash or not work in other weird ways. # In[ ]: