{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Tutorial on standard modules\n", "\n", "PyGSTi comes shipped with a number of *standard modules*. These standard modules live in `pygsti.construction` and have names beginning with `std`, so you import them like this:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from pygsti.construction import std1Q_XYI" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Target model\n", "Each standard module defines a 1- or 2-qubit model and number of related quantites. Sometimes you'll just want to use the `Model`, and importing a standard module is just a convenient way to create a commonly used model for 1 or 2 qubits (the `std1Q_XYI` module is for the 1-qubit model containing *Idle*, $X(\\pi/2)$ and $Y(\\pi/2)$ gates). A standard module's model always contains *perfect* (unitary) operations, and is called the *target model* because often times this is the model you wish described your system. You can get a copy of it by using the `target_model` function:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "rho0 = FullSPAMVec with dimension 4\n", " 0.71 0 0 0.71\n", "\n", "\n", "Mdefault = UnconstrainedPOVM with effect vectors:\n", "0: FullSPAMVec with dimension 4\n", " 0.71 0 0 0.71\n", "\n", "1: FullSPAMVec with dimension 4\n", " 0.71 0 0-0.71\n", "\n", "\n", "\n", "Gi = \n", "FullDenseOp with shape (4, 4)\n", " 1.00 0 0 0\n", " 0 1.00 0 0\n", " 0 0 1.00 0\n", " 0 0 0 1.00\n", "\n", "\n", "Gx = \n", "FullDenseOp with shape (4, 4)\n", " 1.00 0 0 0\n", " 0 1.00 0 0\n", " 0 0 0-1.00\n", " 0 0 1.00 0\n", "\n", "\n", "Gy = \n", "FullDenseOp with shape (4, 4)\n", " 1.00 0 0 0\n", " 0 0 0 1.00\n", " 0 0 1.00 0\n", " 0-1.00 0 0\n", "\n", "\n", "\n", "\n" ] } ], "source": [ "mdl = std1Q_XYI.target_model()\n", "print(mdl)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now let's review a few things about this target model:\n", "\n", "1. **It's a *copy*.** If you modify it, it won't change what's stored in the standard module. This means that you don't need to add a `.copy()` (e.g. `mdl = std1Q_XYI.target_model().copy()`).\n", "\n", "\n", "2. **It's *fully parameterized*.** By default, `target_model()` returns a fully-parameterized `Model`, meaning that each of its operations contain an independent parameter for each one of their elements. If you want a different parameterization, such as a TP-constrained model, you can specify this as an argument:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "mdl_TP = std1Q_XYI.target_model(\"TP\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "3. **It has gate names that are *simple strings*.** Even for 2-qubit standard-module models, the gate names (keys of the models `.operations` dictionary) are simple strings like `\"Gx\"` or `\"Gix\"` or `\"Gcnot\"`. That is, these names label *layers* rather than *gates* per se. A more multi-qubit friendly convention would be to label these operations `(\"Gx\",0)`, `(\"Gx\",1)`, or `(\"Gcnot\",0,1)`, respectively. If you want to use a standard module using multi-qubit-friendly conventions, you can *convert* the standard module to a \"standard multiqubit module\" like this:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "odict_keys([Label{Gi}, Label[Gx:0], Label[Gy:0]])\n" ] } ], "source": [ "import pygsti\n", "pygsti.construction.stdmodule_to_smqmodule(std1Q_XYI) # makes \"smq1Q_XYI\" importable\n", "from pygsti.construction import smq1Q_XYI\n", "\n", "smq_mdl = smq1Q_XYI.target_model()\n", "print(smq_mdl.operations.keys())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## General additional quantities\n", "For convenience standard modules contain `description` and `gates` members giving a simple text description of the standard module's target model and its gates:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Idle, X(pi/2), and Y(pi/2) gates'" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "std1Q_XYI.description" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['Gi', 'Gx', 'Gy']" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "std1Q_XYI.gates" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Quantities for running GST\n", "In addition to a target `Model`, a standard module contains a number of `Circuit` lists used for running Gate Set Tomography (GST). These include:\n", "- preparation fiducials: `prepStrs`\n", "- measurement (effect) fiducials: `effectStrs`\n", "- germ sequences:\n", " - `germs_lite` is a shorter list of germ circuits that amplify all the errors in the target model to *first order*. This is usually all that is needed to achieve the high-accuracy typically desired from GST results, and so we recommend starting with this list of germs since it's shorter.\n", " - `germs` is a longer list of germ circuits that amplify all the errors in the target model to *higher orders*. Although typically unnecessary, this \"paranoid\" set of germs can be particularly helpful when you expect and don't care about some departures (errors) from the target model.\n", "- fiducial pair reductions (see the [circuit reduction tutorial](../../algorithms/advanced/GST-FiducialPairReduction.ipynb) for more details):\n", " - `global_fidPairs_lite` and `global_fidPairs` are lists of 2-tuples giving the indices (within `prepStrs` and `effectStrs`) of the fiducial circuits to keep when implementing global fiducial pair reduction.\n", " - `pergerm_fidPairsDict_lite` and `pergerm_fidPairsDict` are dictionaries of lists-of-2-tuples giving the indices of the fiducial circuits to keep on a per-germ basis (dict keys are germ circuits) when implementing per-germ fiducial pair reduction.\n", " \n", "Here are a couple examples:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[Circuit({}),\n", " Circuit(Gx),\n", " Circuit(Gy),\n", " Circuit(GxGx),\n", " Circuit(GxGxGx),\n", " Circuit(GyGyGy)]" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "std1Q_XYI.prepStrs" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{('Gx',): [(1, 1), (3, 4), (4, 2), (5, 5)],\n", " ('Gi',): [(0, 3), (1, 1), (5, 5)],\n", " ('Gy',): [(0, 2), (2, 2), (2, 4), (4, 4)],\n", " ('Gx', 'Gy'): [(0, 0), (0, 4), (2, 5), (5, 4)],\n", " ('Gx', 'Gx', 'Gy'): [(1, 3), (1, 4), (3, 5), (5, 0), (5, 4), (5, 5)]}" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "std1Q_XYI.pergerm_fidPairsDict_lite" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[Circuit({}),\n", " Circuit(Gx:0@(0)),\n", " Circuit(Gy:0@(0)),\n", " Circuit(Gx:0Gx:0@(0)),\n", " Circuit(Gx:0Gx:0Gx:0@(0)),\n", " Circuit(Gy:0Gy:0Gy:0@(0))]" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "smq1Q_XYI.prepStrs #multi-qubit friendly version" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Quantities for running RB\n", "Standard Clifford-based randomized benchmarking (RB) requires knowing how to \"compile\" the elements of the Clifford group from your native gate set. Most standard modules contain a `clifford_compilation` dictionary that describes this compilation, and can be used when running Clifford RB (see the [Clifford RB tutorial](../../algorithms/CliffordRB.ipynb) for more info)." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "OrderedDict([('Gc0', ['Gi']),\n", " ('Gc1', ['Gy', 'Gx']),\n", " ('Gc2', ['Gx', 'Gx', 'Gx', 'Gy', 'Gy', 'Gy']),\n", " ('Gc3', ['Gx', 'Gx']),\n", " ('Gc4', ['Gy', 'Gy', 'Gy', 'Gx', 'Gx', 'Gx']),\n", " ('Gc5', ['Gx', 'Gy', 'Gy', 'Gy']),\n", " ('Gc6', ['Gy', 'Gy']),\n", " ('Gc7', ['Gy', 'Gy', 'Gy', 'Gx']),\n", " ('Gc8', ['Gx', 'Gy']),\n", " ('Gc9', ['Gx', 'Gx', 'Gy', 'Gy']),\n", " ('Gc10', ['Gy', 'Gx', 'Gx', 'Gx']),\n", " ('Gc11', ['Gx', 'Gx', 'Gx', 'Gy']),\n", " ('Gc12', ['Gy', 'Gx', 'Gx']),\n", " ('Gc13', ['Gx', 'Gx', 'Gx']),\n", " ('Gc14', ['Gx', 'Gy', 'Gy', 'Gy', 'Gx', 'Gx', 'Gx']),\n", " ('Gc15', ['Gy', 'Gy', 'Gy']),\n", " ('Gc16', ['Gx']),\n", " ('Gc17', ['Gx', 'Gy', 'Gx']),\n", " ('Gc18', ['Gy', 'Gy', 'Gy', 'Gx', 'Gx']),\n", " ('Gc19', ['Gx', 'Gy', 'Gy']),\n", " ('Gc20', ['Gx', 'Gy', 'Gy', 'Gy', 'Gx']),\n", " ('Gc21', ['Gy']),\n", " ('Gc22', ['Gx', 'Gx', 'Gx', 'Gy', 'Gy']),\n", " ('Gc23', ['Gx', 'Gy', 'Gx', 'Gx', 'Gx'])])" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "std1Q_XYI.clifford_compilation" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.7.0" } }, "nbformat": 4, "nbformat_minor": 2 }