{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Examples of tables and plots available from a `Workspace`\n",
    "\n",
    "PyGSTi's `Workspace` object is first a foremost a container and factory for plots and tables.  At the most basic level, it can be used to generate nice output based on quantities (e.g. `Model`, `DataSet`, etc. objects) that you've computed or loaded within a notebook.  For this, it's useful to call `init_notebook_mode` with `autodisplay=True` (see below) so that you don't have to `.display()` everything - `display()` gets called automatically when a plot or table is created.\n",
    "\n",
    "## Getting some results\n",
    "First, let's run Gate Set Tomography (GST) on the standard 1-qubit model to get some results to play with.  We generate a few `DataSet` objects and then call `run_long_sequence_gst` to run GST, generating a `ModelEstimateResults` object (essentially a container for `Model` objects).  For more details, see the tutorials [GST overview tutorial](../algorithms/GST-Overview.ipynb), the [tutorial on GST functions](../algorithms/GST-Driverfunctions.ipynb), and the [tutorial explaining the ModelEstimateResults object](../objects/advanced/Results.ipynb).   "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pygsti\n",
    "from pygsti.modelpacks import smq1Q_XYI"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#The usual GST setup: we're going to run GST on the standard XYI 1-qubit model\n",
    "target_model = smq1Q_XYI.target_model()\n",
    "prep_fiducials = smq1Q_XYI.prep_fiducials()\n",
    "meas_fiducials = smq1Q_XYI.meas_fiducials()\n",
    "germs = smq1Q_XYI.germs()\n",
    "maxLengths = [1,2]\n",
    "listOfExperiments = pygsti.circuits.create_lsgst_circuits(\n",
    "    target_model.operations.keys(), prep_fiducials, meas_fiducials, germs, maxLengths)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Create some datasets for analysis\n",
    "mdl_datagen1 = target_model.depolarize(op_noise=0.1, spam_noise=0.02)\n",
    "mdl_datagen2 = target_model.depolarize(op_noise=0.05, spam_noise=0.01).rotate(rotate=(0.01,0.01,0.01))\n",
    "\n",
    "ds1 = pygsti.data.simulate_data(mdl_datagen1, listOfExperiments, num_samples=1000,\n",
    "                                            sample_error=\"binomial\", seed=1234)\n",
    "ds2 = pygsti.data.simulate_data(mdl_datagen2, listOfExperiments, num_samples=1000,\n",
    "                                            sample_error=\"binomial\", seed=1234)\n",
    "ds3 = ds1.copy_nonstatic(); ds3.add_counts_from_dataset(ds2); ds3.done_adding_data()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Run GST on all three datasets\n",
    "target_model.set_all_parameterizations(\"full TP\")\n",
    "results1 = pygsti.run_long_sequence_gst(ds1, target_model, prep_fiducials, meas_fiducials, germs, maxLengths, verbosity=0)\n",
    "results2 = pygsti.run_long_sequence_gst(ds2, target_model, prep_fiducials, meas_fiducials, germs, maxLengths, verbosity=0)\n",
    "results3 = pygsti.run_long_sequence_gst(ds3, target_model, prep_fiducials, meas_fiducials, germs, maxLengths, verbosity=0)\n",
    "\n",
    "#make some shorthand variable names for later\n",
    "tgt = results1.estimates['GateSetTomography'].models['target']\n",
    "\n",
    "ds1 = results1.dataset\n",
    "ds2 = results2.dataset\n",
    "ds3 = results3.dataset\n",
    "\n",
    "mdl1 = results1.estimates['GateSetTomography'].models['go0']\n",
    "mdl2 = results2.estimates['GateSetTomography'].models['go0']\n",
    "mdl3 = results3.estimates['GateSetTomography'].models['go0']\n",
    "\n",
    "gss = results1.circuit_lists['final']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Gallery of `Workspace` plots and tables.\n",
    "Now that we have some results, let's create a `Workspace` and make some plots and tables.\n",
    "\n",
    "To get tables and plots to display properly, one must run `init_notebook_mode`.  The `connected` argument indicates whether you want to rely on an active internet connection.  If `True`, then resources will be loaded from the web (e.g. a CDN), and if you save a notebook as HTML the file size may be smaller.  If `False`, then all the needed resources (except MathJax) are provided by pyGSTi, and an `offline` directory is automatically created in the same directory as your notebook.  This directory contains all the necessary resources, and must \"tag along\" with the notebook and any saved-as-HTML versions of it in order for everything to work.  The second argument, `autodisplay`, determines whether tables and plots are automatically displayed when they are created.  If `autodisplay=False`, one must call the `display()` member function of a table or plot to display it. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "from pygsti.report import workspace\n",
    "w = workspace.Workspace()\n",
    "w.init_notebook_mode(connected=False, autodisplay=True) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Plots and tables are created via member functions of a `Workspace` (`w` in our case).  Note that you can start typing \"`w.`\" and TAB-complete to see the different things a `Workspace` can make for you.  Furthermore, pressing SHIFT-TAB after the opening parenthesis of a function,  e.g. after typing \"`w.GatesVsTargetTable(`\", will bring up Jupyter's help window showing you the function signature (the arguments you need to give the function).\n",
    "\n",
    "#### The remainder of this tutorial demonstrates some of the tables and plots you can create. \n",
    "Note that displayed objects have a resize handle in their lower right corner."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "w.ColorBoxPlot((\"logl\",), gss, ds1, mdl1, typ='scatter')\n",
    "w.ColorBoxPlot((\"logl\",), gss, ds1, mdl1, typ='boxes')\n",
    "w.ColorBoxPlot((\"logl\",), gss, ds1, mdl1, typ='histogram')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "iteration_estimates = [results1.estimates['GateSetTomography'].models['iteration %d estimate' % i]\n",
    "                       for i in range(results1.estimates['GateSetTomography'].num_iterations)]\n",
    "w.FitComparisonBarPlot(gss, results1.circuit_lists['iteration'],iteration_estimates, ds1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "w.GramMatrixBarPlot(ds1,tgt)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "w.GatesVsTargetTable(mdl1, tgt)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "w.SpamVsTargetTable(mdl2, tgt)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "w.ColorBoxPlot((\"chi2\",\"logl\"), gss, ds1, mdl1, box_labels=True)\n",
    "  #Notice how long it takes to switch between \"chi2\" and \"logl\".  This \n",
    "  # is due to drawing all of the box labels (box_labels=True)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#This one requires knowng that each Results object holds a list of models\n",
    "# from each GST intation along with the corresponding operation sequences that were used.\n",
    "iteration_estimates = [results1.estimates['GateSetTomography'].models['iteration %d estimate' % i]\n",
    "                       for i in range(results1.estimates['GateSetTomography'].num_iterations)]\n",
    "w.FitComparisonTable(gss, results1.circuit_lists['iteration'], iteration_estimates, ds1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# We can reuse 'gss' for all three since the operation sequences are the same.\n",
    "w.FitComparisonTable([\"GS1\",\"GS2\",\"GS3\"], [gss, gss, gss], [mdl1,mdl2,mdl3], ds1, x_label=\"Model\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "w.ChoiTable(mdl3, display=('matrix','barplot'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "w.GateMatrixPlot(mdl1[('Gxpi2',0)],scale=1.0, box_labels=True,ylabel=\"hello\")\n",
    "w.GateMatrixPlot(pygsti.tools.error_generator(mdl1[('Gxpi2',0)], tgt[('Gxpi2',0)], 'pp'), scale=1.5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pygsti.modelpacks import smq2Q_XYCNOT\n",
    "w.GateMatrixPlot(smq2Q_XYCNOT.target_model()[('Gxpi2',0)],scale=1.0, box_labels=False,ylabel=\"hello\",mx_basis=\"pp\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "mx = np.array( \n",
    "[[ 7.3380823,   8.28446943,  7.4593754,   3.91256384,  0.68631199],\n",
    " [ 3.36139818,  7.42955114,  6.78516082,  0.35863173,  5.57713093],\n",
    " [ 2.61489939,  3.40182958,  6.77389064,  9.29736475,  0.33824271],\n",
    " [ 9.64258149,  9.45928809,  6.91516602,  5.61423854,  0.56480777],\n",
    " [ 2.15195669,  9.37588783,  5.1781991,   7.20087591,  1.46096288]], 'd')\n",
    "cMap = pygsti.report.colormaps.LinlogColormap(vmin=0, vmax=10, num_boxes=25, pcntle=0.55, dof_per_box=1, color='blue')\n",
    "w.MatrixPlot(mx, colormap=cMap, colorbar=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "mx = np.identity(3,'d')\n",
    "mx[0,1] = 2.1\n",
    "mx[2,2] = 4.0\n",
    "mx[2,0] = 3.0\n",
    "mx[0,2] = 7.0\n",
    "mx[2,1] = 10.0\n",
    "mx[0,0] = np.nan\n",
    "cMap = pygsti.report.colormaps.PiecewiseLinearColormap(\n",
    "            [[0,(0,0.5,0)],[1,(0,1.0,0)],[2,(1.0,1.0,0)],\n",
    "             [4,(1.0,0.5,0)],[10,(1.0,0,0)]])\n",
    "#print(cMap.colorscale())\n",
    "w.MatrixPlot(mx, colormap=cMap, colorbar=False, grid=\"white:1\", box_labels=True, prec=2,\n",
    "             xlabels=('full TP',\"CPTPLND\",\"full\"),ylabels=(\"DS0\",\"DS1\",\"DS2\"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "w.ErrgenTable(mdl3,tgt)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "w.PolarEigenvaluePlot([np.linalg.eigvals(mdl2[('Gxpi2',0)])],[\"purple\"],scale=1.5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "w.GateEigenvalueTable(mdl2, display=('evals','polar'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "w.GateDecompTable(mdl1,target_model)\n",
    "#w.old_GateDecompTable(gs1) #historical; 1Q only"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Note 2Q angle decompositions\n",
    "from pygsti.modelpacks import smq2Q_XXYYII\n",
    "from pygsti.modelpacks import smq2Q_XYCNOT\n",
    "\n",
    "w.GateDecompTable(smq2Q_XXYYII.target_model(), smq2Q_XXYYII.target_model())\n",
    "\n",
    "import scipy\n",
    "I = np.array([[1,0],[0,1]],'complex')\n",
    "X = np.array([[0,1],[1,0]],'complex')\n",
    "Y = np.array([[0,1j],[-1j,0]],'complex')\n",
    "XX = np.kron(X,X)\n",
    "YY = np.kron(Y,Y)\n",
    "IX = np.kron(I,X)\n",
    "XI = np.kron(X,I)\n",
    "testU = scipy.linalg.expm(-1j*np.pi/2*XX)\n",
    "testS = pygsti.unitary_to_process_mx(testU)\n",
    "testS = pygsti.change_basis(testS,\"std\",\"pp\")\n",
    "\n",
    "#mdl_decomp = std2Q_XYCNOT.target_model()\n",
    "#mdl_decomp.operations['Gtest'] = testS\n",
    "#w.GateDecompTable(mdl_decomp, mdl_decomp)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "dsLabels = [\"A\",\"B\",\"C\"]\n",
    "datasets = [ds1, ds2, ds3]\n",
    "dscmps = {}\n",
    "for i,ds_a in enumerate(datasets):\n",
    "    for j,ds_b in enumerate(datasets[i+1:],start=i+1):\n",
    "        dscmps[(i,j)] = pygsti.data.DataComparator([ds_a, ds_b])\n",
    "\n",
    "w.DatasetComparisonSummaryPlot(dsLabels, dscmps)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "w.DatasetComparisonHistogramPlot(dscmps[(1,2)])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Saving figures to file\n",
    "You can also save plot and figures to separate files using their `saveas` method.  The output format is determined by the file extension, and allowed extensions are:\n",
    "\n",
    "- 'pdf': Adobe portable document format\n",
    "- 'tex': LaTeX source (uncompiled, *tables only*)\n",
    "- 'pkl': Python pickle (of a pandas `DataFrame` for tables, a dict for plots)\n",
    "- 'html': A stand-alone HTML document"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "if not os.path.exists(\"../tutorial_files/tempTest\"):\n",
    "    os.mkdir(\"../tutorial_files/tempTest\")\n",
    "\n",
    "obj = w.GatesVsTargetTable(mdl1, tgt)\n",
    "#obj = w.ErrgenTable(mdl3,tgt)\n",
    "#obj = w.ColorBoxPlot((\"logl\",), gss, ds1, mdl1, typ='boxes')\n",
    "\n",
    "obj.saveas(\"../tutorial_files/tempTest/testSave.tex\")\n",
    "obj.saveas(\"../tutorial_files/tempTest/testSave.pkl\")\n",
    "obj.saveas(\"../tutorial_files/tempTest/testSave.html\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Saving as a pdf requires having pdflatex installed and on the system path."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": [
     "nbval-skip"
    ]
   },
   "outputs": [],
   "source": [
    "obj.saveas(\"../tutorial_files/tempTest/testSave.pdf\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Exporting notebooks to HTML\n",
    "If you want, you can save figure-containing notebooks (like this one) as an HTML file by going to **File => Download As => HTML** in the Jupyter menu.  The resulting file will retain all of the plot interactivity, so long as its in a directory with an `offline` folder (because we set `connected=False` above)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "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.9.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
