{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Frequently Asked Questions\n",
    "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.\n",
    "\n",
    "## Contents\n",
    "- [What is GST?](#What-is-GST?)\r\n",
    "- [What is pyGSTi?](#What-is-pyGSTi?)\r\n",
    "- [How do I run GST (1 or 2 qubits)?](#How-do-I-run-GST-(1-or-2-qubits)?)\r\n",
    "- [How do I constrain my gates to be Trace-Preserving (TP)?](#How-do-I-constrain-my-gates-to-be-Trace-Preserving-(TP)?)\r\n",
    "- [How do I constrain my gates to be CPTP?](#How-do-I-constrain-my-gates-to-be-CPTP?)\r\n",
    "- [What is gauge optimization?](#What-is-gauge-optimization?)\r\n",
    "- [How do I specify the details of gauge optimization?](#How-do-I-specify-the-details-of-gauge-optimization?)\r\n",
    "- [2-qubit GST is running very slowly - how do I speed it up?](#2-qubit-GST-is-running-very-slowly---how-do-I-speed-it-up?)\r\n",
    "- [My report doesn't have error bars!](#My-report-doesn't-have-error-bars!)\r\n",
    "- [Generating reports takes a long time - can it go any faster?](#Generating-reports-takes-a-long-time---can-it-go-any-faster?)\r\n",
    "- [Germ selection is slow - can it go faster?](#Germ-selection-is-slow---can-it-go-faster?)\r\n",
    "- [Can I generate bootstrapped error bars with pyGSTi?](#Can-I-generate-bootstrapped-error-bars-with-pyGSTi?)\r\n",
    "- [How can I model context dependence?](#How-can-I-model-context-dependence?)\r\n",
    "- [I have an 2-ion system that doesn't have independent readout.  Can I run GST on a qutrit?](#I-have-an-2-ion-system-that-doesn't-have-independent-readout.--Can-I-run-GST-on-a-qutrit?)\r\n",
    "- [I'd like to make a nice HTML report using only LGST results, is this possible?](#I'd-like-to-make-a-nice-HTML-report-using-only-LGST-results,-is-this-possible?)\r\n",
    "- [Can I model leakage level(s) in pyGSTi?](#Can-I-model-leakage-level(s)-in-pyGSTi?)\r\n",
    "- [Aaaah! Nothing works after updating to version 0.9.7! What do I do?](#Aaaah!-Nothing-works-after-updating-to-version-0.9.7!-What-do-I-do?)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id=\"what_is_gst\"></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## What is GST?\n",
    "\"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)](http://dx.doi.org/10.1038/ncomms14485)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id=\"what_is_pygsti\"></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## What is pyGSTi?\n",
    "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 Apache License Version 2.0.  \"pyGSTi\" stands for \"python GST implementation\"."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id=\"how_do_I_run_GST\"></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## How do I run GST (1 or 2 qubits)?\n",
    "Using pyGSTi, running GST is fairly simple.  Single-qubit GST is demonstrated in full in the [GST overview tutorial](Tutorials/algorithms/GST-Overview.ipynb), and 2-qubit GST (though very similar to 1-qubit GST) is separately demonstrated in [this 2Q-GST example](Examples/2QGST-RunningIt.ipynb).  The core GST algorithm is run by calling `pygsti.run_long_sequence_gst` or `pygsti.run_stdpractice_gst`.  There are also example notebooks on [creating 2-qubit GST models](Examples/2QGST-CreatingModels.ipynb) and generating [error bars with 2Q-GST](Examples/2QGST-ErrorBars.ipynb)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id=\"how_constrain_TP\"></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## How do I constrain my gates to be Trace-Preserving (TP)?\n",
    "Constraint on the gates (and SPAM operations) in pyGSTi are imposed via the \"parameterization\" of `Model` objects.  Each `Model` 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 an `ExplicitOpModel` 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\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    },
    "tags": [
     "nbval-skip"
    ]
   },
   "outputs": [],
   "source": [
    "my_target_model.set_all_parameterizations(\"TP\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "before calling `run_long_sequence_gst` or `run_stdpractice_gst` with `my_target_gateset`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id=\"how_constrain_CPTP\"></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## How do I constrain my gates to be CPTP?\n",
    "Similar to the above question, you simply set the parameterization of your target `Model` to \"CPTP\" before calling `run_long_sequence_gst` or `run_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.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    },
    "tags": [
     "nbval-skip"
    ]
   },
   "outputs": [],
   "source": [
    "my_target_model.set_all_parameterizations(\"CPTP\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id=\"what_is_gaugeopt\"></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## What is gauge optimization?\n",
    "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)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id=\"how_specify_gaugeopt\"></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## How do I specify the details of gauge optimization?\n",
    "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](http://pygsti.readthedocs.io)) 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-AddingNewOptimizations.ipynb).  One particularly powerful way to control gauge optimization is by specifying an imperfect target `Model` 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-NonIdealTargets.ipynb)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id=\"twoQ_GST_is_slow\"></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2-qubit GST is running very slowly - how do I speed it up?\n",
    "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. `run_long_sequence_gst`) a `mpi4py.MPI.Comm` object (and often a per-core memory limit too), and is demonstrated in an [example](Examples/MPI-RunningGST.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/algorithms/advanced/GST-FiducialPairReduction.ipynb), retains the accuracy of GST while eliminating sequences.  This, however, results is less robustness and sensitivity to out-of-model errors."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id=\"reportGen_isnt_giving_errbars\"></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## My report doesn't have error bars!\n",
    "\n",
    "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:\n",
    "\n",
    "1. Compute the Hessian of the log-likelihood function at the best-estimate gate set.\n",
    "2. Project that Hessian onto a set of non-gauge directions.\n",
    "3. Create a report using a non-`None` `confidenceLevel` argument.\n",
    "\n",
    "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/2QGST-ErrorBars.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 `construct_standard_report` with `confidenceLevel=95`, for instance, to create a report with 95% confidence interval error bars.\n",
    "\n",
    "**A note about Hessian projection:**\n",
    "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."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id=\"reportGen_is_slow\"></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Generating reports takes a long time - can it go any faster?\n",
    "Currently there aren't many options for speeding up the core computation required to generate a report (using, e.g. `pygsti.report.construct_standard_report`.  One can, however, take advantage of the caching built into the pyGSTi `Results`, `Workspace`, and `Report` objects that can effectively speedup report-generation times.  \n",
    "\n",
    "**`Report` objects cache the various tables and plots within a report.** This can be used to generate multiple similar versions of the same report, but with different parameters. For instance, you might want to generate one \"full\" version (with `brevity=0`, the default) and one \"brief\" version of the same report. Furthermore, **report factory functions such as `construct_standard_report` take an optional `Workspace` as an argument that caches the various tables and plots within a report as an argument.**  This `Workspace` can be stored and shared between multiple report factories to 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. 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 `construct_standard_report` calls."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": [
     "nbval-skip"
    ]
   },
   "outputs": [],
   "source": [
    "#On large & fast computer\n",
    "results = pygsti.run_long_sequence_gst(..., comm=my_comm)\n",
    "crfact = results.estimates['default'].add_confidence_region_factory('go0', 'final')\n",
    "crfact.compute_hessian(comm=comm) # use multiple processors for hessian calc\n",
    "crfact.project_hessian('intrinsic error') # see above\n",
    "\n",
    "ws = pygsti.report.Workspace()\n",
    "report = pygsti.report.construct_standard_report(results, \"Dummy Title\", confidenceLevel=95)\n",
    "report._build()  # This method is used internally to build workspace components\n",
    "pickle.dump(report, open(\"my_saved_report.pkl\",\"wb\") )\n",
    "\n",
    "#On small laptop\n",
    "report = pickle.load( open(\"my_saved_report.pkl\",\"rb\") )\n",
    "report.write_html(results, \"full_report.html\") # FAST!\n",
    "report.write_html(results, \"brief_report.html\", brevity=3) # even FASTER!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id=\"germsel_is_slow\"></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Germ selection is slow - can it go faster?\n",
    "One way of making germ selection faster is running it on muliple processors.  Using `mpi4py` to accelerate germ selection is demonstrated in [this example](Examples/MPI-GermSelection.ipynb).  We also continue to make minor improvements to the germ selection routines, so that they should be (somewhat) faster in more recent versions of pyGSTi."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id=\"bootstrapped_error_bars\"></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Can I generate bootstrapped error bars with pyGSTi?\n",
    "Yes, you can - though we've found the Hessian-based methods to be faster and just as reliable.  See [this example](Examples/BootstrappedErrorBars.ipynb) on how to generate bootstrapped error bars. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id=\"context_dependence\"></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## How can I model context dependence?\n",
    "Context dependence is a broad category that includes many types of noise, and some types are easier to model than others within pyGSTi.  One case that is easy to model is when a gate behaves differently when it precedes or follows another gate (e.g. due to ring-down from the preceding gate).  Creating a model for this case and running GST to optimize the model is demonstrated in this [example on context dependence](Examples/ContextDependence.ipynb)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id=\"qutrit_gst\"></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## I have an 2-ion system that doesn't have independent readout.  Can I run GST on a qutrit?\n",
    "Yes, pyGSTi's GST implementation is pretty much agnostic to the Hilbert-space dimension of system being characterized.  When you have two ions but no independent readout this looks like a 3-level or *qutrit* system because you can only distinguish between \"0 ions are bright\", \"1 ion is bright\" and \"2 ions are bright\" (rather than a full 2-qubit space).  Because this is a common case, pyGSTi has a specific routine (`make_qutrit_model`) for forming qutrit models.  Then running GST on the model follows the same pattern as any other model.  Our [example of running GST on a qutrit](Examples/QutritGST.ipynb) demonstrates this."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id=\"lgstonly_report\"></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## I'd like to make a nice HTML report using only LGST results, is this possible?\n",
    "Linear Gate Set Tomography (LGST) provides a *rough* estimate of the gate (really *layer*) operations of a system.  It's primary advantanges are that it doesn't require much data and it's very fast to compute.  If all you're looking for is a rough estimate, it's useful to be able to visualize LGST results in, for example, a HTML report.  This can now be easily done using `pygsti.do_linear_gst` in a parallel fashion to how you would use `pygsti.run_long_sequence_gst`.  `do_linear_gst` generates a `Results` object that can then be used to generate a report, as demonstrated in [this example](Examples/Reports-LGSTonly.ipynb). "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id=\"leakage\"></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Can I model leakage level(s) in pyGSTi?\n",
    "For certain types of \"leakage\", yes: PyGSTi can create models whose operations act on n-level state spaces.  For instance, a 3-level space can be interpreted as a qubit plus a leakage level.  Model operations must be constructed and interpreted accordingly, but apart from these nuances pyGSTi treats a system with leakage levels exactly as it would a larget (e.g. multi-qubit) system.  See this [example analyzing a qubit + leakage level](Examples/Leakage.ipynb)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id=\"v097woes\"></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Aaaah! Nothing works after updating to version 0.9.7! What do I do?\n",
    "Stay calm; don't panic.  Version 0.9.7 brought with it a number of compatibility-breaking improvements (for instance, \"gate sets\" have turned into \"models\" and \"gate strings\" have become \"circuits\").  To help you transition from version 0.9.6 and below to version 0.9.7 we've built into the latter a few pieces of functionality:\n",
    "- The `scripts/upgrade2v0.9.7.py` script automatically renames everything that has been renamed in pyGSTi. In many cases, this is all you need to upgrade your scripts and jupyter notebooks.  You simply pass the script the names of files you want upgraded, e.g.\n",
    "\n",
    "  ```python path/to/pyGSTi/scripts/upgrade2v0.9.7.py myScript.py myNotebook.ipynb ...```\n",
    "\n",
    "  The conversion will automatically create backup files with a `.bak` extension, so there's no chance of it destroying your hard work.\n",
    "\n",
    "\n",
    "- If you have Python pickles created with version 0.9.6 or below they won't normally be load-able in version 0.9.7 because many of the Python class names have changed.  To work around this, `pygsti.io` contains the context-manager `enable_old_object_unpickling`, that can be used to temporarily enable the un-pickling of version 0.9.6 objects.  You should then re-pickle the objects using version 0.9.7.  Here's an example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": [
     "nbval-skip"
    ]
   },
   "outputs": [],
   "source": [
    "with pygsti.io.enable_old_object_unpickling(): \n",
    "    # within this block you can load old pickles\n",
    "    with open(\"pygsti0.9.6_gateset.pkl\",'rb') as f:\n",
    "        mdl = pickle.load(f) # works!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If you're still having issues with the transition to 0.9.7, please contact the pyGSTi developers at [pygsti@sandia.gov](mailto:pygsti@sandia.gov)."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
