diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index a505cde42..149e3b9b2 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,5 +1,93 @@ -# This is a comment. -# Each line is a file pattern followed by one or more owners. +## Global owners (default to pyGSTi maintainers) ## +# These will also be owners for everything below +# so they can approve minor PRs without adding +# undue burden on volunteer code owners +* @sandialabs/pygsti-maintainers @sandialabs/pygsti-gatekeepers + + +## Drift analysis ## +pygsti/protocols/stability.py @tjproct @sandialabs/pygsti-gatekeepers +pygsti/report/section/drift.py @tjproct @sandialabs/pygsti-gatekeepers +pygsti/report/templates/drift_html_report/ @tjproct @sandialabs/pygsti-gatekeepers + +## Forward simulators ## +pygsti/forwardsims @rileyjmurray @sandialabs/pygsti-gatekeepers +pygsti/forwardsims/termforwardsim* @adhumu @sandialabs/pygsti-gatekeepers + +## IBMQ interface ## +pygsti/extras/devices @sandialabs/pygsti-ibmq @sandialabs/pygsti-gatekeepers +pygsti/extras/ibmq @sandialabs/pygsti-ibmq @sandialabs/pygsti-gatekeepers + +## Interpygate ## +pygsti/extras/interpygate/ @kevincyoung @sandialabs/pygsti-gatekeepers + +## Modelmembers ## +pygsti/modelmembers/ @rileyjmurray @sandialabs/pygsti-gatekeepers +pygsti/modelmembers/instruments/ @sandialabs/pygsti-mcm @sandialabs/pygsti-gatekeepers + +## Modelpack owners ## +pygsti/modelpacks/ @kmrudin @sandialabs/pygsti-gatekeepers + +## Optimizer owners ## +pygsti/objectivefns @rileyjmurray @sandialabs/pygsti-gatekeepers +pygsti/optimize @rileyjmurray @sandialabs/pygsti-gatekeepers + +## RB owners ## +pygsti/algorithms/compilers.py @sandialabs/pygsti-rb @sandialabs/pygsti-gatekeepers +pygsti/algorithms/mirroring.py @sandialabs/pygsti-rb @sandialabs/pygsti-gatekeepers +pygsti/algorithms/randomcircuit.py @sandialabs/pygsti-rb @sandialabs/pygsti-gatekeepers +pygsti/algorithms/rbfit.py @sandialabs/pygsti-rb @sandialabs/pygsti-gatekeepers +pygsti/extras/rb.py @sandialabs/pygsti-rb @sandialabs/pygsti-gatekeepers # Should this just be deprecated and removed? +pygsti/protocols/rb.py @sandialabs/pygsti-rb @sandialabs/pygsti-gatekeepers +pygsti/tools/rbtheory.py @sandialabs/pygsti-rb @sandialabs/pygsti-gatekeepers +pygsti/tools/rbtools.py @sandialabs/pygsti-rb @sandialabs/pygsti-gatekeepers +pygsti/tools/symplectic.py @sandialabs/pygsti-rb @sandialabs/pygsti-gatekeepers + +## RPE owners ## +pygsti/extras/rpe @kmrudin @sandialabs/pygsti-gatekeepers +pygsti/models/rpemodel.py @kmrudin @sandialabs/pygsti-gatekeepers +pygsti/protocols/rpe.py @kmrudin @sandialabs/pygsti-gatekeepers + +## Reporting owners ## +# Specifically just for workspace plots/tables +pygsti/report/workspace*.py @pcwysoc @sandialabs/pygsti-gatekeepers + + + +## Tutorial owners ## +# In addition to general tutorial owners, +# we will also have specific tutorials be owned +# by topics owners are responsible for above +jupyter_notebooks/ @sandialabs/pygsti-tutorials @sandialabs/pygsti-gatekeepers +jupyter_notebooks/**/*RB-*.ipynb @sandialabs/pygsti-rb @sandialabs/pygsti-gatekeepers +jupyter_notebooks/Examples/1QGST-InterpolatedOps.ipynb @kevincyoung @sandialabs/pygsti-gatekeepers +jupyter_notebooks/Tutorials/algorithms/DriftCharacterization.ipynb @tjproct @sandialabs/pygsti-gatekeepers +jupyter_notebooks/Tutorials/algorithms/MirrorCircuitBenchmarks.ipynb @sandialabs/pygsti-rb @sandialabs/pygsti-gatekeepers +jupyter_notebooks/Tutorials/algorithms/RobustPhaseEstimation.ipynb @kmrudin @sandialabs/pygsti-gatekeepers +jupyter_notebooks/Tutorials/objects/advanced/IBMQExperiment.ipynb @sandialabs/pygsti-ibmq @sandialabs/pygsti-gatekeepers +jupyter_notebooks/Tutorials/objects/advanced/Instruments.ipynb @sandialabs/pygsti-mcm @sandialabs/pygsti-gatekeepers +jupyter_notebooks/Tutorials/objects/advanced/InterpolatedOperators.ipynb @kevincyoung @sandialabs/pygsti-gatekeepers +jupyter_notebooks/Tutorials/objects/advanced/ModelPacks.ipynb @kmrudin @sandialabs/pygsti-gatekeepers +jupyter_notebooks/Tutorials/reporting/ @pcwysoc @sandialabs/pygsti-gatekeepers + +## Test owners ## +test/ @rileyjmurray @sandialabs/pygsti-gatekeepers +test/test_packages/extras/test_drift.py @tjproct @sandialabs/pygsti-gatekeepers +test/test_packages/extras/test_interpygate.py @kevincyoung @sandialabs/pygsti-gatekeepers +test/test_packages/extras/test_rb.py @sandialabs/pygsti-rb @sandialabs/pygsti-gatekeepers +test/test_packages/extras/test_rpe.py @kmrudin @sandialabs/pygsti-gatekeepers +test/test_packages/extras/test_rpeobjects.py @kmrudin @sandialabs/pygsti-gatekeepers +test/test_packages/objects/test_instruments.py @sandialabs/pygsti-mcm @sandialabs/pygsti-gatekeepers +test/test_packages/report/ @pcwysoc @sandialabs/pygsti-gatekeepers +test/test_packages/reportb/ @pcwysoc @sandialabs/pygsti-gatekeepers +test/unit/algorithms/test_randomcircuit.py @sandialabs/pygsti-rb @sandialabs/pygsti-gatekeepers +test/unit/extras/interpygate @kevincyoung @sandialabs/pygsti-gatekeepers +test/unit/extras/rb/ @sandialabs/pygsti-rb @sandialabs/pygsti-gatekeepers +test/unit/extras/rpe/ @kmrudin @sandialabs/pygsti-gatekeepers +test/unit/modelpacks/ @kmrudin @sandialabs/pygsti-gatekeepers +test/unit/objects/test_instrument.py @sandialabs/pygsti-mcm @sandialabs/pygsti-gatekeepers +test/unit/protocols/test_rb.py @sandialabs/pygsti-rb @sandialabs/pygsti-gatekeepers +test/unit/report/ @pcwysoc @sandialabs/pygsti-gatekeepers +test/unit/tools/test_symplectic.py @sandialabs/pygsti-rb @sandialabs/pygsti-gatekeepers + -# Global owners -* @sserita @coreyostrove @rileyjmurray diff --git a/.github/workflows/autodeploy.yml b/.github/workflows/autodeploy.yml index 5ad63e206..6747aa760 100644 --- a/.github/workflows/autodeploy.yml +++ b/.github/workflows/autodeploy.yml @@ -6,9 +6,9 @@ name: Deploy new version on pypi.org on: push: branches: [ "master" ] - # Pattern matched against refs/tags - tags: - - 'v*' # Push events to every tag not containing '/' (use '**' for hierarchical tags) + release: + types: + - published # Dont allow running manually from Actions tab -- use manualdeploy for this #workflow_dispatch: @@ -17,17 +17,16 @@ jobs: build_wheels: name: Build wheels on ${{ matrix.os }} runs-on: ${{ matrix.os }} - #if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') # doesn't work -- try using tags: above strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: fetch-depth: 0 # to fetch all branches and *tags* (needed to get version number correctly) - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v5 name: Install Python with: python-version: '3.10' @@ -39,8 +38,9 @@ jobs: CIBW_BUILD_VERBOSITY: 1 CIBW_BEFORE_ALL_LINUX: ./.github/ci-scripts/before_install.sh - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 with: + name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }} path: ./wheelhouse/*.whl build_sdist: @@ -49,11 +49,11 @@ jobs: #if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') # doesn't work -- try using tags: above steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: fetch-depth: 0 # to fetch all branches and *tags* (needed to get version number correctly) - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v5 name: Install Python with: python-version: '3.10' @@ -61,26 +61,26 @@ jobs: - name: Build sdist run: python setup.py sdist - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 with: + name: cibw-sdist path: dist/*.tar.gz upload_pypi: needs: [build_wheels, build_sdist] runs-on: ubuntu-latest - # upload to PyPI on every tag starting with 'v' -- doesn't work -> try using tags: above - #if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') - # alternatively, to publish when a GitHub Release is created, use the following rule: - # if: github.event_name == 'release' && github.event.action == 'published' + if: github.event_name == 'release' && github.event.action == 'published' + permissions: + # IMPORTANT: this permission is mandatory for trusted publishing + id-token: write steps: - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v4 with: - name: artifact + pattern: cibw-* path: dist + merge-multiple: true - name: Publish package on PyPI uses: pypa/gh-action-pypi-publish@release/v1 - with: - user: __token__ - password: ${{ secrets.PYPI_API_TOKEN }} - verbose: true + # With the use of OIDC, API tokens are no longer needed + # See https://docs.pypi.org/trusted-publishers/using-a-publisher/ for more info \ No newline at end of file diff --git a/.github/workflows/extras.yml b/.github/workflows/extras.yml index 1e7de0c29..c4e83e292 100644 --- a/.github/workflows/extras.yml +++ b/.github/workflows/extras.yml @@ -21,25 +21,25 @@ jobs: strategy: fail-fast: false # Finish all tests even if one fails matrix: - os: [ubuntu-20.04, windows-2019, macos-11] + os: [ubuntu-latest, windows-latest, macos-latest] python-version: [3.8, 3.9, '3.10', '3.11'] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up installation environment (Ubuntu or Windows) - if: ${{matrix.os == 'ubuntu-20.04' || matrix.os == 'windows-2019'}} + if: ${{matrix.os == 'ubuntu-latest' || matrix.os == 'windows-latest'}} run: | ./.github/ci-scripts/before_install.sh - name: Set up installation environment (MacOS) - if: ${{matrix.os == 'macos-11'}} + if: ${{matrix.os == 'macos-latest'}} run: | ./.github/ci-scripts/before_install_macos.sh - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Cache pip packages - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('setup.py') }}-${{ hashFiles('**/*requirements.txt') }} @@ -51,17 +51,17 @@ jobs: python -m pip install -e .[testing] python setup.py build_ext --inplace - name: Run test_packages Ubuntu - if: ${{matrix.os == 'ubuntu-20.04'}} + if: ${{matrix.os == 'ubuntu-latest'}} run: | python -Ic "import pygsti; print(pygsti.__version__); print(pygsti.__path__)" python -m pytest -v -n auto --dist loadscope --ignore=test/test_packages/mpi --ignore=test/test_packages/notebooks test/test_packages - name: Run test_packages Windows - if: ${{matrix.os == 'windows-2019'}} + if: ${{matrix.os == 'windows-latest'}} run: | python -Ic "import pygsti; print(pygsti.__version__); print(pygsti.__path__)" python -m pytest -v -n auto --dist loadscope --ignore=test/test_packages/mpi --ignore=test/test_packages/notebooks test/test_packages - name: Run test_packages MacOS - if: ${{matrix.os == 'macos-11'}} + if: ${{matrix.os == 'macos-latest'}} run: | python -Ic "import pygsti; print(pygsti.__version__); print(pygsti.__path__)" diff --git a/.github/workflows/main-mac.yml b/.github/workflows/main-mac.yml new file mode 100644 index 000000000..dad834209 --- /dev/null +++ b/.github/workflows/main-mac.yml @@ -0,0 +1,61 @@ +# This workflow will install Python dependencies, run tests and lint with a variety of Python versions +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions + +name: Build and run tests (MacOS only, all Python versions) + +on: + push: + # Mac runners are expensive and oversubscribed. Only run on beta and master + branches: [ "beta", "master" ] + # Allow running manually from Actions tab + workflow_dispatch: + +env: + SKIP_DEAP: 1 + +jobs: + build: # Main build + unit test check + + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macos-latest] + python-version: [3.8, 3.9, '3.10', '3.11'] + + steps: + - uses: actions/checkout@v4 + - name: Set up installation environment (MacOS) + run: | + ./.github/ci-scripts/before_install_macos.sh + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Cache pip packages + uses: actions/cache@v4 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('setup.py') }}-${{ hashFiles('**/*requirements.txt') }} + - name: Install package + run: | + python -m pip install --upgrade pip + python -m pip install wheel + python -m pip install flake8 + python -m pip install -e .[testing] + python setup.py build_ext --inplace + # python -m pip freeze # this isn't relevant anymore since pip install builds a wheel separately + - name: Lint with flake8 + run: | + # Critical errors, exit on failure + flake8 . --count --show-source --statistics --config=.flake8-critical + # Standard PEP8, allowed to fail since exit-zero treats all errors as warnings + flake8 . --exit-zero --statistics + - name: Run unit tests MacOS + if: ${{matrix.os == 'macos-latest'}} + run: | + python -Ic "import pygsti; print(pygsti.__version__); print(pygsti.__path__)" + python -m pytest -n auto --dist loadscope --cov=pygsti test/unit + + + + diff --git a/.github/workflows/main-minimal.yml b/.github/workflows/main-minimal.yml new file mode 100644 index 000000000..033c06cff --- /dev/null +++ b/.github/workflows/main-minimal.yml @@ -0,0 +1,72 @@ +# This workflow will install Python dependencies, run tests and lint with a variety of Python versions +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions + +name: Build and run tests (no MacOS, low/high Python versions only) + +on: + push: + # Intended to be fast checks on non-main branches + branches-ignore: [ "beta", "develop", "master" ] + # Hacky way to only run pull requests from forked repositories (assumes : is not used in branch names unless forked) + # https://github.community/t/how-to-trigger-an-action-on-push-or-pull-request-but-not-both/16662/10 + pull_request: + branches: [ "**:**" ] + # Allow running manually from Actions tab + workflow_dispatch: + +env: + SKIP_DEAP: 1 + +jobs: + build: # Main build + unit test check + + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest] + python-version: [3.8,'3.11'] + + steps: + - uses: actions/checkout@v4 + - name: Set up installation environment (Ubuntu or Windows) + if: ${{matrix.os == 'ubuntu-latest' || matrix.os == 'windows-latest'}} + run: | + ./.github/ci-scripts/before_install.sh + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Cache pip packages + uses: actions/cache@v4 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('setup.py') }}-${{ hashFiles('**/*requirements.txt') }} + - name: Install package + run: | + python -m pip install --upgrade pip + python -m pip install wheel + python -m pip install flake8 + python -m pip install -e .[testing] + python setup.py build_ext --inplace + # python -m pip freeze # this isn't relevant anymore since pip install builds a wheel separately + - name: Lint with flake8 + if: ${{matrix.os != 'windows-latest'}} + run: | + # Critical errors, exit on failure + flake8 . --count --show-source --statistics --config=.flake8-critical + # Standard PEP8, allowed to fail since exit-zero treats all errors as warnings + flake8 . --exit-zero --statistics + - name: Run unit tests ubuntu + if: ${{matrix.os == 'ubuntu-latest'}} + run: | + python -Ic "import pygsti; print(pygsti.__version__); print(pygsti.__path__)" + python -m pytest -n auto --dist loadscope --cov=pygsti test/unit + - name: Run unit tests windows + if: ${{matrix.os == 'windows-latest'}} + run: | + python -Ic "import pygsti; print(pygsti.__version__); print(pygsti.__path__)" + python -m pytest -n auto --dist loadscope --cov=pygsti test/unit + + + + diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f5361f6c8..eb3306fbf 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -5,9 +5,7 @@ name: Build and run tests on: push: - branches-ignore: [ "beta" ] - # Hacky way to only run pull requests from forked repositories (assumes : is not used in branch names unless forked) - # https://github.community/t/how-to-trigger-an-action-on-push-or-pull-request-but-not-both/16662/10 + branches: [ "develop", "master" ] pull_request: branches: [ "**:**" ] # Allow running manually from Actions tab @@ -22,25 +20,21 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-20.04, windows-2019, macos-11] + os: [ubuntu-latest, windows-latest] python-version: [3.8, 3.9, '3.10', '3.11'] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up installation environment (Ubuntu or Windows) - if: ${{matrix.os == 'ubuntu-20.04' || matrix.os == 'windows-2019'}} + if: ${{matrix.os == 'ubuntu-latest' || matrix.os == 'windows-latest'}} run: | ./.github/ci-scripts/before_install.sh - - name: Set up installation environment (MacOS) - if: ${{matrix.os == 'macos-11'}} - run: | - ./.github/ci-scripts/before_install_macos.sh - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Cache pip packages - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('setup.py') }}-${{ hashFiles('**/*requirements.txt') }} @@ -53,24 +47,19 @@ jobs: python setup.py build_ext --inplace # python -m pip freeze # this isn't relevant anymore since pip install builds a wheel separately - name: Lint with flake8 - if: ${{matrix.os != 'windows-2019'}} + if: ${{matrix.os != 'windows-latest'}} run: | # Critical errors, exit on failure flake8 . --count --show-source --statistics --config=.flake8-critical # Standard PEP8, allowed to fail since exit-zero treats all errors as warnings flake8 . --exit-zero --statistics - name: Run unit tests ubuntu - if: ${{matrix.os == 'ubuntu-20.04'}} + if: ${{matrix.os == 'ubuntu-latest'}} run: | python -Ic "import pygsti; print(pygsti.__version__); print(pygsti.__path__)" python -m pytest -n auto --dist loadscope --cov=pygsti test/unit - name: Run unit tests windows - if: ${{matrix.os == 'windows-2019'}} - run: | - python -Ic "import pygsti; print(pygsti.__version__); print(pygsti.__path__)" - python -m pytest -n auto --dist loadscope --cov=pygsti test/unit - - name: Run unit tests MacOS - if: ${{matrix.os == 'macos-11'}} + if: ${{matrix.os == 'windows-latest'}} run: | python -Ic "import pygsti; print(pygsti.__version__); print(pygsti.__path__)" python -m pytest -n auto --dist loadscope --cov=pygsti test/unit @@ -78,14 +67,14 @@ jobs: push: # Push to stable "beta" branch on successful build - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest # Only run on "develop" branch if tests pass needs: build if: github.ref == 'refs/heads/develop' && github.event_name == 'push' steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: fetch-depth: 0 token: ${{ secrets.PYGSTI_TOKEN }} diff --git a/.github/workflows/manualdeploy.yml b/.github/workflows/manualdeploy.yml index b54972b15..bf8967cab 100644 --- a/.github/workflows/manualdeploy.yml +++ b/.github/workflows/manualdeploy.yml @@ -16,11 +16,11 @@ jobs: matrix: os: [ubuntu-latest, macos-latest, windows-latest] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: fetch-depth: 0 # to fetch all branches and *tags* (needed to get version number correctly) - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v5 name: Install Python with: python-version: '3.10' @@ -32,8 +32,9 @@ jobs: CIBW_BUILD_VERBOSITY: 1 CIBW_BEFORE_ALL_LINUX: ./.github/ci-scripts/before_install.sh - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 with: + name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }} path: ./wheelhouse/*.whl build_sdist: @@ -41,11 +42,11 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: fetch-depth: 0 # to fetch all branches and *tags* (needed to get version number correctly) - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v5 name: Install Python with: python-version: '3.10' @@ -53,22 +54,23 @@ jobs: - name: Build sdist run: python setup.py sdist - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 with: + name: cibw-sdist path: dist/*.tar.gz upload_pypi: needs: [build_wheels, build_sdist] runs-on: ubuntu-latest + permissions: + # IMPORTANT: this permission is mandatory for trusted publishing + id-token: write steps: - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v4 with: - name: artifact + pattern: cibw-* path: dist + merge-multiple: true - name: Publish package on PyPI - uses: pypa/gh-action-pypi-publish@release/v1 - with: - user: __token__ - password: ${{ secrets.PYPI_API_TOKEN }} - verbose: true + uses: pypa/gh-action-pypi-publish@release/v1 \ No newline at end of file diff --git a/.github/workflows/notebook.yml b/.github/workflows/notebook.yml index c3b3e3204..5758258b5 100644 --- a/.github/workflows/notebook.yml +++ b/.github/workflows/notebook.yml @@ -19,13 +19,13 @@ jobs: strategy: fail-fast: false # Finish all tests even if one fails matrix: - os: [ubuntu-20.04, windows-2019, macos-11] + os: [ubuntu-latest, windows-latest, macos-latest] python-version: [3.8, 3.9, '3.10', '3.11'] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up installation environment (Ubuntu or Windows) - if: ${{matrix.os == 'ubuntu-20.04' || matrix.os == 'windows-2019'}} + if: ${{matrix.os == 'ubuntu-latest' || matrix.os == 'windows-latest'}} run: | ./.github/ci-scripts/before_install.sh #download chp source code @@ -33,7 +33,7 @@ jobs: #compile chp gcc -o ./jupyter_notebooks/Tutorials/algorithms/advanced/chp ./jupyter_notebooks/Tutorials/algorithms/advanced/chp.c - name: Set up installation environment (MacOS) - if: ${{matrix.os == 'macos-11'}} + if: ${{matrix.os == 'macos-latest'}} run: | ./.github/ci-scripts/before_install_macos.sh #download chp source code @@ -41,11 +41,11 @@ jobs: #compile chp source code gcc -o ./jupyter_notebooks/Tutorials/algorithms/advanced/chp ./jupyter_notebooks/Tutorials/algorithms/advanced/chp.c - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Cache pip packages - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('setup.py') }}-${{ hashFiles('**/*requirements.txt') }} @@ -57,17 +57,17 @@ jobs: python -m pip install -e .[testing] python setup.py build_ext --inplace - name: Run notebook regression ubuntu - if: ${{matrix.os == 'ubuntu-20.04'}} + if: ${{matrix.os == 'ubuntu-latest'}} run: | python -Ic "import pygsti; print(pygsti.__version__); print(pygsti.__path__)" python -m pytest -n auto --nbval-lax --dist loadscope --nbval-current-env jupyter_notebooks - name: Run notebook regression windows - if: ${{matrix.os == 'windows-2019'}} + if: ${{matrix.os == 'windows-latest'}} run: | python -Ic "import pygsti; print(pygsti.__version__); print(pygsti.__path__)" python -m pytest -n auto --nbval-lax --dist loadscope --nbval-current-env jupyter_notebooks - name: Run notebook regression MacOS - if: ${{matrix.os == 'macos-11'}} + if: ${{matrix.os == 'macos-latest'}} run: | python -Ic "import pygsti; print(pygsti.__version__); print(pygsti.__path__)" python -m pytest -n auto --nbval-lax --dist loadscope --nbval-current-env jupyter_notebooks diff --git a/.github/workflows/testdeploy.yml b/.github/workflows/testdeploy.yml deleted file mode 100644 index 2926f62eb..000000000 --- a/.github/workflows/testdeploy.yml +++ /dev/null @@ -1,86 +0,0 @@ -# This workflow will install Python dependencies, run tests and lint with a variety of Python versions -# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions - -name: Deploy on test.pypi.org - -on: - push: - branches: [ "feature-tutorial-evotype-fixes" ] # for initial testing - - # Allow running manually from Actions tab - workflow_dispatch: - - -jobs: - build_wheels: - name: Build wheels on ${{ matrix.os }} - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, macos-latest, windows-latest] - steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 0 # to fetch all branches and *tags* (needed to get version number correctly) - - - uses: actions/setup-python@v2 - name: Install Python - with: - python-version: '3.10' - - #Now this is the default: - #- name: Use cython-enabled pyproject.toml - # run: | - # rm pyproject.toml - # mv pyproject.toml.with_cython pyproject.toml - - - name: Build wheels - uses: pypa/cibuildwheel@v2.1.2 - env: - CIBW_BUILD: cp38-* cp39-* cp310-* cp311-* - CIBW_BUILD_VERBOSITY: 1 - CIBW_BEFORE_ALL_LINUX: ./.github/ci-scripts/before_install.sh - - - uses: actions/upload-artifact@v2 - with: - path: ./wheelhouse/*.whl - - build_sdist: - name: Build source distribution - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 0 # to fetch all branches and *tags* (needed to get version number correctly) - - - uses: actions/setup-python@v2 - name: Install Python - with: - python-version: '3.10' - - - name: Build sdist - run: python setup.py sdist - - - uses: actions/upload-artifact@v2 - with: - path: dist/*.tar.gz - - upload_pypi: - needs: [build_wheels, build_sdist] - runs-on: ubuntu-latest - # upload to PyPI on every tag starting with 'v' - #if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags/v') - # alternatively, to publish when a GitHub Release is created, use the following rule: - # if: github.event_name == 'release' && github.event.action == 'published' - steps: - - uses: actions/download-artifact@v2 - with: - name: artifact - path: dist - - - uses: pypa/gh-action-pypi-publish@release/v1 - with: - user: __token__ - password: ${{ secrets.TESTPYPI_API_TOKEN }} - repository_url: https://test.pypi.org/legacy/ - verbose: true diff --git a/.gitignore b/.gitignore index 026134b95..c2e522264 100644 --- a/.gitignore +++ b/.gitignore @@ -24,7 +24,13 @@ doc/_autosummary doc/autoapi doc/build .venv* +*.pyc* +# Protocol Checkpointing # +########################## +*gst_checkpoints* +*model_test_checkpoints* +*standard_gst_checkpoints* # Test Metadata # ################# @@ -40,6 +46,7 @@ jupyter_notebooks/Tutorials/tutorial_files/modeltest_report jupyter_notebooks/Tutorials/tutorial_files/gettingStartedReport jupyter_notebooks/Examples/example_files/*.pkl jupyter_notebooks/Examples/example_files/*.json +jupyter_notebooks/Examples/example_files/leakage_* jupyter_notebooks/Tutorials/tutorial_files/exampleReport jupyter_notebooks/Tutorials/tutorial_files/exampleStdReport jupyter_notebooks/Tutorials/tutorial_files/exampleMultiEstimateReport diff --git a/CHANGELOG b/CHANGELOG index a969d344b..af238b94b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,44 @@ # CHANGELOG +## [0.9.12.2] - 2024-04-16 + +### Added +* Updated Cirq parsing capabilities (#411) +* Added ability for reports to use CircuitListDesigns and results without gauge optimizations (#412, #415) +* Indicator that figure/title headings can be clicked for expanded details (#416) + + +### Fixed +* Several tutorial updates and fixes (#282, #317, #421) +* Fixed fiducial selection with wrong qubit labels (#396, #418) +* Casting operators to dense matrices to avoid type errors in `pygsti.tools.optools` (#406, #414) +* LGST fitting with sparse dataset (#420) + + +### Changed +* Increased the speed of unit/integration tests in GitHub Actions (#380, #403) + +## [0.9.12.1] - 2024-02-07 + +### Added +* Warnings for JupyterLab incompatibility (#328) +* Warning for modifying static DataSets (#340) +* Keyword argument to change ForwardSim types at Protocol runtime (#358) +* Flag to drop new `delay` instructions in QASM2 circuit output (#377) +* Warning for non-TP gauge transformations on CPTPLND-parameterized objects (#378) +* Code owner assignments (#384) +* A new AffineShiftOp modelmember (#386) + +### Fixed +* Several tutorial updates and fixes (#247, #395) +* LGST fitting with various model parameterizations (#366) +* Deprecated convolve import in scipy 1.12 (#391, #392) + +### Changed +* Stricter enforcement of line labels when using "*" in circuits (#373) +* Reimplementation of ProtectedArray (#386) +* GitHub runner updates for faster runs on development branches (#388) + ## [0.9.12] - 2023-11-28 ### Added diff --git a/README.md b/README.md index ea09cd2c2..d92b58b4e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ ******************************************************************************** - pyGSTi 0.9 + pyGSTi 0.9.12.1 ******************************************************************************** ![master build](https://github.com/pyGSTio/pyGSTi/workflows/Build%20and%20run%20tests/badge.svg?branch=master) @@ -37,7 +37,7 @@ In particular, there are a number of characterization protocols currently implem PyGSTi is designed with a modular structure so as to be highly customizable and easily integrated to new or existing python software. It runs using -python2.7 or python3. To faclilitate integration with software for running +python 3.8 or higher. To faclilitate integration with software for running cloud-QIP experiments, pyGSTi `Circuit` objects can be converted to IBM's **OpenQASM** and Rigetti Quantum Computing's **Quil** circuit description languages. diff --git a/jupyter_notebooks/Examples/BootstrappedErrorBars.ipynb b/jupyter_notebooks/Examples/BootstrappedErrorBars.ipynb index ddf48e4b4..b2e386abf 100644 --- a/jupyter_notebooks/Examples/BootstrappedErrorBars.ipynb +++ b/jupyter_notebooks/Examples/BootstrappedErrorBars.ipynb @@ -17,11 +17,10 @@ "import sys\n", "import time\n", "import json\n", - "\n", + "import numpy as np\n", "import pygsti\n", - "from pygsti.modelpacks.legacy import std1Q_XYI\n", - "\n", - "%pylab inline" + "from pygsti.modelpacks import smq1Q_XY\n", + "import matplotlib.pyplot as plt" ] }, { @@ -33,12 +32,13 @@ "#Get a GST estimate (similar to Tutorial 0)\n", "\n", "# 1) get the target Model\n", - "target_model = std1Q_XYI.target_model()\n", + "target_model = smq1Q_XY.target_model('full TP')\n", "\n", "# 2) get the building blocks needed to specify which operation sequences are needed\n", - "prep_fiducials, meas_fiducials = std1Q_XYI.prepStrs, std1Q_XYI.effectStrs\n", - "germs = std1Q_XYI.germs\n", - "maxLengths = [1,2,4,8,16]\n", + "prep_fiducials = smq1Q_XY.prep_fiducials()[0:4]\n", + "meas_fiducials = smq1Q_XY.meas_fiducials()[0:3]\n", + "germs = smq1Q_XY.germs()\n", + "maxLengths = [1,2,4,8]\n", "\n", "# 3) generate \"fake\" data from a depolarized version of target_model\n", "mdl_datagen = target_model.depolarize(op_noise=0.1, spam_noise=0.001)\n", @@ -53,24 +53,6 @@ "estimated_model = results.estimates['full TP'].models['stdgaugeopt']" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(target_model)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "estimated_model.operations" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -85,7 +67,8 @@ "cell_type": "code", "execution_count": null, "metadata": { - "scrolled": true + "scrolled": true, + "tags": [] }, "outputs": [], "source": [ @@ -103,13 +86,24 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "gauge_opt_pboot_models = pygsti.drivers.gauge_optimize_models(param_boot_models, estimated_model,\n", " plot=False) #plotting support removed w/matplotlib" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(gauge_opt_pboot_models[0])" + ] + }, { "cell_type": "code", "execution_count": null, @@ -125,12 +119,10 @@ "print(pboot_std['rho0'].to_vector(), end='\\n\\n')\n", "print(\"Error in effect vecs:\")\n", "print(pboot_std['Mdefault'].to_vector(), end='\\n\\n')\n", - "print(\"Error in Gi:\")\n", - "print(pboot_std['Gi'].to_vector(), end='\\n\\n')\n", - "print(\"Error in Gx:\")\n", - "print(pboot_std['Gx'].to_vector(), end='\\n\\n')\n", - "print(\"Error in Gy:\")\n", - "print(pboot_std['Gy'].to_vector())" + "print(\"Error in Gxpi2:\")\n", + "print(pboot_std['Gxpi2',0].to_vector(), end='\\n\\n')\n", + "print(\"Error in Gypi2:\")\n", + "print(pboot_std['Gypi2',0].to_vector())" ] }, { @@ -187,12 +179,10 @@ "print(npboot_std['rho0'].to_vector(), end='\\n\\n')\n", "print(\"Error in effect vecs:\")\n", "print(npboot_std['Mdefault'].to_vector(), end='\\n\\n')\n", - "print(\"Error in Gi:\")\n", - "print(npboot_std['Gi'].to_vector(), end='\\n\\n')\n", - "print(\"Error in Gx:\")\n", - "print(npboot_std['Gx'].to_vector(), end='\\n\\n')\n", - "print(\"Error in Gy:\")\n", - "print(npboot_std['Gy'].to_vector())" + "print(\"Error in Gxpi2:\")\n", + "print(npboot_std['Gxpi2',0].to_vector(), end='\\n\\n')\n", + "print(\"Error in Gypi2:\")\n", + "print(npboot_std['Gypi2',0].to_vector())" ] }, { @@ -203,12 +193,13 @@ }, "outputs": [], "source": [ - "loglog(npboot_std.to_vector(),pboot_std.to_vector(),'.')\n", - "loglog(np.logspace(-4,-2,10),np.logspace(-4,-2,10),'--')\n", - "xlabel('Non-parametric')\n", - "ylabel('Parametric')\n", - "xlim((1e-4,1e-2)); ylim((1e-4,1e-2))\n", - "title('Scatter plot comparing param vs. non-param bootstrapping error bars.')" + "plt.loglog(npboot_std.to_vector(),pboot_std.to_vector(),'.')\n", + "plt.loglog(np.logspace(-4,-2,10),np.logspace(-4,-2,10),'--')\n", + "plt.xlabel('Non-parametric')\n", + "plt.ylabel('Parametric')\n", + "plt.xlim((1e-4,1e-2)); plt.ylim((1e-4,1e-2))\n", + "plt.title('Scatter plot comparing param vs. non-param bootstrapping error bars.')\n", + "plt.show()" ] }, { @@ -221,9 +212,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "api_updates", "language": "python", - "name": "python3" + "name": "api_updates" }, "language_info": { "codemirror_mode": { diff --git a/jupyter_notebooks/Examples/CirqIntegration.ipynb b/jupyter_notebooks/Examples/CirqIntegration.ipynb index c5bab68d0..b89c173dc 100644 --- a/jupyter_notebooks/Examples/CirqIntegration.ipynb +++ b/jupyter_notebooks/Examples/CirqIntegration.ipynb @@ -18,12 +18,13 @@ "\n", "1. Sets up pyGSTi.\n", "2. Shows how pyGSTi circuits can be converted to Cirq circuits.\n", - "3. Shows how the Cirq circuits can be run and the results loaded back into pyGSTi for analysis." + "3. Shows how Cirq circuits can be converted into pyGSTi circuits.\n", + "4. Shows how the Cirq circuits can be run and the results loaded back into pyGSTi for analysis." ] }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": { "colab": {}, "colab_type": "code", @@ -34,6 +35,7 @@ "import cirq\n", "import pygsti\n", "from pygsti.modelpacks import smq1Q_XYI\n", + "from pygsti.circuits import Circuit\n", "import numpy as np\n", "import tqdm" ] @@ -55,12 +57,12 @@ "id": "cWpHwZVtvejH" }, "source": [ - "### Make target gate set $\\{\\sqrt{X},\\sqrt{Y},I\\}$" + "### Make target gate set $\\{R_{X}(\\pi/2), R_{Y}(\\pi/2),I\\}$" ] }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -79,7 +81,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": { "colab": {}, "colab_type": "code", @@ -104,7 +106,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": { "colab": {}, "colab_type": "code", @@ -117,7 +119,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", @@ -127,22 +129,14 @@ "id": "SuvgxDpKwCul", "outputId": "6654eeeb-3870-4b61-af43-0c66cb09169e" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]\n" - ] - } - ], + "outputs": [], "source": [ "print(max_lengths)" ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": { "colab": {}, "colab_type": "code", @@ -155,7 +149,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", @@ -165,18 +159,7 @@ "id": "9vD8DXOPwHSV", "outputId": "06e10aec-f7ab-4b7b-d0c6-242ce225d5a2" }, - "outputs": [ - { - "data": { - "text/plain": [ - "1624" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "len(pygsti_circuits)" ] @@ -204,7 +187,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -228,23 +211,11 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": { "scrolled": true }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "pyGSTi:\n", - "Qubit 0 ---|Gxpi2|-|Gxpi2|-| |-| |-|Gxpi2|---\n", - "\n", - "Cirq:\n", - "(8, 3): ───X^0.5───X^0.5───────────X^0.5───\n" - ] - } - ], + "outputs": [], "source": [ "pygsti_circuit = pygsti_circuits[111]\n", "print('pyGSTi:')\n", @@ -262,21 +233,9 @@ }, { "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "pyGSTi:\n", - "Qubit 0 ---|Gypi2|-|Gypi2|-|Gypi2|-|Gypi2|-|Gxpi2|-|Gxpi2|-|Gxpi2|---\n", - "\n", - "Cirq:\n", - "(8, 3): ───Y^0.5───Y^0.5───Y^0.5───Y^0.5───X^0.5───X^0.5───X^0.5───\n" - ] - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "pygsti_circuit = pygsti_circuits[90]\n", "print('pyGSTi:')\n", @@ -294,7 +253,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -303,21 +262,9 @@ }, { "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "pyGSTi:\n", - "Qubit 0 ---|Gxpi2|-|Gxpi2|-| |-| |-|Gxpi2|---\n", - "\n", - "Cirq:\n", - "(8, 3): ───X^0.5───X^0.5───WaitGate(100 ns)───WaitGate(100 ns)───X^0.5───\n" - ] - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "pygsti_circuit = pygsti_circuits[111]\n", "print('pyGSTi:')\n", @@ -328,21 +275,9 @@ }, { "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "pyGSTi:\n", - "Qubit 0 ---|Gypi2|-|Gypi2|-|Gypi2|-|Gypi2|-|Gxpi2|-|Gxpi2|-|Gxpi2|---\n", - "\n", - "Cirq:\n", - "(8, 3): ───Y^0.5───Y^0.5───Y^0.5───Y^0.5───X^0.5───X^0.5───X^0.5───\n" - ] - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "pygsti_circuit = pygsti_circuits[90]\n", "print('pyGSTi:')\n", @@ -367,33 +302,188 @@ }, { "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "100%|██████████| 1624/1624 [00:08<00:00, 189.73it/s]\n" - ] - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "cirq_circuits = [c.convert_to_cirq(qubit_label_dict, wait_duration) for c in tqdm.tqdm(pygsti_circuits)]" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "cirq_circuits" + ] + }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Note that we're missing the measurments, the idle operations don't have a time associated with them, and the first circuit is empty (it's should just be an idle). Otherwise, the results look good, and those things should be easy to fix." + "Note that we're missing the measurments and the first circuit is empty (it's should just be an idle). Otherwise, the results look good, and those things should be easy to fix." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## 3. Run the circuits" + "## 3. Convert Cirq circuits to pyGSTi circuits\n", + "We also have support for converting a cirq circuit to a pyGSTi circuit, which is demonstrated below.\n", + "Begin by constructing a cirq circuit directly." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#create to cirq qubit objects\n", + "qubit_00 = cirq.GridQubit(0,0)\n", + "qubit_01 = cirq.GridQubit(0,1)\n", + "#define a series of Moment objects, which fill the same role as circuit layers in pyGSTi.\n", + "moment1 = cirq.Moment([cirq.XPowGate(exponent=.5).on(qubit_00), cirq.I(qubit_01)])\n", + "moment2 = cirq.Moment([cirq.I(qubit_00), cirq.I(qubit_01)])\n", + "#This weird looking gate is the so-called N gate.\n", + "moment3 = cirq.Moment([cirq.PhasedXZGate(axis_phase_exponent=0.14758361765043326, \n", + " x_exponent=0.4195693767448338, \n", + " z_exponent=-0.2951672353008665).on(qubit_00),\n", + " cirq.I(qubit_01)])\n", + "moment4 = cirq.Moment([cirq.H(qubit_00), (cirq.T**-1).on(qubit_01)])\n", + "moment5 = cirq.Moment([cirq.CNOT.on(qubit_00, qubit_01)])\n", + "cirq_circuit_example = cirq.Circuit([moment1, moment2, moment3, moment4, moment5])\n", + "print(cirq_circuit_example)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To convert this into a pyGSTi circuit we can use the `from_cirq` class method of the Circuit class." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "converted_cirq_circuit_default = Circuit.from_cirq(cirq_circuit_example)\n", + "print(converted_cirq_circuit_default)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Above you can see the result of converting the circuit using the default conversion settings. The classmethod has multiple options for customizing the returned pyGSTi circuit.\n", + "1. By default the method constructs a mapping between cirq qubit objects and pygsti qubit labels based on the type of cirq qubit provided. E.g. a GridQubit gets mapped to `Q{row}_{col}` where row and col are the corresponding attribute values for the GridQubit. Something similar is done for NamedQubit and LineQubit objects. This can be overridden by passing in a dictionary for the `qubit_conversion` kwarg." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "converted_cirq_circuit_custom_qubit_map = Circuit.from_cirq(cirq_circuit_example, qubit_conversion={qubit_00: 'Qalice', qubit_01: 'Qbob'})\n", + "print(converted_cirq_circuit_custom_qubit_map)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. By default cirq included idle gates explicitly on all qubits in a layer without a specified operation applied. In pygsti we typically treat these as implied, and so the default behavior is to strip these extra idles. This can be turned off by setting `remove_implied_idles` to `False`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "converted_cirq_circuit_implied_idles = Circuit.from_cirq(cirq_circuit_example, remove_implied_idles=True)\n", + "print(converted_cirq_circuit_implied_idles)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "3. Layers consisting entirely of idle gates are by default converted to the default pyGSTi global idle convention or Label(()), or to a user specified replacement. This is controlled by the `global_idle_replacement_label` kwarg. The default value is the string 'auto', which will utilize the aforementioned default convention. Users can instead pass in either a string, which is converted to a corresponding Label object, or a circuit Label object directly. Finally, by passing in `None` the global idle replacement is not performed, and the full verbatim translation of that cirq layer is produced." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#auto is the default value, explicitly including here for comparison to alternative options.\n", + "converted_cirq_circuit_global_idle = Circuit.from_cirq(cirq_circuit_example, global_idle_replacement_label='auto')\n", + "print(converted_cirq_circuit_global_idle)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "converted_cirq_circuit_global_idle_1 = Circuit.from_cirq(cirq_circuit_example, global_idle_replacement_label='Gbanana')\n", + "print(converted_cirq_circuit_global_idle_1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from pygsti.baseobjs import Label\n", + "converted_cirq_circuit_global_idle_2 = Circuit.from_cirq(cirq_circuit_example, global_idle_replacement_label=Label('Gbanana', ('Q0_0','Q0_1')))\n", + "print(converted_cirq_circuit_global_idle_2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "converted_cirq_circuit_global_idle_3 = Circuit.from_cirq(cirq_circuit_example, global_idle_replacement_label= None)\n", + "print(converted_cirq_circuit_global_idle_3)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "4. There is built-in support for converting _most_ Cirq gates into their corresponding built-in pyGSTi gate names (see `cirq_gatenames_standard_conversions` in `pygsti.tools.internalgates` for more on this). There is also a fallback behavior where if not found in the default map, the converter will search among the built-in gate unitaries for one that matches (up to a global phase). If this doesn't work for a particular gate of user interest, of you simply want to override the default mapping as needed, this can be done by passing in a custom dictionary for the `cirq_gate_conversion` kwarg." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "custom_gate_map = pygsti.tools.internalgates.cirq_gatenames_standard_conversions()\n", + "custom_gate_map[cirq.H] = 'Gdefinitelynoth'\n", + "converted_cirq_circuit_custom_gate_map = Circuit.from_cirq(cirq_circuit_example, cirq_gate_conversion=custom_gate_map)\n", + "print(converted_cirq_circuit_custom_gate_map)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 4. Run the circuits" ] }, { @@ -405,7 +495,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -422,17 +512,9 @@ }, { "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "100%|██████████| 1624/1624 [00:39<00:00, 41.60it/s]\n" - ] - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "simulator = cirq.Simulator()\n", "results = [simulator.run(circuit, repetitions=1000) for circuit in tqdm.tqdm(cirq_circuits)]" @@ -447,7 +529,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -465,18 +547,9 @@ }, { "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "--- Circuit Creation ---\n", - "-- Std Practice: [##################################################] 100.0% (Target) --\n" - ] - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "gst_results = pygsti.run_stdpractice_gst(dataset, target_model, preps, effects, germs, max_lengths, modes=[\"full TP\",\"Target\"], verbosity=1)" ] @@ -490,18 +563,9 @@ }, { "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2DeltaLogL(estimate, data): 1102.0101377779301\n", - "2DeltaLogL(ideal, data): 1118.865389448009\n" - ] - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "mdl_estimate = gst_results.estimates['full TP'].models['stdgaugeopt']\n", "print(\"2DeltaLogL(estimate, data): \", pygsti.tools.two_delta_logl(mdl_estimate, dataset))\n", @@ -523,9 +587,9 @@ "provenance": [] }, "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "api_updates", "language": "python", - "name": "python3" + "name": "api_updates" }, "language_info": { "codemirror_mode": { diff --git a/jupyter_notebooks/Examples/Leakage.ipynb b/jupyter_notebooks/Examples/Leakage.ipynb index 051e6dd9b..f840cd303 100644 --- a/jupyter_notebooks/Examples/Leakage.ipynb +++ b/jupyter_notebooks/Examples/Leakage.ipynb @@ -15,7 +15,9 @@ "outputs": [], "source": [ "import pygsti\n", - "import pygsti.modelpacks.legacy.std1Q_XYI as std1Q\n", + "import pygsti.modelpacks.smq1Q_XYI as smq1Q\n", + "from pygsti.baseobjs import Label\n", + "from pygsti.circuits import Circuit\n", "import numpy as np\n", "import scipy.linalg as sla\n", "#import pickle" @@ -49,8 +51,7 @@ "metadata": {}, "outputs": [], "source": [ - "mdl_2level_ideal = std1Q.target_model()\n", - "mdl_2level_ideal.sim = \"matrix\" # so we can create reports later on" + "mdl_2level_ideal = smq1Q.target_model(qubit_labels=[\"Qubit\"])" ] }, { @@ -67,17 +68,16 @@ " [0,1,0],\n", " [0,0,1]], complex)\n", "\n", - "sslbls = pygsti.baseobjs.ExplicitStateSpace(['Qubit+Leakage'],[3])\n", - "mdl_3level_ideal = pygsti.models.ExplicitOpModel(sslbls, 'gm')\n", + "sslbls = pygsti.baseobjs.ExplicitStateSpace(['Qubit_leakage'],[3])\n", + "mdl_3level_ideal = pygsti.models.ExplicitOpModel(sslbls, 'gm', simulator='matrix')\n", "mdl_3level_ideal['rho0'] = pygsti.tools.stdmx_to_gmvec(rho0)\n", "mdl_3level_ideal['Mdefault'] = pygsti.modelmembers.povms.TPPOVM([('0',pygsti.tools.stdmx_to_gmvec(E0)),\n", " ('1',pygsti.tools.stdmx_to_gmvec(E1))],\n", " evotype='default')\n", "\n", - "mdl_3level_ideal['Gi'] = unitary_to_gmgate( to_3level_unitary(Us['Gi']))\n", - "mdl_3level_ideal['Gx'] = unitary_to_gmgate( to_3level_unitary(Us['Gxpi2']))\n", - "mdl_3level_ideal['Gy'] = unitary_to_gmgate( to_3level_unitary(Us['Gypi2']))\n", - "mdl_3level_ideal.sim = \"matrix\" # so we can create reports later on" + "mdl_3level_ideal[tuple()] = unitary_to_gmgate( to_3level_unitary(Us['Gi']))\n", + "mdl_3level_ideal['Gxpi2', 'Qubit_leakage'] = unitary_to_gmgate( to_3level_unitary(Us['Gxpi2']))\n", + "mdl_3level_ideal['Gypi2', 'Qubit_leakage'] = unitary_to_gmgate( to_3level_unitary(Us['Gypi2']))" ] }, { @@ -95,15 +95,15 @@ "\n", "#Guess of a model w/just unitary leakage\n", "mdl_3level_guess = mdl_3level_ideal.copy()\n", - "mdl_3level_guess['Gi'] = np.dot(leakageOp, mdl_3level_guess['Gi'])\n", - "#mdl_3level_guess['Gx'] = np.dot(leakageOp, mdl_3level_guess['Gx'])\n", - "#mdl_3level_guess['Gy'] = np.dot(leakageOp, mdl_3level_guess['Gy'])\n", + "mdl_3level_guess[tuple()] = np.dot(leakageOp, mdl_3level_guess[tuple()])\n", + "#mdl_3level_guess['Gxpi2', 'Qubit_leakage'] = np.dot(leakageOp, mdl_3level_guess['Gxpi2', 'Qubit_leakage'])\n", + "#mdl_3level_guess['Gypi2', 'Qubit_leakage'] = np.dot(leakageOp, mdl_3level_guess['Gypi2', 'Qubit_leakage'])\n", "\n", "#Actual model used for data generation (some depolarization too)\n", "mdl_3level_noisy = mdl_3level_ideal.depolarize(op_noise=0.005, spam_noise=0.01)\n", - "mdl_3level_noisy['Gi'] = np.dot(leakageOp, mdl_3level_noisy['Gi'])\n", - "#mdl_3level_noisy['Gx'] = np.dot(leakageOp, mdl_3level_noisy['Gx'])\n", - "#mdl_3level_noisy['Gy'] = np.dot(leakageOp, mdl_3level_noisy['Gy'])" + "mdl_3level_noisy[tuple()] = np.dot(leakageOp, mdl_3level_noisy[tuple()])\n", + "#mdl_3level_noisy['Gxpi2', 'Qubit_leakage'] = np.dot(leakageOp, mdl_3level_noisy['Gxpi2', 'Qubit_leakage'])\n", + "#mdl_3level_noisy['Gypi2', 'Qubit_leakage'] = np.dot(leakageOp, mdl_3level_noisy['Gypi2', 'Qubit_leakage'])" ] }, { @@ -126,7 +126,7 @@ "\n", "if find_fiducials:\n", " prepfids, measfids = pygsti.algorithms.find_fiducials(\n", - " mdl_3level_guess, omit_identity=False, max_fid_length=4, verbosity=4)\n", + " mdl_3level_guess, omit_identity=False, candidate_fid_counts={4: \"all upto\"}, verbosity=4)\n", " pygsti.io.write_circuit_list(\"example_files/leakage_prepfids.txt\", prepfids)\n", " pygsti.io.write_circuit_list(\"example_files/leakage_measfids.txt\", measfids)" ] @@ -140,10 +140,7 @@ "# If files missing, run previous cell at least once with find_fiducials = True\n", "prepfids = pygsti.io.read_circuit_list(\"example_files/leakage_prepfids.txt\")\n", "measfids = pygsti.io.read_circuit_list(\"example_files/leakage_measfids.txt\")\n", - "# HACK: Fix broken force empty labels\n", - "prepfids[-1] = pygsti.circuits.Circuit([])\n", - "measfids[-1] = pygsti.circuits.Circuit([])\n", - "germs = std1Q.germs\n", + "germs = smq1Q.germs(qubit_labels=[\"Qubit_leakage\"])\n", "maxLengths = [1,]\n", "expList = pygsti.circuits.create_lsgst_circuits(mdl_3level_noisy, prepfids, measfids, germs, maxLengths)\n", "ds = pygsti.data.simulate_data(mdl_3level_noisy, expList, 1000, 'binomial', seed=1234)" @@ -155,8 +152,37 @@ "metadata": {}, "outputs": [], "source": [ - "results_2level = pygsti.run_stdpractice_gst(ds, mdl_2level_ideal, prepfids, measfids,\n", - " germs, maxLengths, modes=\"CPTPLND\", verbosity=3)" + "\n", + "# We have found out prep fids, meas fids, and germs, as well as simulated noisy data, for the 3 level model\n", + "# If we want to run GST on another model, we need to get versions of the circuits will the correct state space labels\n", + "\n", + "def map_2level_sslbls(circuit):\n", + " sslbl_map = {'Qubit_leakage': 'Qubit'}\n", + " return circuit.map_state_space_labels(sslbl_map)\n", + "\n", + "prepfids_2level = [map_2level_sslbls(c) for c in prepfids]\n", + "measfids_2level = [map_2level_sslbls(c) for c in measfids]\n", + "germs_2level = [map_2level_sslbls(c) for c in germs]\n", + "ds_2level = ds.process_circuits(map_2level_sslbls)\n", + "\n", + "results_2level = pygsti.run_stdpractice_gst(ds_2level, mdl_2level_ideal, prepfids_2level, measfids_2level,\n", + " germs_2level, maxLengths, modes=\"CPTPLND\", verbosity=3)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pygsti.report.construct_standard_report(results_2level, \"2-level Leakage Example Report\").write_html('example_files/leakage_report_2level')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Open the report [here](example_files/leakage_report_2level/main.html)" ] }, { @@ -168,7 +194,7 @@ "outputs": [], "source": [ "results_3level = pygsti.run_stdpractice_gst(ds, mdl_3level_ideal, prepfids, measfids,\n", - " germs, maxLengths, modes=[\"CPTP\",\"True\"],\n", + " germs, maxLengths, modes=[\"CPTPLND\",\"True\"],\n", " models_to_test={'True': mdl_3level_noisy}, \n", " verbosity=4, advanced_options={'all': {'tolerance': 1e-2}})" ] @@ -179,10 +205,14 @@ "metadata": {}, "outputs": [], "source": [ - "pygsti.report.construct_standard_report(\n", - " {'two-level': results_2level, 'three-level': results_3level},\n", - " \"Leakage Example Report\"\n", - ").write_html('example_files/leakage_report')" + "pygsti.report.construct_standard_report(results_3level, \"3-level Leakage Example Report\").write_html('example_files/leakage_report')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Open the report [here](example_files/leakage_report/main.html)" ] }, { @@ -254,17 +284,15 @@ "metadata": {}, "outputs": [], "source": [ - "pygsti.report.construct_standard_report(\n", - " {'two-level': results_2level, 'three-level': results_3level_leakage_basis},\n", - " \"Leakage Example Report\"\n", - ").write_html('example_files/leakage_report')" + "pygsti.report.construct_standard_report(results_3level_leakage_basis, \"3-level with Basis Change Leakage Example Report\"\n", + " ).write_html('example_files/leakage_report_basis')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Open the report [here](example_files/leakage_report/main.html)" + "Open the report [here](example_files/leakage_report_basis/main.html)" ] }, { @@ -288,15 +316,15 @@ "E1 = np.concatenate( (mdl_2level_ideal.povms['Mdefault']['1'].to_dense(),[eps]), axis=0)\n", "\n", "\n", - "statespace = pygsti.baseobjs.ExplicitStateSpace([('Qubit',),('Leakage',)],[(2,),(1,)])\n", - "mdl_2plus1_ideal = pygsti.models.ExplicitOpModel(statespace, 'gm')\n", + "statespace = pygsti.baseobjs.ExplicitStateSpace([('Qubit',),('Leakage',)], [(2,), (1,)])\n", + "mdl_2plus1_ideal = pygsti.models.ExplicitOpModel(statespace, 'gm', simulator='matrix')\n", "mdl_2plus1_ideal['rho0'] = rho0\n", "mdl_2plus1_ideal['Mdefault'] = pygsti.modelmembers.povms.UnconstrainedPOVM([('0',E0),('1',E1)],\n", " evotype='default', state_space=statespace)\n", "\n", - "mdl_2plus1_ideal['Gi'] = to_2plus1_superop(mdl_2level_ideal['Gi'])\n", - "mdl_2plus1_ideal['Gx'] = to_2plus1_superop(mdl_2level_ideal['Gx'])\n", - "mdl_2plus1_ideal['Gy'] = to_2plus1_superop(mdl_2level_ideal['Gy'])" + "mdl_2plus1_ideal[tuple()] = to_2plus1_superop(mdl_2level_ideal[tuple()])\n", + "mdl_2plus1_ideal['Gxpi2'] = to_2plus1_superop(mdl_2level_ideal['Gxpi2', 'Qubit'])\n", + "mdl_2plus1_ideal['Gypi2'] = to_2plus1_superop(mdl_2level_ideal['Gypi2', 'Qubit'])" ] }, { @@ -305,9 +333,22 @@ "metadata": {}, "outputs": [], "source": [ - "mdl_2plus1_ideal.sim = \"matrix\" # so we can construct report below\n", - "results_2plus1 = pygsti.run_long_sequence_gst(ds, mdl_2plus1_ideal, prepfids, measfids,\n", - " germs, maxLengths, verbosity=2,\n", + "# We have found out prep fids, meas fids, and germs, as well as simulated noisy data, for the 3 level model\n", + "# If we want to run GST on another model, we need to get versions of the circuits will the correct state space labels\n", + "\n", + "# We do this in a slightly different/awkward way here for this case since our state space labels are not a single entry\n", + "# This would not be necessary if we were rebuilding the circuits/dataset from scratch, only hacky since we are reusing the 3-level information\n", + "def map_2plus1_circuit_linelabels(circuit):\n", + " return Circuit([Label(l.name) if l.name != \"COMPOUND\" else tuple() for l in circuit.layertup],\n", + " \"*\", None, not circuit._static)\n", + "\n", + "prepfids_2plus1 = [map_2plus1_circuit_linelabels(c) for c in prepfids]\n", + "measfids_2plus1 = [map_2plus1_circuit_linelabels(c) for c in measfids]\n", + "germs_2plus1 = [map_2plus1_circuit_linelabels(c) for c in germs]\n", + "ds_2plus1 = ds.process_circuits(map_2plus1_circuit_linelabels)\n", + "\n", + "results_2plus1 = pygsti.run_long_sequence_gst(ds_2plus1, mdl_2plus1_ideal, prepfids_2plus1, measfids_2plus1,\n", + " germs_2plus1, maxLengths, verbosity=2,\n", " advanced_options={\"starting_point\": \"target\",\n", " \"tolerance\": 1e-8, # (lowering tolerance from 1e-6 gave a better fit)\n", " \"estimate_label\": \"kite\"})" @@ -324,11 +365,8 @@ "outputs": [], "source": [ "# TODO: This is currently broken\n", - "pygsti.report.construct_standard_report(\n", - " {'two-level': results_2level, 'three-level': results_3level_leakage_basis,\n", - " 'two+one level': results_2plus1},\n", - " \"Leakage Example Report\"\n", - ").write_html('example_files/leakage_report', autosize='none')" + "pygsti.report.construct_standard_report(results_2plus1,\"2+1 Leakage Example Report\"\n", + ").write_html('example_files/leakage_report_2plus1', autosize='none')" ] }, { @@ -341,9 +379,9 @@ ], "metadata": { "kernelspec": { - "display_name": "leakage_models", + "display_name": "pygsti", "language": "python", - "name": "leakage_models" + "name": "python3" }, "language_info": { "codemirror_mode": { @@ -355,7 +393,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.13" + "version": "3.11.5" } }, "nbformat": 4, diff --git a/jupyter_notebooks/Examples/QutritGST.ipynb b/jupyter_notebooks/Examples/QutritGST.ipynb index f9498fc82..29a2ccc71 100644 --- a/jupyter_notebooks/Examples/QutritGST.ipynb +++ b/jupyter_notebooks/Examples/QutritGST.ipynb @@ -16,6 +16,8 @@ "source": [ "import pygsti\n", "from pygsti.models import qutrit\n", + "from pygsti.algorithms.fiducialselection import find_fiducials\n", + "from pygsti.algorithms.germselection import find_germs\n", "\n", "from numpy import pi, array\n", "import pickle\n", @@ -27,88 +29,40 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "First, we construct the target model. This functionality is built into pyGSTi, so we just need to specify the single-qubit and M-S angles." + "First, we construct the target model. This functionality is built into pyGSTi, so we just need to specify the single-qubit and M-S angles.\n", + "Note there are alternative approaches for building a qutrit model in pygsti using processor specification objects, but for this particular class of qutrit models in this example notebook there exist helper functions for creating the relevant models." ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "target_model = qutrit.create_qutrit_model(error_scale=0, x_angle=pi/2, y_angle=pi/2, ms_global=pi/2, ms_local=0, basis=\"qt\")\n", - "#print(target_model)" + "#change the forward simulator for the purposes of experiment design code\n", + "target_model.sim = 'matrix'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Now construct the operation sequences needed by GST. These fiducials and germs have been computed ahead of time and the results are used to construct the operation sequence lists below. Then we construct an empty dataset containing all of the necessary experimental sequences which can serve as a template for the actual experimental results." + "Now construct the operation sequences needed by GST. Then we construct an empty dataset containing all of the necessary experimental sequences which can serve as a template for the actual experimental results." ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fiducialPrep = pygsti.circuits.to_circuits(\n", - " [(),('Gy',),('Gx',),('Gm',),\n", - " ('Gx','Gx'), ('Gm','Gy'),('Gm','Gx'),\n", - " ('Gy','Gy','Gy'),('Gx','Gx','Gx')])\n", - "\n", - "fiducialMeasure = pygsti.circuits.to_circuits(\n", - " [(),('Gy',),('Gx',),('Gm',),\n", - " ('Gy','Gm'),('Gx','Gm')])\n", - "\n", - "maxLengths = [1,2,4]\n", - "\n", - "germs = pygsti.circuits.to_circuits(\n", - "[('Gi',),\n", - " ('Gy',),\n", - " ('Gx',),\n", - " ('Gm',),\n", - " ('Gi', 'Gy'),\n", - " ('Gi', 'Gx'),\n", - " ('Gi', 'Gm'),\n", - " ('Gy', 'Gx'),\n", - " ('Gy', 'Gm'),\n", - " ('Gx', 'Gm'),\n", - " ('Gi', 'Gi', 'Gy'),\n", - " ('Gi', 'Gi', 'Gx'),\n", - " ('Gi', 'Gi', 'Gm'),\n", - " ('Gi', 'Gy', 'Gy'),\n", - " ('Gi', 'Gy', 'Gx'),\n", - " ('Gi', 'Gy', 'Gm'),\n", - " ('Gi', 'Gx', 'Gy'),\n", - " ('Gi', 'Gx', 'Gx'),\n", - " ('Gi', 'Gx', 'Gm'),\n", - " ('Gi', 'Gm', 'Gy'),\n", - " ('Gi', 'Gm', 'Gx'),\n", - " ('Gi', 'Gm', 'Gm'),\n", - " ('Gy', 'Gy', 'Gx'),\n", - " ('Gy', 'Gy', 'Gm'),\n", - " ('Gy', 'Gx', 'Gx'),\n", - " ('Gy', 'Gx', 'Gm'),\n", - " ('Gy', 'Gm', 'Gx'),\n", - " ('Gy', 'Gm', 'Gm'),\n", - " ('Gx', 'Gx', 'Gm'),\n", - " ('Gx', 'Gm', 'Gm')])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ - "#Note above construction is now a \"standard\" qutrit model\n", - "from pygsti.modelpacks.legacy import stdQT_XYIMS\n", - "target_model = stdQT_XYIMS.target_model()\n", - "fiducialPrep = stdQT_XYIMS.prepStrs\n", - "fiducialMeasure = stdQT_XYIMS.effectStrs\n", - "germs = stdQT_XYIMS.germs_lite\n", + "fiducialPrep, fiducialMeasure = find_fiducials(target_model, candidate_fid_counts={4: 'all upto'}, algorithm= 'greedy')\n", + "germs = find_germs(target_model, randomize=False, candidate_germ_counts={4: 'all upto'}, mode= 'compactEVD', assume_real=True, float_type=np.double)\n", "maxLengths = [1,2,4]" ] }, @@ -147,8 +101,8 @@ "metadata": {}, "outputs": [], "source": [ - "mdl_datagen = target_model.depolarize(op_noise=0.05)\n", - "DS = pygsti.data.simulate_data(mdl_datagen, expList, 500, sample_error='multinomial', seed=2018)" + "mdl_datagen = target_model.depolarize(op_noise=0.05, spam_noise = .01)\n", + "DS = pygsti.data.simulate_data(mdl_datagen, expList, 1000, sample_error='multinomial', seed=2018)" ] }, { @@ -170,9 +124,11 @@ "source": [ "#Run qutrit GST... which could take a while on a single CPU. Please adjust memLimit to machine specs \n", "# (now 3GB; usually set to slightly less than the total machine memory)\n", + "#Setting max_iterations lower than default for the sake of the example running faster. \n", "target_model.sim = \"matrix\"\n", - "result = pygsti.run_stdpractice_gst(DS,target_model,fiducialPrep,fiducialMeasure,germs,maxLengths,\n", - " verbosity=4, comm=None, mem_limit=3*(1024)**3, modes=\"CPTPLND\")" + "result = pygsti.run_stdpractice_gst(DS, target_model, fiducialPrep, fiducialMeasure, germs, maxLengths,\n", + " verbosity=3, comm=None, mem_limit=3*(1024)**3, modes=\"CPTPLND\",\n", + " advanced_options= {'max_iterations':50})" ] }, { @@ -186,20 +142,13 @@ " result, \"Example Qutrit Report\", verbosity=3\n", ").write_html('example_files/sampleQutritReport', auto_open=False, verbosity=3)" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { "kernelspec": { - "display_name": "New_FPR", + "display_name": "api_updates", "language": "python", - "name": "new_fpr" + "name": "api_updates" }, "language_info": { "codemirror_mode": { diff --git a/jupyter_notebooks/Examples/example_files/dataTemplate_qutrit_maxL=4.txt b/jupyter_notebooks/Examples/example_files/dataTemplate_qutrit_maxL=4.txt index 89f5d6ff5..e1c822bce 100644 --- a/jupyter_notebooks/Examples/example_files/dataTemplate_qutrit_maxL=4.txt +++ b/jupyter_notebooks/Examples/example_files/dataTemplate_qutrit_maxL=4.txt @@ -1,2018 +1,775 @@ ## Columns = 0bright count, 1bright count, 2bright count -{} 0 0 0 -Gx 0 0 0 -Gy 0 0 0 -Gm 0 0 0 -GxGx 0 0 0 -GyGm 0 0 0 -GxGm 0 0 0 -GmGx 0 0 0 -GmGy 0 0 0 -GyGyGy 0 0 0 -GxGxGx 0 0 0 -GxGy 0 0 0 -GxGyGm 0 0 0 -GxGxGm 0 0 0 -GyGx 0 0 0 -GyGy 0 0 0 -GyGxGx 0 0 0 -GyGyGm 0 0 0 -GyGxGm 0 0 0 -GmGm 0 0 0 -GmGxGx 0 0 0 -GmGyGm 0 0 0 -GmGxGm 0 0 0 -GxGxGy 0 0 0 -GxGxGxGx 0 0 0 -GxGxGyGm 0 0 0 -GxGxGxGm 0 0 0 -GmGxGy 0 0 0 -GmGxGxGx 0 0 0 -GmGxGyGm 0 0 0 -GmGxGxGm 0 0 0 -GmGyGx 0 0 0 -GmGyGy 0 0 0 -GmGyGxGx 0 0 0 -GmGyGyGm 0 0 0 -GmGyGxGm 0 0 0 -GyGyGyGx 0 0 0 -GyGyGyGy 0 0 0 -GyGyGyGm 0 0 0 -GyGyGyGxGx 0 0 0 -GyGyGyGyGm 0 0 0 -GyGyGyGxGm 0 0 0 -GxGxGxGy 0 0 0 -GxGxGxGxGx 0 0 0 -GxGxGxGyGm 0 0 0 -GxGxGxGxGm 0 0 0 -(Gi) 0 0 0 -(Gi)Gx 0 0 0 -(Gi)Gy 0 0 0 -(Gi)Gm 0 0 0 -(Gi)GxGx 0 0 0 -(Gi)GyGm 0 0 0 -(Gi)GxGm 0 0 0 -Gx(Gi) 0 0 0 -Gx(Gi)Gx 0 0 0 -Gx(Gi)Gy 0 0 0 -Gx(Gi)Gm 0 0 0 -Gx(Gi)GxGx 0 0 0 -Gx(Gi)GyGm 0 0 0 -Gx(Gi)GxGm 0 0 0 -Gy(Gi) 0 0 0 -Gy(Gi)Gx 0 0 0 -Gy(Gi)Gy 0 0 0 -Gy(Gi)Gm 0 0 0 -Gy(Gi)GxGx 0 0 0 -Gy(Gi)GyGm 0 0 0 -Gy(Gi)GxGm 0 0 0 -Gm(Gi) 0 0 0 -Gm(Gi)Gx 0 0 0 -Gm(Gi)Gy 0 0 0 -Gm(Gi)Gm 0 0 0 -Gm(Gi)GxGx 0 0 0 -Gm(Gi)GyGm 0 0 0 -Gm(Gi)GxGm 0 0 0 -GxGx(Gi) 0 0 0 -GxGx(Gi)Gx 0 0 0 -GxGx(Gi)Gy 0 0 0 -GxGx(Gi)Gm 0 0 0 -GxGx(Gi)GxGx 0 0 0 -GxGx(Gi)GyGm 0 0 0 -GxGx(Gi)GxGm 0 0 0 -GmGx(Gi) 0 0 0 -GmGx(Gi)Gx 0 0 0 -GmGx(Gi)Gy 0 0 0 -GmGx(Gi)Gm 0 0 0 -GmGx(Gi)GxGx 0 0 0 -GmGx(Gi)GyGm 0 0 0 -GmGx(Gi)GxGm 0 0 0 -GmGy(Gi) 0 0 0 -GmGy(Gi)Gx 0 0 0 -GmGy(Gi)Gy 0 0 0 -GmGy(Gi)Gm 0 0 0 -GmGy(Gi)GxGx 0 0 0 -GmGy(Gi)GyGm 0 0 0 -GmGy(Gi)GxGm 0 0 0 -GyGyGy(Gi) 0 0 0 -GyGyGy(Gi)Gx 0 0 0 -GyGyGy(Gi)Gy 0 0 0 -GyGyGy(Gi)Gm 0 0 0 -GyGyGy(Gi)GxGx 0 0 0 -GyGyGy(Gi)GyGm 0 0 0 -GyGyGy(Gi)GxGm 0 0 0 -GxGxGx(Gi) 0 0 0 -GxGxGx(Gi)Gx 0 0 0 -GxGxGx(Gi)Gy 0 0 0 -GxGxGx(Gi)Gm 0 0 0 -GxGxGx(Gi)GxGx 0 0 0 -GxGxGx(Gi)GyGm 0 0 0 -GxGxGx(Gi)GxGm 0 0 0 -Gy(Gx)Gy 0 0 0 -Gy(Gx)GxGx 0 0 0 -Gy(Gx)GyGm 0 0 0 -Gy(Gx)GxGm 0 0 0 -GmGx(Gx)Gy 0 0 0 -GmGx(Gx)GxGx 0 0 0 -GmGx(Gx)GyGm 0 0 0 -GmGx(Gx)GxGm 0 0 0 -GmGy(Gx)Gy 0 0 0 -GmGy(Gx)GxGx 0 0 0 -GmGy(Gx)GyGm 0 0 0 -GmGy(Gx)GxGm 0 0 0 -GyGyGy(Gx)Gy 0 0 0 -GyGyGy(Gx)GxGx 0 0 0 -GyGyGy(Gx)GyGm 0 0 0 -GyGyGy(Gx)GxGm 0 0 0 -GxGxGx(Gx)Gy 0 0 0 -GxGxGx(Gx)GxGx 0 0 0 -GxGxGx(Gx)GyGm 0 0 0 -GxGxGx(Gx)GxGm 0 0 0 -Gx(Gy)Gx 0 0 0 -Gx(Gy)Gy 0 0 0 -Gx(Gy)GxGx 0 0 0 -Gx(Gy)GyGm 0 0 0 -Gx(Gy)GxGm 0 0 0 -Gy(Gy)Gx 0 0 0 -Gy(Gy)GxGx 0 0 0 -Gy(Gy)GxGm 0 0 0 -GxGx(Gy)Gx 0 0 0 -GxGx(Gy)Gy 0 0 0 -GxGx(Gy)GxGx 0 0 0 -GxGx(Gy)GyGm 0 0 0 -GxGx(Gy)GxGm 0 0 0 -GmGx(Gy)Gx 0 0 0 -GmGx(Gy)Gy 0 0 0 -GmGx(Gy)GxGx 0 0 0 -GmGx(Gy)GyGm 0 0 0 -GmGx(Gy)GxGm 0 0 0 -GmGy(Gy)Gx 0 0 0 -GmGy(Gy)Gy 0 0 0 -GmGy(Gy)GxGx 0 0 0 -GmGy(Gy)GyGm 0 0 0 -GmGy(Gy)GxGm 0 0 0 -GyGyGy(Gy)Gx 0 0 0 -GyGyGy(Gy)Gy 0 0 0 -GyGyGy(Gy)GxGx 0 0 0 -GyGyGy(Gy)GyGm 0 0 0 -GyGyGy(Gy)GxGm 0 0 0 -GxGxGx(Gy)Gx 0 0 0 -GxGxGx(Gy)Gy 0 0 0 -GxGxGx(Gy)GxGx 0 0 0 -GxGxGx(Gy)GyGm 0 0 0 -GxGxGx(Gy)GxGm 0 0 0 -Gx(Gm)Gx 0 0 0 -Gx(Gm)Gy 0 0 0 -Gx(Gm)Gm 0 0 0 -Gx(Gm)GxGx 0 0 0 -Gx(Gm)GyGm 0 0 0 -Gx(Gm)GxGm 0 0 0 -Gy(Gm)Gx 0 0 0 -Gy(Gm)Gy 0 0 0 -Gy(Gm)Gm 0 0 0 -Gy(Gm)GxGx 0 0 0 -Gy(Gm)GyGm 0 0 0 -Gy(Gm)GxGm 0 0 0 -Gm(Gm)Gx 0 0 0 -Gm(Gm)Gy 0 0 0 -Gm(Gm)Gm 0 0 0 -Gm(Gm)GxGx 0 0 0 -Gm(Gm)GyGm 0 0 0 -Gm(Gm)GxGm 0 0 0 -GxGx(Gm)Gx 0 0 0 -GxGx(Gm)Gy 0 0 0 -GxGx(Gm)Gm 0 0 0 -GxGx(Gm)GxGx 0 0 0 -GxGx(Gm)GyGm 0 0 0 -GxGx(Gm)GxGm 0 0 0 -GmGx(Gm)Gx 0 0 0 -GmGx(Gm)Gy 0 0 0 -GmGx(Gm)Gm 0 0 0 -GmGx(Gm)GxGx 0 0 0 -GmGx(Gm)GyGm 0 0 0 -GmGx(Gm)GxGm 0 0 0 -GmGy(Gm)Gx 0 0 0 -GmGy(Gm)Gy 0 0 0 -GmGy(Gm)Gm 0 0 0 -GmGy(Gm)GxGx 0 0 0 -GmGy(Gm)GyGm 0 0 0 -GmGy(Gm)GxGm 0 0 0 -GyGyGy(Gm)Gx 0 0 0 -GyGyGy(Gm)Gy 0 0 0 -GyGyGy(Gm)Gm 0 0 0 -GyGyGy(Gm)GxGx 0 0 0 -GyGyGy(Gm)GyGm 0 0 0 -GyGyGy(Gm)GxGm 0 0 0 -GxGxGx(Gm)Gx 0 0 0 -GxGxGx(Gm)Gy 0 0 0 -GxGxGx(Gm)Gm 0 0 0 -GxGxGx(Gm)GxGx 0 0 0 -GxGxGx(Gm)GyGm 0 0 0 -GxGxGx(Gm)GxGm 0 0 0 -(Gi)^2 0 0 0 -(Gi)^2Gx 0 0 0 -(Gi)^2Gy 0 0 0 -(Gi)^2Gm 0 0 0 -(Gi)^2GxGx 0 0 0 -(Gi)^2GyGm 0 0 0 -(Gi)^2GxGm 0 0 0 -Gx(Gi)^2 0 0 0 -Gx(Gi)^2Gx 0 0 0 -Gx(Gi)^2Gy 0 0 0 -Gx(Gi)^2Gm 0 0 0 -Gx(Gi)^2GxGx 0 0 0 -Gx(Gi)^2GyGm 0 0 0 -Gx(Gi)^2GxGm 0 0 0 -Gy(Gi)^2 0 0 0 -Gy(Gi)^2Gx 0 0 0 -Gy(Gi)^2Gy 0 0 0 -Gy(Gi)^2Gm 0 0 0 -Gy(Gi)^2GxGx 0 0 0 -Gy(Gi)^2GyGm 0 0 0 -Gy(Gi)^2GxGm 0 0 0 -Gm(Gi)^2 0 0 0 -Gm(Gi)^2Gx 0 0 0 -Gm(Gi)^2Gy 0 0 0 -Gm(Gi)^2Gm 0 0 0 -Gm(Gi)^2GxGx 0 0 0 -Gm(Gi)^2GyGm 0 0 0 -Gm(Gi)^2GxGm 0 0 0 -GxGx(Gi)^2 0 0 0 -GxGx(Gi)^2Gx 0 0 0 -GxGx(Gi)^2Gy 0 0 0 -GxGx(Gi)^2Gm 0 0 0 -GxGx(Gi)^2GxGx 0 0 0 -GxGx(Gi)^2GyGm 0 0 0 -GxGx(Gi)^2GxGm 0 0 0 -GmGx(Gi)^2 0 0 0 -GmGx(Gi)^2Gx 0 0 0 -GmGx(Gi)^2Gy 0 0 0 -GmGx(Gi)^2Gm 0 0 0 -GmGx(Gi)^2GxGx 0 0 0 -GmGx(Gi)^2GyGm 0 0 0 -GmGx(Gi)^2GxGm 0 0 0 -GmGy(Gi)^2 0 0 0 -GmGy(Gi)^2Gx 0 0 0 -GmGy(Gi)^2Gy 0 0 0 -GmGy(Gi)^2Gm 0 0 0 -GmGy(Gi)^2GxGx 0 0 0 -GmGy(Gi)^2GyGm 0 0 0 -GmGy(Gi)^2GxGm 0 0 0 -GyGyGy(Gi)^2 0 0 0 -GyGyGy(Gi)^2Gx 0 0 0 -GyGyGy(Gi)^2Gy 0 0 0 -GyGyGy(Gi)^2Gm 0 0 0 -GyGyGy(Gi)^2GxGx 0 0 0 -GyGyGy(Gi)^2GyGm 0 0 0 -GyGyGy(Gi)^2GxGm 0 0 0 -GxGxGx(Gi)^2 0 0 0 -GxGxGx(Gi)^2Gx 0 0 0 -GxGxGx(Gi)^2Gy 0 0 0 -GxGxGx(Gi)^2Gm 0 0 0 -GxGxGx(Gi)^2GxGx 0 0 0 -GxGxGx(Gi)^2GyGm 0 0 0 -GxGxGx(Gi)^2GxGm 0 0 0 -Gx(Gy)^2Gx 0 0 0 -Gx(Gy)^2Gy 0 0 0 -Gx(Gy)^2GxGx 0 0 0 -Gx(Gy)^2GyGm 0 0 0 -Gx(Gy)^2GxGm 0 0 0 -GxGx(Gy)^2Gx 0 0 0 -GxGx(Gy)^2Gy 0 0 0 -GxGx(Gy)^2GxGx 0 0 0 -GxGx(Gy)^2GyGm 0 0 0 -GxGx(Gy)^2GxGm 0 0 0 -GmGx(Gy)^2Gx 0 0 0 -GmGx(Gy)^2Gy 0 0 0 -GmGx(Gy)^2GxGx 0 0 0 -GmGx(Gy)^2GyGm 0 0 0 -GmGx(Gy)^2GxGm 0 0 0 -GmGy(Gy)^2Gx 0 0 0 -GmGy(Gy)^2Gy 0 0 0 -GmGy(Gy)^2GxGx 0 0 0 -GmGy(Gy)^2GyGm 0 0 0 -GmGy(Gy)^2GxGm 0 0 0 -GyGyGy(Gy)^2Gx 0 0 0 -GyGyGy(Gy)^2Gy 0 0 0 -GyGyGy(Gy)^2GxGx 0 0 0 -GyGyGy(Gy)^2GyGm 0 0 0 -GyGyGy(Gy)^2GxGm 0 0 0 -GxGxGx(Gy)^2Gx 0 0 0 -GxGxGx(Gy)^2Gy 0 0 0 -GxGxGx(Gy)^2GxGx 0 0 0 -GxGxGx(Gy)^2GyGm 0 0 0 -GxGxGx(Gy)^2GxGm 0 0 0 -Gy(Gx)^2Gy 0 0 0 -Gy(Gx)^2GxGx 0 0 0 -Gy(Gx)^2GyGm 0 0 0 -Gy(Gx)^2GxGm 0 0 0 -GmGx(Gx)^2Gy 0 0 0 -GmGx(Gx)^2GxGx 0 0 0 -GmGx(Gx)^2GyGm 0 0 0 -GmGx(Gx)^2GxGm 0 0 0 -GmGy(Gx)^2Gy 0 0 0 -GmGy(Gx)^2GxGx 0 0 0 -GmGy(Gx)^2GyGm 0 0 0 -GmGy(Gx)^2GxGm 0 0 0 -GyGyGy(Gx)^2Gy 0 0 0 -GyGyGy(Gx)^2GxGx 0 0 0 -GyGyGy(Gx)^2GyGm 0 0 0 -GyGyGy(Gx)^2GxGm 0 0 0 -GxGxGx(Gx)^2Gy 0 0 0 -GxGxGx(Gx)^2GxGx 0 0 0 -GxGxGx(Gx)^2GyGm 0 0 0 -GxGxGx(Gx)^2GxGm 0 0 0 -Gx(Gm)^2Gx 0 0 0 -Gx(Gm)^2Gy 0 0 0 -Gx(Gm)^2Gm 0 0 0 -Gx(Gm)^2GxGx 0 0 0 -Gx(Gm)^2GyGm 0 0 0 -Gx(Gm)^2GxGm 0 0 0 -Gy(Gm)^2Gx 0 0 0 -Gy(Gm)^2Gy 0 0 0 -Gy(Gm)^2Gm 0 0 0 -Gy(Gm)^2GxGx 0 0 0 -Gy(Gm)^2GyGm 0 0 0 -Gy(Gm)^2GxGm 0 0 0 -Gm(Gm)^2Gx 0 0 0 -Gm(Gm)^2Gy 0 0 0 -Gm(Gm)^2Gm 0 0 0 -Gm(Gm)^2GxGx 0 0 0 -Gm(Gm)^2GyGm 0 0 0 -Gm(Gm)^2GxGm 0 0 0 -GxGx(Gm)^2Gx 0 0 0 -GxGx(Gm)^2Gy 0 0 0 -GxGx(Gm)^2Gm 0 0 0 -GxGx(Gm)^2GxGx 0 0 0 -GxGx(Gm)^2GyGm 0 0 0 -GxGx(Gm)^2GxGm 0 0 0 -GmGx(Gm)^2Gx 0 0 0 -GmGx(Gm)^2Gy 0 0 0 -GmGx(Gm)^2Gm 0 0 0 -GmGx(Gm)^2GxGx 0 0 0 -GmGx(Gm)^2GyGm 0 0 0 -GmGx(Gm)^2GxGm 0 0 0 -GmGy(Gm)^2Gx 0 0 0 -GmGy(Gm)^2Gy 0 0 0 -GmGy(Gm)^2Gm 0 0 0 -GmGy(Gm)^2GxGx 0 0 0 -GmGy(Gm)^2GyGm 0 0 0 -GmGy(Gm)^2GxGm 0 0 0 -GyGyGy(Gm)^2Gx 0 0 0 -GyGyGy(Gm)^2Gy 0 0 0 -GyGyGy(Gm)^2Gm 0 0 0 -GyGyGy(Gm)^2GxGx 0 0 0 -GyGyGy(Gm)^2GyGm 0 0 0 -GyGyGy(Gm)^2GxGm 0 0 0 -GxGxGx(Gm)^2Gx 0 0 0 -GxGxGx(Gm)^2Gy 0 0 0 -GxGxGx(Gm)^2Gm 0 0 0 -GxGxGx(Gm)^2GxGx 0 0 0 -GxGxGx(Gm)^2GyGm 0 0 0 -GxGxGx(Gm)^2GxGm 0 0 0 -(GiGy)Gx 0 0 0 -(GiGy)Gy 0 0 0 -(GiGy)GxGx 0 0 0 -(GiGy)GyGm 0 0 0 -(GiGy)GxGm 0 0 0 -Gx(GiGy)Gx 0 0 0 -Gx(GiGy)Gy 0 0 0 -Gx(GiGy)GxGx 0 0 0 -Gx(GiGy)GyGm 0 0 0 -Gx(GiGy)GxGm 0 0 0 -Gy(GiGy)Gx 0 0 0 -Gy(GiGy)Gy 0 0 0 -Gy(GiGy)GxGx 0 0 0 -Gy(GiGy)GyGm 0 0 0 -Gy(GiGy)GxGm 0 0 0 -Gm(GiGy)Gx 0 0 0 -Gm(GiGy)Gy 0 0 0 -Gm(GiGy)GxGx 0 0 0 -Gm(GiGy)GyGm 0 0 0 -Gm(GiGy)GxGm 0 0 0 -GxGx(GiGy)Gx 0 0 0 -GxGx(GiGy)Gy 0 0 0 -GxGx(GiGy)GxGx 0 0 0 -GxGx(GiGy)GyGm 0 0 0 -GxGx(GiGy)GxGm 0 0 0 -GmGx(GiGy)Gx 0 0 0 -GmGx(GiGy)Gy 0 0 0 -GmGx(GiGy)GxGx 0 0 0 -GmGx(GiGy)GyGm 0 0 0 -GmGx(GiGy)GxGm 0 0 0 -GmGy(GiGy)Gx 0 0 0 -GmGy(GiGy)Gy 0 0 0 -GmGy(GiGy)GxGx 0 0 0 -GmGy(GiGy)GyGm 0 0 0 -GmGy(GiGy)GxGm 0 0 0 -GyGyGy(GiGy)Gx 0 0 0 -GyGyGy(GiGy)Gy 0 0 0 -GyGyGy(GiGy)GxGx 0 0 0 -GyGyGy(GiGy)GyGm 0 0 0 -GyGyGy(GiGy)GxGm 0 0 0 -GxGxGx(GiGy)Gx 0 0 0 -GxGxGx(GiGy)Gy 0 0 0 -GxGxGx(GiGy)GxGx 0 0 0 -GxGxGx(GiGy)GyGm 0 0 0 -GxGxGx(GiGy)GxGm 0 0 0 -(GiGx)Gy 0 0 0 -(GiGx)GxGx 0 0 0 -(GiGx)GyGm 0 0 0 -(GiGx)GxGm 0 0 0 -Gx(GiGx)Gy 0 0 0 -Gx(GiGx)GxGx 0 0 0 -Gx(GiGx)GyGm 0 0 0 -Gx(GiGx)GxGm 0 0 0 -Gy(GiGx)Gy 0 0 0 -Gy(GiGx)GxGx 0 0 0 -Gy(GiGx)GyGm 0 0 0 -Gy(GiGx)GxGm 0 0 0 -Gm(GiGx)Gy 0 0 0 -Gm(GiGx)GxGx 0 0 0 -Gm(GiGx)GyGm 0 0 0 -Gm(GiGx)GxGm 0 0 0 -GxGx(GiGx)Gy 0 0 0 -GxGx(GiGx)GxGx 0 0 0 -GxGx(GiGx)GyGm 0 0 0 -GxGx(GiGx)GxGm 0 0 0 -GmGx(GiGx)Gy 0 0 0 -GmGx(GiGx)GxGx 0 0 0 -GmGx(GiGx)GyGm 0 0 0 -GmGx(GiGx)GxGm 0 0 0 -GmGy(GiGx)Gy 0 0 0 -GmGy(GiGx)GxGx 0 0 0 -GmGy(GiGx)GyGm 0 0 0 -GmGy(GiGx)GxGm 0 0 0 -GyGyGy(GiGx)Gy 0 0 0 -GyGyGy(GiGx)GxGx 0 0 0 -GyGyGy(GiGx)GyGm 0 0 0 -GyGyGy(GiGx)GxGm 0 0 0 -GxGxGx(GiGx)Gy 0 0 0 -GxGxGx(GiGx)GxGx 0 0 0 -GxGxGx(GiGx)GyGm 0 0 0 -GxGxGx(GiGx)GxGm 0 0 0 -(GiGm)Gx 0 0 0 -(GiGm)Gy 0 0 0 -(GiGm)Gm 0 0 0 -(GiGm)GxGx 0 0 0 -(GiGm)GyGm 0 0 0 -(GiGm)GxGm 0 0 0 -Gx(GiGm)Gx 0 0 0 -Gx(GiGm)Gy 0 0 0 -Gx(GiGm)Gm 0 0 0 -Gx(GiGm)GxGx 0 0 0 -Gx(GiGm)GyGm 0 0 0 -Gx(GiGm)GxGm 0 0 0 -Gy(GiGm)Gx 0 0 0 -Gy(GiGm)Gy 0 0 0 -Gy(GiGm)Gm 0 0 0 -Gy(GiGm)GxGx 0 0 0 -Gy(GiGm)GyGm 0 0 0 -Gy(GiGm)GxGm 0 0 0 -Gm(GiGm)Gx 0 0 0 -Gm(GiGm)Gy 0 0 0 -Gm(GiGm)Gm 0 0 0 -Gm(GiGm)GxGx 0 0 0 -Gm(GiGm)GyGm 0 0 0 -Gm(GiGm)GxGm 0 0 0 -GxGx(GiGm)Gx 0 0 0 -GxGx(GiGm)Gy 0 0 0 -GxGx(GiGm)Gm 0 0 0 -GxGx(GiGm)GxGx 0 0 0 -GxGx(GiGm)GyGm 0 0 0 -GxGx(GiGm)GxGm 0 0 0 -GmGx(GiGm)Gx 0 0 0 -GmGx(GiGm)Gy 0 0 0 -GmGx(GiGm)Gm 0 0 0 -GmGx(GiGm)GxGx 0 0 0 -GmGx(GiGm)GyGm 0 0 0 -GmGx(GiGm)GxGm 0 0 0 -GmGy(GiGm)Gx 0 0 0 -GmGy(GiGm)Gy 0 0 0 -GmGy(GiGm)Gm 0 0 0 -GmGy(GiGm)GxGx 0 0 0 -GmGy(GiGm)GyGm 0 0 0 -GmGy(GiGm)GxGm 0 0 0 -GyGyGy(GiGm)Gx 0 0 0 -GyGyGy(GiGm)Gy 0 0 0 -GyGyGy(GiGm)Gm 0 0 0 -GyGyGy(GiGm)GxGx 0 0 0 -GyGyGy(GiGm)GyGm 0 0 0 -GyGyGy(GiGm)GxGm 0 0 0 -GxGxGx(GiGm)Gx 0 0 0 -GxGxGx(GiGm)Gy 0 0 0 -GxGxGx(GiGm)Gm 0 0 0 -GxGxGx(GiGm)GxGx 0 0 0 -GxGxGx(GiGm)GyGm 0 0 0 -GxGxGx(GiGm)GxGm 0 0 0 -Gy(GxGy)Gx 0 0 0 -Gy(GxGy)Gy 0 0 0 -Gy(GxGy)GxGx 0 0 0 -Gy(GxGy)GyGm 0 0 0 -Gy(GxGy)GxGm 0 0 0 -GmGx(GxGy)Gx 0 0 0 -GmGx(GxGy)Gy 0 0 0 -GmGx(GxGy)GxGx 0 0 0 -GmGx(GxGy)GyGm 0 0 0 -GmGx(GxGy)GxGm 0 0 0 -GmGy(GxGy)Gx 0 0 0 -GmGy(GxGy)Gy 0 0 0 -GmGy(GxGy)GxGx 0 0 0 -GmGy(GxGy)GyGm 0 0 0 -GmGy(GxGy)GxGm 0 0 0 -GyGyGy(GxGy)Gx 0 0 0 -GyGyGy(GxGy)Gy 0 0 0 -GyGyGy(GxGy)GxGx 0 0 0 -GyGyGy(GxGy)GyGm 0 0 0 -GyGyGy(GxGy)GxGm 0 0 0 -GxGxGx(GxGy)Gx 0 0 0 -GxGxGx(GxGy)Gy 0 0 0 -GxGxGx(GxGy)GxGx 0 0 0 -GxGxGx(GxGy)GyGm 0 0 0 -GxGxGx(GxGy)GxGm 0 0 0 -Gx(GyGm)Gx 0 0 0 -Gx(GyGm)Gy 0 0 0 -Gx(GyGm)Gm 0 0 0 -Gx(GyGm)GxGx 0 0 0 -Gx(GyGm)GyGm 0 0 0 -Gx(GyGm)GxGm 0 0 0 -Gy(GyGm)Gx 0 0 0 -Gy(GyGm)Gy 0 0 0 -Gy(GyGm)Gm 0 0 0 -Gy(GyGm)GxGx 0 0 0 -Gy(GyGm)GyGm 0 0 0 -Gy(GyGm)GxGm 0 0 0 -GxGx(GyGm)Gx 0 0 0 -GxGx(GyGm)Gy 0 0 0 -GxGx(GyGm)Gm 0 0 0 -GxGx(GyGm)GxGx 0 0 0 -GxGx(GyGm)GyGm 0 0 0 -GxGx(GyGm)GxGm 0 0 0 -GmGx(GyGm)Gx 0 0 0 -GmGx(GyGm)Gy 0 0 0 -GmGx(GyGm)Gm 0 0 0 -GmGx(GyGm)GxGx 0 0 0 -GmGx(GyGm)GyGm 0 0 0 -GmGx(GyGm)GxGm 0 0 0 -GmGy(GyGm)Gx 0 0 0 -GmGy(GyGm)Gy 0 0 0 -GmGy(GyGm)Gm 0 0 0 -GmGy(GyGm)GxGx 0 0 0 -GmGy(GyGm)GyGm 0 0 0 -GmGy(GyGm)GxGm 0 0 0 -GyGyGy(GyGm)Gx 0 0 0 -GyGyGy(GyGm)Gy 0 0 0 -GyGyGy(GyGm)Gm 0 0 0 -GyGyGy(GyGm)GxGx 0 0 0 -GyGyGy(GyGm)GyGm 0 0 0 -GyGyGy(GyGm)GxGm 0 0 0 -GxGxGx(GyGm)Gx 0 0 0 -GxGxGx(GyGm)Gy 0 0 0 -GxGxGx(GyGm)Gm 0 0 0 -GxGxGx(GyGm)GxGx 0 0 0 -GxGxGx(GyGm)GyGm 0 0 0 -GxGxGx(GyGm)GxGm 0 0 0 -Gy(GxGm)Gx 0 0 0 -Gy(GxGm)Gy 0 0 0 -Gy(GxGm)Gm 0 0 0 -Gy(GxGm)GxGx 0 0 0 -Gy(GxGm)GyGm 0 0 0 -Gy(GxGm)GxGm 0 0 0 -GmGx(GxGm)Gx 0 0 0 -GmGx(GxGm)Gy 0 0 0 -GmGx(GxGm)Gm 0 0 0 -GmGx(GxGm)GxGx 0 0 0 -GmGx(GxGm)GyGm 0 0 0 -GmGx(GxGm)GxGm 0 0 0 -GmGy(GxGm)Gx 0 0 0 -GmGy(GxGm)Gy 0 0 0 -GmGy(GxGm)Gm 0 0 0 -GmGy(GxGm)GxGx 0 0 0 -GmGy(GxGm)GyGm 0 0 0 -GmGy(GxGm)GxGm 0 0 0 -GyGyGy(GxGm)Gx 0 0 0 -GyGyGy(GxGm)Gy 0 0 0 -GyGyGy(GxGm)Gm 0 0 0 -GyGyGy(GxGm)GxGx 0 0 0 -GyGyGy(GxGm)GyGm 0 0 0 -GyGyGy(GxGm)GxGm 0 0 0 -GxGxGx(GxGm)Gx 0 0 0 -GxGxGx(GxGm)Gy 0 0 0 -GxGxGx(GxGm)Gm 0 0 0 -GxGxGx(GxGm)GxGx 0 0 0 -GxGxGx(GxGm)GyGm 0 0 0 -GxGxGx(GxGm)GxGm 0 0 0 -(Gi)^4 0 0 0 -(Gi)^4Gx 0 0 0 -(Gi)^4Gy 0 0 0 -(Gi)^4Gm 0 0 0 -(Gi)^4GxGx 0 0 0 -(Gi)^4GyGm 0 0 0 -(Gi)^4GxGm 0 0 0 -Gx(Gi)^4 0 0 0 -Gx(Gi)^4Gx 0 0 0 -Gx(Gi)^4Gy 0 0 0 -Gx(Gi)^4Gm 0 0 0 -Gx(Gi)^4GxGx 0 0 0 -Gx(Gi)^4GyGm 0 0 0 -Gx(Gi)^4GxGm 0 0 0 -Gy(Gi)^4 0 0 0 -Gy(Gi)^4Gx 0 0 0 -Gy(Gi)^4Gy 0 0 0 -Gy(Gi)^4Gm 0 0 0 -Gy(Gi)^4GxGx 0 0 0 -Gy(Gi)^4GyGm 0 0 0 -Gy(Gi)^4GxGm 0 0 0 -Gm(Gi)^4 0 0 0 -Gm(Gi)^4Gx 0 0 0 -Gm(Gi)^4Gy 0 0 0 -Gm(Gi)^4Gm 0 0 0 -Gm(Gi)^4GxGx 0 0 0 -Gm(Gi)^4GyGm 0 0 0 -Gm(Gi)^4GxGm 0 0 0 -GxGx(Gi)^4 0 0 0 -GxGx(Gi)^4Gx 0 0 0 -GxGx(Gi)^4Gy 0 0 0 -GxGx(Gi)^4Gm 0 0 0 -GxGx(Gi)^4GxGx 0 0 0 -GxGx(Gi)^4GyGm 0 0 0 -GxGx(Gi)^4GxGm 0 0 0 -GmGx(Gi)^4 0 0 0 -GmGx(Gi)^4Gx 0 0 0 -GmGx(Gi)^4Gy 0 0 0 -GmGx(Gi)^4Gm 0 0 0 -GmGx(Gi)^4GxGx 0 0 0 -GmGx(Gi)^4GyGm 0 0 0 -GmGx(Gi)^4GxGm 0 0 0 -GmGy(Gi)^4 0 0 0 -GmGy(Gi)^4Gx 0 0 0 -GmGy(Gi)^4Gy 0 0 0 -GmGy(Gi)^4Gm 0 0 0 -GmGy(Gi)^4GxGx 0 0 0 -GmGy(Gi)^4GyGm 0 0 0 -GmGy(Gi)^4GxGm 0 0 0 -GyGyGy(Gi)^4 0 0 0 -GyGyGy(Gi)^4Gx 0 0 0 -GyGyGy(Gi)^4Gy 0 0 0 -GyGyGy(Gi)^4Gm 0 0 0 -GyGyGy(Gi)^4GxGx 0 0 0 -GyGyGy(Gi)^4GyGm 0 0 0 -GyGyGy(Gi)^4GxGm 0 0 0 -GxGxGx(Gi)^4 0 0 0 -GxGxGx(Gi)^4Gx 0 0 0 -GxGxGx(Gi)^4Gy 0 0 0 -GxGxGx(Gi)^4Gm 0 0 0 -GxGxGx(Gi)^4GxGx 0 0 0 -GxGxGx(Gi)^4GyGm 0 0 0 -GxGxGx(Gi)^4GxGm 0 0 0 -Gx(Gy)^4 0 0 0 -Gx(Gy)^4Gx 0 0 0 -Gx(Gy)^4Gy 0 0 0 -Gx(Gy)^4Gm 0 0 0 -Gx(Gy)^4GxGx 0 0 0 -Gx(Gy)^4GyGm 0 0 0 -Gx(Gy)^4GxGm 0 0 0 -Gm(Gy)^4Gx 0 0 0 -Gm(Gy)^4Gy 0 0 0 -Gm(Gy)^4GxGx 0 0 0 -Gm(Gy)^4GyGm 0 0 0 -Gm(Gy)^4GxGm 0 0 0 -GxGx(Gy)^4 0 0 0 -GxGx(Gy)^4Gx 0 0 0 -GxGx(Gy)^4Gy 0 0 0 -GxGx(Gy)^4Gm 0 0 0 -GxGx(Gy)^4GxGx 0 0 0 -GxGx(Gy)^4GyGm 0 0 0 -GxGx(Gy)^4GxGm 0 0 0 -GmGx(Gy)^4 0 0 0 -GmGx(Gy)^4Gx 0 0 0 -GmGx(Gy)^4Gy 0 0 0 -GmGx(Gy)^4Gm 0 0 0 -GmGx(Gy)^4GxGx 0 0 0 -GmGx(Gy)^4GyGm 0 0 0 -GmGx(Gy)^4GxGm 0 0 0 -GmGy(Gy)^4Gx 0 0 0 -GmGy(Gy)^4Gy 0 0 0 -GmGy(Gy)^4GxGx 0 0 0 -GmGy(Gy)^4GyGm 0 0 0 -GmGy(Gy)^4GxGm 0 0 0 -GyGyGy(Gy)^4 0 0 0 -GyGyGy(Gy)^4Gx 0 0 0 -GyGyGy(Gy)^4Gy 0 0 0 -GyGyGy(Gy)^4Gm 0 0 0 -GyGyGy(Gy)^4GxGx 0 0 0 -GyGyGy(Gy)^4GyGm 0 0 0 -GyGyGy(Gy)^4GxGm 0 0 0 -GxGxGx(Gy)^4 0 0 0 -GxGxGx(Gy)^4Gx 0 0 0 -GxGxGx(Gy)^4Gy 0 0 0 -GxGxGx(Gy)^4Gm 0 0 0 -GxGxGx(Gy)^4GxGx 0 0 0 -GxGxGx(Gy)^4GyGm 0 0 0 -GxGxGx(Gy)^4GxGm 0 0 0 -Gy(Gx)^4Gx 0 0 0 -Gy(Gx)^4Gy 0 0 0 -Gy(Gx)^4Gm 0 0 0 -Gy(Gx)^4GxGx 0 0 0 -Gy(Gx)^4GyGm 0 0 0 -Gy(Gx)^4GxGm 0 0 0 -Gm(Gx)^4Gy 0 0 0 -Gm(Gx)^4GxGx 0 0 0 -Gm(Gx)^4GyGm 0 0 0 -Gm(Gx)^4GxGm 0 0 0 -GxGx(Gx)^4Gy 0 0 0 -GxGx(Gx)^4GxGx 0 0 0 -GxGx(Gx)^4GyGm 0 0 0 -GxGx(Gx)^4GxGm 0 0 0 -GmGx(Gx)^4Gy 0 0 0 -GmGx(Gx)^4GxGx 0 0 0 -GmGx(Gx)^4GyGm 0 0 0 -GmGx(Gx)^4GxGm 0 0 0 -GmGy(Gx)^4Gx 0 0 0 -GmGy(Gx)^4Gy 0 0 0 -GmGy(Gx)^4Gm 0 0 0 -GmGy(Gx)^4GxGx 0 0 0 -GmGy(Gx)^4GyGm 0 0 0 -GmGy(Gx)^4GxGm 0 0 0 -GyGyGy(Gx)^4Gx 0 0 0 -GyGyGy(Gx)^4Gy 0 0 0 -GyGyGy(Gx)^4Gm 0 0 0 -GyGyGy(Gx)^4GxGx 0 0 0 -GyGyGy(Gx)^4GyGm 0 0 0 -GyGyGy(Gx)^4GxGm 0 0 0 -GxGxGx(Gx)^4Gy 0 0 0 -GxGxGx(Gx)^4GxGx 0 0 0 -GxGxGx(Gx)^4GyGm 0 0 0 -GxGxGx(Gx)^4GxGm 0 0 0 -(Gm)^4Gx 0 0 0 -(Gm)^4Gy 0 0 0 -(Gm)^4Gm 0 0 0 -(Gm)^4GxGx 0 0 0 -(Gm)^4GyGm 0 0 0 -(Gm)^4GxGm 0 0 0 -Gx(Gm)^4 0 0 0 -Gx(Gm)^4Gx 0 0 0 -Gx(Gm)^4Gy 0 0 0 -Gx(Gm)^4Gm 0 0 0 -Gx(Gm)^4GxGx 0 0 0 -Gx(Gm)^4GyGm 0 0 0 -Gx(Gm)^4GxGm 0 0 0 -Gy(Gm)^4 0 0 0 -Gy(Gm)^4Gx 0 0 0 -Gy(Gm)^4Gy 0 0 0 -Gy(Gm)^4Gm 0 0 0 -Gy(Gm)^4GxGx 0 0 0 -Gy(Gm)^4GyGm 0 0 0 -Gy(Gm)^4GxGm 0 0 0 -Gm(Gm)^4Gx 0 0 0 -Gm(Gm)^4Gy 0 0 0 -Gm(Gm)^4Gm 0 0 0 -Gm(Gm)^4GxGx 0 0 0 -Gm(Gm)^4GyGm 0 0 0 -Gm(Gm)^4GxGm 0 0 0 -GxGx(Gm)^4 0 0 0 -GxGx(Gm)^4Gx 0 0 0 -GxGx(Gm)^4Gy 0 0 0 -GxGx(Gm)^4Gm 0 0 0 -GxGx(Gm)^4GxGx 0 0 0 -GxGx(Gm)^4GyGm 0 0 0 -GxGx(Gm)^4GxGm 0 0 0 -GmGx(Gm)^4 0 0 0 -GmGx(Gm)^4Gx 0 0 0 -GmGx(Gm)^4Gy 0 0 0 -GmGx(Gm)^4Gm 0 0 0 -GmGx(Gm)^4GxGx 0 0 0 -GmGx(Gm)^4GyGm 0 0 0 -GmGx(Gm)^4GxGm 0 0 0 -GmGy(Gm)^4 0 0 0 -GmGy(Gm)^4Gx 0 0 0 -GmGy(Gm)^4Gy 0 0 0 -GmGy(Gm)^4Gm 0 0 0 -GmGy(Gm)^4GxGx 0 0 0 -GmGy(Gm)^4GyGm 0 0 0 -GmGy(Gm)^4GxGm 0 0 0 -GyGyGy(Gm)^4 0 0 0 -GyGyGy(Gm)^4Gx 0 0 0 -GyGyGy(Gm)^4Gy 0 0 0 -GyGyGy(Gm)^4Gm 0 0 0 -GyGyGy(Gm)^4GxGx 0 0 0 -GyGyGy(Gm)^4GyGm 0 0 0 -GyGyGy(Gm)^4GxGm 0 0 0 -GxGxGx(Gm)^4 0 0 0 -GxGxGx(Gm)^4Gx 0 0 0 -GxGxGx(Gm)^4Gy 0 0 0 -GxGxGx(Gm)^4Gm 0 0 0 -GxGxGx(Gm)^4GxGx 0 0 0 -GxGxGx(Gm)^4GyGm 0 0 0 -GxGxGx(Gm)^4GxGm 0 0 0 -(GiGy)^2 0 0 0 -(GiGy)^2Gx 0 0 0 -(GiGy)^2Gy 0 0 0 -(GiGy)^2Gm 0 0 0 -(GiGy)^2GxGx 0 0 0 -(GiGy)^2GyGm 0 0 0 -(GiGy)^2GxGm 0 0 0 -Gx(GiGy)^2 0 0 0 -Gx(GiGy)^2Gx 0 0 0 -Gx(GiGy)^2Gy 0 0 0 -Gx(GiGy)^2Gm 0 0 0 -Gx(GiGy)^2GxGx 0 0 0 -Gx(GiGy)^2GyGm 0 0 0 -Gx(GiGy)^2GxGm 0 0 0 -Gy(GiGy)^2 0 0 0 -Gy(GiGy)^2Gx 0 0 0 -Gy(GiGy)^2Gy 0 0 0 -Gy(GiGy)^2Gm 0 0 0 -Gy(GiGy)^2GxGx 0 0 0 -Gy(GiGy)^2GyGm 0 0 0 -Gy(GiGy)^2GxGm 0 0 0 -Gm(GiGy)^2 0 0 0 -Gm(GiGy)^2Gx 0 0 0 -Gm(GiGy)^2Gy 0 0 0 -Gm(GiGy)^2Gm 0 0 0 -Gm(GiGy)^2GxGx 0 0 0 -Gm(GiGy)^2GyGm 0 0 0 -Gm(GiGy)^2GxGm 0 0 0 -GxGx(GiGy)^2 0 0 0 -GxGx(GiGy)^2Gx 0 0 0 -GxGx(GiGy)^2Gy 0 0 0 -GxGx(GiGy)^2Gm 0 0 0 -GxGx(GiGy)^2GxGx 0 0 0 -GxGx(GiGy)^2GyGm 0 0 0 -GxGx(GiGy)^2GxGm 0 0 0 -GmGx(GiGy)^2 0 0 0 -GmGx(GiGy)^2Gx 0 0 0 -GmGx(GiGy)^2Gy 0 0 0 -GmGx(GiGy)^2Gm 0 0 0 -GmGx(GiGy)^2GxGx 0 0 0 -GmGx(GiGy)^2GyGm 0 0 0 -GmGx(GiGy)^2GxGm 0 0 0 -GmGy(GiGy)^2 0 0 0 -GmGy(GiGy)^2Gx 0 0 0 -GmGy(GiGy)^2Gy 0 0 0 -GmGy(GiGy)^2Gm 0 0 0 -GmGy(GiGy)^2GxGx 0 0 0 -GmGy(GiGy)^2GyGm 0 0 0 -GmGy(GiGy)^2GxGm 0 0 0 -GyGyGy(GiGy)^2 0 0 0 -GyGyGy(GiGy)^2Gx 0 0 0 -GyGyGy(GiGy)^2Gy 0 0 0 -GyGyGy(GiGy)^2Gm 0 0 0 -GyGyGy(GiGy)^2GxGx 0 0 0 -GyGyGy(GiGy)^2GyGm 0 0 0 -GyGyGy(GiGy)^2GxGm 0 0 0 -GxGxGx(GiGy)^2 0 0 0 -GxGxGx(GiGy)^2Gx 0 0 0 -GxGxGx(GiGy)^2Gy 0 0 0 -GxGxGx(GiGy)^2Gm 0 0 0 -GxGxGx(GiGy)^2GxGx 0 0 0 -GxGxGx(GiGy)^2GyGm 0 0 0 -GxGxGx(GiGy)^2GxGm 0 0 0 -(GiGx)^2 0 0 0 -(GiGx)^2Gx 0 0 0 -(GiGx)^2Gy 0 0 0 -(GiGx)^2Gm 0 0 0 -(GiGx)^2GxGx 0 0 0 -(GiGx)^2GyGm 0 0 0 -(GiGx)^2GxGm 0 0 0 -Gx(GiGx)^2 0 0 0 -Gx(GiGx)^2Gx 0 0 0 -Gx(GiGx)^2Gy 0 0 0 -Gx(GiGx)^2Gm 0 0 0 -Gx(GiGx)^2GxGx 0 0 0 -Gx(GiGx)^2GyGm 0 0 0 -Gx(GiGx)^2GxGm 0 0 0 -Gy(GiGx)^2 0 0 0 -Gy(GiGx)^2Gx 0 0 0 -Gy(GiGx)^2Gy 0 0 0 -Gy(GiGx)^2Gm 0 0 0 -Gy(GiGx)^2GxGx 0 0 0 -Gy(GiGx)^2GyGm 0 0 0 -Gy(GiGx)^2GxGm 0 0 0 -Gm(GiGx)^2 0 0 0 -Gm(GiGx)^2Gx 0 0 0 -Gm(GiGx)^2Gy 0 0 0 -Gm(GiGx)^2Gm 0 0 0 -Gm(GiGx)^2GxGx 0 0 0 -Gm(GiGx)^2GyGm 0 0 0 -Gm(GiGx)^2GxGm 0 0 0 -GxGx(GiGx)^2 0 0 0 -GxGx(GiGx)^2Gx 0 0 0 -GxGx(GiGx)^2Gy 0 0 0 -GxGx(GiGx)^2Gm 0 0 0 -GxGx(GiGx)^2GxGx 0 0 0 -GxGx(GiGx)^2GyGm 0 0 0 -GxGx(GiGx)^2GxGm 0 0 0 -GmGx(GiGx)^2 0 0 0 -GmGx(GiGx)^2Gx 0 0 0 -GmGx(GiGx)^2Gy 0 0 0 -GmGx(GiGx)^2Gm 0 0 0 -GmGx(GiGx)^2GxGx 0 0 0 -GmGx(GiGx)^2GyGm 0 0 0 -GmGx(GiGx)^2GxGm 0 0 0 -GmGy(GiGx)^2 0 0 0 -GmGy(GiGx)^2Gx 0 0 0 -GmGy(GiGx)^2Gy 0 0 0 -GmGy(GiGx)^2Gm 0 0 0 -GmGy(GiGx)^2GxGx 0 0 0 -GmGy(GiGx)^2GyGm 0 0 0 -GmGy(GiGx)^2GxGm 0 0 0 -GyGyGy(GiGx)^2 0 0 0 -GyGyGy(GiGx)^2Gx 0 0 0 -GyGyGy(GiGx)^2Gy 0 0 0 -GyGyGy(GiGx)^2Gm 0 0 0 -GyGyGy(GiGx)^2GxGx 0 0 0 -GyGyGy(GiGx)^2GyGm 0 0 0 -GyGyGy(GiGx)^2GxGm 0 0 0 -GxGxGx(GiGx)^2 0 0 0 -GxGxGx(GiGx)^2Gx 0 0 0 -GxGxGx(GiGx)^2Gy 0 0 0 -GxGxGx(GiGx)^2Gm 0 0 0 -GxGxGx(GiGx)^2GxGx 0 0 0 -GxGxGx(GiGx)^2GyGm 0 0 0 -GxGxGx(GiGx)^2GxGm 0 0 0 -(GiGm)^2 0 0 0 -(GiGm)^2Gx 0 0 0 -(GiGm)^2Gy 0 0 0 -(GiGm)^2Gm 0 0 0 -(GiGm)^2GxGx 0 0 0 -(GiGm)^2GyGm 0 0 0 -(GiGm)^2GxGm 0 0 0 -Gx(GiGm)^2 0 0 0 -Gx(GiGm)^2Gx 0 0 0 -Gx(GiGm)^2Gy 0 0 0 -Gx(GiGm)^2Gm 0 0 0 -Gx(GiGm)^2GxGx 0 0 0 -Gx(GiGm)^2GyGm 0 0 0 -Gx(GiGm)^2GxGm 0 0 0 -Gy(GiGm)^2 0 0 0 -Gy(GiGm)^2Gx 0 0 0 -Gy(GiGm)^2Gy 0 0 0 -Gy(GiGm)^2Gm 0 0 0 -Gy(GiGm)^2GxGx 0 0 0 -Gy(GiGm)^2GyGm 0 0 0 -Gy(GiGm)^2GxGm 0 0 0 -Gm(GiGm)^2 0 0 0 -Gm(GiGm)^2Gx 0 0 0 -Gm(GiGm)^2Gy 0 0 0 -Gm(GiGm)^2Gm 0 0 0 -Gm(GiGm)^2GxGx 0 0 0 -Gm(GiGm)^2GyGm 0 0 0 -Gm(GiGm)^2GxGm 0 0 0 -GxGx(GiGm)^2 0 0 0 -GxGx(GiGm)^2Gx 0 0 0 -GxGx(GiGm)^2Gy 0 0 0 -GxGx(GiGm)^2Gm 0 0 0 -GxGx(GiGm)^2GxGx 0 0 0 -GxGx(GiGm)^2GyGm 0 0 0 -GxGx(GiGm)^2GxGm 0 0 0 -GmGx(GiGm)^2 0 0 0 -GmGx(GiGm)^2Gx 0 0 0 -GmGx(GiGm)^2Gy 0 0 0 -GmGx(GiGm)^2Gm 0 0 0 -GmGx(GiGm)^2GxGx 0 0 0 -GmGx(GiGm)^2GyGm 0 0 0 -GmGx(GiGm)^2GxGm 0 0 0 -GmGy(GiGm)^2 0 0 0 -GmGy(GiGm)^2Gx 0 0 0 -GmGy(GiGm)^2Gy 0 0 0 -GmGy(GiGm)^2Gm 0 0 0 -GmGy(GiGm)^2GxGx 0 0 0 -GmGy(GiGm)^2GyGm 0 0 0 -GmGy(GiGm)^2GxGm 0 0 0 -GyGyGy(GiGm)^2 0 0 0 -GyGyGy(GiGm)^2Gx 0 0 0 -GyGyGy(GiGm)^2Gy 0 0 0 -GyGyGy(GiGm)^2Gm 0 0 0 -GyGyGy(GiGm)^2GxGx 0 0 0 -GyGyGy(GiGm)^2GyGm 0 0 0 -GyGyGy(GiGm)^2GxGm 0 0 0 -GxGxGx(GiGm)^2 0 0 0 -GxGxGx(GiGm)^2Gx 0 0 0 -GxGxGx(GiGm)^2Gy 0 0 0 -GxGxGx(GiGm)^2Gm 0 0 0 -GxGxGx(GiGm)^2GxGx 0 0 0 -GxGxGx(GiGm)^2GyGm 0 0 0 -GxGxGx(GiGm)^2GxGm 0 0 0 -(GxGy)^2 0 0 0 -(GxGy)^2Gx 0 0 0 -(GxGy)^2Gy 0 0 0 -(GxGy)^2Gm 0 0 0 -(GxGy)^2GxGx 0 0 0 -(GxGy)^2GyGm 0 0 0 -(GxGy)^2GxGm 0 0 0 -Gx(GxGy)^2 0 0 0 -Gx(GxGy)^2Gx 0 0 0 -Gx(GxGy)^2Gy 0 0 0 -Gx(GxGy)^2Gm 0 0 0 -Gx(GxGy)^2GxGx 0 0 0 -Gx(GxGy)^2GyGm 0 0 0 -Gx(GxGy)^2GxGm 0 0 0 -Gy(GxGy)^2 0 0 0 -Gy(GxGy)^2Gx 0 0 0 -Gy(GxGy)^2Gy 0 0 0 -Gy(GxGy)^2Gm 0 0 0 -Gy(GxGy)^2GxGx 0 0 0 -Gy(GxGy)^2GyGm 0 0 0 -Gy(GxGy)^2GxGm 0 0 0 -Gm(GxGy)^2 0 0 0 -Gm(GxGy)^2Gx 0 0 0 -Gm(GxGy)^2Gy 0 0 0 -Gm(GxGy)^2Gm 0 0 0 -Gm(GxGy)^2GxGx 0 0 0 -Gm(GxGy)^2GyGm 0 0 0 -Gm(GxGy)^2GxGm 0 0 0 -GxGx(GxGy)^2 0 0 0 -GxGx(GxGy)^2Gx 0 0 0 -GxGx(GxGy)^2Gy 0 0 0 -GxGx(GxGy)^2Gm 0 0 0 -GxGx(GxGy)^2GxGx 0 0 0 -GxGx(GxGy)^2GyGm 0 0 0 -GxGx(GxGy)^2GxGm 0 0 0 -GmGx(GxGy)^2 0 0 0 -GmGx(GxGy)^2Gx 0 0 0 -GmGx(GxGy)^2Gy 0 0 0 -GmGx(GxGy)^2Gm 0 0 0 -GmGx(GxGy)^2GxGx 0 0 0 -GmGx(GxGy)^2GyGm 0 0 0 -GmGx(GxGy)^2GxGm 0 0 0 -GmGy(GxGy)^2 0 0 0 -GmGy(GxGy)^2Gx 0 0 0 -GmGy(GxGy)^2Gy 0 0 0 -GmGy(GxGy)^2Gm 0 0 0 -GmGy(GxGy)^2GxGx 0 0 0 -GmGy(GxGy)^2GyGm 0 0 0 -GmGy(GxGy)^2GxGm 0 0 0 -GyGyGy(GxGy)^2 0 0 0 -GyGyGy(GxGy)^2Gx 0 0 0 -GyGyGy(GxGy)^2Gy 0 0 0 -GyGyGy(GxGy)^2Gm 0 0 0 -GyGyGy(GxGy)^2GxGx 0 0 0 -GyGyGy(GxGy)^2GyGm 0 0 0 -GyGyGy(GxGy)^2GxGm 0 0 0 -GxGxGx(GxGy)^2 0 0 0 -GxGxGx(GxGy)^2Gx 0 0 0 -GxGxGx(GxGy)^2Gy 0 0 0 -GxGxGx(GxGy)^2Gm 0 0 0 -GxGxGx(GxGy)^2GxGx 0 0 0 -GxGxGx(GxGy)^2GyGm 0 0 0 -GxGxGx(GxGy)^2GxGm 0 0 0 -(GyGm)^2Gx 0 0 0 -(GyGm)^2Gy 0 0 0 -(GyGm)^2Gm 0 0 0 -(GyGm)^2GxGx 0 0 0 -(GyGm)^2GyGm 0 0 0 -(GyGm)^2GxGm 0 0 0 -Gx(GyGm)^2Gx 0 0 0 -Gx(GyGm)^2Gy 0 0 0 -Gx(GyGm)^2Gm 0 0 0 -Gx(GyGm)^2GxGx 0 0 0 -Gx(GyGm)^2GyGm 0 0 0 -Gx(GyGm)^2GxGm 0 0 0 -Gy(GyGm)^2Gx 0 0 0 -Gy(GyGm)^2Gy 0 0 0 -Gy(GyGm)^2Gm 0 0 0 -Gy(GyGm)^2GxGx 0 0 0 -Gy(GyGm)^2GyGm 0 0 0 -Gy(GyGm)^2GxGm 0 0 0 -Gm(GyGm)^2Gx 0 0 0 -Gm(GyGm)^2Gy 0 0 0 -Gm(GyGm)^2Gm 0 0 0 -Gm(GyGm)^2GxGx 0 0 0 -Gm(GyGm)^2GyGm 0 0 0 -Gm(GyGm)^2GxGm 0 0 0 -GxGx(GyGm)^2Gx 0 0 0 -GxGx(GyGm)^2Gy 0 0 0 -GxGx(GyGm)^2Gm 0 0 0 -GxGx(GyGm)^2GxGx 0 0 0 -GxGx(GyGm)^2GyGm 0 0 0 -GxGx(GyGm)^2GxGm 0 0 0 -GmGx(GyGm)^2Gx 0 0 0 -GmGx(GyGm)^2Gy 0 0 0 -GmGx(GyGm)^2Gm 0 0 0 -GmGx(GyGm)^2GxGx 0 0 0 -GmGx(GyGm)^2GyGm 0 0 0 -GmGx(GyGm)^2GxGm 0 0 0 -GmGy(GyGm)^2Gx 0 0 0 -GmGy(GyGm)^2Gy 0 0 0 -GmGy(GyGm)^2Gm 0 0 0 -GmGy(GyGm)^2GxGx 0 0 0 -GmGy(GyGm)^2GyGm 0 0 0 -GmGy(GyGm)^2GxGm 0 0 0 -GyGyGy(GyGm)^2Gx 0 0 0 -GyGyGy(GyGm)^2Gy 0 0 0 -GyGyGy(GyGm)^2Gm 0 0 0 -GyGyGy(GyGm)^2GxGx 0 0 0 -GyGyGy(GyGm)^2GyGm 0 0 0 -GyGyGy(GyGm)^2GxGm 0 0 0 -GxGxGx(GyGm)^2Gx 0 0 0 -GxGxGx(GyGm)^2Gy 0 0 0 -GxGxGx(GyGm)^2Gm 0 0 0 -GxGxGx(GyGm)^2GxGx 0 0 0 -GxGxGx(GyGm)^2GyGm 0 0 0 -GxGxGx(GyGm)^2GxGm 0 0 0 -(GxGm)^2Gx 0 0 0 -(GxGm)^2Gy 0 0 0 -(GxGm)^2Gm 0 0 0 -(GxGm)^2GxGx 0 0 0 -(GxGm)^2GyGm 0 0 0 -(GxGm)^2GxGm 0 0 0 -Gx(GxGm)^2Gx 0 0 0 -Gx(GxGm)^2Gy 0 0 0 -Gx(GxGm)^2Gm 0 0 0 -Gx(GxGm)^2GxGx 0 0 0 -Gx(GxGm)^2GyGm 0 0 0 -Gx(GxGm)^2GxGm 0 0 0 -Gy(GxGm)^2Gx 0 0 0 -Gy(GxGm)^2Gy 0 0 0 -Gy(GxGm)^2Gm 0 0 0 -Gy(GxGm)^2GxGx 0 0 0 -Gy(GxGm)^2GyGm 0 0 0 -Gy(GxGm)^2GxGm 0 0 0 -Gm(GxGm)^2Gx 0 0 0 -Gm(GxGm)^2Gy 0 0 0 -Gm(GxGm)^2Gm 0 0 0 -Gm(GxGm)^2GxGx 0 0 0 -Gm(GxGm)^2GyGm 0 0 0 -Gm(GxGm)^2GxGm 0 0 0 -GxGx(GxGm)^2Gx 0 0 0 -GxGx(GxGm)^2Gy 0 0 0 -GxGx(GxGm)^2Gm 0 0 0 -GxGx(GxGm)^2GxGx 0 0 0 -GxGx(GxGm)^2GyGm 0 0 0 -GxGx(GxGm)^2GxGm 0 0 0 -GmGx(GxGm)^2Gx 0 0 0 -GmGx(GxGm)^2Gy 0 0 0 -GmGx(GxGm)^2Gm 0 0 0 -GmGx(GxGm)^2GxGx 0 0 0 -GmGx(GxGm)^2GyGm 0 0 0 -GmGx(GxGm)^2GxGm 0 0 0 -GmGy(GxGm)^2Gx 0 0 0 -GmGy(GxGm)^2Gy 0 0 0 -GmGy(GxGm)^2Gm 0 0 0 -GmGy(GxGm)^2GxGx 0 0 0 -GmGy(GxGm)^2GyGm 0 0 0 -GmGy(GxGm)^2GxGm 0 0 0 -GyGyGy(GxGm)^2Gx 0 0 0 -GyGyGy(GxGm)^2Gy 0 0 0 -GyGyGy(GxGm)^2Gm 0 0 0 -GyGyGy(GxGm)^2GxGx 0 0 0 -GyGyGy(GxGm)^2GyGm 0 0 0 -GyGyGy(GxGm)^2GxGm 0 0 0 -GxGxGx(GxGm)^2Gx 0 0 0 -GxGxGx(GxGm)^2Gy 0 0 0 -GxGxGx(GxGm)^2Gm 0 0 0 -GxGxGx(GxGm)^2GxGx 0 0 0 -GxGxGx(GxGm)^2GyGm 0 0 0 -GxGxGx(GxGm)^2GxGm 0 0 0 -(GiGiGy)Gx 0 0 0 -(GiGiGy)Gy 0 0 0 -(GiGiGy)GxGx 0 0 0 -(GiGiGy)GyGm 0 0 0 -(GiGiGy)GxGm 0 0 0 -Gx(GiGiGy)Gx 0 0 0 -Gx(GiGiGy)Gy 0 0 0 -Gx(GiGiGy)GxGx 0 0 0 -Gx(GiGiGy)GyGm 0 0 0 -Gx(GiGiGy)GxGm 0 0 0 -Gy(GiGiGy)Gx 0 0 0 -Gy(GiGiGy)Gy 0 0 0 -Gy(GiGiGy)GxGx 0 0 0 -Gy(GiGiGy)GyGm 0 0 0 -Gy(GiGiGy)GxGm 0 0 0 -Gm(GiGiGy)Gx 0 0 0 -Gm(GiGiGy)Gy 0 0 0 -Gm(GiGiGy)GxGx 0 0 0 -Gm(GiGiGy)GyGm 0 0 0 -Gm(GiGiGy)GxGm 0 0 0 -GxGx(GiGiGy)Gx 0 0 0 -GxGx(GiGiGy)Gy 0 0 0 -GxGx(GiGiGy)GxGx 0 0 0 -GxGx(GiGiGy)GyGm 0 0 0 -GxGx(GiGiGy)GxGm 0 0 0 -GmGx(GiGiGy)Gx 0 0 0 -GmGx(GiGiGy)Gy 0 0 0 -GmGx(GiGiGy)GxGx 0 0 0 -GmGx(GiGiGy)GyGm 0 0 0 -GmGx(GiGiGy)GxGm 0 0 0 -GmGy(GiGiGy)Gx 0 0 0 -GmGy(GiGiGy)Gy 0 0 0 -GmGy(GiGiGy)GxGx 0 0 0 -GmGy(GiGiGy)GyGm 0 0 0 -GmGy(GiGiGy)GxGm 0 0 0 -GyGyGy(GiGiGy)Gx 0 0 0 -GyGyGy(GiGiGy)Gy 0 0 0 -GyGyGy(GiGiGy)GxGx 0 0 0 -GyGyGy(GiGiGy)GyGm 0 0 0 -GyGyGy(GiGiGy)GxGm 0 0 0 -GxGxGx(GiGiGy)Gx 0 0 0 -GxGxGx(GiGiGy)Gy 0 0 0 -GxGxGx(GiGiGy)GxGx 0 0 0 -GxGxGx(GiGiGy)GyGm 0 0 0 -GxGxGx(GiGiGy)GxGm 0 0 0 -(GiGiGx)Gy 0 0 0 -(GiGiGx)GxGx 0 0 0 -(GiGiGx)GyGm 0 0 0 -(GiGiGx)GxGm 0 0 0 -Gx(GiGiGx)Gy 0 0 0 -Gx(GiGiGx)GxGx 0 0 0 -Gx(GiGiGx)GyGm 0 0 0 -Gx(GiGiGx)GxGm 0 0 0 -Gy(GiGiGx)Gy 0 0 0 -Gy(GiGiGx)GxGx 0 0 0 -Gy(GiGiGx)GyGm 0 0 0 -Gy(GiGiGx)GxGm 0 0 0 -Gm(GiGiGx)Gy 0 0 0 -Gm(GiGiGx)GxGx 0 0 0 -Gm(GiGiGx)GyGm 0 0 0 -Gm(GiGiGx)GxGm 0 0 0 -GxGx(GiGiGx)Gy 0 0 0 -GxGx(GiGiGx)GxGx 0 0 0 -GxGx(GiGiGx)GyGm 0 0 0 -GxGx(GiGiGx)GxGm 0 0 0 -GmGx(GiGiGx)Gy 0 0 0 -GmGx(GiGiGx)GxGx 0 0 0 -GmGx(GiGiGx)GyGm 0 0 0 -GmGx(GiGiGx)GxGm 0 0 0 -GmGy(GiGiGx)Gy 0 0 0 -GmGy(GiGiGx)GxGx 0 0 0 -GmGy(GiGiGx)GyGm 0 0 0 -GmGy(GiGiGx)GxGm 0 0 0 -GyGyGy(GiGiGx)Gy 0 0 0 -GyGyGy(GiGiGx)GxGx 0 0 0 -GyGyGy(GiGiGx)GyGm 0 0 0 -GyGyGy(GiGiGx)GxGm 0 0 0 -GxGxGx(GiGiGx)Gy 0 0 0 -GxGxGx(GiGiGx)GxGx 0 0 0 -GxGxGx(GiGiGx)GyGm 0 0 0 -GxGxGx(GiGiGx)GxGm 0 0 0 -Gy(GxGxGy)Gx 0 0 0 -Gy(GxGxGy)Gy 0 0 0 -Gy(GxGxGy)GxGx 0 0 0 -Gy(GxGxGy)GyGm 0 0 0 -Gy(GxGxGy)GxGm 0 0 0 -GmGx(GxGxGy)Gx 0 0 0 -GmGx(GxGxGy)Gy 0 0 0 -GmGx(GxGxGy)GxGx 0 0 0 -GmGx(GxGxGy)GyGm 0 0 0 -GmGx(GxGxGy)GxGm 0 0 0 -GmGy(GxGxGy)Gx 0 0 0 -GmGy(GxGxGy)Gy 0 0 0 -GmGy(GxGxGy)GxGx 0 0 0 -GmGy(GxGxGy)GyGm 0 0 0 -GmGy(GxGxGy)GxGm 0 0 0 -GyGyGy(GxGxGy)Gx 0 0 0 -GyGyGy(GxGxGy)Gy 0 0 0 -GyGyGy(GxGxGy)GxGx 0 0 0 -GyGyGy(GxGxGy)GyGm 0 0 0 -GyGyGy(GxGxGy)GxGm 0 0 0 -GxGxGx(GxGxGy)Gx 0 0 0 -GxGxGx(GxGxGy)Gy 0 0 0 -GxGxGx(GxGxGy)GxGx 0 0 0 -GxGxGx(GxGxGy)GyGm 0 0 0 -GxGxGx(GxGxGy)GxGm 0 0 0 -(GiGiGm)Gx 0 0 0 -(GiGiGm)Gy 0 0 0 -(GiGiGm)Gm 0 0 0 -(GiGiGm)GxGx 0 0 0 -(GiGiGm)GyGm 0 0 0 -(GiGiGm)GxGm 0 0 0 -Gx(GiGiGm)Gx 0 0 0 -Gx(GiGiGm)Gy 0 0 0 -Gx(GiGiGm)Gm 0 0 0 -Gx(GiGiGm)GxGx 0 0 0 -Gx(GiGiGm)GyGm 0 0 0 -Gx(GiGiGm)GxGm 0 0 0 -Gy(GiGiGm)Gx 0 0 0 -Gy(GiGiGm)Gy 0 0 0 -Gy(GiGiGm)Gm 0 0 0 -Gy(GiGiGm)GxGx 0 0 0 -Gy(GiGiGm)GyGm 0 0 0 -Gy(GiGiGm)GxGm 0 0 0 -Gm(GiGiGm)Gx 0 0 0 -Gm(GiGiGm)Gy 0 0 0 -Gm(GiGiGm)Gm 0 0 0 -Gm(GiGiGm)GxGx 0 0 0 -Gm(GiGiGm)GyGm 0 0 0 -Gm(GiGiGm)GxGm 0 0 0 -GxGx(GiGiGm)Gx 0 0 0 -GxGx(GiGiGm)Gy 0 0 0 -GxGx(GiGiGm)Gm 0 0 0 -GxGx(GiGiGm)GxGx 0 0 0 -GxGx(GiGiGm)GyGm 0 0 0 -GxGx(GiGiGm)GxGm 0 0 0 -GmGx(GiGiGm)Gx 0 0 0 -GmGx(GiGiGm)Gy 0 0 0 -GmGx(GiGiGm)Gm 0 0 0 -GmGx(GiGiGm)GxGx 0 0 0 -GmGx(GiGiGm)GyGm 0 0 0 -GmGx(GiGiGm)GxGm 0 0 0 -GmGy(GiGiGm)Gx 0 0 0 -GmGy(GiGiGm)Gy 0 0 0 -GmGy(GiGiGm)Gm 0 0 0 -GmGy(GiGiGm)GxGx 0 0 0 -GmGy(GiGiGm)GyGm 0 0 0 -GmGy(GiGiGm)GxGm 0 0 0 -GyGyGy(GiGiGm)Gx 0 0 0 -GyGyGy(GiGiGm)Gy 0 0 0 -GyGyGy(GiGiGm)Gm 0 0 0 -GyGyGy(GiGiGm)GxGx 0 0 0 -GyGyGy(GiGiGm)GyGm 0 0 0 -GyGyGy(GiGiGm)GxGm 0 0 0 -GxGxGx(GiGiGm)Gx 0 0 0 -GxGxGx(GiGiGm)Gy 0 0 0 -GxGxGx(GiGiGm)Gm 0 0 0 -GxGxGx(GiGiGm)GxGx 0 0 0 -GxGxGx(GiGiGm)GyGm 0 0 0 -GxGxGx(GiGiGm)GxGm 0 0 0 -(GiGyGy)Gx 0 0 0 -(GiGyGy)Gy 0 0 0 -(GiGyGy)GxGx 0 0 0 -(GiGyGy)GyGm 0 0 0 -(GiGyGy)GxGm 0 0 0 -Gx(GiGyGy)Gx 0 0 0 -Gx(GiGyGy)Gy 0 0 0 -Gx(GiGyGy)GxGx 0 0 0 -Gx(GiGyGy)GyGm 0 0 0 -Gx(GiGyGy)GxGm 0 0 0 -Gy(GiGyGy)Gx 0 0 0 -Gy(GiGyGy)Gy 0 0 0 -Gy(GiGyGy)GxGx 0 0 0 -Gy(GiGyGy)GyGm 0 0 0 -Gy(GiGyGy)GxGm 0 0 0 -Gm(GiGyGy)Gx 0 0 0 -Gm(GiGyGy)Gy 0 0 0 -Gm(GiGyGy)GxGx 0 0 0 -Gm(GiGyGy)GyGm 0 0 0 -Gm(GiGyGy)GxGm 0 0 0 -GxGx(GiGyGy)Gx 0 0 0 -GxGx(GiGyGy)Gy 0 0 0 -GxGx(GiGyGy)GxGx 0 0 0 -GxGx(GiGyGy)GyGm 0 0 0 -GxGx(GiGyGy)GxGm 0 0 0 -GmGx(GiGyGy)Gx 0 0 0 -GmGx(GiGyGy)Gy 0 0 0 -GmGx(GiGyGy)GxGx 0 0 0 -GmGx(GiGyGy)GyGm 0 0 0 -GmGx(GiGyGy)GxGm 0 0 0 -GmGy(GiGyGy)Gx 0 0 0 -GmGy(GiGyGy)Gy 0 0 0 -GmGy(GiGyGy)GxGx 0 0 0 -GmGy(GiGyGy)GyGm 0 0 0 -GmGy(GiGyGy)GxGm 0 0 0 -GyGyGy(GiGyGy)Gx 0 0 0 -GyGyGy(GiGyGy)Gy 0 0 0 -GyGyGy(GiGyGy)GxGx 0 0 0 -GyGyGy(GiGyGy)GyGm 0 0 0 -GyGyGy(GiGyGy)GxGm 0 0 0 -GxGxGx(GiGyGy)Gx 0 0 0 -GxGxGx(GiGyGy)Gy 0 0 0 -GxGxGx(GiGyGy)GxGx 0 0 0 -GxGxGx(GiGyGy)GyGm 0 0 0 -GxGxGx(GiGyGy)GxGm 0 0 0 -(GiGyGx)Gy 0 0 0 -(GiGyGx)GxGx 0 0 0 -(GiGyGx)GyGm 0 0 0 -(GiGyGx)GxGm 0 0 0 -Gx(GiGyGx)Gy 0 0 0 -Gx(GiGyGx)GxGx 0 0 0 -Gx(GiGyGx)GyGm 0 0 0 -Gx(GiGyGx)GxGm 0 0 0 -Gy(GiGyGx)Gy 0 0 0 -Gy(GiGyGx)GxGx 0 0 0 -Gy(GiGyGx)GyGm 0 0 0 -Gy(GiGyGx)GxGm 0 0 0 -Gm(GiGyGx)Gy 0 0 0 -Gm(GiGyGx)GxGx 0 0 0 -Gm(GiGyGx)GyGm 0 0 0 -Gm(GiGyGx)GxGm 0 0 0 -GxGx(GiGyGx)Gy 0 0 0 -GxGx(GiGyGx)GxGx 0 0 0 -GxGx(GiGyGx)GyGm 0 0 0 -GxGx(GiGyGx)GxGm 0 0 0 -GmGx(GiGyGx)Gy 0 0 0 -GmGx(GiGyGx)GxGx 0 0 0 -GmGx(GiGyGx)GyGm 0 0 0 -GmGx(GiGyGx)GxGm 0 0 0 -GmGy(GiGyGx)Gy 0 0 0 -GmGy(GiGyGx)GxGx 0 0 0 -GmGy(GiGyGx)GyGm 0 0 0 -GmGy(GiGyGx)GxGm 0 0 0 -GyGyGy(GiGyGx)Gy 0 0 0 -GyGyGy(GiGyGx)GxGx 0 0 0 -GyGyGy(GiGyGx)GyGm 0 0 0 -GyGyGy(GiGyGx)GxGm 0 0 0 -GxGxGx(GiGyGx)Gy 0 0 0 -GxGxGx(GiGyGx)GxGx 0 0 0 -GxGxGx(GiGyGx)GyGm 0 0 0 -GxGxGx(GiGyGx)GxGm 0 0 0 -(GiGyGm)Gx 0 0 0 -(GiGyGm)Gy 0 0 0 -(GiGyGm)Gm 0 0 0 -(GiGyGm)GxGx 0 0 0 -(GiGyGm)GyGm 0 0 0 -(GiGyGm)GxGm 0 0 0 -Gx(GiGyGm)Gx 0 0 0 -Gx(GiGyGm)Gy 0 0 0 -Gx(GiGyGm)Gm 0 0 0 -Gx(GiGyGm)GxGx 0 0 0 -Gx(GiGyGm)GyGm 0 0 0 -Gx(GiGyGm)GxGm 0 0 0 -Gy(GiGyGm)Gx 0 0 0 -Gy(GiGyGm)Gy 0 0 0 -Gy(GiGyGm)Gm 0 0 0 -Gy(GiGyGm)GxGx 0 0 0 -Gy(GiGyGm)GyGm 0 0 0 -Gy(GiGyGm)GxGm 0 0 0 -Gm(GiGyGm)Gx 0 0 0 -Gm(GiGyGm)Gy 0 0 0 -Gm(GiGyGm)Gm 0 0 0 -Gm(GiGyGm)GxGx 0 0 0 -Gm(GiGyGm)GyGm 0 0 0 -Gm(GiGyGm)GxGm 0 0 0 -GxGx(GiGyGm)Gx 0 0 0 -GxGx(GiGyGm)Gy 0 0 0 -GxGx(GiGyGm)Gm 0 0 0 -GxGx(GiGyGm)GxGx 0 0 0 -GxGx(GiGyGm)GyGm 0 0 0 -GxGx(GiGyGm)GxGm 0 0 0 -GmGx(GiGyGm)Gx 0 0 0 -GmGx(GiGyGm)Gy 0 0 0 -GmGx(GiGyGm)Gm 0 0 0 -GmGx(GiGyGm)GxGx 0 0 0 -GmGx(GiGyGm)GyGm 0 0 0 -GmGx(GiGyGm)GxGm 0 0 0 -GmGy(GiGyGm)Gx 0 0 0 -GmGy(GiGyGm)Gy 0 0 0 -GmGy(GiGyGm)Gm 0 0 0 -GmGy(GiGyGm)GxGx 0 0 0 -GmGy(GiGyGm)GyGm 0 0 0 -GmGy(GiGyGm)GxGm 0 0 0 -GyGyGy(GiGyGm)Gx 0 0 0 -GyGyGy(GiGyGm)Gy 0 0 0 -GyGyGy(GiGyGm)Gm 0 0 0 -GyGyGy(GiGyGm)GxGx 0 0 0 -GyGyGy(GiGyGm)GyGm 0 0 0 -GyGyGy(GiGyGm)GxGm 0 0 0 -GxGxGx(GiGyGm)Gx 0 0 0 -GxGxGx(GiGyGm)Gy 0 0 0 -GxGxGx(GiGyGm)Gm 0 0 0 -GxGxGx(GiGyGm)GxGx 0 0 0 -GxGxGx(GiGyGm)GyGm 0 0 0 -GxGxGx(GiGyGm)GxGm 0 0 0 -(GiGxGy)Gx 0 0 0 -(GiGxGy)Gy 0 0 0 -(GiGxGy)GxGx 0 0 0 -(GiGxGy)GyGm 0 0 0 -(GiGxGy)GxGm 0 0 0 -Gx(GiGxGy)Gx 0 0 0 -Gx(GiGxGy)Gy 0 0 0 -Gx(GiGxGy)GxGx 0 0 0 -Gx(GiGxGy)GyGm 0 0 0 -Gx(GiGxGy)GxGm 0 0 0 -Gy(GiGxGy)Gx 0 0 0 -Gy(GiGxGy)Gy 0 0 0 -Gy(GiGxGy)GxGx 0 0 0 -Gy(GiGxGy)GyGm 0 0 0 -Gy(GiGxGy)GxGm 0 0 0 -Gm(GiGxGy)Gx 0 0 0 -Gm(GiGxGy)Gy 0 0 0 -Gm(GiGxGy)GxGx 0 0 0 -Gm(GiGxGy)GyGm 0 0 0 -Gm(GiGxGy)GxGm 0 0 0 -GxGx(GiGxGy)Gx 0 0 0 -GxGx(GiGxGy)Gy 0 0 0 -GxGx(GiGxGy)GxGx 0 0 0 -GxGx(GiGxGy)GyGm 0 0 0 -GxGx(GiGxGy)GxGm 0 0 0 -GmGx(GiGxGy)Gx 0 0 0 -GmGx(GiGxGy)Gy 0 0 0 -GmGx(GiGxGy)GxGx 0 0 0 -GmGx(GiGxGy)GyGm 0 0 0 -GmGx(GiGxGy)GxGm 0 0 0 -GmGy(GiGxGy)Gx 0 0 0 -GmGy(GiGxGy)Gy 0 0 0 -GmGy(GiGxGy)GxGx 0 0 0 -GmGy(GiGxGy)GyGm 0 0 0 -GmGy(GiGxGy)GxGm 0 0 0 -GyGyGy(GiGxGy)Gx 0 0 0 -GyGyGy(GiGxGy)Gy 0 0 0 -GyGyGy(GiGxGy)GxGx 0 0 0 -GyGyGy(GiGxGy)GyGm 0 0 0 -GyGyGy(GiGxGy)GxGm 0 0 0 -GxGxGx(GiGxGy)Gx 0 0 0 -GxGxGx(GiGxGy)Gy 0 0 0 -GxGxGx(GiGxGy)GxGx 0 0 0 -GxGxGx(GiGxGy)GyGm 0 0 0 -GxGxGx(GiGxGy)GxGm 0 0 0 -(GiGxGx)Gy 0 0 0 -(GiGxGx)GxGx 0 0 0 -(GiGxGx)GyGm 0 0 0 -(GiGxGx)GxGm 0 0 0 -Gx(GiGxGx)Gy 0 0 0 -Gx(GiGxGx)GxGx 0 0 0 -Gx(GiGxGx)GyGm 0 0 0 -Gx(GiGxGx)GxGm 0 0 0 -Gy(GiGxGx)Gy 0 0 0 -Gy(GiGxGx)GxGx 0 0 0 -Gy(GiGxGx)GyGm 0 0 0 -Gy(GiGxGx)GxGm 0 0 0 -Gm(GiGxGx)Gy 0 0 0 -Gm(GiGxGx)GxGx 0 0 0 -Gm(GiGxGx)GyGm 0 0 0 -Gm(GiGxGx)GxGm 0 0 0 -GxGx(GiGxGx)Gy 0 0 0 -GxGx(GiGxGx)GxGx 0 0 0 -GxGx(GiGxGx)GyGm 0 0 0 -GxGx(GiGxGx)GxGm 0 0 0 -GmGx(GiGxGx)Gy 0 0 0 -GmGx(GiGxGx)GxGx 0 0 0 -GmGx(GiGxGx)GyGm 0 0 0 -GmGx(GiGxGx)GxGm 0 0 0 -GmGy(GiGxGx)Gy 0 0 0 -GmGy(GiGxGx)GxGx 0 0 0 -GmGy(GiGxGx)GyGm 0 0 0 -GmGy(GiGxGx)GxGm 0 0 0 -GyGyGy(GiGxGx)Gy 0 0 0 -GyGyGy(GiGxGx)GxGx 0 0 0 -GyGyGy(GiGxGx)GyGm 0 0 0 -GyGyGy(GiGxGx)GxGm 0 0 0 -GxGxGx(GiGxGx)Gy 0 0 0 -GxGxGx(GiGxGx)GxGx 0 0 0 -GxGxGx(GiGxGx)GyGm 0 0 0 -GxGxGx(GiGxGx)GxGm 0 0 0 -(GiGxGm)Gx 0 0 0 -(GiGxGm)Gy 0 0 0 -(GiGxGm)Gm 0 0 0 -(GiGxGm)GxGx 0 0 0 -(GiGxGm)GyGm 0 0 0 -(GiGxGm)GxGm 0 0 0 -Gx(GiGxGm)Gx 0 0 0 -Gx(GiGxGm)Gy 0 0 0 -Gx(GiGxGm)Gm 0 0 0 -Gx(GiGxGm)GxGx 0 0 0 -Gx(GiGxGm)GyGm 0 0 0 -Gx(GiGxGm)GxGm 0 0 0 -Gy(GiGxGm)Gx 0 0 0 -Gy(GiGxGm)Gy 0 0 0 -Gy(GiGxGm)Gm 0 0 0 -Gy(GiGxGm)GxGx 0 0 0 -Gy(GiGxGm)GyGm 0 0 0 -Gy(GiGxGm)GxGm 0 0 0 -Gm(GiGxGm)Gx 0 0 0 -Gm(GiGxGm)Gy 0 0 0 -Gm(GiGxGm)Gm 0 0 0 -Gm(GiGxGm)GxGx 0 0 0 -Gm(GiGxGm)GyGm 0 0 0 -Gm(GiGxGm)GxGm 0 0 0 -GxGx(GiGxGm)Gx 0 0 0 -GxGx(GiGxGm)Gy 0 0 0 -GxGx(GiGxGm)Gm 0 0 0 -GxGx(GiGxGm)GxGx 0 0 0 -GxGx(GiGxGm)GyGm 0 0 0 -GxGx(GiGxGm)GxGm 0 0 0 -GmGx(GiGxGm)Gx 0 0 0 -GmGx(GiGxGm)Gy 0 0 0 -GmGx(GiGxGm)Gm 0 0 0 -GmGx(GiGxGm)GxGx 0 0 0 -GmGx(GiGxGm)GyGm 0 0 0 -GmGx(GiGxGm)GxGm 0 0 0 -GmGy(GiGxGm)Gx 0 0 0 -GmGy(GiGxGm)Gy 0 0 0 -GmGy(GiGxGm)Gm 0 0 0 -GmGy(GiGxGm)GxGx 0 0 0 -GmGy(GiGxGm)GyGm 0 0 0 -GmGy(GiGxGm)GxGm 0 0 0 -GyGyGy(GiGxGm)Gx 0 0 0 -GyGyGy(GiGxGm)Gy 0 0 0 -GyGyGy(GiGxGm)Gm 0 0 0 -GyGyGy(GiGxGm)GxGx 0 0 0 -GyGyGy(GiGxGm)GyGm 0 0 0 -GyGyGy(GiGxGm)GxGm 0 0 0 -GxGxGx(GiGxGm)Gx 0 0 0 -GxGxGx(GiGxGm)Gy 0 0 0 -GxGxGx(GiGxGm)Gm 0 0 0 -GxGxGx(GiGxGm)GxGx 0 0 0 -GxGxGx(GiGxGm)GyGm 0 0 0 -GxGxGx(GiGxGm)GxGm 0 0 0 -(GiGmGy)Gx 0 0 0 -(GiGmGy)Gy 0 0 0 -(GiGmGy)GxGx 0 0 0 -(GiGmGy)GyGm 0 0 0 -(GiGmGy)GxGm 0 0 0 -Gx(GiGmGy)Gx 0 0 0 -Gx(GiGmGy)Gy 0 0 0 -Gx(GiGmGy)GxGx 0 0 0 -Gx(GiGmGy)GyGm 0 0 0 -Gx(GiGmGy)GxGm 0 0 0 -Gy(GiGmGy)Gx 0 0 0 -Gy(GiGmGy)Gy 0 0 0 -Gy(GiGmGy)GxGx 0 0 0 -Gy(GiGmGy)GyGm 0 0 0 -Gy(GiGmGy)GxGm 0 0 0 -Gm(GiGmGy)Gx 0 0 0 -Gm(GiGmGy)Gy 0 0 0 -Gm(GiGmGy)GxGx 0 0 0 -Gm(GiGmGy)GyGm 0 0 0 -Gm(GiGmGy)GxGm 0 0 0 -GxGx(GiGmGy)Gx 0 0 0 -GxGx(GiGmGy)Gy 0 0 0 -GxGx(GiGmGy)GxGx 0 0 0 -GxGx(GiGmGy)GyGm 0 0 0 -GxGx(GiGmGy)GxGm 0 0 0 -GmGx(GiGmGy)Gx 0 0 0 -GmGx(GiGmGy)Gy 0 0 0 -GmGx(GiGmGy)GxGx 0 0 0 -GmGx(GiGmGy)GyGm 0 0 0 -GmGx(GiGmGy)GxGm 0 0 0 -GmGy(GiGmGy)Gx 0 0 0 -GmGy(GiGmGy)Gy 0 0 0 -GmGy(GiGmGy)GxGx 0 0 0 -GmGy(GiGmGy)GyGm 0 0 0 -GmGy(GiGmGy)GxGm 0 0 0 -GyGyGy(GiGmGy)Gx 0 0 0 -GyGyGy(GiGmGy)Gy 0 0 0 -GyGyGy(GiGmGy)GxGx 0 0 0 -GyGyGy(GiGmGy)GyGm 0 0 0 -GyGyGy(GiGmGy)GxGm 0 0 0 -GxGxGx(GiGmGy)Gx 0 0 0 -GxGxGx(GiGmGy)Gy 0 0 0 -GxGxGx(GiGmGy)GxGx 0 0 0 -GxGxGx(GiGmGy)GyGm 0 0 0 -GxGxGx(GiGmGy)GxGm 0 0 0 -(GiGmGx)Gy 0 0 0 -(GiGmGx)GxGx 0 0 0 -(GiGmGx)GyGm 0 0 0 -(GiGmGx)GxGm 0 0 0 -Gx(GiGmGx)Gy 0 0 0 -Gx(GiGmGx)GxGx 0 0 0 -Gx(GiGmGx)GyGm 0 0 0 -Gx(GiGmGx)GxGm 0 0 0 -Gy(GiGmGx)Gy 0 0 0 -Gy(GiGmGx)GxGx 0 0 0 -Gy(GiGmGx)GyGm 0 0 0 -Gy(GiGmGx)GxGm 0 0 0 -Gm(GiGmGx)Gy 0 0 0 -Gm(GiGmGx)GxGx 0 0 0 -Gm(GiGmGx)GyGm 0 0 0 -Gm(GiGmGx)GxGm 0 0 0 -GxGx(GiGmGx)Gy 0 0 0 -GxGx(GiGmGx)GxGx 0 0 0 -GxGx(GiGmGx)GyGm 0 0 0 -GxGx(GiGmGx)GxGm 0 0 0 -GmGx(GiGmGx)Gy 0 0 0 -GmGx(GiGmGx)GxGx 0 0 0 -GmGx(GiGmGx)GyGm 0 0 0 -GmGx(GiGmGx)GxGm 0 0 0 -GmGy(GiGmGx)Gy 0 0 0 -GmGy(GiGmGx)GxGx 0 0 0 -GmGy(GiGmGx)GyGm 0 0 0 -GmGy(GiGmGx)GxGm 0 0 0 -GyGyGy(GiGmGx)Gy 0 0 0 -GyGyGy(GiGmGx)GxGx 0 0 0 -GyGyGy(GiGmGx)GyGm 0 0 0 -GyGyGy(GiGmGx)GxGm 0 0 0 -GxGxGx(GiGmGx)Gy 0 0 0 -GxGxGx(GiGmGx)GxGx 0 0 0 -GxGxGx(GiGmGx)GyGm 0 0 0 -GxGxGx(GiGmGx)GxGm 0 0 0 -(GiGmGm)Gx 0 0 0 -(GiGmGm)Gy 0 0 0 -(GiGmGm)Gm 0 0 0 -(GiGmGm)GxGx 0 0 0 -(GiGmGm)GyGm 0 0 0 -(GiGmGm)GxGm 0 0 0 -Gx(GiGmGm)Gx 0 0 0 -Gx(GiGmGm)Gy 0 0 0 -Gx(GiGmGm)Gm 0 0 0 -Gx(GiGmGm)GxGx 0 0 0 -Gx(GiGmGm)GyGm 0 0 0 -Gx(GiGmGm)GxGm 0 0 0 -Gy(GiGmGm)Gx 0 0 0 -Gy(GiGmGm)Gy 0 0 0 -Gy(GiGmGm)Gm 0 0 0 -Gy(GiGmGm)GxGx 0 0 0 -Gy(GiGmGm)GyGm 0 0 0 -Gy(GiGmGm)GxGm 0 0 0 -Gm(GiGmGm)Gx 0 0 0 -Gm(GiGmGm)Gy 0 0 0 -Gm(GiGmGm)Gm 0 0 0 -Gm(GiGmGm)GxGx 0 0 0 -Gm(GiGmGm)GyGm 0 0 0 -Gm(GiGmGm)GxGm 0 0 0 -GxGx(GiGmGm)Gx 0 0 0 -GxGx(GiGmGm)Gy 0 0 0 -GxGx(GiGmGm)Gm 0 0 0 -GxGx(GiGmGm)GxGx 0 0 0 -GxGx(GiGmGm)GyGm 0 0 0 -GxGx(GiGmGm)GxGm 0 0 0 -GmGx(GiGmGm)Gx 0 0 0 -GmGx(GiGmGm)Gy 0 0 0 -GmGx(GiGmGm)Gm 0 0 0 -GmGx(GiGmGm)GxGx 0 0 0 -GmGx(GiGmGm)GyGm 0 0 0 -GmGx(GiGmGm)GxGm 0 0 0 -GmGy(GiGmGm)Gx 0 0 0 -GmGy(GiGmGm)Gy 0 0 0 -GmGy(GiGmGm)Gm 0 0 0 -GmGy(GiGmGm)GxGx 0 0 0 -GmGy(GiGmGm)GyGm 0 0 0 -GmGy(GiGmGm)GxGm 0 0 0 -GyGyGy(GiGmGm)Gx 0 0 0 -GyGyGy(GiGmGm)Gy 0 0 0 -GyGyGy(GiGmGm)Gm 0 0 0 -GyGyGy(GiGmGm)GxGx 0 0 0 -GyGyGy(GiGmGm)GyGm 0 0 0 -GyGyGy(GiGmGm)GxGm 0 0 0 -GxGxGx(GiGmGm)Gx 0 0 0 -GxGxGx(GiGmGm)Gy 0 0 0 -GxGxGx(GiGmGm)Gm 0 0 0 -GxGxGx(GiGmGm)GxGx 0 0 0 -GxGxGx(GiGmGm)GyGm 0 0 0 -GxGxGx(GiGmGm)GxGm 0 0 0 -(GyGyGx)Gy 0 0 0 -(GyGyGx)GxGx 0 0 0 -(GyGyGx)GyGm 0 0 0 -(GyGyGx)GxGm 0 0 0 -Gx(GyGyGx)Gy 0 0 0 -Gx(GyGyGx)GxGx 0 0 0 -Gx(GyGyGx)GyGm 0 0 0 -Gx(GyGyGx)GxGm 0 0 0 -Gm(GyGyGx)Gy 0 0 0 -Gm(GyGyGx)GxGx 0 0 0 -Gm(GyGyGx)GyGm 0 0 0 -Gm(GyGyGx)GxGm 0 0 0 -GxGx(GyGyGx)Gy 0 0 0 -GxGx(GyGyGx)GxGx 0 0 0 -GxGx(GyGyGx)GyGm 0 0 0 -GxGx(GyGyGx)GxGm 0 0 0 -GmGx(GyGyGx)Gy 0 0 0 -GmGx(GyGyGx)GxGx 0 0 0 -GmGx(GyGyGx)GyGm 0 0 0 -GmGx(GyGyGx)GxGm 0 0 0 -GmGy(GyGyGx)Gy 0 0 0 -GmGy(GyGyGx)GxGx 0 0 0 -GmGy(GyGyGx)GyGm 0 0 0 -GmGy(GyGyGx)GxGm 0 0 0 -GyGyGy(GyGyGx)Gy 0 0 0 -GyGyGy(GyGyGx)GxGx 0 0 0 -GyGyGy(GyGyGx)GyGm 0 0 0 -GyGyGy(GyGyGx)GxGm 0 0 0 -GxGxGx(GyGyGx)Gy 0 0 0 -GxGxGx(GyGyGx)GxGx 0 0 0 -GxGxGx(GyGyGx)GyGm 0 0 0 -GxGxGx(GyGyGx)GxGm 0 0 0 -Gx(GyGyGm)Gx 0 0 0 -Gx(GyGyGm)Gy 0 0 0 -Gx(GyGyGm)Gm 0 0 0 -Gx(GyGyGm)GxGx 0 0 0 -Gx(GyGyGm)GyGm 0 0 0 -Gx(GyGyGm)GxGm 0 0 0 -GxGx(GyGyGm)Gx 0 0 0 -GxGx(GyGyGm)Gy 0 0 0 -GxGx(GyGyGm)Gm 0 0 0 -GxGx(GyGyGm)GxGx 0 0 0 -GxGx(GyGyGm)GyGm 0 0 0 -GxGx(GyGyGm)GxGm 0 0 0 -GmGx(GyGyGm)Gx 0 0 0 -GmGx(GyGyGm)Gy 0 0 0 -GmGx(GyGyGm)Gm 0 0 0 -GmGx(GyGyGm)GxGx 0 0 0 -GmGx(GyGyGm)GyGm 0 0 0 -GmGx(GyGyGm)GxGm 0 0 0 -GmGy(GyGyGm)Gx 0 0 0 -GmGy(GyGyGm)Gy 0 0 0 -GmGy(GyGyGm)Gm 0 0 0 -GmGy(GyGyGm)GxGx 0 0 0 -GmGy(GyGyGm)GyGm 0 0 0 -GmGy(GyGyGm)GxGm 0 0 0 -GyGyGy(GyGyGm)Gx 0 0 0 -GyGyGy(GyGyGm)Gy 0 0 0 -GyGyGy(GyGyGm)Gm 0 0 0 -GyGyGy(GyGyGm)GxGx 0 0 0 -GyGyGy(GyGyGm)GyGm 0 0 0 -GyGyGy(GyGyGm)GxGm 0 0 0 -GxGxGx(GyGyGm)Gx 0 0 0 -GxGxGx(GyGyGm)Gy 0 0 0 -GxGxGx(GyGyGm)Gm 0 0 0 -GxGxGx(GyGyGm)GxGx 0 0 0 -GxGxGx(GyGyGm)GyGm 0 0 0 -GxGxGx(GyGyGm)GxGm 0 0 0 -Gx(GyGxGx)Gx 0 0 0 -Gx(GyGxGx)Gy 0 0 0 -Gx(GyGxGx)Gm 0 0 0 -Gx(GyGxGx)GxGx 0 0 0 -Gx(GyGxGx)GyGm 0 0 0 -Gx(GyGxGx)GxGm 0 0 0 -Gy(GyGxGx)Gy 0 0 0 -Gy(GyGxGx)GxGx 0 0 0 -Gy(GyGxGx)GyGm 0 0 0 -Gy(GyGxGx)GxGm 0 0 0 -GxGx(GyGxGx)Gx 0 0 0 -GxGx(GyGxGx)Gy 0 0 0 -GxGx(GyGxGx)Gm 0 0 0 -GxGx(GyGxGx)GxGx 0 0 0 -GxGx(GyGxGx)GyGm 0 0 0 -GxGx(GyGxGx)GxGm 0 0 0 -GmGx(GyGxGx)Gx 0 0 0 -GmGx(GyGxGx)Gy 0 0 0 -GmGx(GyGxGx)Gm 0 0 0 -GmGx(GyGxGx)GxGx 0 0 0 -GmGx(GyGxGx)GyGm 0 0 0 -GmGx(GyGxGx)GxGm 0 0 0 -GmGy(GyGxGx)Gy 0 0 0 -GmGy(GyGxGx)GxGx 0 0 0 -GmGy(GyGxGx)GyGm 0 0 0 -GmGy(GyGxGx)GxGm 0 0 0 -GyGyGy(GyGxGx)Gx 0 0 0 -GyGyGy(GyGxGx)Gy 0 0 0 -GyGyGy(GyGxGx)Gm 0 0 0 -GyGyGy(GyGxGx)GxGx 0 0 0 -GyGyGy(GyGxGx)GyGm 0 0 0 -GyGyGy(GyGxGx)GxGm 0 0 0 -GxGxGx(GyGxGx)Gx 0 0 0 -GxGxGx(GyGxGx)Gy 0 0 0 -GxGxGx(GyGxGx)Gm 0 0 0 -GxGxGx(GyGxGx)GxGx 0 0 0 -GxGxGx(GyGxGx)GyGm 0 0 0 -GxGxGx(GyGxGx)GxGm 0 0 0 -Gx(GyGxGm)Gx 0 0 0 -Gx(GyGxGm)Gy 0 0 0 -Gx(GyGxGm)Gm 0 0 0 -Gx(GyGxGm)GxGx 0 0 0 -Gx(GyGxGm)GyGm 0 0 0 -Gx(GyGxGm)GxGm 0 0 0 -Gy(GyGxGm)Gx 0 0 0 -Gy(GyGxGm)Gy 0 0 0 -Gy(GyGxGm)Gm 0 0 0 -Gy(GyGxGm)GxGx 0 0 0 -Gy(GyGxGm)GyGm 0 0 0 -Gy(GyGxGm)GxGm 0 0 0 -GxGx(GyGxGm)Gx 0 0 0 -GxGx(GyGxGm)Gy 0 0 0 -GxGx(GyGxGm)Gm 0 0 0 -GxGx(GyGxGm)GxGx 0 0 0 -GxGx(GyGxGm)GyGm 0 0 0 -GxGx(GyGxGm)GxGm 0 0 0 -GmGx(GyGxGm)Gx 0 0 0 -GmGx(GyGxGm)Gy 0 0 0 -GmGx(GyGxGm)Gm 0 0 0 -GmGx(GyGxGm)GxGx 0 0 0 -GmGx(GyGxGm)GyGm 0 0 0 -GmGx(GyGxGm)GxGm 0 0 0 -GmGy(GyGxGm)Gx 0 0 0 -GmGy(GyGxGm)Gy 0 0 0 -GmGy(GyGxGm)Gm 0 0 0 -GmGy(GyGxGm)GxGx 0 0 0 -GmGy(GyGxGm)GyGm 0 0 0 -GmGy(GyGxGm)GxGm 0 0 0 -GyGyGy(GyGxGm)Gx 0 0 0 -GyGyGy(GyGxGm)Gy 0 0 0 -GyGyGy(GyGxGm)Gm 0 0 0 -GyGyGy(GyGxGm)GxGx 0 0 0 -GyGyGy(GyGxGm)GyGm 0 0 0 -GyGyGy(GyGxGm)GxGm 0 0 0 -GxGxGx(GyGxGm)Gx 0 0 0 -GxGxGx(GyGxGm)Gy 0 0 0 -GxGxGx(GyGxGm)Gm 0 0 0 -GxGxGx(GyGxGm)GxGx 0 0 0 -GxGxGx(GyGxGm)GyGm 0 0 0 -GxGxGx(GyGxGm)GxGm 0 0 0 -(GyGmGx)Gy 0 0 0 -(GyGmGx)GxGx 0 0 0 -(GyGmGx)GyGm 0 0 0 -(GyGmGx)GxGm 0 0 0 -Gx(GyGmGx)Gy 0 0 0 -Gx(GyGmGx)GxGx 0 0 0 -Gx(GyGmGx)GyGm 0 0 0 -Gx(GyGmGx)GxGm 0 0 0 -Gy(GyGmGx)Gy 0 0 0 -Gy(GyGmGx)GxGx 0 0 0 -Gy(GyGmGx)GyGm 0 0 0 -Gy(GyGmGx)GxGm 0 0 0 -Gm(GyGmGx)Gy 0 0 0 -Gm(GyGmGx)GxGx 0 0 0 -Gm(GyGmGx)GyGm 0 0 0 -Gm(GyGmGx)GxGm 0 0 0 -GxGx(GyGmGx)Gy 0 0 0 -GxGx(GyGmGx)GxGx 0 0 0 -GxGx(GyGmGx)GyGm 0 0 0 -GxGx(GyGmGx)GxGm 0 0 0 -GmGx(GyGmGx)Gy 0 0 0 -GmGx(GyGmGx)GxGx 0 0 0 -GmGx(GyGmGx)GyGm 0 0 0 -GmGx(GyGmGx)GxGm 0 0 0 -GmGy(GyGmGx)Gy 0 0 0 -GmGy(GyGmGx)GxGx 0 0 0 -GmGy(GyGmGx)GyGm 0 0 0 -GmGy(GyGmGx)GxGm 0 0 0 -GyGyGy(GyGmGx)Gy 0 0 0 -GyGyGy(GyGmGx)GxGx 0 0 0 -GyGyGy(GyGmGx)GyGm 0 0 0 -GyGyGy(GyGmGx)GxGm 0 0 0 -GxGxGx(GyGmGx)Gy 0 0 0 -GxGxGx(GyGmGx)GxGx 0 0 0 -GxGxGx(GyGmGx)GyGm 0 0 0 -GxGxGx(GyGmGx)GxGm 0 0 0 -Gx(GyGmGm)Gx 0 0 0 -Gx(GyGmGm)Gy 0 0 0 -Gx(GyGmGm)Gm 0 0 0 -Gx(GyGmGm)GxGx 0 0 0 -Gx(GyGmGm)GyGm 0 0 0 -Gx(GyGmGm)GxGm 0 0 0 -Gy(GyGmGm)Gx 0 0 0 -Gy(GyGmGm)Gy 0 0 0 -Gy(GyGmGm)Gm 0 0 0 -Gy(GyGmGm)GxGx 0 0 0 -Gy(GyGmGm)GyGm 0 0 0 -Gy(GyGmGm)GxGm 0 0 0 -GxGx(GyGmGm)Gx 0 0 0 -GxGx(GyGmGm)Gy 0 0 0 -GxGx(GyGmGm)Gm 0 0 0 -GxGx(GyGmGm)GxGx 0 0 0 -GxGx(GyGmGm)GyGm 0 0 0 -GxGx(GyGmGm)GxGm 0 0 0 -GmGx(GyGmGm)Gx 0 0 0 -GmGx(GyGmGm)Gy 0 0 0 -GmGx(GyGmGm)Gm 0 0 0 -GmGx(GyGmGm)GxGx 0 0 0 -GmGx(GyGmGm)GyGm 0 0 0 -GmGx(GyGmGm)GxGm 0 0 0 -GmGy(GyGmGm)Gx 0 0 0 -GmGy(GyGmGm)Gy 0 0 0 -GmGy(GyGmGm)Gm 0 0 0 -GmGy(GyGmGm)GxGx 0 0 0 -GmGy(GyGmGm)GyGm 0 0 0 -GmGy(GyGmGm)GxGm 0 0 0 -GyGyGy(GyGmGm)Gx 0 0 0 -GyGyGy(GyGmGm)Gy 0 0 0 -GyGyGy(GyGmGm)Gm 0 0 0 -GyGyGy(GyGmGm)GxGx 0 0 0 -GyGyGy(GyGmGm)GyGm 0 0 0 -GyGyGy(GyGmGm)GxGm 0 0 0 -GxGxGx(GyGmGm)Gx 0 0 0 -GxGxGx(GyGmGm)Gy 0 0 0 -GxGxGx(GyGmGm)Gm 0 0 0 -GxGxGx(GyGmGm)GxGx 0 0 0 -GxGxGx(GyGmGm)GyGm 0 0 0 -GxGxGx(GyGmGm)GxGm 0 0 0 -Gy(GxGxGm)Gx 0 0 0 -Gy(GxGxGm)Gy 0 0 0 -Gy(GxGxGm)Gm 0 0 0 -Gy(GxGxGm)GxGx 0 0 0 -Gy(GxGxGm)GyGm 0 0 0 -Gy(GxGxGm)GxGm 0 0 0 -GmGx(GxGxGm)Gx 0 0 0 -GmGx(GxGxGm)Gy 0 0 0 -GmGx(GxGxGm)Gm 0 0 0 -GmGx(GxGxGm)GxGx 0 0 0 -GmGx(GxGxGm)GyGm 0 0 0 -GmGx(GxGxGm)GxGm 0 0 0 -GmGy(GxGxGm)Gx 0 0 0 -GmGy(GxGxGm)Gy 0 0 0 -GmGy(GxGxGm)Gm 0 0 0 -GmGy(GxGxGm)GxGx 0 0 0 -GmGy(GxGxGm)GyGm 0 0 0 -GmGy(GxGxGm)GxGm 0 0 0 -GyGyGy(GxGxGm)Gx 0 0 0 -GyGyGy(GxGxGm)Gy 0 0 0 -GyGyGy(GxGxGm)Gm 0 0 0 -GyGyGy(GxGxGm)GxGx 0 0 0 -GyGyGy(GxGxGm)GyGm 0 0 0 -GyGyGy(GxGxGm)GxGm 0 0 0 -GxGxGx(GxGxGm)Gx 0 0 0 -GxGxGx(GxGxGm)Gy 0 0 0 -GxGxGx(GxGxGm)Gm 0 0 0 -GxGxGx(GxGxGm)GxGx 0 0 0 -GxGxGx(GxGxGm)GyGm 0 0 0 -GxGxGx(GxGxGm)GxGm 0 0 0 -Gy(GxGmGm)Gx 0 0 0 -Gy(GxGmGm)Gy 0 0 0 -Gy(GxGmGm)Gm 0 0 0 -Gy(GxGmGm)GxGx 0 0 0 -Gy(GxGmGm)GyGm 0 0 0 -Gy(GxGmGm)GxGm 0 0 0 -GmGx(GxGmGm)Gx 0 0 0 -GmGx(GxGmGm)Gy 0 0 0 -GmGx(GxGmGm)Gm 0 0 0 -GmGx(GxGmGm)GxGx 0 0 0 -GmGx(GxGmGm)GyGm 0 0 0 -GmGx(GxGmGm)GxGm 0 0 0 -GmGy(GxGmGm)Gx 0 0 0 -GmGy(GxGmGm)Gy 0 0 0 -GmGy(GxGmGm)Gm 0 0 0 -GmGy(GxGmGm)GxGx 0 0 0 -GmGy(GxGmGm)GyGm 0 0 0 -GmGy(GxGmGm)GxGm 0 0 0 -GyGyGy(GxGmGm)Gx 0 0 0 -GyGyGy(GxGmGm)Gy 0 0 0 -GyGyGy(GxGmGm)Gm 0 0 0 -GyGyGy(GxGmGm)GxGx 0 0 0 -GyGyGy(GxGmGm)GyGm 0 0 0 -GyGyGy(GxGmGm)GxGm 0 0 0 -GxGxGx(GxGmGm)Gx 0 0 0 -GxGxGx(GxGmGm)Gy 0 0 0 -GxGxGx(GxGmGm)Gm 0 0 0 -GxGxGx(GxGmGm)GxGx 0 0 0 -GxGxGx(GxGmGm)GyGm 0 0 0 -GxGxGx(GxGmGm)GxGm 0 0 0 +{}@(QT) 0 0 0 +Gx:QT@(QT) 0 0 0 +Gy:QT@(QT) 0 0 0 +Gm:QT@(QT) 0 0 0 +Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT@(QT) 0 0 0 +Gm:QTGy:QT@(QT) 0 0 0 +Gm:QTGm:QTGx:QT@(QT) 0 0 0 +Gm:QTGm:QTGy:QT@(QT) 0 0 0 +Gm:QTGm:QTGm:QT@(QT) 0 0 0 +Gm:QTGm:QTGy:QTGm:QT@(QT) 0 0 0 +Gm:QTGm:QTGm:QTGx:QT@(QT) 0 0 0 +Gx:QTGx:QT@(QT) 0 0 0 +Gx:QTGy:QT@(QT) 0 0 0 +Gx:QTGm:QT@(QT) 0 0 0 +Gx:QTGy:QTGm:QT@(QT) 0 0 0 +Gx:QTGm:QTGx:QT@(QT) 0 0 0 +Gy:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QT@(QT) 0 0 0 +Gy:QTGy:QTGm:QT@(QT) 0 0 0 +Gy:QTGm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QTGy:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QTGy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QTGm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QTGy:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QTGy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QTGm:QTGx:QT@(QT) 0 0 0 +Gm:QTGy:QTGm:QT@(QT) 0 0 0 +Gm:QTGx:QTGx:QT@(QT) 0 0 0 +Gm:QTGx:QTGy:QT@(QT) 0 0 0 +Gm:QTGx:QTGm:QT@(QT) 0 0 0 +Gm:QTGx:QTGy:QTGm:QT@(QT) 0 0 0 +Gm:QTGx:QTGm:QTGx:QT@(QT) 0 0 0 +Gm:QTGy:QTGx:QT@(QT) 0 0 0 +Gm:QTGy:QTGy:QT@(QT) 0 0 0 +Gm:QTGy:QTGy:QTGm:QT@(QT) 0 0 0 +Gm:QTGy:QTGm:QTGx:QT@(QT) 0 0 0 +(Gi:QT)@(QT) 0 0 0 +(Gi:QT)Gx:QT@(QT) 0 0 0 +(Gi:QT)Gy:QT@(QT) 0 0 0 +(Gi:QT)Gm:QT@(QT) 0 0 0 +(Gi:QT)Gy:QTGm:QT@(QT) 0 0 0 +(Gi:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gi:QT)@(QT) 0 0 0 +Gm:QTGm:QT(Gi:QT)Gx:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gi:QT)Gy:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gi:QT)Gm:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gi:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gi:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gx:QT(Gi:QT)@(QT) 0 0 0 +Gx:QT(Gi:QT)Gx:QT@(QT) 0 0 0 +Gx:QT(Gi:QT)Gy:QT@(QT) 0 0 0 +Gx:QT(Gi:QT)Gm:QT@(QT) 0 0 0 +Gx:QT(Gi:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gx:QT(Gi:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gy:QT(Gi:QT)@(QT) 0 0 0 +Gy:QT(Gi:QT)Gx:QT@(QT) 0 0 0 +Gy:QT(Gi:QT)Gy:QT@(QT) 0 0 0 +Gy:QT(Gi:QT)Gm:QT@(QT) 0 0 0 +Gy:QT(Gi:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gy:QT(Gi:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gi:QT)@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gi:QT)Gx:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gi:QT)Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gi:QT)Gm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gi:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gi:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gi:QT)@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gi:QT)Gx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gi:QT)Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gi:QT)Gm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gi:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gi:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gm:QT(Gi:QT)@(QT) 0 0 0 +Gm:QT(Gi:QT)Gx:QT@(QT) 0 0 0 +Gm:QT(Gi:QT)Gy:QT@(QT) 0 0 0 +Gm:QT(Gi:QT)Gm:QT@(QT) 0 0 0 +Gm:QT(Gi:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gm:QT(Gi:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gi:QT)@(QT) 0 0 0 +Gm:QTGx:QT(Gi:QT)Gx:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gi:QT)Gy:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gi:QT)Gm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gi:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gi:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gi:QT)@(QT) 0 0 0 +Gm:QTGy:QT(Gi:QT)Gx:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gi:QT)Gy:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gi:QT)Gm:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gi:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gi:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QT)Gx:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QT)Gy:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QT)Gm:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gx:QT(Gx:QT)Gx:QT@(QT) 0 0 0 +Gx:QT(Gx:QT)Gy:QT@(QT) 0 0 0 +Gx:QT(Gx:QT)Gm:QT@(QT) 0 0 0 +Gx:QT(Gx:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gx:QT(Gx:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gy:QT(Gx:QT)Gx:QT@(QT) 0 0 0 +Gy:QT(Gx:QT)Gy:QT@(QT) 0 0 0 +Gy:QT(Gx:QT)Gm:QT@(QT) 0 0 0 +Gy:QT(Gx:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gy:QT(Gx:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QT)Gx:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QT)Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QT)Gm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QT)Gx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QT)Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QT)Gm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gx:QT)Gx:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gx:QT)Gy:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gx:QT)Gm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gx:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gx:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QT)Gx:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QT)Gy:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QT)Gm:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gy:QT)Gx:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gy:QT)Gy:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gy:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gy:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gx:QT(Gy:QT)Gx:QT@(QT) 0 0 0 +Gx:QT(Gy:QT)Gy:QT@(QT) 0 0 0 +Gx:QT(Gy:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gx:QT(Gy:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gy:QT(Gy:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gy:QT)Gx:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gy:QT)Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gy:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gy:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gy:QT)Gx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gy:QT)Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gy:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gy:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gy:QT)Gx:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gy:QT)Gy:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gy:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gy:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gy:QT)Gx:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gy:QT)Gy:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gy:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gy:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gm:QT)Gy:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gm:QT)Gm:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gm:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gm:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gx:QT(Gm:QT)Gy:QT@(QT) 0 0 0 +Gx:QT(Gm:QT)Gm:QT@(QT) 0 0 0 +Gx:QT(Gm:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gx:QT(Gm:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gy:QT(Gm:QT)Gy:QT@(QT) 0 0 0 +Gy:QT(Gm:QT)Gm:QT@(QT) 0 0 0 +Gy:QT(Gm:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gy:QT(Gm:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gm:QT)Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gm:QT)Gm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gm:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gm:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gm:QT)Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gm:QT)Gm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gm:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gm:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gm:QT)Gy:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gm:QT)Gm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gm:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gm:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gm:QT)Gy:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gm:QT)Gm:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gm:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gm:QT)Gm:QTGx:QT@(QT) 0 0 0 +(Gi:QT)^2@(QT) 0 0 0 +(Gi:QT)^2Gx:QT@(QT) 0 0 0 +(Gi:QT)^2Gy:QT@(QT) 0 0 0 +(Gi:QT)^2Gm:QT@(QT) 0 0 0 +(Gi:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +(Gi:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gi:QT)^2@(QT) 0 0 0 +Gm:QTGm:QT(Gi:QT)^2Gx:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gi:QT)^2Gy:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gi:QT)^2Gm:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gi:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gi:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gx:QT(Gi:QT)^2@(QT) 0 0 0 +Gx:QT(Gi:QT)^2Gx:QT@(QT) 0 0 0 +Gx:QT(Gi:QT)^2Gy:QT@(QT) 0 0 0 +Gx:QT(Gi:QT)^2Gm:QT@(QT) 0 0 0 +Gx:QT(Gi:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gx:QT(Gi:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gy:QT(Gi:QT)^2@(QT) 0 0 0 +Gy:QT(Gi:QT)^2Gx:QT@(QT) 0 0 0 +Gy:QT(Gi:QT)^2Gy:QT@(QT) 0 0 0 +Gy:QT(Gi:QT)^2Gm:QT@(QT) 0 0 0 +Gy:QT(Gi:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gy:QT(Gi:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gi:QT)^2@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gi:QT)^2Gx:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gi:QT)^2Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gi:QT)^2Gm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gi:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gi:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gi:QT)^2@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gi:QT)^2Gx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gi:QT)^2Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gi:QT)^2Gm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gi:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gi:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gm:QT(Gi:QT)^2@(QT) 0 0 0 +Gm:QT(Gi:QT)^2Gx:QT@(QT) 0 0 0 +Gm:QT(Gi:QT)^2Gy:QT@(QT) 0 0 0 +Gm:QT(Gi:QT)^2Gm:QT@(QT) 0 0 0 +Gm:QT(Gi:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gm:QT(Gi:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gi:QT)^2@(QT) 0 0 0 +Gm:QTGx:QT(Gi:QT)^2Gx:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gi:QT)^2Gy:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gi:QT)^2Gm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gi:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gi:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gi:QT)^2@(QT) 0 0 0 +Gm:QTGy:QT(Gi:QT)^2Gx:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gi:QT)^2Gy:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gi:QT)^2Gm:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gi:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gi:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QT)^2Gx:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QT)^2Gy:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QT)^2Gm:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gx:QT(Gx:QT)^2Gx:QT@(QT) 0 0 0 +Gx:QT(Gx:QT)^2Gy:QT@(QT) 0 0 0 +Gx:QT(Gx:QT)^2Gm:QT@(QT) 0 0 0 +Gx:QT(Gx:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gx:QT(Gx:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gy:QT(Gx:QT)^2Gx:QT@(QT) 0 0 0 +Gy:QT(Gx:QT)^2Gy:QT@(QT) 0 0 0 +Gy:QT(Gx:QT)^2Gm:QT@(QT) 0 0 0 +Gy:QT(Gx:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gy:QT(Gx:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QT)^2Gx:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QT)^2Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QT)^2Gm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QT)^2Gx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QT)^2Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QT)^2Gm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gx:QT)^2Gx:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gx:QT)^2Gy:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gx:QT)^2Gm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gx:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gx:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QT)^2Gx:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QT)^2Gy:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QT)^2Gm:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gy:QT)^2Gx:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gy:QT)^2Gy:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gy:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gy:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gx:QT(Gy:QT)^2Gx:QT@(QT) 0 0 0 +Gx:QT(Gy:QT)^2Gy:QT@(QT) 0 0 0 +Gx:QT(Gy:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gx:QT(Gy:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gy:QT)^2Gx:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gy:QT)^2Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gy:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gy:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gy:QT)^2Gx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gy:QT)^2Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gy:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gy:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gy:QT)^2Gx:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gy:QT)^2Gy:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gy:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gy:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gy:QT)^2Gx:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gy:QT)^2Gy:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gy:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gy:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gm:QT)^2Gy:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gm:QT)^2Gm:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gm:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gm:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gx:QT(Gm:QT)^2Gy:QT@(QT) 0 0 0 +Gx:QT(Gm:QT)^2Gm:QT@(QT) 0 0 0 +Gx:QT(Gm:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gx:QT(Gm:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gy:QT(Gm:QT)^2Gy:QT@(QT) 0 0 0 +Gy:QT(Gm:QT)^2Gm:QT@(QT) 0 0 0 +Gy:QT(Gm:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gy:QT(Gm:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gm:QT)^2Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gm:QT)^2Gm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gm:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gm:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gm:QT)^2Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gm:QT)^2Gm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gm:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gm:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gm:QT)^2Gy:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gm:QT)^2Gm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gm:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gm:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gm:QT)^2Gy:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gm:QT)^2Gm:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gm:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gm:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QTGm:QT)Gy:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QTGm:QT)Gm:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QTGm:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QTGm:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gx:QT(Gx:QTGm:QT)Gy:QT@(QT) 0 0 0 +Gx:QT(Gx:QTGm:QT)Gm:QT@(QT) 0 0 0 +Gx:QT(Gx:QTGm:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gx:QT(Gx:QTGm:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gy:QT(Gx:QTGm:QT)Gy:QT@(QT) 0 0 0 +Gy:QT(Gx:QTGm:QT)Gm:QT@(QT) 0 0 0 +Gy:QT(Gx:QTGm:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gy:QT(Gx:QTGm:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QTGm:QT)Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QTGm:QT)Gm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QTGm:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QTGm:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QTGm:QT)Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QTGm:QT)Gm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QTGm:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QTGm:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gx:QTGm:QT)Gy:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gx:QTGm:QT)Gm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gx:QTGm:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gx:QTGm:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QTGm:QT)Gy:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QTGm:QT)Gm:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QTGm:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QTGm:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gy:QTGm:QT)Gy:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gy:QTGm:QT)Gm:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gy:QTGm:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gy:QTGm:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gx:QT(Gy:QTGm:QT)Gy:QT@(QT) 0 0 0 +Gx:QT(Gy:QTGm:QT)Gm:QT@(QT) 0 0 0 +Gx:QT(Gy:QTGm:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gx:QT(Gy:QTGm:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gy:QT(Gy:QTGm:QT)Gy:QT@(QT) 0 0 0 +Gy:QT(Gy:QTGm:QT)Gm:QT@(QT) 0 0 0 +Gy:QT(Gy:QTGm:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gy:QT(Gy:QTGm:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gy:QTGm:QT)Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gy:QTGm:QT)Gm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gy:QTGm:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gy:QTGm:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gy:QTGm:QT)Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gy:QTGm:QT)Gm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gy:QTGm:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gy:QTGm:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gy:QTGm:QT)Gy:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gy:QTGm:QT)Gm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gy:QTGm:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gy:QTGm:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gy:QTGm:QT)Gy:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gy:QTGm:QT)Gm:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gy:QTGm:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gy:QTGm:QT)Gm:QTGx:QT@(QT) 0 0 0 +(Gi:QT)^4@(QT) 0 0 0 +(Gi:QT)^4Gx:QT@(QT) 0 0 0 +(Gi:QT)^4Gy:QT@(QT) 0 0 0 +(Gi:QT)^4Gm:QT@(QT) 0 0 0 +(Gi:QT)^4Gy:QTGm:QT@(QT) 0 0 0 +(Gi:QT)^4Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gi:QT)^4@(QT) 0 0 0 +Gm:QTGm:QT(Gi:QT)^4Gx:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gi:QT)^4Gy:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gi:QT)^4Gm:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gi:QT)^4Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gi:QT)^4Gm:QTGx:QT@(QT) 0 0 0 +Gx:QT(Gi:QT)^4@(QT) 0 0 0 +Gx:QT(Gi:QT)^4Gx:QT@(QT) 0 0 0 +Gx:QT(Gi:QT)^4Gy:QT@(QT) 0 0 0 +Gx:QT(Gi:QT)^4Gm:QT@(QT) 0 0 0 +Gx:QT(Gi:QT)^4Gy:QTGm:QT@(QT) 0 0 0 +Gx:QT(Gi:QT)^4Gm:QTGx:QT@(QT) 0 0 0 +Gy:QT(Gi:QT)^4@(QT) 0 0 0 +Gy:QT(Gi:QT)^4Gx:QT@(QT) 0 0 0 +Gy:QT(Gi:QT)^4Gy:QT@(QT) 0 0 0 +Gy:QT(Gi:QT)^4Gm:QT@(QT) 0 0 0 +Gy:QT(Gi:QT)^4Gy:QTGm:QT@(QT) 0 0 0 +Gy:QT(Gi:QT)^4Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gi:QT)^4@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gi:QT)^4Gx:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gi:QT)^4Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gi:QT)^4Gm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gi:QT)^4Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gi:QT)^4Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gi:QT)^4@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gi:QT)^4Gx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gi:QT)^4Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gi:QT)^4Gm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gi:QT)^4Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gi:QT)^4Gm:QTGx:QT@(QT) 0 0 0 +Gm:QT(Gi:QT)^4@(QT) 0 0 0 +Gm:QT(Gi:QT)^4Gx:QT@(QT) 0 0 0 +Gm:QT(Gi:QT)^4Gy:QT@(QT) 0 0 0 +Gm:QT(Gi:QT)^4Gm:QT@(QT) 0 0 0 +Gm:QT(Gi:QT)^4Gy:QTGm:QT@(QT) 0 0 0 +Gm:QT(Gi:QT)^4Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gi:QT)^4@(QT) 0 0 0 +Gm:QTGx:QT(Gi:QT)^4Gx:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gi:QT)^4Gy:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gi:QT)^4Gm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gi:QT)^4Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gi:QT)^4Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gi:QT)^4@(QT) 0 0 0 +Gm:QTGy:QT(Gi:QT)^4Gx:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gi:QT)^4Gy:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gi:QT)^4Gm:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gi:QT)^4Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gi:QT)^4Gm:QTGx:QT@(QT) 0 0 0 +(Gx:QT)^4Gx:QT@(QT) 0 0 0 +(Gx:QT)^4Gy:QT@(QT) 0 0 0 +(Gx:QT)^4Gm:QT@(QT) 0 0 0 +(Gx:QT)^4Gy:QTGm:QT@(QT) 0 0 0 +(Gx:QT)^4Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QT)^4@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QT)^4Gx:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QT)^4Gy:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QT)^4Gm:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QT)^4Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QT)^4Gm:QTGx:QT@(QT) 0 0 0 +Gx:QT(Gx:QT)^4Gx:QT@(QT) 0 0 0 +Gx:QT(Gx:QT)^4Gy:QT@(QT) 0 0 0 +Gx:QT(Gx:QT)^4Gm:QT@(QT) 0 0 0 +Gx:QT(Gx:QT)^4Gy:QTGm:QT@(QT) 0 0 0 +Gx:QT(Gx:QT)^4Gm:QTGx:QT@(QT) 0 0 0 +Gy:QT(Gx:QT)^4@(QT) 0 0 0 +Gy:QT(Gx:QT)^4Gx:QT@(QT) 0 0 0 +Gy:QT(Gx:QT)^4Gy:QT@(QT) 0 0 0 +Gy:QT(Gx:QT)^4Gm:QT@(QT) 0 0 0 +Gy:QT(Gx:QT)^4Gy:QTGm:QT@(QT) 0 0 0 +Gy:QT(Gx:QT)^4Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QT)^4@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QT)^4Gx:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QT)^4Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QT)^4Gm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QT)^4Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QT)^4Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QT)^4@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QT)^4Gx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QT)^4Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QT)^4Gm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QT)^4Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QT)^4Gm:QTGx:QT@(QT) 0 0 0 +Gm:QT(Gx:QT)^4Gx:QT@(QT) 0 0 0 +Gm:QT(Gx:QT)^4Gy:QT@(QT) 0 0 0 +Gm:QT(Gx:QT)^4Gm:QT@(QT) 0 0 0 +Gm:QT(Gx:QT)^4Gy:QTGm:QT@(QT) 0 0 0 +Gm:QT(Gx:QT)^4Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gx:QT)^4Gx:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gx:QT)^4Gy:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gx:QT)^4Gm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gx:QT)^4Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gx:QT)^4Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QT)^4@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QT)^4Gx:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QT)^4Gy:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QT)^4Gm:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QT)^4Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QT)^4Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gy:QT)^4@(QT) 0 0 0 +Gm:QTGm:QT(Gy:QT)^4Gx:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gy:QT)^4Gy:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gy:QT)^4Gm:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gy:QT)^4Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gy:QT)^4Gm:QTGx:QT@(QT) 0 0 0 +Gx:QT(Gy:QT)^4@(QT) 0 0 0 +Gx:QT(Gy:QT)^4Gx:QT@(QT) 0 0 0 +Gx:QT(Gy:QT)^4Gy:QT@(QT) 0 0 0 +Gx:QT(Gy:QT)^4Gm:QT@(QT) 0 0 0 +Gx:QT(Gy:QT)^4Gy:QTGm:QT@(QT) 0 0 0 +Gx:QT(Gy:QT)^4Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gy:QT)^4@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gy:QT)^4Gx:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gy:QT)^4Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gy:QT)^4Gm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gy:QT)^4Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gy:QT)^4Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gy:QT)^4@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gy:QT)^4Gx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gy:QT)^4Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gy:QT)^4Gm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gy:QT)^4Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gy:QT)^4Gm:QTGx:QT@(QT) 0 0 0 +Gm:QT(Gy:QT)^4Gx:QT@(QT) 0 0 0 +Gm:QT(Gy:QT)^4Gy:QT@(QT) 0 0 0 +Gm:QT(Gy:QT)^4Gy:QTGm:QT@(QT) 0 0 0 +Gm:QT(Gy:QT)^4Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gy:QT)^4@(QT) 0 0 0 +Gm:QTGx:QT(Gy:QT)^4Gx:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gy:QT)^4Gy:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gy:QT)^4Gm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gy:QT)^4Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gy:QT)^4Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gy:QT)^4Gx:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gy:QT)^4Gy:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gy:QT)^4Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gy:QT)^4Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gm:QT)^4@(QT) 0 0 0 +Gm:QTGm:QT(Gm:QT)^4Gx:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gm:QT)^4Gy:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gm:QT)^4Gm:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gm:QT)^4Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gm:QT)^4Gm:QTGx:QT@(QT) 0 0 0 +Gx:QT(Gm:QT)^4@(QT) 0 0 0 +Gx:QT(Gm:QT)^4Gx:QT@(QT) 0 0 0 +Gx:QT(Gm:QT)^4Gy:QT@(QT) 0 0 0 +Gx:QT(Gm:QT)^4Gm:QT@(QT) 0 0 0 +Gx:QT(Gm:QT)^4Gy:QTGm:QT@(QT) 0 0 0 +Gx:QT(Gm:QT)^4Gm:QTGx:QT@(QT) 0 0 0 +Gy:QT(Gm:QT)^4@(QT) 0 0 0 +Gy:QT(Gm:QT)^4Gx:QT@(QT) 0 0 0 +Gy:QT(Gm:QT)^4Gy:QT@(QT) 0 0 0 +Gy:QT(Gm:QT)^4Gm:QT@(QT) 0 0 0 +Gy:QT(Gm:QT)^4Gy:QTGm:QT@(QT) 0 0 0 +Gy:QT(Gm:QT)^4Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gm:QT)^4@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gm:QT)^4Gx:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gm:QT)^4Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gm:QT)^4Gm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gm:QT)^4Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gm:QT)^4Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gm:QT)^4@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gm:QT)^4Gx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gm:QT)^4Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gm:QT)^4Gm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gm:QT)^4Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gm:QT)^4Gm:QTGx:QT@(QT) 0 0 0 +Gm:QT(Gm:QT)^4Gy:QT@(QT) 0 0 0 +Gm:QT(Gm:QT)^4Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gm:QT)^4@(QT) 0 0 0 +Gm:QTGx:QT(Gm:QT)^4Gx:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gm:QT)^4Gy:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gm:QT)^4Gm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gm:QT)^4Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gm:QT)^4Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gm:QT)^4@(QT) 0 0 0 +Gm:QTGy:QT(Gm:QT)^4Gx:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gm:QT)^4Gy:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gm:QT)^4Gm:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gm:QT)^4Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gm:QT)^4Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QTGy:QTGy:QT)@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QTGy:QTGy:QT)Gx:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QTGy:QTGy:QT)Gy:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QTGy:QTGy:QT)Gm:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QTGy:QTGy:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QTGy:QTGy:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gx:QT(Gx:QTGy:QTGy:QT)@(QT) 0 0 0 +Gx:QT(Gx:QTGy:QTGy:QT)Gx:QT@(QT) 0 0 0 +Gx:QT(Gx:QTGy:QTGy:QT)Gy:QT@(QT) 0 0 0 +Gx:QT(Gx:QTGy:QTGy:QT)Gm:QT@(QT) 0 0 0 +Gx:QT(Gx:QTGy:QTGy:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gx:QT(Gx:QTGy:QTGy:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gy:QT(Gx:QTGy:QTGy:QT)@(QT) 0 0 0 +Gy:QT(Gx:QTGy:QTGy:QT)Gx:QT@(QT) 0 0 0 +Gy:QT(Gx:QTGy:QTGy:QT)Gy:QT@(QT) 0 0 0 +Gy:QT(Gx:QTGy:QTGy:QT)Gm:QT@(QT) 0 0 0 +Gy:QT(Gx:QTGy:QTGy:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gy:QT(Gx:QTGy:QTGy:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QTGy:QTGy:QT)@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QTGy:QTGy:QT)Gx:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QTGy:QTGy:QT)Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QTGy:QTGy:QT)Gm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QTGy:QTGy:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QTGy:QTGy:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QTGy:QTGy:QT)@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QTGy:QTGy:QT)Gx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QTGy:QTGy:QT)Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QTGy:QTGy:QT)Gm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QTGy:QTGy:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QTGy:QTGy:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gx:QTGy:QTGy:QT)@(QT) 0 0 0 +Gm:QTGx:QT(Gx:QTGy:QTGy:QT)Gx:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gx:QTGy:QTGy:QT)Gy:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gx:QTGy:QTGy:QT)Gm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gx:QTGy:QTGy:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gx:QTGy:QTGy:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QTGy:QTGy:QT)@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QTGy:QTGy:QT)Gx:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QTGy:QTGy:QT)Gy:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QTGy:QTGy:QT)Gm:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QTGy:QTGy:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QTGy:QTGy:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gy:QTGm:QTGm:QT)Gy:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gy:QTGm:QTGm:QT)Gm:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gy:QTGm:QTGm:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gy:QTGm:QTGm:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gx:QT(Gy:QTGm:QTGm:QT)Gy:QT@(QT) 0 0 0 +Gx:QT(Gy:QTGm:QTGm:QT)Gm:QT@(QT) 0 0 0 +Gx:QT(Gy:QTGm:QTGm:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gx:QT(Gy:QTGm:QTGm:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gy:QT(Gy:QTGm:QTGm:QT)Gy:QT@(QT) 0 0 0 +Gy:QT(Gy:QTGm:QTGm:QT)Gm:QT@(QT) 0 0 0 +Gy:QT(Gy:QTGm:QTGm:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gy:QT(Gy:QTGm:QTGm:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gy:QTGm:QTGm:QT)Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gy:QTGm:QTGm:QT)Gm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gy:QTGm:QTGm:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gy:QTGm:QTGm:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gy:QTGm:QTGm:QT)Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gy:QTGm:QTGm:QT)Gm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gy:QTGm:QTGm:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gy:QTGm:QTGm:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gy:QTGm:QTGm:QT)Gy:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gy:QTGm:QTGm:QT)Gm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gy:QTGm:QTGm:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gy:QTGm:QTGm:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gy:QTGm:QTGm:QT)Gy:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gy:QTGm:QTGm:QT)Gm:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gy:QTGm:QTGm:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gy:QTGm:QTGm:QT)Gm:QTGx:QT@(QT) 0 0 0 +(Gx:QTGm:QT)^2@(QT) 0 0 0 +(Gx:QTGm:QT)^2Gx:QT@(QT) 0 0 0 +(Gx:QTGm:QT)^2Gy:QT@(QT) 0 0 0 +(Gx:QTGm:QT)^2Gm:QT@(QT) 0 0 0 +(Gx:QTGm:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +(Gx:QTGm:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QTGm:QT)^2@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QTGm:QT)^2Gx:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QTGm:QT)^2Gy:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QTGm:QT)^2Gm:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QTGm:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QTGm:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gx:QT(Gx:QTGm:QT)^2@(QT) 0 0 0 +Gx:QT(Gx:QTGm:QT)^2Gx:QT@(QT) 0 0 0 +Gx:QT(Gx:QTGm:QT)^2Gy:QT@(QT) 0 0 0 +Gx:QT(Gx:QTGm:QT)^2Gm:QT@(QT) 0 0 0 +Gx:QT(Gx:QTGm:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gx:QT(Gx:QTGm:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gy:QT(Gx:QTGm:QT)^2@(QT) 0 0 0 +Gy:QT(Gx:QTGm:QT)^2Gx:QT@(QT) 0 0 0 +Gy:QT(Gx:QTGm:QT)^2Gy:QT@(QT) 0 0 0 +Gy:QT(Gx:QTGm:QT)^2Gm:QT@(QT) 0 0 0 +Gy:QT(Gx:QTGm:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gy:QT(Gx:QTGm:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QTGm:QT)^2@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QTGm:QT)^2Gx:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QTGm:QT)^2Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QTGm:QT)^2Gm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QTGm:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QTGm:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QTGm:QT)^2@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QTGm:QT)^2Gx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QTGm:QT)^2Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QTGm:QT)^2Gm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QTGm:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QTGm:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gm:QT(Gx:QTGm:QT)^2@(QT) 0 0 0 +Gm:QT(Gx:QTGm:QT)^2Gx:QT@(QT) 0 0 0 +Gm:QT(Gx:QTGm:QT)^2Gy:QT@(QT) 0 0 0 +Gm:QT(Gx:QTGm:QT)^2Gm:QT@(QT) 0 0 0 +Gm:QT(Gx:QTGm:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gm:QT(Gx:QTGm:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gx:QTGm:QT)^2@(QT) 0 0 0 +Gm:QTGx:QT(Gx:QTGm:QT)^2Gx:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gx:QTGm:QT)^2Gy:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gx:QTGm:QT)^2Gm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gx:QTGm:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gx:QTGm:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QTGm:QT)^2@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QTGm:QT)^2Gx:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QTGm:QT)^2Gy:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QTGm:QT)^2Gm:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QTGm:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QTGm:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +(Gx:QTGm:QTGy:QT)Gx:QT@(QT) 0 0 0 +(Gx:QTGm:QTGy:QT)Gy:QT@(QT) 0 0 0 +(Gx:QTGm:QTGy:QT)Gy:QTGm:QT@(QT) 0 0 0 +(Gx:QTGm:QTGy:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QTGm:QTGy:QT)Gx:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QTGm:QTGy:QT)Gy:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QTGm:QTGy:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gx:QTGm:QTGy:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gx:QT(Gx:QTGm:QTGy:QT)Gx:QT@(QT) 0 0 0 +Gx:QT(Gx:QTGm:QTGy:QT)Gy:QT@(QT) 0 0 0 +Gx:QT(Gx:QTGm:QTGy:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gx:QT(Gx:QTGm:QTGy:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gy:QT(Gx:QTGm:QTGy:QT)Gx:QT@(QT) 0 0 0 +Gy:QT(Gx:QTGm:QTGy:QT)Gy:QT@(QT) 0 0 0 +Gy:QT(Gx:QTGm:QTGy:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gy:QT(Gx:QTGm:QTGy:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QTGm:QTGy:QT)Gx:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QTGm:QTGy:QT)Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QTGm:QTGy:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gx:QTGm:QTGy:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QTGm:QTGy:QT)Gx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QTGm:QTGy:QT)Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QTGm:QTGy:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gx:QTGm:QTGy:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gm:QT(Gx:QTGm:QTGy:QT)Gx:QT@(QT) 0 0 0 +Gm:QT(Gx:QTGm:QTGy:QT)Gy:QT@(QT) 0 0 0 +Gm:QT(Gx:QTGm:QTGy:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gm:QT(Gx:QTGm:QTGy:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gx:QTGm:QTGy:QT)Gx:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gx:QTGm:QTGy:QT)Gy:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gx:QTGm:QTGy:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gx:QTGm:QTGy:QT)Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QTGm:QTGy:QT)Gx:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QTGm:QTGy:QT)Gy:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QTGm:QTGy:QT)Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gx:QTGm:QTGy:QT)Gm:QTGx:QT@(QT) 0 0 0 +(Gy:QTGm:QT)^2Gx:QT@(QT) 0 0 0 +(Gy:QTGm:QT)^2Gy:QT@(QT) 0 0 0 +(Gy:QTGm:QT)^2Gm:QT@(QT) 0 0 0 +(Gy:QTGm:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +(Gy:QTGm:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gy:QTGm:QT)^2Gx:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gy:QTGm:QT)^2Gy:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gy:QTGm:QT)^2Gm:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gy:QTGm:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGm:QT(Gy:QTGm:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gx:QT(Gy:QTGm:QT)^2Gx:QT@(QT) 0 0 0 +Gx:QT(Gy:QTGm:QT)^2Gy:QT@(QT) 0 0 0 +Gx:QT(Gy:QTGm:QT)^2Gm:QT@(QT) 0 0 0 +Gx:QT(Gy:QTGm:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gx:QT(Gy:QTGm:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gy:QT(Gy:QTGm:QT)^2Gx:QT@(QT) 0 0 0 +Gy:QT(Gy:QTGm:QT)^2Gy:QT@(QT) 0 0 0 +Gy:QT(Gy:QTGm:QT)^2Gm:QT@(QT) 0 0 0 +Gy:QT(Gy:QTGm:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gy:QT(Gy:QTGm:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gy:QTGm:QT)^2Gx:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gy:QTGm:QT)^2Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gy:QTGm:QT)^2Gm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gy:QTGm:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGx:QT(Gy:QTGm:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gy:QTGm:QT)^2Gx:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gy:QTGm:QT)^2Gy:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gy:QTGm:QT)^2Gm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gy:QTGm:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gy:QTGy:QTGy:QT(Gy:QTGm:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gm:QT(Gy:QTGm:QT)^2Gx:QT@(QT) 0 0 0 +Gm:QT(Gy:QTGm:QT)^2Gy:QT@(QT) 0 0 0 +Gm:QT(Gy:QTGm:QT)^2Gm:QT@(QT) 0 0 0 +Gm:QT(Gy:QTGm:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gm:QT(Gy:QTGm:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gy:QTGm:QT)^2Gx:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gy:QTGm:QT)^2Gy:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gy:QTGm:QT)^2Gm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gy:QTGm:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGx:QT(Gy:QTGm:QT)^2Gm:QTGx:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gy:QTGm:QT)^2Gx:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gy:QTGm:QT)^2Gy:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gy:QTGm:QT)^2Gm:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gy:QTGm:QT)^2Gy:QTGm:QT@(QT) 0 0 0 +Gm:QTGy:QT(Gy:QTGm:QT)^2Gm:QTGx:QT@(QT) 0 0 0 diff --git a/jupyter_notebooks/Tutorials/00-Protocols.ipynb b/jupyter_notebooks/Tutorials/00-Protocols.ipynb index 0efa74c5f..a6be34b77 100644 --- a/jupyter_notebooks/Tutorials/00-Protocols.ipynb +++ b/jupyter_notebooks/Tutorials/00-Protocols.ipynb @@ -67,10 +67,10 @@ "metadata": {}, "outputs": [], "source": [ - "from pygsti.modelpacks import smq1Q_XYI\n", + "from pygsti.modelpacks import smq1Q_XY\n", "\n", "# get experiment design\n", - "exp_design = smq1Q_XYI.create_gst_experiment_design(max_max_length=32) \n", + "exp_design = smq1Q_XY.create_gst_experiment_design(max_max_length=316) \n", "\n", "# write an empty data object (creates a template to fill in)\n", "pygsti.io.write_empty_protocol_data('tutorial_files/test_gst_dir', exp_design, clobber_ok=True)\n", @@ -78,7 +78,7 @@ "# fill in the template with simulated data (you would run the experiment and use actual data)\n", "pygsti.io.fill_in_empty_dataset_with_fake_data(\n", " \"tutorial_files/test_gst_dir/data/dataset.txt\",\n", - " smq1Q_XYI.target_model().depolarize(op_noise=0.01, spam_noise=0.001),\n", + " smq1Q_XY.target_model().depolarize(op_noise=0.01, spam_noise=0.001),\n", " num_samples=1000, seed=1234)\n", "\n", "# load the data object back in, now with the experimental data\n", @@ -106,7 +106,7 @@ "metadata": {}, "source": [ "## Randomized benchmarking\n", - "Randomized benchmarking (RB) can be used to estimate the average per-Clifford error rate by fitting a simple curve to the data from randomized circuits of different depths. To create the experiment design, the user specifies a `QubitProcessorSpec` object that describes the quantum processor (see the [ProcessorSpec tutorial](objects/ProcessorSpec.pynb), the depths (in number of Clifford gates) to use, and the number of circuits at each depth. The results from running the protocol are then used to create a plot of the RB decay curve along with the data. For more information, see the [RB Overview tutorial](algorithms/RB-Overview.ipynb)." + "Randomized benchmarking (RB) can be used to estimate the average per-Clifford error rate by fitting a simple curve to the data from randomized circuits of different depths. To create the experiment design, the user specifies a `QubitProcessorSpec` object that describes the quantum processor (see the [ProcessorSpec tutorial](objects/ProcessorSpec.pynb)), the depths (in number of Clifford gates) to use, and the number of circuits at each depth. The results from running the protocol are then used to create a plot of the RB decay curve along with the data. For more information, see the [RB Overview tutorial](algorithms/RB-Overview.ipynb)." ] }, { @@ -230,16 +230,16 @@ "outputs": [], "source": [ "# An experiment design\n", - "from pygsti.modelpacks import smq1Q_Xpi2_rpe, smq1Q_XYI\n", + "from pygsti.modelpacks import smq1Q_Xpi2_rpe, smq1Q_XY\n", "exp_design = smq1Q_Xpi2_rpe.create_rpe_experiment_design(max_max_length=64)\n", "\n", "# write an empty data object (creates a template to fill in)\n", - "pygsti.io.write_empty_protocol_data(exp_design, 'tutorial_files/test_rpe_dir', clobber_ok=True)\n", + "pygsti.io.write_empty_protocol_data('tutorial_files/test_rpe_dir', exp_design, clobber_ok=True)\n", "\n", "# fill in the template with simulated data (you would run the experiment and use actual data)\n", "pygsti.io.fill_in_empty_dataset_with_fake_data(\n", " \"tutorial_files/test_rpe_dir/data/dataset.txt\",\n", - " smq1Q_XYI.target_model().depolarize(op_noise=0.01, spam_noise=0.1),\n", + " smq1Q_XY.target_model().depolarize(op_noise=0.01, spam_noise=0.1),\n", " num_samples=1000, seed=1234)\n", "\n", "# read the data object back in, now with the experimental data\n", @@ -273,12 +273,12 @@ "metadata": {}, "outputs": [], "source": [ - "from pygsti.modelpacks import smq1Q_XYI\n", - "exp_design = smq1Q_XYI.create_gst_experiment_design(max_max_length=4)\n", + "from pygsti.modelpacks import smq1Q_XY\n", + "exp_design = smq1Q_XY.create_gst_experiment_design(max_max_length=4)\n", "pygsti.io.write_empty_protocol_data('tutorial_files/test_drift_dir', exp_design, clobber_ok=True)\n", "\n", "# Simulate time dependent data (right now, this just uses a time-independent model so this is uninteresting) \n", - "datagen_model = smq1Q_XYI.target_model().depolarize(op_noise=0.05, spam_noise=0.1)\n", + "datagen_model = smq1Q_XY.target_model().depolarize(op_noise=0.05, spam_noise=0.1)\n", "datagen_model.sim = \"map\" # only map-type can generate time-dep data\n", " # can also construct this as target_model(simulator=\"map\") above\n", "pygsti.io.fill_in_empty_dataset_with_fake_data('tutorial_files/test_drift_dir/data/dataset.txt',\n", @@ -318,7 +318,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -332,9 +332,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.9.13" } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 4 } diff --git a/jupyter_notebooks/Tutorials/01-Essential-Objects.ipynb b/jupyter_notebooks/Tutorials/01-Essential-Objects.ipynb index d00d5ea52..86ca9d820 100644 --- a/jupyter_notebooks/Tutorials/01-Essential-Objects.ipynb +++ b/jupyter_notebooks/Tutorials/01-Essential-Objects.ipynb @@ -343,7 +343,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Another thing to note is that `DataSet` objects are \"sparse\" in that 0-counts are not typically stored:" + "Another thing to note is that `DataSet` objects can be made \"sparse\" by dropping 0-counts:" ] }, { @@ -352,9 +352,33 @@ "metadata": {}, "outputs": [], "source": [ + "ds_sparse = ds_fake.drop_zero_counts()\n", + "\n", "c = Circuit([('Gxpi2',0)], line_labels=(0,1))\n", "print(\"No 01 or 11 outcomes here: \",ds_fake[c])\n", - "for outlbl, cnt in ds_fake[c].counts.items():\n", + "for outlbl, cnt in ds_sparse[c].counts.items():\n", + " print(\"Item: \",outlbl, cnt) # Note: this loop never loops over 01 or 11!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this case, simulated `Datasets` can be initialized to always drop 0-counts also:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ds_sparse2 = pygsti.data.simulate_data(mdl, circuit_list, num_samples=100,\n", + " sample_error='multinomial', seed=8675309,\n", + " record_zero_counts=False)\n", + "\n", + "\n", + "for outlbl, cnt in ds_sparse2[c].counts.items():\n", " print(\"Item: \",outlbl, cnt) # Note: this loop never loops over 01 or 11!" ] }, @@ -411,7 +435,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.11.5" } }, "nbformat": 4, diff --git a/jupyter_notebooks/Tutorials/02-Using-Essential-Objects.ipynb b/jupyter_notebooks/Tutorials/02-Using-Essential-Objects.ipynb index e96a87832..e7ffd7e12 100644 --- a/jupyter_notebooks/Tutorials/02-Using-Essential-Objects.ipynb +++ b/jupyter_notebooks/Tutorials/02-Using-Essential-Objects.ipynb @@ -210,7 +210,7 @@ "metadata": {}, "source": [ "## Randomized Benchmarking (RB)\n", - "PyGSTi is able to perform two types of Randomized Benchmarking (RB). First, there is the [standard Clifford-circuit-based RB](http://journals.aps.org/prl/abstract/10.1103/PhysRevLett.106.180504) protocol first defined by Magesan et al. Second, there is [\"Direct RB\"](https://arxiv.org/abs/1807.07975), which is particularly suited to multi-qubit benchmarking. More more details on using these protocols (e.g. how to generate a set of RB sequences) see the separate [RB overview tutorial](algorithms/RB-Overview.ipynb) and related tutorials." + "PyGSTi is able to perform two types of Randomized Benchmarking (RB). First, there is the [standard Clifford-circuit-based RB](http://journals.aps.org/prl/abstract/10.1103/PhysRevLett.106.180504) protocol first defined by Magesan et al. Second, there is [\"Direct RB\"](https://arxiv.org/abs/1807.07975), which is particularly suited to multi-qubit benchmarking. More details on using these protocols (e.g. how to generate a set of RB sequences) see the separate [RB overview tutorial](algorithms/RB-Overview.ipynb) and related tutorials." ] }, { diff --git a/jupyter_notebooks/Tutorials/algorithms/DriftCharacterization.ipynb b/jupyter_notebooks/Tutorials/algorithms/DriftCharacterization.ipynb index 7054552d4..d91c2d464 100644 --- a/jupyter_notebooks/Tutorials/algorithms/DriftCharacterization.ipynb +++ b/jupyter_notebooks/Tutorials/algorithms/DriftCharacterization.ipynb @@ -31,7 +31,7 @@ "metadata": {}, "source": [ "## Quick and Easy Analysis\n", - "First we import some *time-stamped* data. For more information on the mechanics of using time-stamped `DataSets` see the [TimestampedDataSets](../objects/advanced/TimestampedDataSets.ipynb) tutorial. The data we are importing is from long-sequence GST on $G_i$, $G_x$, and $G_y$ with time-dependent coherent errors on the gates.\n", + "First we import some *time-stamped* data. For more information on the mechanics of using time-stamped `DataSets` see the [TimestampedDataSets](../objects/advanced/TimestampedDataSets.ipynb) tutorial. The data we are importing is from long-sequence GST on $G_x$, and $G_y$ with time-dependent coherent errors on the gates.\n", "\n", "We load the time-dependent data from the `timestamped_dataset.txt` file included with pyGSTi, and then build a `ProtocolData` object out of it so it can be used as input for `Protocol` objects. We can pass `None` as the experiment design when constructing `data` because the stability analysis doesn't require any special structure to the circuits - it just requires the data to have timestamps." ] @@ -46,21 +46,25 @@ "\n", "# Construct a basic ExplicitModel for the experiment design\n", "model = pygsti.models.create_explicit_model_from_expressions(\n", - " ['Q0'], ['Gi','Gx','Gy'],\n", - " [ \"I(Q0)\",\"X(pi/2,Q0)\", \"Y(pi/2,Q0)\"] )\n", + " ['Q0'], ['Gx','Gy'],\n", + " [ \"X(pi/2,Q0)\", \"Y(pi/2,Q0)\"] )\n", "\n", "# This manually specifies the germ and fiducial structure for the imported data.\n", - "fiducial_strs = ['{}','Gx','Gy','GxGx','GxGxGx','GyGyGy']\n", - "germ_strs = ['Gi','Gx','Gy','GxGy','GxGyGi','GxGiGy','GxGiGi','GyGiGi','GxGxGiGy','GxGyGyGi','GxGxGyGxGyGy']\n", - "log2maxL = 9 # log2 of the maximum germ power\n", + "prep_fiducials = ['{}','Gx','Gy','GxGx']\n", + "meas_fiducials = ['{}','Gx','Gy']\n", + "\n", + "germ_strs = ['Gx','Gy','GxGy','GxGxGyGxGyGy']\n", + "log2maxL = 7 # log2 of the maximum germ power\n", "\n", "# Below we use the maxlength, germ and fiducial lists to create the GST structures needed for box plots.\n", - "fiducials = [pygsti.circuits.Circuit(fs) for fs in fiducial_strs]\n", + "prep_fiducials = [pygsti.circuits.Circuit(fs) for fs in prep_fiducials]\n", + "meas_fiducials = [pygsti.circuits.Circuit(fs) for fs in meas_fiducials]\n", "germs = [pygsti.circuits.Circuit(g) for g in germ_strs]\n", - "max_lengths = [2**i for i in range(0,log2maxL)]\n", - "exp_design = pygsti.protocols.StandardGSTDesign(model, fiducials, fiducials, germs, max_lengths)\n", + "max_lengths = [2**i for i in range(0,log2maxL+1)]\n", + "exp_design = pygsti.protocols.StandardGSTDesign(model, prep_fiducials, meas_fiducials, germs, max_lengths)\n", "\n", "ds = pygsti.io.load_dataset(\"../tutorial_files/timestamped_dataset.txt\") # a DataSet\n", + "ds = ds.truncate(list(exp_design.all_circuits_needing_data))\n", "data = pygsti.protocols.ProtocolData(exp_design, ds)" ] }, @@ -77,6 +81,7 @@ "metadata": {}, "outputs": [], "source": [ + "%%time\n", "protocol = pygsti.protocols.StabilityAnalysis()\n", "results = protocol.run(data)" ] @@ -106,6 +111,13 @@ "print(results.stabilityanalyzer)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "NOTE: In notebook display of report figures does not work in jupyterlab due to restrictions on running javascript. Please use classic jupyter notebook if this is desired." + ] + }, { "cell_type": "code", "execution_count": null, @@ -166,7 +178,7 @@ "metadata": {}, "outputs": [], "source": [ - "spectrumlabel = {'circuit':pygsti.circuits.Circuit('Gx(Gi)^128')}\n", + "spectrumlabel = {'circuit':pygsti.circuits.Circuit('(Gx)^128')}\n", "print(\"significant frequencies: \", results.instability_frequencies(spectrumlabel))\n", "w.PowerSpectraPlot(results, spectrumlabel)" ] @@ -205,7 +217,7 @@ "metadata": {}, "outputs": [], "source": [ - "circuits = {L: pygsti.circuits.Circuit(None,stringrep='Gx(Gi)^'+str(L)+'Gx') for L in [1,2,4,16,64,128,256]}\n", + "circuits = {L: pygsti.circuits.Circuit(None,stringrep='Gx(Gx)^'+str(L)+'Gx') for L in [1,2,4,16,64,128]}\n", "w.PowerSpectraPlot(results, {'circuit':circuits}, showlegend=True)" ] }, @@ -221,12 +233,10 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "scrolled": false - }, + "metadata": {}, "outputs": [], "source": [ - "circuit = pygsti.circuits.Circuit(None, stringrep= 'Gx(Gi)^256GxGxGx')\n", + "circuit = pygsti.circuits.Circuit(None, stringrep= 'Gx(Gx)^128Gx')\n", "w.ProbTrajectoriesPlot(results.stabilityanalyzer, circuit, ('1',))" ] }, @@ -281,8 +291,8 @@ "metadata": {}, "outputs": [], "source": [ - "w.GermFiducialPowerSpectraPlot(results, 'Gy', 'Gi', 'Gx', showlegend=True)\n", - "w.GermFiducialProbTrajectoriesPlot(results, 'Gy', 'Gi', 'Gx', ('0',), showlegend=True)" + "w.GermFiducialPowerSpectraPlot(results, 'Gy', 'Gx', 'Gx', showlegend=True)\n", + "w.GermFiducialProbTrajectoriesPlot(results, 'Gy', 'Gx', 'Gx', ('0',), showlegend=True)" ] }, { @@ -298,8 +308,8 @@ "metadata": {}, "outputs": [], "source": [ - "circuits256 = exp_design.circuit_lists[-1] # Pull out circuits up to max L (256)\n", - "w.ColorBoxPlot('driftdetector', circuits256, None, None, stabilityanalyzer=results.stabilityanalyzer)" + "circuits128 = exp_design.circuit_lists[-1] # Pull out circuits up to max L\n", + "w.ColorBoxPlot('driftdetector', circuits128, None, None, stabilityanalyzer=results.stabilityanalyzer)" ] }, { @@ -318,7 +328,7 @@ "outputs": [], "source": [ "# Create a boxplot of the maximum power in the power spectra for each sequence.\n", - "w.ColorBoxPlot('driftsize', circuits256, None, None, stabilityanalyzer=results.stabilityanalyzer)" + "w.ColorBoxPlot('driftsize', circuits128, None, None, stabilityanalyzer=results.stabilityanalyzer)" ] }, { @@ -348,9 +358,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "api_updates", "language": "python", - "name": "python3" + "name": "api_updates" }, "language_info": { "codemirror_mode": { @@ -362,9 +372,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.9.13" } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 4 } diff --git a/jupyter_notebooks/Tutorials/algorithms/GST-Driverfunctions.ipynb b/jupyter_notebooks/Tutorials/algorithms/GST-Driverfunctions.ipynb index 337b37600..59a91563c 100644 --- a/jupyter_notebooks/Tutorials/algorithms/GST-Driverfunctions.ipynb +++ b/jupyter_notebooks/Tutorials/algorithms/GST-Driverfunctions.ipynb @@ -37,7 +37,7 @@ "metadata": {}, "source": [ "### Setup\n", - "First, we set our desired *target model* to be the standard $I$, $X(\\pi/2)$, $Y(\\pi/2)$ model that we've been using in many of these tutorials, and use the standard fiducial and germ sequences needed to generate the GST operation sequences (see the [standard module tutorial](../objects/advanced/StandardModules.ipynb)). We also specify a list of maximum lengths. We'll analyze the simulated data generated in the [DataSet tutorial](../objects/DataSet.ipynb), so you'll need to run that tutorial if you haven't already." + "First, we set our desired *target model* to be the standard $X(\\pi/2)$, $Y(\\pi/2)$ model that we've been using in many of these tutorials, and use the standard fiducial and germ sequences needed to generate the GST operation sequences (see the [standard module tutorial](../objects/advanced/StandardModules.ipynb)). We also specify a list of maximum lengths. We'll analyze the simulated data generated in the [DataSet tutorial](../objects/DataSet.ipynb), so you'll need to run that tutorial if you haven't already." ] }, { @@ -64,12 +64,12 @@ } ], "source": [ - "from pygsti.modelpacks import smq1Q_XYI\n", - "target_model = smq1Q_XYI.target_model()\n", - "prep_fiducials, meas_fiducials = smq1Q_XYI.prep_fiducials(), smq1Q_XYI.meas_fiducials()\n", - "germs = smq1Q_XYI.germs()\n", + "from pygsti.modelpacks import smq1Q_XY\n", + "target_model = smq1Q_XY.target_model()\n", + "prep_fiducials, meas_fiducials = smq1Q_XY.prep_fiducials(), smq1Q_XY.meas_fiducials()\n", + "germs = smq1Q_XY.germs()\n", "\n", - "maxLengths = [1,2,4,8,16,32]\n", + "maxLengths = [1,2,4,8,16]\n", "\n", "ds = pygsti.io.load_dataset(\"../tutorial_files/Example_Dataset.txt\", cache=True)" ] @@ -258,7 +258,7 @@ "outputs": [], "source": [ "my_goparams = { 'item_weights': {'gates': 1.0, 'spam': 0.001} }\n", - "my_gaugeOptTarget= smq1Q_XYI.target_model('full TP')\n", + "my_gaugeOptTarget= smq1Q_XY.target_model('full TP')\n", "my_gaugeOptTarget = my_gaugeOptTarget.depolarize(op_noise=0.005, spam_noise=0.01) # a guess at what estimate should be\n", "results_stdprac_customgo = pygsti.run_stdpractice_gst(\n", " ds, target_model, prep_fiducials, meas_fiducials, germs, maxLengths,\n", diff --git a/jupyter_notebooks/Tutorials/algorithms/GST-Overview-functionbased.ipynb b/jupyter_notebooks/Tutorials/algorithms/GST-Overview-functionbased.ipynb index fd8ef5b49..c96a89922 100644 --- a/jupyter_notebooks/Tutorials/algorithms/GST-Overview-functionbased.ipynb +++ b/jupyter_notebooks/Tutorials/algorithms/GST-Overview-functionbased.ipynb @@ -15,7 +15,7 @@ "\n", "To run GST, we need three inputs:\n", "1. a \"**target model**\" which describes the desired, or ideal, operations we want our experimental hardware to perform. In the example below, we use one of pyGSTi's build-in \"model packs\" (see the [tutorial on model packs](objects/advanced/ModelPacks.ipynb)) - which acts on a single qubit with the following operations:\n", - " - three gates: the identity, and $\\pi/2$ rotations around the $x$- and $y$-axes.\n", + " - two gates: $\\pi/2$ rotations around the $x$- and $y$-axes.\n", " - a single state preparation in the $|0\\rangle$ state.\n", " - a 2-outcome measurement with the label \"0\" associated with measuring $|0\\rangle$ and \"1\" with measuring $|1\\rangle$.\n", " \n", @@ -26,21 +26,21 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#Import the pygsti module (always do this) and the XYI model pack\n", "import pygsti\n", - "from pygsti.modelpacks import smq1Q_XYI\n", + "from pygsti.modelpacks import smq1Q_XY\n", "\n", "# 1) get the target Model\n", - "target_model = smq1Q_XYI.target_model()\n", + "target_model = smq1Q_XY.target_model()\n", "\n", "# 2) get the building blocks needed to specify which operation sequences are needed\n", - "prep_fiducials, meas_fiducials = smq1Q_XYI.prep_fiducials(), smq1Q_XYI.meas_fiducials()\n", - "germs = smq1Q_XYI.germs()\n", - "maxLengths = [1,2,4,8,16,32] # roughly gives the length of the sequences used by GST\n", + "prep_fiducials, meas_fiducials = smq1Q_XY.prep_fiducials(), smq1Q_XY.meas_fiducials()\n", + "germs = smq1Q_XY.germs()\n", + "maxLengths = [1,2,4,8,16] # roughly gives the length of the sequences used by GST\n", "\n", "# 3) generate \"fake\" data from a depolarized version of target_model\n", "mdl_datagen = target_model.depolarize(op_noise=0.01, spam_noise=0.001)\n", @@ -68,217 +68,11 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": { "scrolled": true }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "--- Circuit Creation ---\n", - " 784 circuits created\n", - " Dataset has 784 entries: 784 utilized, 0 requested circuits were missing\n", - "-- Std Practice: Iter 1 of 3 (full TP) --: \n", - " --- Iterative GST: Iter 1 of 6 92 circuits ---: \n", - " MatrixLayout: 1 processors divided into 1 x 1 (= 1) grid along circuit and parameter directions.\n", - " 1 atoms, parameter block size limits (None,)\n", - " *** Distributing 1 atoms to 1 atom-processing groups (1 cores) ***\n", - " More atom-processors than hosts: each host gets ~1 atom-processors\n", - " Atom-processors already occupy a single node, dividing atom-processor into 1 param-processors.\n", - " *** Divided 1-host atom-processor (~1 procs) into 1 param-processing groups ***\n", - " --- chi2 GST ---\n", - " Sum of Chi^2 = 80.4914 (92 data params - 43 (approx) model params = expected mean of 49; p-value = 0.00305059)\n", - " Completed in 0.3s\n", - " Iteration 1 took 0.3s\n", - " \n", - " --- Iterative GST: Iter 2 of 6 168 circuits ---: \n", - " MatrixLayout: 1 processors divided into 1 x 1 (= 1) grid along circuit and parameter directions.\n", - " 1 atoms, parameter block size limits (None,)\n", - " *** Distributing 1 atoms to 1 atom-processing groups (1 cores) ***\n", - " More atom-processors than hosts: each host gets ~1 atom-processors\n", - " Atom-processors already occupy a single node, dividing atom-processor into 1 param-processors.\n", - " *** Divided 1-host atom-processor (~1 procs) into 1 param-processing groups ***\n", - " --- chi2 GST ---\n", - " Sum of Chi^2 = 147.984 (168 data params - 43 (approx) model params = expected mean of 125; p-value = 0.0785975)\n", - " Completed in 0.2s\n", - " Iteration 2 took 0.3s\n", - " \n", - " --- Iterative GST: Iter 3 of 6 285 circuits ---: \n", - " MatrixLayout: 1 processors divided into 1 x 1 (= 1) grid along circuit and parameter directions.\n", - " 1 atoms, parameter block size limits (None,)\n", - " *** Distributing 1 atoms to 1 atom-processing groups (1 cores) ***\n", - " More atom-processors than hosts: each host gets ~1 atom-processors\n", - " Atom-processors already occupy a single node, dividing atom-processor into 1 param-processors.\n", - " *** Divided 1-host atom-processor (~1 procs) into 1 param-processing groups ***\n", - " --- chi2 GST ---\n", - " Sum of Chi^2 = 263.377 (285 data params - 43 (approx) model params = expected mean of 242; p-value = 0.16489)\n", - " Completed in 0.3s\n", - " Iteration 3 took 0.4s\n", - " \n", - " --- Iterative GST: Iter 4 of 6 448 circuits ---: \n", - " MatrixLayout: 1 processors divided into 1 x 1 (= 1) grid along circuit and parameter directions.\n", - " 1 atoms, parameter block size limits (None,)\n", - " *** Distributing 1 atoms to 1 atom-processing groups (1 cores) ***\n", - " More atom-processors than hosts: each host gets ~1 atom-processors\n", - " Atom-processors already occupy a single node, dividing atom-processor into 1 param-processors.\n", - " *** Divided 1-host atom-processor (~1 procs) into 1 param-processing groups ***\n", - " --- chi2 GST ---\n", - " Sum of Chi^2 = 402.715 (448 data params - 43 (approx) model params = expected mean of 405; p-value = 0.522733)\n", - " Completed in 0.3s\n", - " Iteration 4 took 0.5s\n", - " \n", - " --- Iterative GST: Iter 5 of 6 616 circuits ---: \n", - " MatrixLayout: 1 processors divided into 1 x 1 (= 1) grid along circuit and parameter directions.\n", - " 1 atoms, parameter block size limits (None,)\n", - " *** Distributing 1 atoms to 1 atom-processing groups (1 cores) ***\n", - " More atom-processors than hosts: each host gets ~1 atom-processors\n", - " Atom-processors already occupy a single node, dividing atom-processor into 1 param-processors.\n", - " *** Divided 1-host atom-processor (~1 procs) into 1 param-processing groups ***\n", - " --- chi2 GST ---\n", - " Sum of Chi^2 = 574.5 (616 data params - 43 (approx) model params = expected mean of 573; p-value = 0.474504)\n", - " Completed in 0.4s\n", - " Iteration 5 took 0.7s\n", - " \n", - " --- Iterative GST: Iter 6 of 6 784 circuits ---: \n", - " MatrixLayout: 1 processors divided into 1 x 1 (= 1) grid along circuit and parameter directions.\n", - " 1 atoms, parameter block size limits (None,)\n", - " *** Distributing 1 atoms to 1 atom-processing groups (1 cores) ***\n", - " More atom-processors than hosts: each host gets ~1 atom-processors\n", - " Atom-processors already occupy a single node, dividing atom-processor into 1 param-processors.\n", - " *** Divided 1-host atom-processor (~1 procs) into 1 param-processing groups ***\n", - " --- chi2 GST ---\n", - " Sum of Chi^2 = 731.437 (784 data params - 43 (approx) model params = expected mean of 741; p-value = 0.591788)\n", - " Completed in 0.5s\n", - " Iteration 6 took 0.9s\n", - " \n", - " Last iteration:\n", - " --- dlogl GST ---\n", - " 2*Delta(log(L)) = 733.924 (784 data params - 43 (approx) model params = expected mean of 741; p-value = 0.566338)\n", - " Completed in 1.5s\n", - " Final optimization took 1.6s\n", - " \n", - " Iterative GST Total Time: 4.7s\n", - "-- Std Practice: Iter 2 of 3 (CPTP) --: \n", - " --- Iterative GST: Iter 1 of 6 92 circuits ---: \n", - " MatrixLayout: 1 processors divided into 1 x 1 (= 1) grid along circuit and parameter directions.\n", - " 1 atoms, parameter block size limits (None,)\n", - " *** Distributing 1 atoms to 1 atom-processing groups (1 cores) ***\n", - " More atom-processors than hosts: each host gets ~1 atom-processors\n", - " Atom-processors already occupy a single node, dividing atom-processor into 1 param-processors.\n", - " *** Divided 1-host atom-processor (~1 procs) into 1 param-processing groups ***\n", - " --- chi2 GST ---\n", - " Sum of Chi^2 = 83.4926 (92 data params - 60 (approx) model params = expected mean of 32; p-value = 1.76926e-06)\n", - " Completed in 7.2s\n", - " Iteration 1 took 7.2s\n", - " \n", - " --- Iterative GST: Iter 2 of 6 168 circuits ---: \n", - " MatrixLayout: 1 processors divided into 1 x 1 (= 1) grid along circuit and parameter directions.\n", - " 1 atoms, parameter block size limits (None,)\n", - " *** Distributing 1 atoms to 1 atom-processing groups (1 cores) ***\n", - " More atom-processors than hosts: each host gets ~1 atom-processors\n", - " Atom-processors already occupy a single node, dividing atom-processor into 1 param-processors.\n", - " *** Divided 1-host atom-processor (~1 procs) into 1 param-processing groups ***\n", - " --- chi2 GST ---\n", - " Sum of Chi^2 = 148.066 (168 data params - 60 (approx) model params = expected mean of 108; p-value = 0.00636252)\n", - " Completed in 6.1s\n", - " Iteration 2 took 6.2s\n", - " \n", - " --- Iterative GST: Iter 3 of 6 285 circuits ---: \n", - " MatrixLayout: 1 processors divided into 1 x 1 (= 1) grid along circuit and parameter directions.\n", - " 1 atoms, parameter block size limits (None,)\n", - " *** Distributing 1 atoms to 1 atom-processing groups (1 cores) ***\n", - " More atom-processors than hosts: each host gets ~1 atom-processors\n", - " Atom-processors already occupy a single node, dividing atom-processor into 1 param-processors.\n", - " *** Divided 1-host atom-processor (~1 procs) into 1 param-processing groups ***\n", - " --- chi2 GST ---\n", - " Sum of Chi^2 = 263.563 (285 data params - 60 (approx) model params = expected mean of 225; p-value = 0.0396886)\n", - " Completed in 3.0s\n", - " Iteration 3 took 3.1s\n", - " \n", - " --- Iterative GST: Iter 4 of 6 448 circuits ---: \n", - " MatrixLayout: 1 processors divided into 1 x 1 (= 1) grid along circuit and parameter directions.\n", - " 1 atoms, parameter block size limits (None,)\n", - " *** Distributing 1 atoms to 1 atom-processing groups (1 cores) ***\n", - " More atom-processors than hosts: each host gets ~1 atom-processors\n", - " Atom-processors already occupy a single node, dividing atom-processor into 1 param-processors.\n", - " *** Divided 1-host atom-processor (~1 procs) into 1 param-processing groups ***\n", - " --- chi2 GST ---\n", - " Sum of Chi^2 = 405.54 (448 data params - 60 (approx) model params = expected mean of 388; p-value = 0.25971)\n", - " Completed in 2.5s\n", - " Iteration 4 took 2.7s\n", - " \n", - " --- Iterative GST: Iter 5 of 6 616 circuits ---: \n", - " MatrixLayout: 1 processors divided into 1 x 1 (= 1) grid along circuit and parameter directions.\n", - " 1 atoms, parameter block size limits (None,)\n", - " *** Distributing 1 atoms to 1 atom-processing groups (1 cores) ***\n", - " More atom-processors than hosts: each host gets ~1 atom-processors\n", - " Atom-processors already occupy a single node, dividing atom-processor into 1 param-processors.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " *** Divided 1-host atom-processor (~1 procs) into 1 param-processing groups ***\n", - " --- chi2 GST ---\n", - " Sum of Chi^2 = 616.91 (616 data params - 60 (approx) model params = expected mean of 556; p-value = 0.0372415)\n", - " Completed in 6.6s\n", - " Iteration 5 took 6.8s\n", - " \n", - " --- Iterative GST: Iter 6 of 6 784 circuits ---: \n", - " MatrixLayout: 1 processors divided into 1 x 1 (= 1) grid along circuit and parameter directions.\n", - " 1 atoms, parameter block size limits (None,)\n", - " *** Distributing 1 atoms to 1 atom-processing groups (1 cores) ***\n", - " More atom-processors than hosts: each host gets ~1 atom-processors\n", - " Atom-processors already occupy a single node, dividing atom-processor into 1 param-processors.\n", - " *** Divided 1-host atom-processor (~1 procs) into 1 param-processing groups ***\n", - " --- chi2 GST ---\n", - " Sum of Chi^2 = 835.363 (784 data params - 60 (approx) model params = expected mean of 724; p-value = 0.00250815)\n", - " Completed in 8.6s\n", - " Iteration 6 took 8.8s\n", - " \n", - " Last iteration:\n", - " --- dlogl GST ---\n", - " 2*Delta(log(L)) = 837.281 (784 data params - 60 (approx) model params = expected mean of 724; p-value = 0.00217365)\n", - " Completed in 1.1s\n", - " Final optimization took 1.1s\n", - " \n", - " Iterative GST Total Time: 36.0s\n", - "-- Std Practice: Iter 3 of 3 (Target) --: \n", - " MatrixLayout: 1 processors divided into 1 (= 1) grid along circuit and parameter directions.\n", - " 1 atoms, parameter block size limits ()\n", - " *** Distributing 1 atoms to 1 atom-processing groups (1 cores) ***\n", - " More atom-processors than hosts: each host gets ~1 atom-processors\n", - " MatrixLayout: 1 processors divided into 1 (= 1) grid along circuit and parameter directions.\n", - " 1 atoms, parameter block size limits ()\n", - " *** Distributing 1 atoms to 1 atom-processing groups (1 cores) ***\n", - " More atom-processors than hosts: each host gets ~1 atom-processors\n", - " MatrixLayout: 1 processors divided into 1 (= 1) grid along circuit and parameter directions.\n", - " 1 atoms, parameter block size limits ()\n", - " *** Distributing 1 atoms to 1 atom-processing groups (1 cores) ***\n", - " More atom-processors than hosts: each host gets ~1 atom-processors\n", - " MatrixLayout: 1 processors divided into 1 (= 1) grid along circuit and parameter directions.\n", - " 1 atoms, parameter block size limits ()\n", - " *** Distributing 1 atoms to 1 atom-processing groups (1 cores) ***\n", - " More atom-processors than hosts: each host gets ~1 atom-processors\n", - " MatrixLayout: 1 processors divided into 1 (= 1) grid along circuit and parameter directions.\n", - " 1 atoms, parameter block size limits ()\n", - " *** Distributing 1 atoms to 1 atom-processing groups (1 cores) ***\n", - " More atom-processors than hosts: each host gets ~1 atom-processors\n", - " MatrixLayout: 1 processors divided into 1 (= 1) grid along circuit and parameter directions.\n", - " 1 atoms, parameter block size limits ()\n", - " *** Distributing 1 atoms to 1 atom-processing groups (1 cores) ***\n", - " More atom-processors than hosts: each host gets ~1 atom-processors\n", - "Running idle tomography\n", - "Computing switchable properties\n", - "Found standard clifford compilation from smq1Q_XYI\n", - "Found standard clifford compilation from smq1Q_XYI\n", - "Found standard clifford compilation from smq1Q_XYI\n" - ] - } - ], + "outputs": [], "source": [ "#Run GST and create a report\n", "results = pygsti.run_stdpractice_gst(ds, target_model, prep_fiducials, meas_fiducials, \n", @@ -308,7 +102,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -322,9 +116,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.9.13" } }, "nbformat": 4, - "nbformat_minor": 1 + "nbformat_minor": 4 } diff --git a/jupyter_notebooks/Tutorials/algorithms/GST-Overview.ipynb b/jupyter_notebooks/Tutorials/algorithms/GST-Overview.ipynb index 932b5fd88..c2397edcc 100644 --- a/jupyter_notebooks/Tutorials/algorithms/GST-Overview.ipynb +++ b/jupyter_notebooks/Tutorials/algorithms/GST-Overview.ipynb @@ -20,7 +20,7 @@ "\n", "To run GST, we need the following three inputs:\n", "1. a \"**target model**\" which describes the desired, or ideal, operations we want our experimental hardware to perform. In the example below, we use the target model from one of pyGSTi's build-in \"model packs\" (see the [tutorial on model packs](objects/advanced/ModelPacks.ipynb)) - which acts on a single qubit with the following operations:\n", - " - three gates: the identity, and $\\pi/2$ rotations around the $x$- and $y$-axes.\n", + " - two gates: $\\pi/2$ rotations around the $x$- and $y$-axes.\n", " - a single state preparation in the $|0\\rangle$ state.\n", " - a 2-outcome measurement with the label \"0\" associated with measuring $|0\\rangle$ and \"1\" with measuring $|1\\rangle$.\n", " \n", @@ -35,19 +35,19 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import pygsti\n", - "from pygsti.modelpacks import smq1Q_XYI\n", + "from pygsti.modelpacks import smq1Q_XY\n", "\n", "#Step 1: create an \"experiment design\" for doing GST on the std1Q_XYI gate set\n", - "target_model = smq1Q_XYI.target_model() # a Model object\n", - "prep_fiducials = smq1Q_XYI.prep_fiducials() # a list of Circuit objects\n", - "meas_fiducials = smq1Q_XYI.meas_fiducials() # a list of Circuit objects\n", - "germs = smq1Q_XYI.germs() # a list of Circuit objects\n", - "maxLengths = [1,2,4,8,16,32]\n", + "target_model = smq1Q_XY.target_model() # a Model object\n", + "prep_fiducials = smq1Q_XY.prep_fiducials() # a list of Circuit objects\n", + "meas_fiducials = smq1Q_XY.meas_fiducials() # a list of Circuit objects\n", + "germs = smq1Q_XY.germs() # a list of Circuit objects\n", + "maxLengths = [1,2,4,8,16]\n", "exp_design = pygsti.protocols.StandardGSTDesign(target_model, prep_fiducials, meas_fiducials,\n", " germs, maxLengths)" ] @@ -67,19 +67,19 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def simulate_taking_data(data_template_filename):\n", " \"\"\"Simulate taking 1-qubit data and filling the results into a template dataset.txt file\"\"\"\n", - " datagen_model = smq1Q_XYI.target_model().depolarize(op_noise=0.01, spam_noise=0.001)\n", + " datagen_model = smq1Q_XY.target_model().depolarize(op_noise=0.01, spam_noise=0.001)\n", " pygsti.io.fill_in_empty_dataset_with_fake_data(data_template_filename, datagen_model, num_samples=1000, seed=1234)" ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ diff --git a/jupyter_notebooks/Tutorials/algorithms/GST-Protocols.ipynb b/jupyter_notebooks/Tutorials/algorithms/GST-Protocols.ipynb index 0ab42b10a..d2b3d9a71 100644 --- a/jupyter_notebooks/Tutorials/algorithms/GST-Protocols.ipynb +++ b/jupyter_notebooks/Tutorials/algorithms/GST-Protocols.ipynb @@ -138,6 +138,95 @@ "custom_gauge_opt_model = results_TP2.estimates['GSTwithMyGO'].models['my_gauge_opt']" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Wildcard parameters\n", + "\n", + "TODO" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "proto = pygsti.protocols.GateSetTomography(\n", + " target_model_TP, name=\"GSTwithPerGateWildcard\",\n", + " badfit_options={'actions': ['wildcard']}\n", + " )\n", + "\n", + "# Artifically unset threshold so that wildcard runs. YOU WOULD NOT DO THIS IN PRODUCTION RUNS\n", + "proto.badfit_options.threshold = None\n", + "\n", + "results_pergate_wildcard = proto.run(data, disable_checkpointing=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# The wildcard can be retrieved by looking at unmodeled_error in the estimates\n", + "results_pergate_wildcard.estimates['GSTwithPerGateWildcard'].parameters['unmodeled_error']" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Another common form of wildcard is to have one parameter for SPAM and one for all the other gates." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "op_label_dict = {k:0 for k in target_model_TP.operations} # Assign all gates to value 0\n", + "op_label_dict['SPAM'] = 1 # Assign SPAM to value 1\n", + "\n", + "proto = pygsti.protocols.GateSetTomography(\n", + " target_model_TP, name=\"GSTwithPerGateWildcard\",\n", + " badfit_options={'actions': ['wildcard'], 'wildcard_primitive_op_labels': op_label_dict}\n", + " )\n", + "\n", + "# Artifically unset threshold so that wildcard runs. YOU WOULD NOT DO THIS IN PRODUCTION RUNS\n", + "proto.badfit_options.threshold = None\n", + "\n", + "results_globalgate_wildcard = proto.run(data, disable_checkpointing=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Unfortunately both of these wildcard strategies have the same problem. They are not unique, i.e. it is possible to \"slosh\" wildcard strength from one parameter to another to get another valid wildcard solution. This makes it difficult to make any quantitative statements about relative wildcard strengths.\n", + "\n", + "In order to avoid this, we have also introduced a 1D wildcard solution. This takes some reference weighting for the model operations and scales a single wildcard parameter ($\\alpha$) up until the model fits the data. Since there is only one parameter, this does not have any of the ambiguity of the above wildcard strategies. Currently, the reference weighting used is the diamond distance from the noisy model to the target model, with the intuition that \"noisier\" operations are more likely to contribute to model violation." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "proto = pygsti.protocols.GateSetTomography(\n", + " target_model_TP, name=\"GSTwithPerGateWildcard\",\n", + " badfit_options={'actions': ['wildcard1d'], 'wildcard1d_reference': 'diamond distance'}\n", + " )\n", + "\n", + "# Artifically unset threshold so that wildcard runs. YOU WOULD NOT DO THIS IN PRODUCTION RUNS\n", + "proto.badfit_options.threshold = None\n", + "\n", + "results_1d_wildcard = proto.run(data, disable_checkpointing=True)" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -487,9 +576,9 @@ ], "metadata": { "kernelspec": { - "display_name": "gst_checkpointing", + "display_name": "pygsti", "language": "python", - "name": "gst_checkpointing" + "name": "python3" }, "language_info": { "codemirror_mode": { @@ -501,7 +590,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.13" + "version": "3.11.5" } }, "nbformat": 4, diff --git a/jupyter_notebooks/Tutorials/algorithms/ModelTesting-functions.ipynb b/jupyter_notebooks/Tutorials/algorithms/ModelTesting-functions.ipynb index f4b7f0d23..fa45805b5 100644 --- a/jupyter_notebooks/Tutorials/algorithms/ModelTesting-functions.ipynb +++ b/jupyter_notebooks/Tutorials/algorithms/ModelTesting-functions.ipynb @@ -31,9 +31,10 @@ "outputs": [], "source": [ "datagen_model = smq1Q_XYI.target_model().depolarize(op_noise=0.05, spam_noise=0.1).rotate((0.05,0,0.03))\n", + "max_lens = [1,2,4,8]\n", "exp_list = pygsti.circuits.create_lsgst_circuits(\n", " smq1Q_XYI.target_model(), smq1Q_XYI.prep_fiducials(), smq1Q_XYI.meas_fiducials(),\n", - " smq1Q_XYI.germs(), [1,2,4,8,16,32,64])\n", + " smq1Q_XYI.germs(), max_lens)\n", "ds = pygsti.data.simulate_data(datagen_model, exp_list, num_samples=1000,\n", " sample_error='binomial', seed=100)" ] @@ -80,17 +81,17 @@ "# creates a Results object with a \"default\" estimate\n", "results = pygsti.run_model_test(test_model1, ds, target_model, \n", " smq1Q_XYI.prep_fiducials(), smq1Q_XYI.meas_fiducials(), smq1Q_XYI.germs(),\n", - " [1,2,4,8,16,32,64]) \n", + " max_lens) \n", "\n", "# creates a Results object with a \"default2\" estimate\n", "results2 = pygsti.run_model_test(test_model2, ds, target_model, \n", " smq1Q_XYI.prep_fiducials(), smq1Q_XYI.meas_fiducials(), smq1Q_XYI.germs(),\n", - " [1,2,4,8,16,32,64], advanced_options={'estimate_label': 'default2'}) \n", + " max_lens, advanced_options={'estimate_label': 'default2'}) \n", "\n", "# creates a Results object with a \"default3\" estimate\n", "results3 = pygsti.run_model_test(test_model3, ds, target_model, \n", " smq1Q_XYI.prep_fiducials(), smq1Q_XYI.meas_fiducials(), smq1Q_XYI.germs(),\n", - " [1,2,4,8,16,32,64], advanced_options={'estimate_label': 'default3'})" + " max_lens, advanced_options={'estimate_label': 'default3'})" ] }, { @@ -149,7 +150,7 @@ "#Create some GST results using run_stdpractice_gst\n", "gst_results = pygsti.run_stdpractice_gst(ds, target_model, \n", " smq1Q_XYI.prep_fiducials(), smq1Q_XYI.meas_fiducials(), smq1Q_XYI.germs(),\n", - " [1,2,4,8,16,32,64])\n", + " max_lens)\n", "\n", "#Add a model to test\n", "gst_results.add_model_test(target_model, test_model3, estimate_key='MyModel3')\n", @@ -179,7 +180,7 @@ "outputs": [], "source": [ "gst_results = pygsti.run_stdpractice_gst(ds, target_model, smq1Q_XYI.prep_fiducials(), smq1Q_XYI.meas_fiducials(), smq1Q_XYI.germs(),\n", - " [1,2,4,8,16,32,64], modes=\"full TP,Test2,Test3,Target\", # You MUST \n", + " max_lens, modes=\"full TP,Test2,Test3,Target\", # You MUST \n", " models_to_test={'Test2': test_model2, 'Test3': test_model3})\n", "\n", "pygsti.report.construct_standard_report(\n", @@ -197,9 +198,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "api_updates", "language": "python", - "name": "python3" + "name": "api_updates" }, "language_info": { "codemirror_mode": { diff --git a/jupyter_notebooks/Tutorials/algorithms/ModelTesting.ipynb b/jupyter_notebooks/Tutorials/algorithms/ModelTesting.ipynb index 11530f8bc..49e56f0f1 100644 --- a/jupyter_notebooks/Tutorials/algorithms/ModelTesting.ipynb +++ b/jupyter_notebooks/Tutorials/algorithms/ModelTesting.ipynb @@ -21,7 +21,7 @@ "import numpy as np\n", "import scipy\n", "from scipy import stats\n", - "from pygsti.modelpacks import smq1Q_XYI" + "from pygsti.modelpacks import smq1Q_XY" ] }, { @@ -30,8 +30,8 @@ "metadata": {}, "outputs": [], "source": [ - "datagen_model = smq1Q_XYI.target_model().depolarize(op_noise=0.05, spam_noise=0.1).rotate((0.05,0,0.03))\n", - "exp_design = smq1Q_XYI.create_gst_experiment_design(max_max_length=64)\n", + "datagen_model = smq1Q_XY.target_model().depolarize(op_noise=0.05, spam_noise=0.1).rotate((0.05,0,0.03))\n", + "exp_design = smq1Q_XY.create_gst_experiment_design(max_max_length=16)\n", "ds = pygsti.data.simulate_data(datagen_model, exp_design.all_circuits_needing_data,\n", " num_samples=1000, sample_error='binomial', seed=100)\n", "data = pygsti.protocols.ProtocolData(exp_design, ds)" @@ -51,7 +51,7 @@ "metadata": {}, "outputs": [], "source": [ - "target_model = smq1Q_XYI.target_model()\n", + "target_model = smq1Q_XY.target_model()\n", "test_model1 = target_model.copy()\n", "test_model2 = target_model.depolarize(op_noise=0.07, spam_noise=0.07)\n", "test_model3 = target_model.depolarize(op_noise=0.07, spam_noise=0.07).rotate( (0.02,0.02,0.02) )" diff --git a/jupyter_notebooks/Tutorials/algorithms/advanced/CliffordRB-Simulation-ImplicitModel.ipynb b/jupyter_notebooks/Tutorials/algorithms/advanced/CliffordRB-Simulation-ImplicitModel.ipynb index 8954f94cb..4031d8910 100644 --- a/jupyter_notebooks/Tutorials/algorithms/advanced/CliffordRB-Simulation-ImplicitModel.ipynb +++ b/jupyter_notebooks/Tutorials/algorithms/advanced/CliffordRB-Simulation-ImplicitModel.ipynb @@ -11,7 +11,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -33,25 +33,12 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "- Sampling 10 circuits at CRB length 0 (1 of 6 depths) with seed 784558\n", - "- Sampling 10 circuits at CRB length 1 (2 of 6 depths) with seed 784568\n", - "- Sampling 10 circuits at CRB length 2 (3 of 6 depths) with seed 784578\n", - "- Sampling 10 circuits at CRB length 4 (4 of 6 depths) with seed 784588\n", - "- Sampling 10 circuits at CRB length 8 (5 of 6 depths) with seed 784598\n", - "- Sampling 10 circuits at CRB length 16 (6 of 6 depths) with seed 784608\n" - ] - } - ], + "outputs": [], "source": [ "#Specify the device to be benchmarked - in this case 2 qubits\n", - "n_qubits = 3\n", + "n_qubits = 2\n", "qubit_labels = list(range(n_qubits)) \n", "gate_names = ['Gxpi2', 'Gypi2','Gcphase'] \n", "availability = {'Gcphase':[(i,i+1) for i in range(n_qubits-1)]}\n", @@ -62,8 +49,8 @@ " 'paulieq': CCR.create_standard(pspec, 'paulieq', ('1Qcliffords', 'allcnots'), verbosity=0)}\n", "\n", "#Specify RB parameters (k = number of repetitions at each length)\n", - "lengths = [0,1,2,4,8,16]\n", - "k = 10\n", + "lengths = [0,1,2,4,8]\n", + "k = 8\n", "subsetQs = qubit_labels\n", "randomizeout = False # ==> all circuits have the *same* ideal outcome (the all-zeros bitstring)\n", "\n", @@ -91,11 +78,12 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "myModel = pygsti.models.create_crosstalk_free_model(pspec, ideal_gate_type='full')" + "myModel = pygsti.models.create_crosstalk_free_model(pspec, ideal_gate_type='full')\n", + "myModel.sim = 'map'" ] }, { @@ -110,7 +98,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -130,7 +118,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -148,46 +136,9 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "FullArbitraryOp with shape (4, 4)\n", - " 1.00 0 0 0\n", - " 0 0.99 0 0\n", - " 0 0 0-0.99\n", - " 0 0 0.99 0\n", - "\n", - "FullArbitraryOp with shape (4, 4)\n", - " 1.00 0 0 0\n", - " 0 0 0 0.99\n", - " 0 0 0.99 0\n", - " 0-0.99 0 0\n", - "\n", - "FullArbitraryOp with shape (16, 16)\n", - " 1.00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n", - " 0 0 0 0 0 0 0 0 0 0 0 0 0 0.99 0 0\n", - " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.99 0\n", - " 0 0 0 0.99 0 0 0 0 0 0 0 0 0 0 0 0\n", - " 0 0 0 0 0 0 0 0.99 0 0 0 0 0 0 0 0\n", - " 0 0 0 0 0 0 0 0 0 0 0.98 0 0 0 0 0\n", - " 0 0 0 0 0 0 0 0 0-0.98 0 0 0 0 0 0\n", - " 0 0 0 0 0.98 0 0 0 0 0 0 0 0 0 0 0\n", - " 0 0 0 0 0 0 0 0 0 0 0 0.99 0 0 0 0\n", - " 0 0 0 0 0 0-0.98 0 0 0 0 0 0 0 0 0\n", - " 0 0 0 0 0 0.98 0 0 0 0 0 0 0 0 0 0\n", - " 0 0 0 0 0 0 0 0 0.98 0 0 0 0 0 0 0\n", - " 0 0 0 0 0 0 0 0 0 0 0 0 0.99 0 0 0\n", - " 0 0.98 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n", - " 0 0 0.98 0 0 0 0 0 0 0 0 0 0 0 0 0\n", - " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.98\n", - "\n" - ] - } - ], + "outputs": [], "source": [ "print(myModel.operation_blks['gates'][\"Gxpi2\"])\n", "print(myModel.operation_blks['gates'][\"Gypi2\"])\n", @@ -203,7 +154,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -220,7 +171,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -230,22 +181,9 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAe4AAAFACAYAAAB6AZ/IAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAABNPUlEQVR4nO3dd5xU1d348c+9U7bD0otUKUdQQSyhhFhjREyiwYa9hmD0yaOkiP6MJYkae4wdy2Mi0TyiaHxiNEYwGkGNKCoWDkIERPrCLmyZdu/9/XFn19ndKXd3Z3Z3dr9vXvOamdvmzM6y3zntewzHcRBCCCFEfjA7ugBCCCGE8E4CtxBCCJFHJHALIYQQeUQCtxBCCJFHJHALIYQQeUQCtxBCCJFH/B1dAC8mT57s7LPPPh1dDCGEEKJdfPLJJzu11v2S7cuLwL3PPvuwePHiji6GEEII0S6UUhtS7ZOmciGEECKPSOAWQggh8ogEbiGEECKP5EUftxBCtEU0GmXTpk2EQqGOLooQjRQWFjJkyBACgYDncyRwCyG6vE2bNlFWVsaIESMwDKOjiyMEAI7jUFFRwaZNmxg5cqTn86SpXAjR5YVCIfr06SNBW3QqhmHQp0+fFrcESeAWQnQLErRFZ9Sa30sJ3EII0Y4efvhhpk+fTjgc7uiidHnnnHMO69at83Ts/PnzeeONNxpt27FjB9dffz0ARx99NOFwmAULFvDRRx8RDodZtGgRAIsXL2bJkiVZLXs6EriFEKKJ51d+xTd/u5SR81/km79dyvMrv8ratV944QVmzpzJiy++mLVritzo169fQ+CuN2fOHCZMmMCOHTsaAvesWbM45phj2q1cMjhNCCESPL/yK65avIq6qAXAV5V1XLV4FQAnTWpb6uV33nmHYcOGMXv2bH7+858zfvx4brzxRp544gkAfvSjH/Hf//3fVFdXc9ddd+Hz+Rg6dCi/+tWv+L//+z+effZZbNvmJz/5CevWreOVV16hrq6OXr16ce+992LbNr/4xS/Yvn07gwYN4t133+XNN99Ea81vfvMbAMrLy7npppsoKytrKNd7773HLbfcgt/vp6ioiLvvvptXXnmF//znP/zsZz8jHA5z/PHHs3TpUj788ENuuukmbNtmwIAB3H777Witm23bsGFDs9eMRqNcfvnlOI5DOBzmhhtuYN999214z3V1dVxxxRVMnz690c/swQcfxDRNduzYwemnn85ZZ53FOeecQ+/evamqqmLBggVcffXVbNq0CcuyuOCCC5g5cyYAv//979m9ezfBYJBbb72Vnj17cu2117J161a2b9/O0UcfzRVXXAHAk08+yaOPPoplWdx44434fD7mzZvH008/3VCe+fPnM3PmTF555RXWrl3Lvffei+M49O3blzPOOIM77riDFStWYNs2559/Pscffzx/+tOfeP755zFNkwMPPJBrrrmmTb9HErhTiFpRYnYs6b4CfwGmIY0VQnRFt/1dNwTtenVRi9v+rtscuBctWsSpp57KvvvuSzAYJBwOE4lE+OqrrwgEAuzevZtx48YxY8YMnnzySfr06cPvfvc7nnvuOfx+Pz169OCBBx7Atm3ee+89Hn/8cUzT5KKLLmLVqlV8/PHHDBkyhN///vesW7eO7373uwD88pe/5KabbmL06NEsWrSIRx55pCFYAbz66qscf/zxnHfeeSxdupQ9e/akfA/XXnstd955J6NGjWLRokWsW7cu6bYbbrih2WtOmjSJ8vJybr31VtauXUttbS0bN26ksrKSRx55hIqKCtavX9/sNbdt28bzzz+Pbdt873vfY8aMGQB897vf5dhjj2XhwoX07t2b22+/nerqambNmsWUKVMA+M53vsMJJ5zAn/70Jx566CHOOeccDjroIE499VTC4TCHH354w8/i4IMPZs6cObz++uvcdtttzJ8/P+XPYe7cuaxZs4bLLruMe+65B4DXX3+dTZs28dRTTxEOhznttNP45je/yeLFi7nuuuuYMGECTz75JLFYDL+/9eFXAncK22q3sXHvxmbb/YafA/oeQHGguANKJYTItc2VdS3a7lVVVRVvvPEGu3bt4oknnqC6upqFCxdyyimn8PzzzxMMBpk1axa7du1i+/btXH755YA7In7atGkMHz68YcqQaZoEAgHmzZtHcXExW7duJRaLsW7dOg4//HAARo0aRe/evQEaAim4c9pHjBjRqGxz587lwQcf5LzzzmPAgAFMmDCh0X7HcRoe79y5k1GjRgFw6qmnptyW7DUPP/xw1q9fz49//GP8fj+XXHIJY8aM4fTTT2fevHnEYjHOOeecZj+7SZMmEQwGARgzZgwbN7p/m+t/HuvWrWPatGkAlJaWMmrUKL788ksADj30UMANyq+//jrl5eWsWrWKt99+m9LSUiKRSMPr1B87adIkbr311tQfZgpr1qzhk08+aXgPsViMr776iptvvpnHHnuMW2+9lYMOOqjRz7M1JHCnELWjRKxIs+22aaesiQsh8t/g8iK+ShKkB5cXtem6L7zwAieffDJXXnklAHV1dRxzzDHMmzePn/zkJ5imyaOPPkpxcTEDBw7k/vvvp6ysjCVLllBcXMyWLVswTbelb/Xq1bz66qssWrSIuro6Zs2aheM4jB07lpUrV/Ltb3+bjRs3snv3bsANcLfccguDBw/mvffeY8eOHc3K9oMf/IArr7yShx56iKeffpqRI0c2HPfJJ580HNu/f3/Wr1/PiBEjWLBgASNHjky6LdlrvvPOO/Tv35/HHnuMlStXcuedd3LNNddQU1PDggUL2L59O7Nnz+aoo45qVL7PPvsMy7KIRCKsXbuW4cOHA1+PyB41ahQrVqzg2GOPpbq6mjVr1jBkyBAAVq1axYABA1ixYgVjxoxh8eLFlJWV8atf/YoNGzbw9NNPNwTSjz76iIMPPrjh2HRM08S27Ubb9t13XyZPnsyvf/1rbNvm/vvvZ+jQofzud7/jhhtuoKCggIsuuoiVK1fyjW98w+NvTnMSuFNIFZwdx5HALUQX9vPjVKM+boCigI+fH6fadN1FixY1qsUVFRXxne98h7/85S/st99+xGIxSktLAfh//+//MWfOHBzHoaSkhFtvvZUtW7Y0nDt8+HCKioqYPXs24A6i2r59O6eccgrz58/nrLPOYvDgwRQUFABw/fXXc+WVVxKLxTAMgxtvvLFR2SZMmMA111xDUVERpmnyq1/9ip49e/LUU09xxhlnsP/++1NSUgLADTfcwNVXX41pmvTr14/zzz+fAQMGNNs2aNCgZq9ZXl7OvHnzeOqpp4jFYlx66aWMGDGC++67j5deeqmh/76pWCzGD3/4QyorK7nkkksaWhLqnXbaafzyl7/kjDPOIBwOc9lll9GnTx/A7Qb4wx/+QElJCbfccgvbt2/npz/9KR988AHBYJDhw4ezfft2AD788EPOPfdcDMPgpptuSlsz7tOnD9FolNtuu43CwkLAHXn+73//mzPPPJPa2lq+/e1vU1pailKKM888k5KSEgYMGMDEiRM9/MakZrS1yt4eZs2a5bT3sp6f7vyU7XXbm203MBjfZzz9ipMukyqE6IQ+++wzxo0b5/n451d+xW1/12yurGNweRE/P061uX+7Pbz//vvU1tYyffp01q9fz8UXX8yrr77a0cVqk3feeYc///nP3HXXXR1dlJxJ9vuplHpPa31osuNzUuNWSpnA/cBEIAxcrLVeG993EPC7hMOnACdprV/ORVlaK2I3byYHcHCwHCvpPiFE13DSpH3yIlA3NXToUObNm8e9995LLBbj2muv7egiiRzIVVP5SUCh1nqqUmoKcAdwIoDW+gPgSACl1KnAV50taIPbx52KNJULITqjfv36NUwt6yomT57M5MmTO7oYnUqu5jRNB14G0Fq/DTSr7iulSoAbgP/OURlaLWbHsOzUtWoJ3EIIITpKrmrcPYCqhOeWUsqvtU6MeBcBi7TWO5NdQCk1B5gDMHjw4BwVM7mYHcMhdd9/utq4EEIIkUu5Ctx7gLKE52aToA1wFnBKqgtorRcAC8AdnJb1EqZhORa2Y6fcH7UkcAshhOgYuWoqXwbMBIj3ca9K3KmU6gkUaK2/zNHrt0nMjqWdBpBq4JoQQgiRa7mqcT8HHKuUWg4YwAVKqXnAWq31C8BYYH2OXrvNLNvCJk2NW5rKhRBCdJCcBG6ttQ3MbbJ5dcL+d3FHnndKlmOlrXFbtkXMjuE3JX+NECKzTZs28f3vf5/999+/YdvkyZM55phjWLJkCZdddhn/+Mc/mDBhAgMGDMj663/wwQcNi2ZMnz6dyy67rNH+7du38/Of/5xoNErPnj257bbbqKurY968eQ3HfPbZZ/z0pz/ljDPO8PSav/nNbzjvvPMYOnRo0v1Lly7lvvvuw+/3c/LJJ3Paaac12r9hwwbmz5+PYRiMGTOG6667DtM0ueSSS9i9ezeBQICCggIeeeSRFv408p9EniQyDU5zcCRwCyFaZPTo0UmnatUn3vjjH//I9ddfn5PAfd1113HPPfcwdOhQ5syZw6effsr48eMb9j/88MP84Ac/4KSTTuKee+7hmWee4fzzz28o78qVK7nrrruaBdd0Nm3alDJoR6NRbr75Zp555hmKioo444wzOProo+nbt2/DMTfffDOXX345kydP5tprr2XJkiUce+yxbNiwgRdffLEh3Wl3JJEniUxN4bYj+cqFyFsfPAUrF2b3mpPOhoO81UQT1WcFO/HEE/nss8+48sorefLJJxsW1Eg0f/58Kisrqays5KGHHqJnz54ALFy4kL///e+Njq3PEQ5QXV1NJBJh2LBhAEyfPp3ly5c3CtxXX301juNg2zZbtmxpNJPHcRx+/etfc/vtt+Pz+ZK+j6OPPpqXXnqpIcXq2rVr2XfffVO+73Xr1jFs2LCG93DIIYfw7rvvcvzxxzcc88knnzTk8z788MNZtmwZkyZNYs+ePcydO5c9e/YwZ86cZnnNuwMJ3ElkGnxmOzYxRwK3EMK7tWvXNlr56vbbb294fOSRRzJu3Diuv/76pEG73pQpUzj//PMbbTv77LM5++yzU55TXV3dkAMdoKSkpGHlrHqGYRCLxTjxxBMJh8NceumlDfuWLl3KmDFjkgbiq666ik2bNrFjxw4uvPBC/H4/f/jDH3jttdfSBtTq6upG64GXlJRQXV3d6BjHcRpq1SUlJezdu5doNMqFF17IueeeS1VVFWeccQYTJkxoyEveXUjgTiLTdC/HcdImaBFCdGIHndGq2nFbJWsqT7b2dDr1y1gmylTjLi0tpaampmFfTU0NPXr0aHadQCDA3/72N5YvX86VV17JwoVuq8QLL7zAueeem7Q8N998M+DWuB977LGGGvfKlSu58MILefnll/nTn/4EwJVXXskBBxyQskyJgRxoWAktscx9+/Zl9uzZ+P1++vTpw7hx4/jiiy8kcAsIW+G0+22kqVwIkV2GYWRcpzlZv26mGndpaSmBQICNGzcydOhQ3nzzzWaD066//npmzJjBlClTKCkpafQ6H3/8MQcffLDn91FVVUVpaSk+n48ZM2YwY8aMZseMGjWKDRs2UFlZSXFxMStWrOCiiy5qdMz48eN55513mDx5Mm+88QZTpkxh+fLlLFy4kIcffpiamho+//zztE3yXVWu5nHnLcdxkq7D3ZTM5RZCZNOkSZP4xS9+QWVlJVdccUWzNbPb4oYbbuBnP/sZp5xyCuPHj2fixIlUVlY2BPBzzjmH++67j3POOYc777yT66+/HoBdu3ZRWlqacSDY0qVLG2rbb7zxBt/61rfSHh8IBJg/fz4XXXQRs2fP5uSTT2bAgAGsXbu24bWvvPJK7rnnHk4//XSi0SjHHXccRxxxBCNGjOC0007joosuYt68ec2W+OwOZFnPJqJWlPe2vUfICqU9bljZMPYt737f9ITIRy1d1rOj3XnnncydO5fi4uKOLopoBy1d1lNq3E1E7WjadKf1pMYthMiV2bNnS9AWKUngbiJmx9JmTavnpTldCCFao70XVhL5RQJ3EzE75q3GLYFbiLySD92Covtpze+lBO4mMqU7rRezYzKyXIg8UVhYSEVFhQRv0ak4jkNFRQWFhYUtOk+mgzWRKd1pPRubqBWVtKdC5IEhQ4Y0JAoRojMpLCxkyJAhLTpHok4TXpvAHcfBciQJixD5IBAIJE1eIkQ+kqbyJryOFrcdW/q5hRBCtDsJ3E3URGsyH4TbFy75yoUQQrQ3CdwJLNvKmO40USiWPkmLEEIIkW0SuBNE7EiL+q3rYnU5LI0QQgjRnATuBGErjG1nnsNdry4qgVsIIUT7ksCdIGpFW1TjDtthmcsthBCiXUngThC2wp7mcNezbEtGlgshhGhXErgTZFoRrCnLkcAthBCifUngTtDSPmvbsYna0RyVRgghhGhOAnec7dgtHiXu4MiUMCGEEO1KAndcOBZuVQrTljavCyGEEG0hgTsuardsRHm92mhtDkojhBBCJCeBOy5iR7Ds1tW4vazfLYQQQmSDBO64UCzUoqlg9Szbkn5uIYQQ7UYCd1xrm7wtxyIc857fXAghhGgLCdxx1dHqVp1nOZYMUBNCCNFuJHDjjihvyapgTdXGZICaEEKI9uHPxUWVUiZwPzARCAMXa63XJuw/HrgOMID3gEu11i3vYM6SkBVq1cC0ensje7NYGiGEECK1XNW4TwIKtdZTgfnAHfU7lFJlwG3Ad7XWk4H1QN8clcOTsNW6Odz1QrGQZFATQgjRLnIVuKcDLwNord8GDk3YNw1YBdyhlPoXsE1rvSNH5fCkLlrXqhHl9SzHIhSVfm4hhBC5l5OmcqAHUJXw3FJK+bXWMdza9VHAQUA18C+l1Fta6zWJF1BKzQHmAAwePDhHxXTVRGvadH7MjhGyQpRRlqUSCSGEEMnlKnDvgUZRzIwHbYAK4F2t9VYApdQbuEG8UeDWWi8AFgDMmjUrZ/3ftmO3ekR5PclZLoQQor3kqql8GTATQCk1BbdpvN77wAFKqb5KKT8wBfg0R+XIKBQLEbNjmQ/MQEaWCyGEaA+5qnE/BxyrlFqOO3L8AqXUPGCt1voFpdRVwN/jxz6ttf44R+XIqLWLizRVHanGcRwMw8hCqYQQQojkchK4tdY2MLfJ5tUJ+/8M/DkXr91SISuUlcAdsSOErTCF/sIslEoIIYRIrtsnYMlWE7dlSwY1IYQQuSeBO0vLclqORdSSudxCCCFyq1sHbtuxqYvVZeVaMrJcCCFEe+jWgTscCxNz2j6ivF62vgQIIYQQqXTvwG2HsW07a9fLVrO7EEIIkUq3DtxRK5qVEeX1QlZ25oQLIYQQqXTrwB2KhdqUo7wp27HbtDyoEEIIkUn3DtxZnr5lORbhmARuIYQQudOtA3dbFxdpynIsWd5TCCFETnXbwB2zYzlp1paR5UIIIXKp2wbusBXGsrM3MK2eBG4hhBC51H0Dd5YWF2lKpoQJIYTIpW4buKN2dqeCJV5XUp8KIYTIlW4buCNWJCfXtRyLiJ2bawshhBC5Wo+70/NS216+Jsqzb0WpqHboU2pw8tQA08YG0p7j4OSk71wIIYSAbhy4bSd9qtPla6I8/lqESDwRWkW1w+OvuTXptMHbAZvspVEVQgghEnXbpvJMNe5n34o2BO16kZi7PR0HB8fJXjY2IYQQIpEE7hQqqpMH31Tb6zk4GWvzQgghRGt128CdaVWwPqVGi7bXcxwJ3EIIIXKn2wbuTOtwnzw1QNAPfahipvk24BD0u9vTceL/hBBCiFzovoPTMtS46weg7V32KTfb93C677dMnDY646hyyDzwTQghhGitbhu4vUwHmzY2QGDooThPmdxy4PusHzvO07UzfSkQQgghWksCdwbRonIqBx5A/y+Wsf7gM8FI38ft9dpfVH1BZaiy2Xaf6WNc73EEfJlr9kIIIbqfbtnHbdlWi/qht+/7TYqrvqJk9wZPx3tpKg/FQlRFqprdaqI1xOz0/e9CCCG6r24ZuG3HbtFc653Dp+AYJv2+WObt+h4SsKQKzo7jSAIXIYQQKXXfwN2CGndiczkeAr6XlKepjrGxpY9cCCFESt0ycJuGiUHmvupELWkuN43MP9aokzwDm+M4WEiucyGEEMl1y8DtN/0YHgaZJWpJc3nATD+wzHbslP3gDo7UuIUQQqTULQO3YRgZg2tT0aJyKgd5ay73m+kH61u2lbKP3XGcnKwTLoQQomvoloEbMteKk9k+MnNzuYGRMXDH7FjKPnbJvCaEECKdjPO4lVKHaq1XtOSiSikTuB+YCISBi7XWaxP23w1MB/bGN52ota5qyWu0VWvmSe8cPoWxyx+i3xfLqOk9IukxhmHgM3xpr2OTflS7rOcthBAiFS8JWH6mlBoBLAQWaq0rPZxzElCotZ6qlJoC3AGcmLD/EOA4rfXOlhU3e1pT4/66ufzNlMlYTExMM31DhmVbaad8yTxuIYQQqWRsKtdazwaOBxxgkVLqT0qpIzOcNh14OX7+28Ch9TvitfExwAKl1DKl1IWtLHubtCZwA2zb93CKqzZTtnNt0v2GYeA30n8fyljjlj5uIYQQKXjt4x4ADAP6AjuBU5RSC9Mc3wNIbPq2lFL10awEuAc4G5gB/FgpNaHpBZRSc5RSK5RSK3bv3u2xmN61NnDvHDEV2xdgwLrXk+43DTNzU7mdfh65BG4hhBCpZAzcSql3gAeAD4EpWuv/1lpfBvRLc9oeoCzxdbTW9e2/tcDdWutarfVeYCluX3gjWusFWutDtdaH9urVy+Pb8c5npg+uqcQKStk59DD6r3sDI0lftIGB35e+xu3gkG78mawuJoQQIhUvNe7LtNZHaa2f1FqHlVJHAGitj0tzzjJgJkC8j3tVwr6xwDKllE8pFcBtVn+/dcVvPZ/h85QoJZlto48kGKqi11cfNNtnGqanedxS4xZCCNEaKauGSqlvAeOBK5RSd8Y3+4BLgQMyXPc54Fil1HLAAC5QSs0D1mqtX1BKPQG8DUSBP2qtP2nj+2gxn+lrcfa0eruGHEy0oIwB6/7JrqGHNNoXNIMZz8805UsSsAghhEglXZvubmAgUAAMim+zgV9kuqjW2gbmNtm8OmH/bcBtLSpplvkNP6Zhtqp26/gCbB/5TQZ+vhRfpBYrWNywz8s0s0xN4VLjFkIIkUrKwK21/hj4WCm1QGu9pR3L1C7a0lQObnP5Pqtfpu+Gd9g25qiG7UFf5hp3phq1BG4hhBCppIxcSqln4g/fV0ptjt+2KKU2t1PZcqrAX5Bx9Hc6e/rvR13ZAAas+2ej7YW+woznZlpERAanCSGESCVdjfuU+P2gVMfkM9MwKfIXURurbd0FDINto45g+IfPEKzdRaS4NwYGhf7MgTvTWuBS4xZCCJFKusFpT5Fi0pLW+syclagdlQRKqAhVtPr8baOOYMQHT9P/P/9i0wEn4jN8nvq4MwVm23ETtLR0BTMhhBBdX7rBaQ+2Wyk6SJG/qE3n15UPYU/fMQz8fCmb9v8+Pp+PArMg43lemsJtx25TU74QQoiuKd3orDKt9euASnLrEoK+YJsGqAFsHXsMpbvWU7ZzLX7T76mpPFPgdhxH+rmFEEIklS5q9YnfD4rfBiY87hIKfG0boAawbdThWL4gA9e8SrG/2FPzdqamcgcJ3EIIIZJLGbi11n+I39+Am9msBng7/rxLyEbgtoIl7Bg5jQHr3qDEY0KXTMt2Oo6TdvUwIYQQ3ZeXXOX3AWcBMeBipdStOS9VOwn4Ap7mXWeyZex38EdrKU+x8EhTUTuadr+DI2tyCyGESMrLetwTtdbT44/vjqcx7TKKA8Xsiexp0zWqBo6ntsdgSj5eDJMvyXi8lxp3zJE1uYUQQjTnZWTWRqXUEACl1ADgy9wWqX0V+4szH5SJYbBdHUfgy39DinW663kJyja25CsXQgiRVLrMafVZ0mYAnyulNPAfYEp7Fa49eBkF7kWF+g6O4YOVT6Q9LubEMiZgkT5uIYQQqaTLnNZlRo+nUz9Ara3ZysyyQRhjj4MPnoSjr4EUiVgs20q7MhjIqHIhhBCpZezjjq+nfQEQwF2ic3CGtbjzStAM4jN9WFbbAndpsBQOPhf03+DzV2C/E5IeZzlWxho3ZO4HF0II0T156eN+APgn0BPYAOzMZYHaW6G/0NMa2pkU+4th9LFQOhBWPJbyOMu2PDWDx2wZnCaEEKI5L4F7p9b6KWCP1vp6YEhui9S+DMNwa8ttYBqm21fu88OhF8DaV6FiXdJj6/OQZyKjyoUQQiTjJXDbSqn9gWKllAJ657hM7a7EX9Km8/1GQqrTQ84H05+y1m07dsY+bpCmciGEEMl5CdzzgP2B3wNPAqnbgfNUUaAIw2PWs2T8pv/rdbjLBsK477mjyyPNlwz12sctNW4hhBDJZAzcWutPgM9wc5WfpbW+K+elameFvkL8ppdcNMmVBErwmQmpU78xB0JVsGpRs2NjTsxTjTtiRVpdHiGEEF2Xl5Sn1+AOUJsOPKqUujzXhWpvhf62Be7SQJM+8mFTof/+8O7D0KR2HYl5C8hhK+ypZi6EEKJ78dJUfgJwuNb6CuAIYHZui9T+/Ka/1WtzGxgUBZqcaxjwjYth6yr48t+NdoWskKfrxuyY1LqFEEI04yVwbwPq84IGgR25K07HKQuWteo8n+mjwFfQfMeBp0FBD/j3gkab62J1nq5rO3bGxUiEEEJ0Pynbh5VSbwEO0B835emHwHigop3K1q5am7Pcb6SorReUwkFnwbuPQPXNUNof27EJW2FP17UcS2rcQgghmknXsdu0SdyBNgy97uQK/K1LfVrgK0i9NOhhF8M7D8C7j8JRVxGOhT2nMpUatxBCiGRSNpVrrTdorTcAFnA78BLwO7po8G7tyPKygjRN7H1Hw9gZ7iC1aB1RO9qiLwZS4xZCCNGUl0j1MO6o8jeAI4FHgWNyWKYOUegvpGdBzxYHy2Yjypua9l/w+Anw4VNE9z+xRct1eh3IJoQQovvwErgLtdYvxB8/r5Sal8sCdaTxfcZn/6LDvwmDJ8Fb9xHZ77gWLdfpdSCbEEKI7sPLqHK/UupAgPi9TC5uCcOAqZdBxVrMNf9o0amhWEjmcgshhGjES+D+L+AxpdQm3Gbyn+S2SF3Q+JOg51DKVvxPi06TkeVCCCGa8tJU/m2t9WE5L0lX5vPDlB9T/PerKNuu2dtfeTrNdmwiVoQCf5J54kIIIbolLzXumUopX+bDvqaUMpVSDyql3lJK/VMpNTrFMS8ppea25Nr5KjpxNrFgCUM//ovnc2J2jLDtbd63EEKI7sFL4O4HbFZKvR0PxMs9nHMS7qC2qcB84I4kx/wG6OW5pHmuzudny7jj6bf+LQr3bPF0joNDXVQGqAkhhPial8D9XeAbwOm4SVnO8HDOdOBlAK3128ChiTuVUqcAdv0x3UHYCrNp3Ak4hsmwjxZ7Pq8mVpPDUgkhhMg3XgJ3Ae5a3C+TvOacTA+gKuG5pZTyAyilDgDOBK5NdwGl1Byl1Aql1Irdu3d7fNnOqzZWS7ikN1vGHsvAz5dSUO0t5Xt1pFpGlgshhGjgJXD/EXgQmAL8D/C4h3P2AIkpxUytdSz++FxgH2ApcD4wTyk1o+kFtNYLtNaHaq0P7dUr/1vUa6JuzXnjhFngOJ5r3RE7QigmiViEEEK4vIwqr9FavxR//KLHBCzLgO8BTyulpgCr6ndorX9R/1gpdT2wVWvdpZvMbcduCNzhsv5sG3MUg9b8gw0HnUqkuHfacy3boi5W13zpUCGEEN2Sl8D9pVLqGtwa8iFAWCn1HQCt9SspznkOODY+kM0ALogH/LUJWdi6jVAsRNT6esGQDRNPYeDnSxn60XOsm3JR2nMtx/K8opgQQoiuz0vgdoBR8Ru463OfEd+eNHBrrW2g6TSv1UmOu95rQfNZKBYi5sS+ft5jENtGHc7g1S+zceLJRIvK055fG6vNcQmFEELki4yBW2t9QXsUpCsLxULNlvPcOPFUBqx9nSEfv8AXh52b9vy9kb25LJ4QQog84mVwmmijZFO6asuHsGPkN9nnsxcJhPakPb9pU7sQQojuSwJ3O6iOVCfdvn7S6fiiYYZ9+Gza82NOTFYKE0IIAXhoKldKleBmOIsCc4A/aq035LpgXUXEiqRcV7u21zC2jT6SfT57kU0HfI9wSd+kx1m2DFATQgjh8lLjfgZ3NPltuMF7QU5L1MXUxmqxbCvl/vUHnwGOw/CVT6c8xsGRAWpCCCEAb4G7GHgBGKK1/i3QogVHuruwFW40orypUNkANu93HIPW/IOiqs0pj6uJSOpTIYQQ3gJ3EPhv4D2l1HigJLdF6lq8LBKyceKp2L4AI95/MuUx1dHqZiPThRBCdD9eAvfPgMHAjcDRuEFceORlKlekuBeb9v8eA/7zL0or/pP0mJgtA9SEEEJ4CNxa62W4QTuGu3DI57kuVFcRs2Np+6aXr4ny0z/Ucv59NZz38XHU+UsYuWJh8ms5McIxGaAmhBDdXcbArZT6M27e8VuBbwKP5bpQXUUoFiJmJ+/fXr4myuOvRaiodlf+Wl9Twj3h79Nn03v0+uqDZsfbji01biGEEJ6aygdrrRcC47TWc2m86pdII2yFU44of/atKJEmMf3R6HF8RT9GvfMYJDkvXe3dcRwqw5UtvqUb8S6EEKLz8ZKrPKiUmgV8qpTqiwRuz2pjtdgkH1BWX9NOFCbIbyJn8sDuuxm05lW27Hdco/3p+strojWsrlidsoafjGma7N9nf3oW9PR8jhBCiI7lpcZ9K3A6cDPwE+DXOS1RF1K/lGcyfUqNpNv/XTSZygHjGfnen/A1mQIWtsIp+7n3RvcSstzFTLzeIlaEPZH06VaFEEJ0Ll4Gpy0GfglMwE2+8mKuC9UVOI6TMtUpwMlTAwSbtHcE/XDytCBrp1xEILSH4R8802i/ZVvUWcn7uStDla0q5666Xa06TwghRMfwMjjtMuAB3JHlJwP35LpQXUEoFiJqp14YZNrYAOcfFWyoefcpNTj/qCDTxgao7juabWOOYsgnL1C4Z2vDOfW15KYiVoSqcFWrylkTq6E2KlnZhBAiX3jp454NHA4s0VrfrZR6N8dl6hJidixjwpRpYwNMGxtIuu8/h5xNvy+WMerf/8Mn376qYXuynOXV0WoidvOA7kXUilIdraY4UNyq84UQQrQvL33cJuDEbwAymdiDqB1tU6azSEkfNkw8lX4b3qb3l+99fd0ky3vuCe9p9Ws5OK2urQshhGh/XgL3k8AbwGil1N+A53Naoi7Ccqw2pyj98sCTqOk5hDFvLcCMD0prWrO2HZuKuoo2vc7u0O60zfpCCCE6Dy+D0+4FfgT8FLhSa317zkvVBcTsGA7Np3y1hOML8Pm0H1G0dyvDPnQHqoVijZcIrY3Wplw21KuwFZZFTIQQIk94GZz2Q+ACrfUi4A6l1Dm5L1b+SzaIrDUqB09g6+gjGfbRYooqNxGxIjjO118IaqI1ba4tW45FdTT1CHghhBCdh5em8kuA+tFRJwA/zl1xuo7WDhZLZt03LsDyFzB2+UPYttUoyUq25mFLP7cQQuQHL4Hb0lrHALTWUWhj+283ka0aN0C0qJwvDj2HXls+ovfaJQ01bMu2qAxXZuU19kb2ZrXMQgghcsPLdLC/KKX+BfwbOBh4IbdF6hqSTdtqi837HceAz19j5PKHCB14JvTel5poTdaCbdSOUhOpIVgUzMr1hBBC5IaXwWm/Af4LN3D/Qmv925yXKs9ZtpX9UdqGiT78v/DF6ij4+9WAmzwlW68j/dxCCJEfvA5OO0tr/b/AjTI4LbO2zuFOpbZ8KOsnzSaoX4JPnmNPOLt5xrPV7C6EECJ3ZHBaDnjJmtZaXx74AyIDDsB58WfUVG7I6rWro9UpFzERQgjROcjgtDzjmD52z7gRQlUMXXZvVq8ds2PUxZIvYiKEEKJzkMFpOeAzfRgkX7YzG5z++1H3zf+i37/upO/wKewcOS0r17UcK6vT2IQQQmRfSwenXS6D0zLzGT4MIzeB28DAZ/ioPOR89vQdjVp2P8GatqU8TSQrhQkhROfmZXDatcD3AQWcGH8u0jANM2c17vrAXetE+ezIn2JaUca9/jvIUp+6BG4hhOjcvDSVb4vfG7hN5V6CvQncD0zEXU3sYq312oT9lwLn4/aX3661frplxe7c/KYf0/AyfKDlDMMN3NXRaup6DubzqT9kv3/dw9BVz/PlhFltvn5NrAbHcXLWYiCEEKJtMgZurfVDic+VUi95uO5JQKHWeqpSagpwB3Bi/Py+uCPVJwGFwKdKqUVa6y416M1vevlO1HL1AbV+sZGtY46h95fvMXLFQnYPnkB139Ftun7MjhGKhSgKFLW5rEIIIbLPS+15bMLtCGC4h+tOB14G0Fq/DRxav0NrvRM4KD5CfSAQ6mpBG3IYuDGI2BEsx4pvMFgz/VIixeWM/+cd+KJtGxUes2OEbZkSJoQQnZWX9tyHEm7zcZf3zKQHkLhqhaWUaohkWuuYUuoy4G1gYbILKKXmKKVWKKVW7N6928NLdi65rHFbtvV14AZiBaWsPuIKiqq2MHbZ/eC0/nuQ7dhELVmbWwghOisvo8qP0lofBfwAOE1r7aWpfA9Qlvg69XPBE657LzAIOFwpdVSS112gtT5Ua31or169PLxk5xIwAzm5romZtP+8ctCBfHHImQxY9waDP/PyESXX1jXEhRBC5FbKwK2UOlgptVIpFVBK/QBYA6xQSn3Pw3WXATPj15kCrEq4rlJKLVZKGUAUd/BabtKMdSCf4cvJdQ3DSDlPfOPEU6gYeiij33mUsh1rWnf9HM4/F0II0Xbpaty3AefF+6JvBI4HDsNtLs/kOSCklFoO3AVcoZSap5T6vtZaAx8CbwHLgbe11q+35U10RrlqKjcNM/WXAsPksyMuJ1zcm/2X3EIg1Lpc5jKiXAghOq900cWntf5IKTUYKNFavweglMpYO9Za28DcJptXJ+y/AbihFeXNG7lqKi/wFZCuUhwrKOOTY67k4P+7knH/vJOPvvNLML3X/o34v45QHalmR90OHA999H7Tz7Aew9qhVEII0bmkC9z1I5RmAK8CKKUCNO67FikU+YvwGb5Gg8iyoUewR8bgWt13NJ9P/RFq2X1sePwxrqs7kz6lBidPDTBtbIYvFEbHNZfXRGvYsMfbwimFvkIGlQ7K2RckIYTorNIF7leVUsuAocD3lVKjgHuB/22XkuW54kAxftOPZWUvcBsYlARK3MBqkHa5l2fNoxhmr+E886+s8u3DM9VH8Phrbh7ydMG7I/u4W7LAieVYhGNhAkEJ3EKI7iVlH7fW+hbgYmCK1vqD+OYFWuub26Ng+S7oC1Lkz24SE7/pp8hf5Cml6rNvRbkuci7/sg7gJv8jHGqsJhJzt2eSq6xvmdTGvKdbtRyLsCXzzYUQ3U/av9Ba68+01pvjj9dprZ9rn2J1DT0Lemb1egEz0NAEnym4VlQ7WPi4NPoTNjn9eCh4F0OMHVRUp+8/Ng0zZwPr0nEch5pojefjbceWtcOFEN1Sx1StuomGZu0sKQ2W4jN9FAWKKPKlr833KXVfdw+lXBz9GX4sHgnczvCS9LXaoC9IcaA4a2X2KhQLEbNjmQ9MUGfJ2uFCiO5HAncOFfoKs1p7LQt+PS6wvLA87bEnTw0QjL/0f5zBXBK9nH2Nzfyx9E7MWOo1t8sLyjukqTxsh7Hslo0HqI5U56g0QgjReUngzqH6AWrZYBomJf6ShueZavPTxgY4/6hgQ81bFx/I3/a7jOFVn7Lf63dBiiBZGizNSnlbKmbHWjwCP2yFPU0dE0KIrqT9OzO7Eb/ppyxQ1qLR0umulbhiV3GgmIAZIGKnrj1PG9t0+tfRrO25l9H/fozIO4+ydsoPISHZit/0U+xv/2ZycPusW5pu1XZsLMfCb8ivsRCi+5Aad44lNm+3RYFZQKGvsOF5sb+YoC/Y4utsOvBEvjzgJIZ8+iLDPnq20b6AGeiQ/m2gxc3k4OZVb815QgiRz6SqkmPFgWJMw8R22paOvUdBj0apSA3DoGdBT6qjLe/nXfeN8wjW7WbfFU9g+Qv4an83/XxZsKzDEpq0dGAauCPRs53gRgghOjsJ3DlWEihhcOngtMlSvOhV2HyFtLJgGQZGy1f0MkxWH/4TTCvCmLcfwfYF2LLfDHoEe7StkG0Qc1oRuKXGLYTohiRw51ihv5DR5aNzcu36GnK6fu5UHNPPp0f+lAOW/Ba17AEMfyGl0w7KfiE9ak2N23ZsLCRwCyG6F+njzmMlgRJKAiWZD0zB8QX45Ogr2TX4IMa8cTc9Vr+cxdK1TKuaynGw7S63IqwQQqQlgTvP9S3q26bzbX+Qj4+9mtA+B2M+NxfefyJLJWsZ6eMWQghvJHDnuR7BHm0eUGYEigmd9gSMOhpeuAzeeShLpfMuamfOod6UgwRuIUT3I4E7z5UES9q8mEmhv5DS0n5wxlOw33fhpV/Av+7MUgkzcxynVYEbWjeNTAgh8pkE7jxnGmabm8t7F/Z2a+3+Ajj1cTjwVFhyA/zjWmiHPuSYHWt1BrTWBnwhhMhXMqq8C+hZ0BO/4W/VlCrTMCkvKP96gy8AP3gICnrAsrthzxY48T7wtzzZi1cxO4ZN674gtOY9CyFEPpPA3QWUBkoJ+oLEYi0PYkEz2Dy7m+mDE+6AnvvAkl9B9VY4fSEUZneZ0nqWY7W+xm1JjVsI0b1IU3kX4DN99ChoXfKU4kCK1KmGAd/6qVv73rAcHjseqja1saTJxRxpKhdCCK8kcHcRPQKtC9w9gxlq0RNnw1mLoHIjLDgKNr7TqtdJJ2JFWj06vC5W16qpZEIIka8kcHcRRYEifIavReeYmN4WFRl1NFz8KgRL4A/fhZULW1nK5GqjtS1P2xoXs2OEYqGslkcIITozCdxdREmgpMVrf/tNv/fVwPrvBz9cCsOmwl8uhZevAis7Nd2aaE2rz43ZMUKWBG4hRPchgbuLCPqCLV5Lu8XnFPeGsxfD5Lnw9v3wh++5o87bwLKtVq1wVs/BoS7a9vXOhRAiX0jg7kJ6FrRs1HfPgp6Nlgr1xOeH42+BWQ/Dlg/gwemw7rWWXSNBNvqoa2Ktr7ELIUS+kcDdhZQESjDwHohLg6Wtf7EJp8EPX4PiPvDED+Cft0ArspiFrFCbs5/tjext9ah0IYTINxK4u5ACXwE+09sANdMwKTAL2vaC9f3eE06Df94E/zMTdq9v0SXqonWtTr5SL2pFqYtJc7kQonuQwN2FBHwBTI8fqWmYLR7MllRBqTvXe9bDsP1TeGA6fPhn8FgD3h3e3eYiRO1omwa4CSFEPpHA3YX4TT+m4T1wt3VVsQaG4da6574JAw+E534Ei86H6h1pTwvFQlkJuA4OVZGqNl9HCCHygaQ87UICZsBtKvfQZWxiEvBlKXDX6zUczv+rm+P8nzfDF2/A8bfCgae4wb2J6mh12pSly9dEefatKBXVDn1KDU6eGmDa2ORl3h3aje3Ynr+4CCFEvspJ4FZKmcD9wEQgDFystV6bsP8KYHb86d+01jfkohzdUYGvwFMt1m/6s9NU3pTpg2/NAzXTXdt78cXw8TNwwp1u7vMEeyN7U/ZvL18T5fHXIkTiA84rqh0efy0CkDR4R6wI1ZHqVqd+FUKIfJGr6slJQKHWeiowH7ijfodSal/gLGAaMAX4jlJqQo7K0e0U+LwNOPN6XKv13w8u/DscdzP853W49zBY9nuI17Adx2FX3a6Upz/7VrQhaNeLxNztyUg/txCiu8hV4J4OvAygtX4bODRh35fADK21pbV2gAAgqa+yJOmCIUkU+gtzXBLc2vfUH8Olb8PIb8E/fgkPfgvWv0lNtCZtxrOK6uSD21JtB6gMV7a1xEII0enlqo+7B5A4WshSSvm11jGtdRTYqZQygNuAlVrrNU0voJSaA8wBGDx4cI6K2fV4neKVtYFpXvQaAWf+L+iX4KVfwOMn4Fcz8U84iWiPAUlP6VNqJA3SfUpTz1PfE9lDzI7lpgugi7Mdm511Oz0fX+gvpEdQuiWE6Ai5+gu3B0hc5NnUWjc0fCqlCoHHgL3Aj5NdQGu9AFgAMGvWLMmu4ZHf5+0jbdfAXU8dDyOPgGV3E1z2Ow77/BW+GjeTDQedSqywcRA4eWqgUR83QNDvbk+lfsGRNiWW6aaqQlWs2bWGmOMti13vwt4c2PfAlmfeE0K0Wa6aypcBMwGUUlOAVfU74jXtvwAfaq1/pLVuW9os0YjP8Hmay531EeVeBYvhqKv4/Oz/Zevooxjy6V+ZvGguQz9ajBmLNBw2bWyA848KNtSw+5QanH9UMOWocnDznsuCI62ztXar56ANsCe8R7omhOgguapxPwccq5RaDhjABUqpecBawAccARQopY6PH3+V1vqtHJWlW/EZPrcWlKaNwsRs8RKg2WTZFlUFxWz51mV8tf/32PfdPzDq3T+wz2cvseGgU9k6+igcnzv1K12gbsrGlgxqrbA3vJfdoZYlwok5MbbVbqNXYa8clUoIkUpOArfW2gbmNtm8OuFxO4yM6p7qk7BYTuqGDMMwOjRwh6wQUdsdHV7TezirjruW8s0fsu+7T6DevI/hK59m48ST2TL22zgtbBmQkeUttzO0k4gdyXxgE7vqdlEdqZauCSHamWSr6GIaatxpmEbH1rhDsVCzLxaVgyfy/vdv46PjriNc0puxyx9kytM/Yp9P/g8zFvZ87epItSw40gKhWIhtNdtadW7EjrRoQJsQIjtk+G0X4zf9Gfu4DYwOHXldF6vDdpIkXjEMdg05mF37TKJ8y0eMeP/PjHn7EYZ/sIivxs1k87gZRIvK0147YkcIxUIUBYpyU/guZlfdrjaNC9has5WBJQPbZ3qhEAKQwN3l+E0/AV8AJ00nd8AMdGjgThq0ExkGlYMn8sHgifTc8jHDPlrMyJVPMfzDRWwbdQSb9v8eNX1GJj3VcZw2rzbWXcTsGFtqtrTpGmErzO7QbgaVDspSqYQQmUjg7mIMw2D/PvtnPK4jA3dLphBVDTqAVYMOoKhyE0M+/SsDP1/KoM+XsHvQgXw1/gQqhh2Gk/BeDAzPK6R1d5XhSmpibRsT4OCwpWYL/Yv7e15SVgjRNhK4u6DO3mzpo+V/4OvKh/D5tLl8ccjZDNKvsM+nL3LAkt8SLurFtjFHsWXssdT1HIxhGLLQiEfba7dnbv3woCZaQ1W4it5FvbNQKiFEJhK4RbszzdYH1lhBKV9OmMWmA06k96b3GaT/wdBVzzPso8VUDjyAneNmYvYeD/4c52LPc62ZApaK5Vhsq90mgVuIdiKBW7S7bNSIHdNHxbDDqBh2GMHaXW4Tuv4Ho1+7FWfZ/e7qZAeeAqOOho5KNtOJVYQqGqbkZcPu0G5qojWUBEqydk0hRHISuEW7M+L/0g2ga4lIcW82TjyFjRNm0X/HWsZ99TF8+hdY9TQU9YLxJ8IBp8Dwae7CJ92c4zjsCqVema01onaU6ki1BG4h2oEEbtHuTMPEMIzsz7c2TGr3ORjjkDkw83ZYtwRWPQMfPQ3vPQ7FfUHNAHUCjDoKuumUsZpoDaFYdlPDOjhURaoYUJJ80RghRPZI4BbtriRQQsAMELa8J1bxqryw3H3gD7qLmqjjIVIDa/4Oq1+ET/8PVi6EQLHbjK5mwuhjoGxg1svSWdVEa7LaTF6vMlQpq7MJ0Q7kf5hod4X+QkoCJVkP3AYGPYM9m+8IlsABs9xbLAIb3oTVf3MD+eq/uscMOMAN5KOPgWFTu/TgtqpIVda6KRJFrAg10Rp6FiT5DITIE6FYiIjVOAVwj4LOtYStBG7RIXoV9Mp6P2vADGTuY/UH3QA96miYeRtsXeU2qa9dAm8/AMt/79bGh0+L374Jgyd1mUAes2NUhipzc20nRnWkWgK3yGs763ayfs/6hudBM8ikAZM6ZinkFCRwiw5RGizFZ/jSLobSUsX+YooDxd5PMAwYNMG9Tb8CwtWw/k03kH/xL1jyK/c4fyEMOezrQD7kMHd50jwUtaItWr6zpeosWZ1N5LeIFSFmf/1/xMQkakUlcAtRGiglYAawrOwF7jbPIy4ojQ9em+E+r6mAjW/BhmXu7Y3bwLkFTL/btL7PIbDPwe5937EyYh23u0KIfNa0C892bCJ2hGI6z5d1CdyiQwR8AcoLy9laszUr1/MZPkoDWV5esqQPjPuuewMIVcGX/3aD+FfvuaPVVzzq7guWwqCJbiAffDAMPBB67yvBXIg84jgOtdHaRtssxyJqZX8wZ1tI4BYdpldBL7bVbMvKQKmgL0hZsCwLpUqjsCeMOda9Adg2VKx1g/jm9937dx6C+oEt/kLot59bOx+wPwwY7z4u6ZvbcgohWiUUCzVbm97BoTZWm+KMjiGBW3SYXoW9KPQVZqVfdEDxAALtnSHNNKHfWPd20BnutlgEtn/q3rZ94t4+fwU+WPj1ecV9oe8Y6DPavfUdA33GQK8R7uA5IUSHCFmhRv3b9WoibVuMJ9skcIsOE/QF6V/Snw17NrTpOgEzQO/CTpIn2x+EwQe5t0TV278O5Ds17FwLa16Gmh1fH2P4oNfweECPB/LyYV/fCtreFWAapqd+6OVrojz7VpSKaoc+pQYnTw0wbWzmL0aywIvIZ3XRuqQDZquj1UTtzjNATQK36FC9C3uzuXpzmxKC9Czomftm8rYq7e/eRh3VeHtdJVSsg4rPYefnbtN7xVp3VHusSUtEUe/Ggbx8OPQcAj0GQdlgtwk+Q596gb+AIn9R2jn0y9dEefy1CJF4xaOi2uHx19zmw3TB28DI/jgDIdqJ7dhsr9uedF/IClEVrqJvUefo5pLALTpUj2APyoJlrZ7TbWIyoGhAi9b47lSKymHIIe4tkW27tfHKjVC5wb2v+tK937HabX5vmrbU8EHpgHggr78NdO9LB7iD7Ur60ctfTGW4MmWRnn0r2hC060Vi7vZ0gTtgBlo2HU+ITmRvZC/V0eqk+2zHZkftDgncQgAYhsGA4gHsDu1u1SC1okDR12lOuxLThLIB7m3oYc33O048sH8Je7ck3La69xXr3DnpSZKtDAf2CRQRLexJtLAHkaKeXz8uLOfw2gKqzBL2OMVUUUqVU0IVJVRUp+9/L/QXUuyXwC3y067QrqT92/V2h3dTG63tFF9OJXCLDtersBclgZJWNZf3L+7f/oPSOgPD+Lr5PZ1onRvIq3dA7U6o2Ul07xZ27FyNr66CQN0eCqt3UrZzHYHQHkw7xl0p4nOYAMaTJUSDpcQKSogl3EcLSulRNhijx0p3alxBqZtqNliW8LjUvfnkz47oXGqjtRmnpkasCNtrtzOi54j2KVQa8j9IdLigL8iBfQ/EduwWn+uXIJBeoMidT9573683ATu2f8ju8O7GxzoO/kgNq1bv4tW3Kym2a+hJDT2MWnqbNXxzeB3DS+rwR2rwh6sJhioprvrKfR6pwfD6+fkLvw7kBWXxxyXgL4JAYcJ9oVv+RvfFTY5pcu8rcNdf9wXdNLWm3/2SI0Qam2s2e1o7YXPNZvoW9aU02LFjOeSvnugUCrpILvB80buod/PAbRjECkoZN7GU3UWDmo0qD48NsCbF9QrMAAeVK4psCyLV7i1c3eRxTfLn4b3urXqHOyAvGr/FQu59W+f5+4JJbgE3sNcH+ab76gO/L+AG/4abzx1L0HRbo+dmk+dNjjF8Sc6Jn2f4wDCb38wk2xpuPvfLSdLzEq8nX2CS2RPZw7aabZ6OjVgRNtdsZmxwbI5LlZ4EbiG6oZ7BngTMQMruiWljvU3/arheYS+KGhLLZHFNbsdxE9o0BPJaiIbiAT7xPh7krQhYUbDCCY/j97Gm2xJvUffaoUp3Ln7iPtsCO5ZwH79lMc9+u2kW8M3GgT3xOcSDvZHmnsbPPZ2T7Bq08BwjxTlpXr/hZb4+18HBjNaynxVu9MXGwaC6776sP/jMZj/CHbU76FfUj16FvVr+888SCdxCdEOlwVKK/EVEI21P5Whg0KewTxZKlezihlvz7YwtMo7jBnMnMaA3Ce7Ntlnpj3Hslt1syy1H0v1W/D7JfttKeN50f/yaOEnuSbG9vlUk1b4kx9Y/T3zs9b7hnIRzbTtD2Wh2bsyO4MRCBBNbdeIPI7XJA3PUjrJhzwZKg6UdNq9bArcQ3ZBpmPQt6sueyJ42XyvoC3bPpTwNIz7Qzg90wi8WIq1QLMRHOz9qlpvci6pwFVurtzK0x9AclCwzCdxCdFM9CnrgN/1pp8B4uk6wB4X+wiyVSoj2sWnvpqRB20vWQAeHL6u/pLygnLKC9k/+JPkJheimegR7UOhre8Bt83KqQrSzirqKpNO/6rMGVlS77eX1WQOXr2nepRSxImzYu6FVs2HaSgK3EN2UaZhtbuL2m35JuiLyStRy+6hjTvOWpnRZA5PZFdrF9trkaVJzKSdN5UopE7gfmAiEgYu11mubHNMPWAZM0FqHml9FCJFrbc3xLmlORb7ZXLOZvZG9SffV17S9brcdm417NlJeUN6u3UW5qnGfBBRqracC84E7EncqpY4DXgEG5uj1hRAeFPuL8Zut//5eFijrNCsmCZFJKBZic/XmlOmV+5Qmn+ueajtAbay23WvduQrc04GXAbTWbwOHNtlvA98GWreyhBAiK4oCRW0KvB0xMEeI1qoMVxKxIin3nzw1QLDJ99ig392ezvba7Vh2+83rz9Wo8h5AVcJzSynl11rHALTW/wBQSqW8gFJqDjAHYPDgwTkqphDdW8AMUBYso67pEqIemIZJib8kB6USIjd21O1Iu5hR/ejxlq5FXxeroypc1W4DNXMVuPcAiV/Fzfqg7ZXWegGwAGDWrFltzHkohEiltcHXb/hlGpjIG+FYmOpI8mU7E7U0ayCA5VhUR6vbLXDnqql8GTATQCk1BViVo9cRQrRRa/PEm4ZJ0Jd+qU8hOougL0jQzM3vq4FBkb8oJ9dOJleB+zkgpJRaDtwFXKGUmqeU+n6OXk8I0UpBM4hptPxPQYGvoE0D24RoT4Zh0LMwNxn+/Ka/XQN3Tv7Xaa1tYG6TzauTHDciF68vhPAu6AviM3wtTiRRFGi/P1RCZENZoAwTE5vsJk0p8BW067RIScAiRDcX9LWuxp2NrGtCtKe+RX3pX9w/q9cMmkFGlY9q1f+h1pLALUQ3FzADrZoSJmuoi3zjM32M7DmS8oLy7FzP8DGyfGS7L/EpHVRCdHOGYVDsL6Y6mnnEbT3TMCkwJXCL/FPgL2B0+WhW71pNxE49pzsTA4OBJQMZWNz+ecQkcAsh3P65Fkzl9ht+qXGLvFUaLGVCvwltTpoS9AUxjNRZ1XJFArcQosXzsX2mjwKfBG6Rv4K+IPg6uhStI33cQggKfAX4DO9/xWQqmBAdR/7nCSEo8BVQGij1PCWsR7BHjkskhEhFArcQguJAMZMGTOroYgghPJCmciGEECKPSOAWQggh8ogEbiGEECKPSOAWQggh8ogEbiGEECKPSOAWQggh8ogEbiGEECKPSOAWQggh8ogEbiGEECKPSOAWQggh8ogEbiGEECKP5EWu8k8++WSnUmpDBxahL7CzA1+/vcn77bq603sFeb9dWVd/r8NT7TAcx2nPguQlpdQKrfWhHV2O9iLvt+vqTu8V5P12Zd3pvTYlTeVCCCFEHpHALYQQQuQRCdzeLOjoArQzeb9dV3d6ryDvtyvrTu+1EenjFkIIIfKI1LiFEEKIPJIX08Hai1LKBO4HJgJh4GKt9dqE/T8EfgTEgN9orf/aIQXNAqVUAHgMGAEU4L6fFxL2XwFcDOyIb/qR1lq3dzmzSSn1PrAn/vQLrfUFCfu6zGcLoJQ6Hzg//rQQOAgYqLWujO+/G5gO7I0fc6LWuqpdC5kFSqnJwC1a6yOVUqOBxwEH+Bi4VGttJxxbBCwE+uO+7/O01juaX7XzavJ+DwLuASzcv1fnaq23NTk+5e98PmjyficBfwU+j+9+QGv9vwnH5v3n65UE7sZOAgq11lOVUlOAO4ATAZRSA4GfAIfi/iF8Uyn1D611uKMK20ZnAxVa63OUUr2BD4AXEvYfgvuH4L2OKFy2KaUKAUNrfWSSfV3ts0Vr/ThuEEMpdR/wWH3QjjsEOE5rnbfzYJVSvwDOAWrim+4ErtFa/1Mp9SDu/93nEk65BFiltb5eKTUbuAb47/Ysc1skeb93A/+ltf5AKfUj4EpgXsLxKX/n80GS93sIcKfW+o4Up+T159sS0lTe2HTgZQCt9du4f8jrfQNYprUOx2sma4EJ7V/ErFkE/DL+2MCtaSY6BLhKKfWmUuqqdi1ZbkwEipVSryillsa/mNXrap9tA6XUocD+WusFCdtMYAywQCm1TCl1YYcVsG3WAbMSnh8CvB5//BLw7SbHN/z/TrG/s2v6fmdrrT+IP/YDoSbHp/udzwfJPt8TlFJvKKUeVUqVNTk+3z9fzyRwN9YDSGwutJRS/hT79gI926tg2aa1rtZa743/8j+D++000Z+BucDRwHSl1Hfbu4xZVgvcDhyH+77+1FU/2yauBm5osq0Et4n1bGAG8GOlVN59UdFaPwtEEzYZWuv60bbJPsPEzznvPuOm71drvQVAKTUNuAy4q8kp6X7nO70kn++/gZ9rrQ8H/gNc1+SUvP58W0ICd2N7gMRvcabWOpZiXxlQ2U7lygml1FDgNeAJrfWTCdsN4Hda651a6wjwIjCpg4qZLWuAhVprR2u9BqgABsX3dbnPFkApVQ4orfVrTXbVAndrrWu11nuBpbi1s3xnJzxO9hkmfs5d5TM+HXgQOCFJf2663/l89FxC191zNP+b1OU+31QkcDe2DJgJEG9WWpWw79/At5RShUqpnsA43AEweUkpNQB4BbhSa/1Yk909gI+VUqXxIH40kO993RfijllAKTUY9z1uie/rUp9tgsOBJUm2jwWWKaV88UGK04H327VkubFSKXVk/PHxwL+a7G/4/51if15RSp2NW9M+Umv9nySHpPudz0d/V0p9I/74GJr/TepSn286edNs0k6eA45VSi3H7fe9QCk1D1irtX5BKfV73F8GE/h/WuumfUr55GqgF/BLpVR9X/fDQInWeoFS6mrc2ngYWKK1/lsHlTNbHgUeV0q9iTvq+ELgJ0qprvjZ1lO4TYruk8a/y08Ab+M2Rf5Ra/1JB5Uxm34KPKyUCgKf4XYBoZR6Bfgu8ADwh/jvQAQ4s6MK2lZKKR/we2AjsFgpBfC61vo6pdQfcbu+mv3OJ7Qg5qNLgHuUUlFgKzAHuubnm4kkYBFCCCHyiDSVCyGEEHlEArcQQgiRRyRwCyGEEHlEArcQQgiRRyRwCyGEEHlEArcQQgiRRyRwCyGEEHlEErAIIXIivsziy8DRWmvL4zlB4NX4OfmcLESInJHALUQeiKfyfBr4FDcLVg/crGhnAdMS9hm466tforVemeJahcBqrfWIFpahEDhba/1IfL3v/bTW89OcciGw2GvQBtBaR5RSS4DTgT+1pHxCdBcSuIXIH0u11rPrnyilngS+D+xM3KeU+g7wa9w0kNk0ELgYeMTj8WeRkHZSKbUI2AYcBAyN7/8RMBn4l9b6ovihzwM3I4FbiKQkcAuRh+JNyoOA3Ul29wK2Nzm+FDcQ9sJdb7x+ewB3dakxuGNergFGACfhrrDUF/hVfInF/weMV0pdi5sje0o8T3Q/4IEma34HgX211usTinEg8JbW+rJ4LvxHgSOBHcAmpVSB1jqMu8DLYS3+oQjRTcjgNCHyx9FKqX8qpT7FXc3rOa31kib73gL+B3c99URzgY/jaxk/lLD9YmBnfPuJwH3x7SXAscB3gDvj6zjfCHyqtf5V/Jgo7lrPPwAub/J6fUlYVjHezF4O/C6+yQEe1VpvifdlW7gLQxBvWo/E14oXQjQhgVuI/LFUa30k8C3cIPdF031a66m46xT/OT44rN5Y3OVL0Vq/gxt0wa0Fz1RK/RN4FrcVri/uSlO21nobbq2+X5LyvK+1dnBXaipusq8OKEx4vn/8+Po1sycC7wAopYYAm+PXqlcAdIUV2oTIOgncQuQZrXUFcDbwiFJqUJJDtiXZ9ikwFUApNQkIxLevBp6KfyE4HlgE7AIOiR87AHcg3HbApvHfjJRLC2qtdwO+eE0b3C8IHyYcMgH4KP54YsJjlFJ9cFsBogghmpHALUQe0lp/irse8+/jm+qbypcArwDztNZ1Cac8COwbX6v4Utx11sFtNt9PKfU6sBzYgBugB8av9SLw43jz9XYgqJS6xWMxXwGmxx8fCHwADc3mRfHgDo2DOMBR8dcVQiQh63ELIRrxONXLy3UOBq7QWp/TwvMWA/O11mva8vpCdFVS4xZC5ITW+n3gNaWUz+s58dHoz0vQFiI1qXELIYQQeURq3EIIIUQekcAthBBC5BEJ3EIIIUQekcAthBBC5BEJ3EIIIUQekcAthBBC5BEJ3EIIIUQekcAthBBC5JH/Dx+Z4+aLLUHTAAAAAElFTkSuQmCC\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "%matplotlib inline\n", "results.plot()" @@ -261,9 +199,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "api_updates", "language": "python", - "name": "python3" + "name": "api_updates" }, "language_info": { "codemirror_mode": { @@ -275,9 +213,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.11" + "version": "3.9.13" } }, "nbformat": 4, - "nbformat_minor": 1 + "nbformat_minor": 4 } diff --git a/jupyter_notebooks/Tutorials/algorithms/advanced/GST-FiducialPairReduction.ipynb b/jupyter_notebooks/Tutorials/algorithms/advanced/GST-FiducialPairReduction.ipynb index 376dd2932..e75415e07 100644 --- a/jupyter_notebooks/Tutorials/algorithms/advanced/GST-FiducialPairReduction.ipynb +++ b/jupyter_notebooks/Tutorials/algorithms/advanced/GST-FiducialPairReduction.ipynb @@ -27,17 +27,9 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Gate operation labels = [Label(('Gxpi2', 0)), Label(('Gypi2', 0))]\n" - ] - } - ], + "outputs": [], "source": [ "#Import pyGSTi and the \"stardard 1-qubit quantities for a model with X(pi/2), Y(pi/2)\"\n", "import pygsti\n", @@ -70,25 +62,9 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "** Without any reduction ** \n", - "L=1: 92 operation sequences\n", - "L=2: 168 operation sequences\n", - "L=4: 285 operation sequences\n", - "L=8: 448 operation sequences\n", - "L=16: 616 operation sequences\n", - "L=32: 784 operation sequences\n", - "\n", - "784 experiments to run GST.\n" - ] - } - ], + "outputs": [], "source": [ "#Make list-of-lists of GST operation sequences\n", "fullStructs = pc.create_lsgst_circuit_lists(\n", @@ -116,12 +92,14 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "fid_pairs = pygsti.alg.find_sufficient_fiducial_pairs(\n", " target_model, prep_fiducials, meas_fiducials, germs,\n", - " search_mode=\"random\", n_random=100, seed=1234,\n", + " search_mode=\"random\", n_random=10, seed=1234,\n", " verbosity=1, mem_limit=int(2*(1024)**3), minimum_pairs=2)\n", "\n", "# fid_pairs is a list of (prepIndex,measIndex) 2-tuples, where\n", @@ -194,38 +172,9 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "------ Per Germ (L=1) Fiducial Pair Reduction --------\n", - "Progress: [##################################################] 100.0% -- Circuit(Gxpi2:0Gxpi2:0Gypi2:0@(0)) germ (5 params)\n", - "\n", - "Per-germ FPR to keep the pairs:\n", - "Qubit 0 ---|Gxpi2|---\n", - ": [(0, 1), (3, 1), (3, 3), (5, 5)]\n", - "Qubit 0 ---|Gypi2|---\n", - ": [(0, 3), (2, 3), (5, 2), (4, 4)]\n", - "Qubit 0 ---|Gxpi2|-|Gypi2|---\n", - ": [(3, 4), (5, 2), (5, 5), (5, 4)]\n", - "Qubit 0 ---|Gxpi2|-|Gxpi2|-|Gypi2|---\n", - ": [(0, 2), (1, 2), (1, 4), (3, 0), (4, 4), (0, 4)]\n", - "\n", - "Per-germ FPR reduction (greedy heuristic)\n", - "L=1: 56 operation sequences\n", - "L=2: 61 operation sequences\n", - "L=4: 71 operation sequences\n", - "L=8: 89 operation sequences\n", - "L=16: 107 operation sequences\n", - "L=32: 125 operation sequences\n", - "\n", - "125 experiments to run GST.\n" - ] - } - ], + "outputs": [], "source": [ "fid_pairsDict = pygsti.alg.find_sufficient_fiducial_pairs_per_germ_greedy(target_model, prep_fiducials, meas_fiducials,\n", " germs, verbosity=1)\n", @@ -275,7 +224,7 @@ "#Next use this set of vectors to find a sufficient reduced set of fiducial pairs.\n", "#Alternatively this function can also take as input a list of germs\n", "fid_pairsDict = pygsti.alg.find_sufficient_fiducial_pairs_per_germ_global(target_model, prep_fiducials, meas_fiducials,\n", - " germ_vector_spanning_set=germ_set_spanning_vectors, verbosity=1)\n", + " germ_vector_spanning_set=germ_set_spanning_vectors, verbosity=2)\n", "print(\"\\nPer-germ Global FPR to keep the pairs:\")\n", "for germ,pairsToKeep in fid_pairsDict.items():\n", " print(\"%s: %s\" % (str(germ),pairsToKeep))\n", diff --git a/jupyter_notebooks/Tutorials/algorithms/advanced/Time-dependent-GST.ipynb b/jupyter_notebooks/Tutorials/algorithms/advanced/Time-dependent-GST.ipynb index 82a282774..72468f428 100644 --- a/jupyter_notebooks/Tutorials/algorithms/advanced/Time-dependent-GST.ipynb +++ b/jupyter_notebooks/Tutorials/algorithms/advanced/Time-dependent-GST.ipynb @@ -12,7 +12,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -31,7 +31,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -82,20 +82,9 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[[1. 0. 0. 0. ]\n", - " [0. 0.9 0. 0. ]\n", - " [0. 0. 0.9 0. ]\n", - " [0. 0. 0. 0.9]]\n" - ] - } - ], + "outputs": [], "source": [ "t = 0.1\n", "Gi_at_t = MyTimeDependentIdle(1.0)\n", @@ -113,7 +102,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -130,20 +119,9 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "OutcomeLabelDict([(('0',), 0.9050000000000002), (('1',), 0.09499999999999997)])" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "mdl.probabilities( ('Gi','Gi'), time=0.1)" ] @@ -157,17 +135,9 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[[0.905]]\n" - ] - } - ], + "outputs": [], "source": [ "E = mdl['Mdefault']['0']\n", "rho = mdl['rho0']\n", @@ -184,20 +154,9 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "OutcomeLabelDict([(('0',), 0.8600000000000002), (('1',), 0.14)])" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "Gi_with_duration = pygsti.baseobjs.Label('Gi',time=0.1)\n", "mdl.probabilities( (Gi_with_duration, Gi_with_duration), time=0.1)" @@ -212,17 +171,9 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[[0.86]]\n" - ] - } - ], + "outputs": [], "source": [ "Gi_at_t.set_time(0.1)\n", "Gi_matrix_at_t1 = Gi_at_t.to_dense().copy() # .copy() is needed because copies of the internal dense rep are not made by default (for performance)\n", @@ -240,20 +191,9 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "OutcomeLabelDict([(('0',), 0.8600000000000002), (('1',), 0.14)])" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "mdl.probabilities( (('Gi','!0.1'),('Gi','!0.1')), time=0.1)" ] @@ -270,34 +210,14 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Dataset outcomes: OrderedDict([(('0',), 0), (('1',), 1)])\n", - "Gi :\n", - "Outcome Label Indices = [0 1 0 1 0 1]\n", - "Time stamps = [0. 0. 0.1 0.1 0.2 0.2]\n", - "Repetitions = [100. 0. 95. 5. 90. 10.]\n", - "\n", - "GiGi :\n", - "Outcome Label Indices = [0 1 0 1 0 1]\n", - "Time stamps = [0. 0. 0.1 0.1 0.2 0.2]\n", - "Repetitions = [100. 0. 90.5 9.5 82. 18. ]\n", - "\n", - "\n", - "\n" - ] - } - ], + "outputs": [], "source": [ "circuits = pygsti.circuits.to_circuits([ ('Gi',), ('Gi','Gi')]) # just pick some circuits\n", "\n", "ds = pygsti.data.simulate_data(mdl, circuits, num_samples=100,\n", - " sample_error='none', seed=1234, times=[0,0.1,0.2])\n", + " sample_error='none', seed=1234, times=[0,0.2])\n", "print(ds)" ] }, @@ -312,34 +232,14 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Dataset outcomes: OrderedDict([(('0',), 0), (('1',), 1)])\n", - "Gi!0.05 :\n", - "Outcome Label Indices = [0 1 0 1 0 1]\n", - "Time stamps = [0. 0. 0.1 0.1 0.2 0.2]\n", - "Repetitions = [100. 0. 95. 5. 90. 10.]\n", - "\n", - "Gi!0.05Gi!0.05 :\n", - "Outcome Label Indices = [0 1 0 1 0 1]\n", - "Time stamps = [0. 0. 0.1 0.1 0.2 0.2]\n", - "Repetitions = [97.5 2.5 88.25 11.75 80. 20. ]\n", - "\n", - "\n", - "\n" - ] - } - ], + "outputs": [], "source": [ "circuits = pygsti.circuits.to_circuits([ (('Gi','!0.05'),), (('Gi','!0.05'),('Gi','!0.05'))])\n", "\n", "ds = pygsti.data.simulate_data(mdl, circuits, num_samples=100,\n", - " sample_error='none', seed=1234, times=[0,0.1,0.2])\n", + " sample_error='none', seed=1234, times=[0,0.2])\n", "print(ds)" ] }, @@ -353,11 +253,12 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "prep_fiducials, meas_fiducials = smq1Q_XYI.prep_fiducials(), smq1Q_XYI.meas_fiducials()\n", + "#taking just the 4/3 prep/meas fiducials below to produce a minimally informationally complete set.\n", + "prep_fiducials, meas_fiducials = smq1Q_XYI.prep_fiducials()[0:4], smq1Q_XYI.meas_fiducials()[0:3]\n", "germs = smq1Q_XYI.germs()\n", "maxLengths = [1, 2]\n", "idle_gate_label = () # the smq1Q_XYI model labels an idle circuit layer by an empty tuple, not 'Gi'\n", @@ -371,7 +272,7 @@ "\n", "#Data for initial non-sparse mode\n", "ds = pygsti.data.simulate_data(mdl_datagen, edesign.all_circuits_needing_data, num_samples=10,\n", - " sample_error=\"binomial\", seed=1234, times=np.linspace(0,0.3,10))" + " sample_error=\"binomial\", seed=1234, times=np.linspace(0,0.3,5))" ] }, { @@ -387,265 +288,11 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "metadata": { "scrolled": true }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "--- Iterative GST: Iter 1 of 2 92 circuits ---: \n", - " MapLayout: 1 processors divided into 1 x 1 (= 1) grid along circuit and parameter directions.\n", - " 8 atoms, parameter block size limits (None,)\n", - " *** Distributing 8 atoms to 1 atom-processing groups (1 cores) ***\n", - " More atom-processors than hosts: each host gets ~1 atom-processors\n", - " Atom-processors already occupy a single node, dividing atom-processor into 1 param-processors.\n", - " *** Divided 1-host atom-processor (~1 procs) into 1 param-processing groups ***\n", - " --- TimeDependentPoissonPicLogLFunction GST ---\n", - " --- Outer Iter 0: norm_f = 1458.18, mu=1, |x|=2.73861, |J|=84056.2\n", - " - Inner Loop: mu=1124.47, norm_dx=1.45626e-06\n", - " (cont): norm_new_f=955.104, dL=1111.98, dF=503.078, reldL=0.762583, reldF=0.345003\n", - " Accepted! gain ratio=0.452414 mu * 1.00086 => 1125.44\n", - " --- Outer Iter 1: norm_f = 955.104, mu=1125.44, |x|=2.73835, |J|=7225.05\n", - " - Inner Loop: mu=1125.44, norm_dx=2.64525e-05\n", - " (cont): norm_new_f=661.735, dL=561.942, dF=293.369, reldL=0.588357, reldF=0.307159\n", - " Accepted! gain ratio=0.522062 mu * 0.999914 => 1125.34\n", - " --- Outer Iter 2: norm_f = 661.735, mu=1125.34, |x|=2.73558, |J|=1000.98\n", - " - Inner Loop: mu=1125.34, norm_dx=5.29004e-05\n", - " (cont): norm_new_f=566.661, dL=86.3544, dF=95.0744, reldL=0.130497, reldF=0.143674\n", - " Accepted! gain ratio=1.10098 mu * 0.333333 => 375.113\n", - " --- Outer Iter 3: norm_f = 566.661, mu=375.113, |x|=2.73022, |J|=444.999\n", - " - Inner Loop: mu=375.113, norm_dx=6.84181e-05\n", - " (cont): norm_new_f=529.67, dL=28.4205, dF=36.9905, reldL=0.0501543, reldF=0.065278\n", - " Accepted! gain ratio=1.30154 mu * 0.333333 => 125.038\n", - " --- Outer Iter 4: norm_f = 529.67, mu=125.038, |x|=2.72428, |J|=293.629\n", - " - Inner Loop: mu=125.038, norm_dx=0.000193623\n", - " (cont): norm_new_f=512.191, dL=13.9916, dF=17.4796, reldL=0.0264158, reldF=0.033001\n", - " Accepted! gain ratio=1.24929 mu * 0.333333 => 41.6792\n", - " --- Outer Iter 5: norm_f = 512.191, mu=41.6792, |x|=2.72059, |J|=222.497\n", - " - Inner Loop: mu=41.6792, norm_dx=0.00119679\n", - " (cont): norm_new_f=502.974, dL=6.6629, dF=9.2165, reldL=0.0130086, reldF=0.0179943\n", - " Accepted! gain ratio=1.38326 mu * 0.333333 => 13.8931\n", - " --- Outer Iter 6: norm_f = 502.974, mu=13.8931, |x|=2.72329, |J|=192.593\n", - " - Inner Loop: mu=13.8931, norm_dx=0.0105899\n", - " (cont): norm_new_f=487.572, dL=9.83005, dF=15.4024, reldL=0.0195439, reldF=0.0306226\n", - " Accepted! gain ratio=1.56686 mu * 0.333333 => 4.63102\n", - " --- Outer Iter 7: norm_f = 487.572, mu=4.63102, |x|=2.74577, |J|=186.93\n", - " - Inner Loop: mu=4.63102, norm_dx=0.0686085\n", - " (cont): norm_new_f=59020.7, dL=16.8328, dF=-58533.1, reldL=0.0345237, reldF=-120.05\n", - " Rejected! mu => mu*nu = 9.26205, nu => 2*nu = 4\n", - " - Inner Loop: mu=9.26205, norm_dx=0.0200332\n", - " (cont): norm_new_f=482.056, dL=9.25978, dF=5.51554, reldL=0.0189916, reldF=0.0113123\n", - " Accepted! gain ratio=0.595644 mu * 0.993 => 9.19722\n", - " --- Outer Iter 8: norm_f = 482.056, mu=9.19722, |x|=2.77247, |J|=2495.51\n", - " - Inner Loop: mu=9.19722, norm_dx=0.031166\n", - " (cont): norm_new_f=1014.24, dL=19.8836, dF=-532.186, reldL=0.0412474, reldF=-1.10399\n", - " Rejected! mu => mu*nu = 18.3944, nu => 2*nu = 4\n", - " - Inner Loop: mu=18.3944, norm_dx=0.00854571\n", - " (cont): norm_new_f=471.562, dL=15.5032, dF=10.4943, reldL=0.0321606, reldF=0.0217698\n", - " Accepted! gain ratio=0.676908 mu * 0.955708 => 17.5797\n", - " --- Outer Iter 9: norm_f = 471.562, mu=17.5797, |x|=2.78264, |J|=337.615\n", - " - Inner Loop: mu=17.5797, norm_dx=0.00998894\n", - " (cont): norm_new_f=466.6, dL=8.15748, dF=4.96203, reldL=0.0172989, reldF=0.0105225\n", - " Accepted! gain ratio=0.608279 mu * 0.989844 => 17.4012\n", - " --- Outer Iter 10: norm_f = 466.6, mu=17.4012, |x|=2.79289, |J|=153.455\n", - " - Inner Loop: mu=17.4012, norm_dx=0.0198957\n", - " (cont): norm_new_f=30022, dL=10.548, dF=-29555.4, reldL=0.0226062, reldF=-63.3421\n", - " Rejected! mu => mu*nu = 34.8023, nu => 2*nu = 4\n", - " - Inner Loop: mu=34.8023, norm_dx=0.00513341\n", - " (cont): norm_new_f=468.493, dL=6.14822, dF=-1.89275, reldL=0.0131766, reldF=-0.00405647\n", - " Rejected! mu => mu*nu = 139.209, nu => 2*nu = 8\n", - " - Inner Loop: mu=139.209, norm_dx=0.000326693\n", - " (cont): norm_new_f=463.733, dL=1.78423, dF=2.86706, reldL=0.00382389, reldF=0.00614458\n", - " Accepted! gain ratio=1.60689 mu * 0.333333 => 46.4031\n", - " --- Outer Iter 11: norm_f = 463.733, mu=46.4031, |x|=2.79745, |J|=171.024\n", - " - Inner Loop: mu=46.4031, norm_dx=0.002531\n", - " (cont): norm_new_f=460.641, dL=2.14449, dF=3.09156, reldL=0.00462441, reldF=0.00666668\n", - " Accepted! gain ratio=1.44163 mu * 0.333333 => 15.4677\n", - " --- Outer Iter 12: norm_f = 460.641, mu=15.4677, |x|=2.80591, |J|=225.884\n", - " - Inner Loop: mu=15.4677, norm_dx=0.0191469\n", - " (cont): norm_new_f=456.758, dL=4.19681, dF=3.88328, reldL=0.00911079, reldF=0.00843017\n", - " Accepted! gain ratio=0.925295 mu * 0.384596 => 5.94882\n", - " --- Outer Iter 13: norm_f = 456.758, mu=5.94882, |x|=2.82807, |J|=163.779\n", - " - Inner Loop: mu=5.94882, norm_dx=0.148192\n", - " (cont): norm_new_f=168561, dL=16.0542, dF=-168104, reldL=0.0351481, reldF=-368.038\n", - " Rejected! mu => mu*nu = 11.8976, nu => 2*nu = 4\n", - " - Inner Loop: mu=11.8976, norm_dx=0.0421518\n", - " (cont): norm_new_f=34961.4, dL=10.6471, dF=-34504.7, reldL=0.02331, reldF=-75.5426\n", - " Rejected! mu => mu*nu = 47.5905, nu => 2*nu = 8\n", - " - Inner Loop: mu=47.5905, norm_dx=0.00288744\n", - " (cont): norm_new_f=454.566, dL=3.83053, dF=2.19244, reldL=0.00838633, reldF=0.0048\n", - " Accepted! gain ratio=0.57236 mu * 0.996969 => 47.4463\n", - " --- Outer Iter 14: norm_f = 454.566, mu=47.4463, |x|=2.84365, |J|=339.313\n", - " - Inner Loop: mu=47.4463, norm_dx=0.0025276\n", - " (cont): norm_new_f=453.491, dL=5.17926, dF=1.07441, reldL=0.0113939, reldF=0.0023636\n", - " Accepted! gain ratio=0.207445 mu * 1.20031 => 56.9505\n", - " --- Outer Iter 15: norm_f = 453.491, mu=56.9505, |x|=2.85093, |J|=166.683\n", - " - Inner Loop: mu=56.9505, norm_dx=0.00139499\n", - " (cont): norm_new_f=451.007, dL=3.11484, dF=2.48409, reldL=0.00686857, reldF=0.0054777\n", - " Accepted! gain ratio=0.797502 mu * 0.78935 => 44.9539\n", - " --- Outer Iter 16: norm_f = 451.007, mu=44.9539, |x|=2.86291, |J|=283.801\n", - " - Inner Loop: mu=44.9539, norm_dx=0.00253741\n", - " (cont): norm_new_f=450.42, dL=2.52299, dF=0.586996, reldL=0.00559413, reldF=0.00130152\n", - " Accepted! gain ratio=0.232659 mu * 1.15286 => 51.8254\n", - " --- Outer Iter 17: norm_f = 450.42, mu=51.8254, |x|=2.87294, |J|=176.225\n", - " - Inner Loop: mu=51.8254, norm_dx=0.000732501\n", - " (cont): norm_new_f=448.586, dL=2.33779, dF=1.834, reldL=0.00519024, reldF=0.00407176\n", - " Accepted! gain ratio=0.784504 mu * 0.815772 => 42.2778\n", - " --- Outer Iter 18: norm_f = 448.586, mu=42.2778, |x|=2.88153, |J|=280.724\n", - " - Inner Loop: mu=42.2778, norm_dx=0.00193976\n", - " (cont): norm_new_f=448.262, dL=2.19893, dF=0.324334, reldL=0.00490191, reldF=0.000723014\n", - " Accepted! gain ratio=0.147497 mu * 1.35041 => 57.0924\n", - " --- Outer Iter 19: norm_f = 448.262, mu=57.0924, |x|=2.89063, |J|=181.224\n", - " - Inner Loop: mu=57.0924, norm_dx=0.000131988\n", - " (cont): norm_new_f=446.529, dL=2.02353, dF=1.73283, reldL=0.00451417, reldF=0.00386565\n", - " Accepted! gain ratio=0.856337 mu * 0.63803 => 36.4267\n", - " --- Outer Iter 20: norm_f = 446.529, mu=36.4267, |x|=2.89406, |J|=268.07\n", - " - Inner Loop: mu=36.4267, norm_dx=0.00150081\n", - " (cont): norm_new_f=446.253, dL=1.60088, dF=0.275977, reldL=0.00358515, reldF=0.000618049\n", - " Accepted! gain ratio=0.172391 mu * 1.28129 => 46.6732\n", - " --- Outer Iter 21: norm_f = 446.253, mu=46.6732, |x|=2.90213, |J|=188.515\n", - " - Inner Loop: mu=46.6732, norm_dx=8.69969e-05\n", - " (cont): norm_new_f=444.948, dL=2.00524, dF=1.3049, reldL=0.00449352, reldF=0.00292412\n", - " Accepted! gain ratio=0.650743 mu * 0.972597 => 45.3942\n", - " --- Outer Iter 22: norm_f = 444.948, mu=45.3942, |x|=2.90282, |J|=289.967\n", - " - Inner Loop: mu=45.3942, norm_dx=0.000791168\n", - " (cont): norm_new_f=444.607, dL=1.98129, dF=0.340962, reldL=0.00445285, reldF=0.000766296\n", - " Accepted! gain ratio=0.172091 mu * 1.28207 => 58.1983\n", - " --- Outer Iter 23: norm_f = 444.607, mu=58.1983, |x|=2.90774, |J|=194.431\n", - " - Inner Loop: mu=58.1983, norm_dx=6.16469e-05\n", - " (cont): norm_new_f=443.268, dL=1.52392, dF=1.33878, reldL=0.00342757, reldF=0.00301115\n", - " Accepted! gain ratio=0.878509 mu * 0.566172 => 32.9503\n", - " --- Outer Iter 24: norm_f = 443.268, mu=32.9503, |x|=2.90751, |J|=266.845\n", - " - Inner Loop: mu=32.9503, norm_dx=0.000863667\n", - " (cont): norm_new_f=442.886, dL=1.16281, dF=0.382834, reldL=0.00262326, reldF=0.000863661\n", - " Accepted! gain ratio=0.329232 mu * 1.03984 => 34.263\n", - " --- Outer Iter 25: norm_f = 442.886, mu=34.263, |x|=2.91267, |J|=204.106\n", - " - Inner Loop: mu=34.263, norm_dx=0.000149476\n", - " (cont): norm_new_f=442.357, dL=1.75881, dF=0.528371, reldL=0.00397124, reldF=0.00119302\n", - " Accepted! gain ratio=0.300415 mu * 1.0636 => 36.4422\n", - " --- Outer Iter 26: norm_f = 442.357, mu=36.4422, |x|=2.91114, |J|=323.905\n", - " - Inner Loop: mu=36.4422, norm_dx=0.00119255\n", - " (cont): norm_new_f=442.133, dL=2.95282, dF=0.224572, reldL=0.00667519, reldF=0.00050767\n", - " Accepted! gain ratio=0.0760533 mu * 1.60957 => 58.6563\n", - " --- Outer Iter 27: norm_f = 442.133, mu=58.6563, |x|=2.91727, |J|=201.683\n", - " - Inner Loop: mu=58.6563, norm_dx=0.000175305\n", - " (cont): norm_new_f=441.013, dL=1.8638, dF=1.1196, reldL=0.00421547, reldF=0.00253228\n", - " Accepted! gain ratio=0.600711 mu * 0.991828 => 58.1769\n", - " --- Outer Iter 28: norm_f = 441.013, mu=58.1769, |x|=2.91593, |J|=293.874\n", - " - Inner Loop: mu=58.1769, norm_dx=0.000228422\n", - " (cont): norm_new_f=440.567, dL=0.995595, dF=0.446361, reldL=0.00225752, reldF=0.00101213\n", - " Accepted! gain ratio=0.448336 mu * 1.0011 => 58.2411\n", - " --- Outer Iter 29: norm_f = 440.567, mu=58.2411, |x|=2.91763, |J|=223.88\n", - " - Inner Loop: mu=58.2411, norm_dx=2.53496e-05\n", - " (cont): norm_new_f=440.077, dL=0.513235, dF=0.48971, reldL=0.00116494, reldF=0.00111155\n", - " Accepted! gain ratio=0.954165 mu * 0.333333 => 19.4137\n", - " --- Outer Iter 30: norm_f = 440.077, mu=19.4137, |x|=2.91721, |J|=267.943\n", - " - Inner Loop: mu=19.4137, norm_dx=0.000934976\n", - " (cont): norm_new_f=439.911, dL=0.656759, dF=0.165392, reldL=0.00149237, reldF=0.000375825\n", - " Accepted! gain ratio=0.25183 mu * 1.12227 => 21.7875\n", - " --- Outer Iter 31: norm_f = 439.911, mu=21.7875, |x|=2.92094, |J|=230.855\n", - " - Inner Loop: mu=21.7875, norm_dx=0.00040805\n", - " (cont): norm_new_f=442.032, dL=1.40753, dF=-2.12064, reldL=0.00319957, reldF=-0.00482061\n", - " Rejected! mu => mu*nu = 43.575, nu => 2*nu = 4\n", - " - Inner Loop: mu=43.575, norm_dx=0.00011802\n", - " (cont): norm_new_f=439.922, dL=0.92053, dF=-0.0103703, reldL=0.00209253, reldF=-2.35737e-05\n", - " Rejected! mu => mu*nu = 174.3, nu => 2*nu = 8\n", - " - Inner Loop: mu=174.3, norm_dx=8.75887e-06\n", - " (cont): norm_new_f=439.477, dL=0.310421, dF=0.434333, reldL=0.000705643, reldF=0.000987319\n", - " Accepted! gain ratio=1.39918 mu * 0.333333 => 58.1\n", - " --- Outer Iter 32: norm_f = 439.477, mu=58.1, |x|=2.92112, |J|=253.926\n", - " - Inner Loop: mu=58.1, norm_dx=1.08758e-05\n", - " (cont): norm_new_f=439.331, dL=0.13707, dF=0.146481, reldL=0.000311893, reldF=0.000333308\n", - " Accepted! gain ratio=1.06866 mu * 0.333333 => 19.3667\n", - " --- Outer Iter 33: norm_f = 439.331, mu=19.3667, |x|=2.92104, |J|=276.992\n", - " - Inner Loop: mu=19.3667, norm_dx=0.00027269\n", - " (cont): norm_new_f=439.229, dL=0.213563, dF=0.101246, reldL=0.000486111, reldF=0.000230456\n", - " Accepted! gain ratio=0.474081 mu * 1.00014 => 19.3694\n", - " --- Outer Iter 34: norm_f = 439.229, mu=19.3694, |x|=2.92229, |J|=253.165\n", - " - Inner Loop: mu=19.3694, norm_dx=0.000127176\n", - " (cont): norm_new_f=439.982, dL=0.473574, dF=-0.752607, reldL=0.00107819, reldF=-0.00171347\n", - " Rejected! mu => mu*nu = 38.7387, nu => 2*nu = 4\n", - " - Inner Loop: mu=38.7387, norm_dx=3.78867e-05\n", - " (cont): norm_new_f=439.301, dL=0.312058, dF=-0.0714881, reldL=0.000710466, reldF=-0.000162758\n", - " Rejected! mu => mu*nu = 154.955, nu => 2*nu = 8\n", - " - Inner Loop: mu=154.955, norm_dx=2.94044e-06\n", - " (cont): norm_new_f=439.093, dL=0.108602, dF=0.136294, reldL=0.000247256, reldF=0.000310303\n", - " Accepted! gain ratio=1.25499 mu * 0.333333 => 51.6517\n", - " --- Outer Iter 35: norm_f = 439.093, mu=51.6517, |x|=2.92267, |J|=270.518\n", - " - Inner Loop: mu=51.6517, norm_dx=4.04036e-06\n", - " (cont): norm_new_f=439.049, dL=0.0313524, dF=0.044587, reldL=7.14026e-05, reldF=0.000101543\n", - " Accepted! gain ratio=1.42213 mu * 0.333333 => 17.2172\n", - " --- Outer Iter 36: norm_f = 439.049, mu=17.2172, |x|=2.92308, |J|=277.647\n", - " - Inner Loop: mu=17.2172, norm_dx=9.05697e-05\n", - " (cont): norm_new_f=438.995, dL=0.0597676, dF=0.0537429, reldL=0.00013613, reldF=0.000122408\n", - " Accepted! gain ratio=0.899197 mu * 0.491078 => 8.455\n", - " --- Outer Iter 37: norm_f = 438.995, mu=8.455, |x|=2.92443, |J|=266.351\n", - " - Inner Loop: mu=8.455, norm_dx=0.00010186\n", - " (cont): norm_new_f=439.442, dL=0.154612, dF=-0.446773, reldL=0.000352196, reldF=-0.00101772\n", - " Rejected! mu => mu*nu = 16.91, nu => 2*nu = 4\n", - " - Inner Loop: mu=16.91, norm_dx=3.22811e-05\n", - " (cont): norm_new_f=439.143, dL=0.107451, dF=-0.148432, reldL=0.000244767, reldF=-0.000338118\n", - " Rejected! mu => mu*nu = 67.64, nu => 2*nu = 8\n", - " - Inner Loop: mu=67.64, norm_dx=2.77282e-06\n", - " (cont): norm_new_f=438.969, dL=0.0429126, dF=0.0254165, reldL=9.77519e-05, reldF=5.7897e-05\n", - " Least squares message = Both actual and predicted relative reductions in the sum of squares are at most 0.0001\n", - " _objfn = 877.99 (920 data params - 32 (approx) model params = expected mean of 888; p-value = 0.588076)\n", - " Completed in 64.9s\n", - " Iteration 1 took 64.9s\n", - " \n", - "--- Iterative GST: Iter 2 of 2 168 circuits ---: \n", - " MapLayout: 1 processors divided into 1 x 1 (= 1) grid along circuit and parameter directions.\n", - " 8 atoms, parameter block size limits (None,)\n", - " *** Distributing 8 atoms to 1 atom-processing groups (1 cores) ***\n", - " More atom-processors than hosts: each host gets ~1 atom-processors\n", - " Atom-processors already occupy a single node, dividing atom-processor into 1 param-processors.\n", - " *** Divided 1-host atom-processor (~1 procs) into 1 param-processing groups ***\n", - " --- TimeDependentPoissonPicLogLFunction GST ---\n", - " --- Outer Iter 0: norm_f = 873.935, mu=1, |x|=2.92443, |J|=316.589\n", - " - Inner Loop: mu=71.329, norm_dx=0.000511043\n", - " (cont): norm_new_f=871.645, dL=1.94724, dF=2.2898, reldL=0.00222813, reldF=0.0026201\n", - " Accepted! gain ratio=1.17592 mu * 0.333333 => 23.7763\n", - " --- Outer Iter 1: norm_f = 871.645, mu=23.7763, |x|=2.91513, |J|=279.853\n", - " - Inner Loop: mu=23.7763, norm_dx=0.0033612\n", - " (cont): norm_new_f=870.886, dL=2.39524, dF=0.759757, reldL=0.00274795, reldF=0.000871636\n", - " Accepted! gain ratio=0.317195 mu * 1.04887 => 24.9383\n", - " --- Outer Iter 2: norm_f = 870.886, mu=24.9383, |x|=2.89746, |J|=513.822\n", - " - Inner Loop: mu=24.9383, norm_dx=0.000214322\n", - " (cont): norm_new_f=872.646, dL=6.20726, dF=-1.7608, reldL=0.00712753, reldF=-0.00202185\n", - " Rejected! mu => mu*nu = 49.8766, nu => 2*nu = 4\n", - " - Inner Loop: mu=49.8766, norm_dx=7.46315e-05\n", - " (cont): norm_new_f=870.551, dL=4.7519, dF=0.3343, reldL=0.0054564, reldF=0.000383863\n", - " Accepted! gain ratio=0.0703508 mu * 1.6345 => 81.5233\n", - " --- Outer Iter 3: norm_f = 870.551, mu=81.5233, |x|=2.89086, |J|=286.137\n", - " - Inner Loop: mu=81.5233, norm_dx=0.000119945\n", - " (cont): norm_new_f=870.267, dL=2.28393, dF=0.283909, reldL=0.00262355, reldF=0.000326125\n", - " Accepted! gain ratio=0.124307 mu * 1.42422 => 116.107\n", - " --- Outer Iter 4: norm_f = 870.267, mu=116.107, |x|=2.89107, |J|=3462.56\n", - " - Inner Loop: mu=116.107, norm_dx=5.75778e-06\n", - " (cont): norm_new_f=868.803, dL=1.76057, dF=1.46469, reldL=0.00202302, reldF=0.00168303\n", - " Accepted! gain ratio=0.83194 mu * 0.707404 => 82.1346\n", - " --- Outer Iter 5: norm_f = 868.803, mu=82.1346, |x|=2.88919, |J|=441.327\n", - " - Inner Loop: mu=82.1346, norm_dx=1.45812e-05\n", - " (cont): norm_new_f=868.666, dL=0.197728, dF=0.136299, reldL=0.000227587, reldF=0.000156881\n", - " Accepted! gain ratio=0.689324 mu * 0.945711 => 77.6756\n", - " --- Outer Iter 6: norm_f = 868.666, mu=77.6756, |x|=2.88799, |J|=365.993\n", - " - Inner Loop: mu=77.6756, norm_dx=1.15541e-05\n", - " (cont): norm_new_f=868.592, dL=0.050525, dF=0.0742624, reldL=5.81639e-05, reldF=8.54901e-05\n", - " Least squares message = Both actual and predicted relative reductions in the sum of squares are at most 0.0001\n", - " _objfn = 1737.33 (1680 data params - 32 (approx) model params = expected mean of 1648; p-value = 0.0617401)\n", - " Completed in 23.6s\n", - " Iteration 2 took 23.7s\n", - " \n", - " Last iteration:\n", - " Final optimization took 0.0s\n", - " \n", - "Iterative GST Total Time: 88.7s\n" - ] - } - ], + "outputs": [], "source": [ "target_model = smq1Q_XYI.target_model(\"full TP\", simulator=\"map\") # TP-constraints on the non-Gi gates\n", "target_model[idle_gate_label] = MyTimeDependentIdle(0.0)\n", @@ -654,7 +301,7 @@ "builders = pygsti.protocols.GSTObjFnBuilders([pygsti.objectivefns.TimeDependentPoissonPicLogLFunction.builder()],[])\n", "custom_opt = {'tol': 1e-4, 'damping_mode': 'JTJ', 'damping_clip': (1.0, 1000.0)} # tweak optimizer parameters for better performance (expert-level)\n", "gst = pygsti.protocols.GateSetTomography(target_model, gaugeopt_suite=None,\n", - " objfn_builders=builders, optimizer=custom_opt, verbosity=4)\n", + " objfn_builders=builders, optimizer=custom_opt, verbosity=3)\n", "data = pygsti.protocols.ProtocolData(edesign, ds)\n", "results = gst.run(data)" ] @@ -668,17 +315,9 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Time-dependent idle parameters = [0.989367]\n" - ] - } - ], + "outputs": [], "source": [ "final_mdl = results.estimates['GateSetTomography'].models['final iteration estimate']\n", "print(\"Time-dependent idle parameters = \",final_mdl[idle_gate_label].to_vector())" @@ -686,18 +325,9 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Objective function at data-generating model = 880.9619775626477\n", - "Objective function at best-fit (GST) model (should be lower) = 868.6663676923431\n" - ] - } - ], + "outputs": [], "source": [ "# Check that GST model fits the data *better* than the data-generating model\n", "builder = pygsti.objectivefns.TimeDependentPoissonPicLogLFunction.builder()\n", @@ -718,9 +348,9 @@ ], "metadata": { "kernelspec": { - "display_name": "random_pygsti_debugging", + "display_name": "api_updates", "language": "python", - "name": "random_pygsti_debugging" + "name": "api_updates" }, "language_info": { "codemirror_mode": { diff --git a/jupyter_notebooks/Tutorials/objects/ImplicitModel.ipynb b/jupyter_notebooks/Tutorials/objects/ImplicitModel.ipynb index 46de40127..94e774aff 100644 --- a/jupyter_notebooks/Tutorials/objects/ImplicitModel.ipynb +++ b/jupyter_notebooks/Tutorials/objects/ImplicitModel.ipynb @@ -533,8 +533,13 @@ "metadata": {}, "source": [ "## Next steps\n", - "To learn more about using implicit models, you may want to check out the [model parameterizations tutorial](ModelParameterization.ipynb), which covers material especially relevant when optimizing implicit models, and the [model noise tutoria](ModelNoise.ipynb), which describes how to add noise to implicit (and explicit) models." + "To learn more about using implicit models, you may want to check out the [model parameterizations tutorial](ModelParameterization.ipynb), which covers material especially relevant when optimizing implicit models, and the [model noise tutorial](ModelNoise.ipynb), which describes how to add noise to implicit (and explicit) models." ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] } ], "metadata": { diff --git a/jupyter_notebooks/Tutorials/objects/ModelNoise.ipynb b/jupyter_notebooks/Tutorials/objects/ModelNoise.ipynb index b05543b93..de4125b79 100644 --- a/jupyter_notebooks/Tutorials/objects/ModelNoise.ipynb +++ b/jupyter_notebooks/Tutorials/objects/ModelNoise.ipynb @@ -10,7 +10,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -24,13 +24,14 @@ "metadata": {}, "source": [ "## Standard noise types\n", - "There are three standard types of noise that can be added to operations in pyGSTi: depolarization, stochastic, and Lindbladian. The first two types are common in the literature, while the third, \"Lindbladian\", needs a bit more explanation. Many types of gate errors can be represented in terms of an *error generator*. If $G$ is a noisy gate (a CPTP map) and $G_0$ is it's ideal counterpart, then if we write $G = e^{\\Lambda}G_0$ then $\\Lambda$ is called the gate's *error generator*. A `LindbladErrorgen` object, exponentiated using a `ExpErrorgenOp` object represent this $e^{\\Lambda}$ in pyGSTi. If we write $\\Lambda$ as a sum of terms, $\\Lambda = \\sum_i \\alpha_i F_i$ then, when the $F_i$ are specific generators for well-known errors (e.g. rotations or stochastic errors), the $\\alpha_i$ can roughly be interpreted as the error *rates* corresponding to the well-known error types. PyGSTi has three specific generator types (where $P_i$ is a Pauli operator or tensor product of Pauli operators):\n", + "There are three standard types of noise that can be added to operations in pyGSTi: depolarization, stochastic, and Lindbladian. The first two types are common in the literature, while the third, \"Lindbladian\", needs a bit more explanation. Many types of gate errors can be represented in terms of an *error generator*. If $G$ is a noisy gate (a CPTP map) and $G_0$ is it's ideal counterpart, then if we write $G = e^{\\Lambda}G_0$ then $\\Lambda$ is called the gate's *error generator*. A `LindbladErrorgen` object, exponentiated using a `ExpErrorgenOp` object represent this $e^{\\Lambda}$ in pyGSTi. If we write $\\Lambda$ as a sum of terms, $\\Lambda = \\sum_i \\alpha_i F_i + \\sum_{i\\neq j} \\alpha_{ij} F_{ij}$ then, when the $F_i/F_{ij}$ are specific generators for well-known errors (e.g. rotations or stochastic errors), the $\\alpha_i/\\alpha_{ij}$ can roughly be interpreted as the error *rates* corresponding to the well-known error types. PyGSTi has three specific generator types (where $P_i$ is a Pauli operator or tensor product of Pauli operators):\n", "\n", - "- **Hamiltonian**: $F_i = H_i$ where $H_i : \\rho \\rightarrow -i[P_i,\\rho]$\n", - "- **Stochastic**: $F_i = S_i$ where $S_i : \\rho \\rightarrow P_i \\rho P_i - \\rho$\n", - "- **Affine**: $F_i = A_i$ where $A_i : \\rho \\rightarrow \\mathrm{Tr}(\\rho_{target})P_i \\otimes \\rho_{non-target}$\n", + "- **Hamiltonian**: $H_i : \\rho \\rightarrow -i[P_i,\\rho]$\n", + "- **Stochastic**: $S_i : \\rho \\rightarrow P_i \\rho P_i - \\rho$\n", + "- **Correlated**: $C_{ij} : \\rho \\rightarrow P_i \\rho P_j + P_j \\rho P_i - \\frac{1}{2}\\{\\{P_i,P_j\\}, \\rho\\}$\n", + "- **Affine/Active**: $A_{ij} : \\rho \\rightarrow i\\left(P_i \\rho P_j + P_j \\rho P_i + \\frac{1}{2}\\{[P_i,P_j], \\rho\\}\\right)$\n", "\n", - "See our recent paper on [the taxonomy of small errors](https://arxiv.org/abs/2103.01928v1) for a more theoretical foundation of error generators.\n", + "See our paper on [the taxonomy of small errors](https://arxiv.org/abs/2103.01928v1) for a more theoretical foundation of error generators.\n", "\n", "Many of the model construction functions take arguments that allow users to add these standard noise types conveniently when a model is created. Each argument expects a dictionary, where the keys are gate names and the values specify the corresponding noise. The values are different types for each argument:\n", "\n", @@ -38,18 +39,19 @@ "- `stochastic_error_probs`: Values are lists of length $4^{N_{qubits} - 1}$, which correspond to coefficients of a stochastic Pauli channel in a `StochasticNoiseOp`. Order of the rates is lexographical, and can be checked by looking at the elements of a `\"pp\"` Basis object.\n", "- `lindblad_error_coeffs`: Values are a dict where the key has the form `(, )` and the values are the $\\alpha_i$ coefficients in the sum of Lindblad terms, which are then exponentiated to give the final noise. The type includes:\n", " - `'H'` for Hamiltonian errors\n", - " - `'S'` for Pauli-stochastic and Pauli-correlation errors (S and C in the error generator taxonomy)\n", - " - `'A'` for affine errors\n", + " - `'S'` for Pauli-stochastic errors\n", + " - `'C'` for correlated Pauli-stochastic errors\n", + " - `'A'` for affine/active errors\n", " \n", " and strings of `I`, `X`, `Y`, and `Z` can be used to label a Pauli basis element. \n", "\n", - "### Crosstalk free (local noise) models\n", - "We'll start with an example of placing noise on a crosstalk free model." + "### Crosstalk-free (local noise) models\n", + "We'll start with an example of placing noise on a crosstalk-free model." ] }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -75,39 +77,9 @@ }, { "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Gxpi2\n", - "Composed operation of 2 factors:\n", - "Factor 0:\n", - "StaticStandardOp with name Gxpi2 and evotype densitymx\n", - "Factor 1:\n", - "Depolarize noise operation map with dim = 4, num params = 1\n", - "Strength: [0.1]\n", - "\n", - "Gypi2\n", - "Composed operation of 2 factors:\n", - "Factor 0:\n", - "StaticStandardOp with name Gypi2 and evotype densitymx\n", - "Factor 1:\n", - "Stochastic noise operation map with state space = QubitSpace((0,)), num params = 3\n", - "Rates: [0.04 0.05 0.02]\n", - "\n", - "Gcnot\n", - "Composed operation of 2 factors:\n", - "Factor 0:\n", - "StaticStandardOp with name Gcnot and evotype densitymx\n", - "Factor 1:\n", - "Exponentiated operation map with dim = 16, num params = 1\n", - "\n" - ] - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "for gate_name, gate in mdl_locnoise.operation_blks['gates'].items():\n", " print(gate_name)\n", @@ -123,67 +95,9 @@ }, { "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Modelmember category: prep_blks|layers\n", - " rho0: ComputationalBasisState (0) : (contents not available)\n", - "\n", - "Modelmember category: povm_blks|layers\n", - " Mdefault: ComputationalBasisPOVM (1) : (contents not available)\n", - "\n", - "Modelmember category: operation_blks|gates\n", - " Gxpi2: ComposedOp (4) : composed of 2 factors\n", - " StaticStandardOp (2) : Gxpi2 gate\n", - " DepolarizeOp (3) : strength: [0.1]\n", - " Gypi2: ComposedOp (7) : composed of 2 factors\n", - " StaticStandardOp (5) : Gypi2 gate\n", - " StochasticNoiseOp (6) : rates: [0.04 0.05 0.02]\n", - " Gcnot: ComposedOp (11) : composed of 2 factors\n", - " StaticStandardOp (8) : Gcnot gate\n", - " ExpErrorgenOp (10) : exponentiates\n", - " LindbladErrorgen (9) : H(ZZ:0,1): 0.15\n", - "\n", - "Modelmember category: operation_blks|layers\n", - " Gxpi2:0: EmbeddedOp (12) : embeds (0,) into QubitSpace((0, 1))\n", - " ComposedOp (4) : --link--^\n", - " StaticStandardOp (2) : --link--^\n", - " DepolarizeOp (3) : --link--^\n", - " Gxpi2:1: EmbeddedOp (13) : embeds (1,) into QubitSpace((0, 1))\n", - " ComposedOp (4) : --link--^\n", - " StaticStandardOp (2) : --link--^\n", - " DepolarizeOp (3) : --link--^\n", - " Gypi2:0: EmbeddedOp (14) : embeds (0,) into QubitSpace((0, 1))\n", - " ComposedOp (7) : --link--^\n", - " StaticStandardOp (5) : --link--^\n", - " StochasticNoiseOp (6) : --link--^\n", - " Gypi2:1: EmbeddedOp (15) : embeds (1,) into QubitSpace((0, 1))\n", - " ComposedOp (7) : --link--^\n", - " StaticStandardOp (5) : --link--^\n", - " StochasticNoiseOp (6) : --link--^\n", - " Gcnot:0:1: ComposedOp (11) : --link--^\n", - " StaticStandardOp (8) : --link--^\n", - " ExpErrorgenOp (10) : --link--^\n", - " LindbladErrorgen (9) : --link--^\n", - " Gcnot:1:0: EmbeddedOp (16) : embeds (1, 0) into QubitSpace((0, 1))\n", - " ComposedOp (11) : --link--^\n", - " StaticStandardOp (8) : --link--^\n", - " ExpErrorgenOp (10) : --link--^\n", - " LindbladErrorgen (9) : --link--^\n", - "\n", - "Modelmember category: instrument_blks|layers\n", - "\n", - "Modelmember category: factories|gates\n", - "\n", - "Modelmember category: factories|layers\n", - "\n" - ] - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "mdl_locnoise.print_modelmembers()" ] @@ -200,55 +114,9 @@ }, { "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Modelmember category: prep_blks|layers\n", - " rho0: ComputationalBasisState (0) : (contents not available)\n", - "\n", - "Modelmember category: povm_blks|layers\n", - " Mdefault: ComputationalBasisPOVM (1) : (contents not available)\n", - "\n", - "Modelmember category: operation_blks|gates\n", - " Gxpi2: ComposedOp (4) : composed of 2 factors\n", - " StaticStandardOp (2) : Gxpi2 gate\n", - " StochasticNoiseOp (3) : rates: [0.04 0.05 0.02]\n", - " Gxpi2:0: ComposedOp (6) : composed of 2 factors\n", - " StaticStandardOp (2) : --link--^\n", - " StochasticNoiseOp (5) : rates: [0.08 0.1 0.06]\n", - " Gypi2: StaticStandardOp (7) : Gypi2 gate\n", - " Gcnot: StaticStandardOp (8) : Gcnot gate\n", - "\n", - "Modelmember category: operation_blks|layers\n", - " Gxpi2:0: EmbeddedOp (9) : embeds (0,) into QubitSpace((0, 1))\n", - " ComposedOp (6) : --link--^\n", - " StaticStandardOp (2) : --link--^\n", - " StochasticNoiseOp (5) : --link--^\n", - " Gxpi2:1: EmbeddedOp (10) : embeds (1,) into QubitSpace((0, 1))\n", - " ComposedOp (4) : --link--^\n", - " StaticStandardOp (2) : --link--^\n", - " StochasticNoiseOp (3) : --link--^\n", - " Gypi2:0: EmbeddedOp (11) : embeds (0,) into QubitSpace((0, 1))\n", - " StaticStandardOp (7) : --link--^\n", - " Gypi2:1: EmbeddedOp (12) : embeds (1,) into QubitSpace((0, 1))\n", - " StaticStandardOp (7) : --link--^\n", - " Gcnot:0:1: StaticStandardOp (8) : --link--^\n", - " Gcnot:1:0: EmbeddedOp (13) : embeds (1, 0) into QubitSpace((0, 1))\n", - " StaticStandardOp (8) : --link--^\n", - "\n", - "Modelmember category: instrument_blks|layers\n", - "\n", - "Modelmember category: factories|gates\n", - "\n", - "Modelmember category: factories|layers\n", - "\n" - ] - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "mdl_locnoise = pygsti.models.create_crosstalk_free_model(pspec,\n", " stochastic_error_probs={\n", @@ -271,7 +139,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -344,10 +212,10 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "#### Nonlocal noise\n", + "### Nonlocal noise (crosstalk)\n", "So far, all the noise we've specified has been directed at the *target* qubits of the relevant operation. For instance, when a depolarization strength is specified for a 1-qubit gates, it applies the given depolarization to gate's single target qubit. When depolarization is applied to a 2-qubit gate, 2-qubit depolarization is applied to the target qubits. When Lindblad error rates are given for a 1-qubit gate, they are indexed by single Pauli elements, e.g. `('H','X')`, whereas for a 2-qubit gate they are indexed by 2-qubit Paulis, e.g. `('H','XX')`.\n", "\n", - "In a crosstalk free model, noise can *only* be specified on the target qubits - noise on non-target qubits is simply not allowed. But for an explicit model, which holds solely $N$-qubit layer operations, noise for a gate (layer) can be applied to *any* of the qubits. To specify noise that is not on the target qubits of a gate,\n", + "In a crosstalk-free model, noise can *only* be specified on the target qubits - noise on non-target qubits is simply not allowed. But for an explicit model, which holds solely $N$-qubit layer operations, noise for a gate (layer) can be applied to *any* of the qubits. To specify noise that is not on the target qubits of a gate,\n", "\n", "- as the values of `depolarization_strengths` or `stochastic_error_probs`, pass a dictionary that maps qubit labels to noise values. The qubit labels (keys) designate which qubits the noise acts upon.\n", "- add a colon followed by comma-separated qubit labels to the basis labels in a Lindblad error term.\n", @@ -387,6 +255,86 @@ "explicit_model.print_modelmembers()" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Reduced error generator models\n", + "\n", + "One potentially powerful way to include nonlocal noise with a few lines of code is to include entire sectors of the elementary error generators. For example, one can extend past a crosstalk-free model with only a few parameters by including the H and S sectors on neighboring qubits.\n", + "\n", + "First, let us create an ideal model similar to those above:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ideal_model = mc.create_explicit_model(pspec) # No noise, we will add that manually!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, we will make lists of all the weight-1 and weight-2 Pauli strings. We will use these to restrict the CA blocks to only weight-1 later." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "w1_labels = [lbl for lbl in ideal_model.basis.labels if sum([c != 'I' for c in lbl]) == 1]\n", + "w2_labels = [lbl for lbl in ideal_model.basis.labels if sum([c != 'I' for c in lbl]) == 2]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can go through each operation and create three \"coefficient blocks\". Naively, what we want are weight-1 and weight-2 H and S errors (HS2) and only weight-1 C and A (CA1) errors, but we have to organize our blocks slightly differently due to how they are stored internally. The blocks we can make are:\n", + "\n", + "- H-only blocks\n", + "- S-only blocks\n", + "- SCA blocks\n", + "\n", + "So we instead build our blocks as: H12, SCA1, S2.\n", + "\n", + "Finally, once we have our blocks, we create the actual Lindbladian error generator and append the exponentiated Lindbladian to the ideal operation." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pygsti.modelmembers.operations as ops\n", + "from pygsti.modelmembers.operations.lindbladcoefficients import LindbladCoefficientBlock as LindbladCBlock\n", + "\n", + "HS2_CA1_model = ideal_model.copy()\n", + "HS2_CA1_model.operations.flags['auto_embed'] = False\n", + "\n", + "for lbl, op in HS2_CA1_model.operations.items():\n", + " # Lindblad coefficient blocks\n", + " H12_block = LindbladCBlock('ham', ideal_model.basis, w1_labels + w2_labels, param_mode='elements')\n", + " \n", + " S2_block = LindbladCBlock('other_diagonal', ideal_model.basis, w2_labels, param_mode='cholesky')\n", + " \n", + " SCA1_block = LindbladCBlock('other', ideal_model.basis, w1_labels, param_mode='cholesky')\n", + " \n", + " # Build op\n", + " errgen = ops.LindbladErrorgen([H12_block, S2_block, SCA1_block], state_space=ideal_model.state_space)\n", + " HS2_CA1_model.operations[lbl] = ops.ComposedOp([\n", + " op.copy(),\n", + " ops.ExpErrorgenOp(errgen)\n", + " ])" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -767,7 +715,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.13" + "version": "3.10.10" } }, "nbformat": 4, diff --git a/jupyter_notebooks/Tutorials/objects/advanced/CustomOperator.ipynb b/jupyter_notebooks/Tutorials/objects/advanced/CustomOperator.ipynb index db5fec14e..ba5f7ac20 100644 --- a/jupyter_notebooks/Tutorials/objects/advanced/CustomOperator.ipynb +++ b/jupyter_notebooks/Tutorials/objects/advanced/CustomOperator.ipynb @@ -44,8 +44,8 @@ " \n", " theta = (np.pi/2 + self.over_rotation)/2\n", " a = 1.0-self.depol_amt\n", - " b = a*2*np.cos(theta)*np.sin(theta)\n", - " c = a*(np.sin(theta)**2 - np.cos(theta)**2)\n", + " b = a*np.sin(2*theta)\n", + " c = a*np.cos(2*theta)\n", " \n", " # ._ptr is a member of DenseOperator and is a numpy array that is \n", " # the dense Pauli transfer matrix of this operator\n", @@ -65,7 +65,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "We'll add a `MyXPi2Operator` instance as the `\"Gx\"` gate in pyGSTi's standard {Idle, $X(\\pi/2)$, $Y(\\pi/2)$} model (see the [standard modules tutorial](StandardModules.ipynb) for more information on standard models)." + "We'll add a `MyXPi2Operator` instance as the `(\"Gxpi2\",0)` gate in pyGSTi's {Idle, $X(\\pi/2)$, $Y(\\pi/2)$} modelpack (see the [modelpacks tutorial](ModelPacks.ipynb) for more information on modelpacks)." ] }, { diff --git a/jupyter_notebooks/Tutorials/objects/advanced/CustomPOVM.ipynb b/jupyter_notebooks/Tutorials/objects/advanced/CustomPOVM.ipynb new file mode 100644 index 000000000..c5f4d5aac --- /dev/null +++ b/jupyter_notebooks/Tutorials/objects/advanced/CustomPOVM.ipynb @@ -0,0 +1,332 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Custom POVM Tutorial\n", + "This tutorial will demonstrate how to encode custom POVMs -- such as two-qubit parity measurement into a pyGSTi model -- rather than the standard Z measurement in the computational basis." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pygsti\n", + "from pygsti.modelpacks import smq2Q_XYCNOT as std\n", + "import numpy as np" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Parity measurement construction\n", + "\n", + "We start with a standard two-qubit model, and replace the default POVM with one that measures the parity instead. We do this by providing the superkets which described the desired measurement. This is straightforward for the parity measurement in the Pauli product basis, as shown below." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "parity_model = std.target_model()\n", + "\n", + "# Here, we specify the superkets for the even/odd effects\n", + "# This can be done in any basis, but we use Pauli-product here since\n", + "# we know the structure of the parity measurements in this basis\n", + "even_dmvec = np.zeros(16)\n", + "even_dmvec[0] = 1.0 # II element should be 1\n", + "even_dmvec[15] = 1.0 # ZZ element should also be 1 for even\n", + "\n", + "odd_dmvec = np.zeros(16)\n", + "odd_dmvec[0] = 1.0 # II element is still 1 for odd...\n", + "odd_dmvec[15] = -1.0 # ... but ZZ element should be -1 for odd\n", + "\n", + "parity_povm_dict = {'e': even_dmvec, 'o': odd_dmvec}\n", + "\n", + "parity_povm = pygsti.modelmembers.povms.create_from_dmvecs(parity_povm_dict, \"full TP\",\n", + " basis='pp', evotype=parity_model.evotype, state_space=parity_model.state_space)\n", + "\n", + "parity_model['Mdefault'] = parity_povm\n", + "print(parity_model)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can test this by running some simple circuits and seeing what outcomes we observe." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Idle circuit should give us even outcome\n", + "dict(parity_model.probabilities( pygsti.circuits.Circuit([], line_labels=(0,1))))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Partial flip of one qubit gives an equal superposition of odd and even\n", + "dict(parity_model.probabilities( pygsti.circuits.Circuit([('Gxpi2', 0)], line_labels=(0,1))))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Full bitflip of one qubit should give us an odd outcome\n", + "dict(parity_model.probabilities( pygsti.circuits.Circuit([('Gxpi2', 0), ('Gxpi2', 0)], line_labels=(0,1))))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Making a Bell pair (using H = Y(pi/2)X(pi), in operation order) should maintain the even outcome\n", + "dict(parity_model.probabilities( pygsti.circuits.Circuit([('Gypi2', 0), ('Gxpi2', 0), ('Gxpi2', 0), ('Gcnot', 0, 1)], line_labels=(0,1))))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Making a Bell pair and then flipping one qubit should give odd\n", + "dict(parity_model.probabilities( pygsti.circuits.Circuit([('Gypi2', 0), ('Gxpi2', 0), ('Gxpi2', 0), ('Gcnot', 0, 1),\n", + " ('Gxpi2', 1), ('Gxpi2', 1)], line_labels=(0,1))))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Combining measurements\n", + "\n", + "It is also possible to use different measurements on different sets of qubits. For example, we can mix computational basis states with our parity measurement from above.\n", + "\n", + "Since we are going up to 3 qubits for this example, we will swap over to using a `QubitProcessorSpec` and `pygsti.modelconstruction` to build our initial `ExplicitModel` rather than loading it from a modelpack." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Get a basic 3-qubit model\n", + "pspec = pygsti.processors.QubitProcessorSpec(3, ['Gxpi2', 'Gypi2', 'Gcnot'], geometry='line')\n", + "Z_parity_model = pygsti.models.create_explicit_model(pspec)\n", + "\n", + "# Get a 1-qubit Z basis (computational) measurement\n", + "computational_povm = pygsti.modelmembers.povms.ComputationalBasisPOVM(nqubits=1)\n", + "\n", + "# Get a composite POVM that performs Z measurement on qubit 1 and a parity measurement on qubits 2 and 3\n", + "# We are using the same parity POVM as the one defined above\n", + "Z_parity_povm = pygsti.modelmembers.povms.TensorProductPOVM([computational_povm, parity_povm])\n", + "\n", + "# Override our standard measurement with the composite one\n", + "Z_parity_model['Mdefault'] = Z_parity_povm\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And we can again test this with some simple measurements. Notice that instead of binary bitstrings, the \"e\"/\"o\" outcome labels are used as the second part of the outcome labels." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Idle circuit should give us 0 on first qubit and even parity on second and third qubits\n", + "dict(Z_parity_model.probabilities( pygsti.circuits.Circuit([], line_labels=(0,1,2)) ))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# We can flip just the first qubit to see a 1 but still even outcome\n", + "dict(Z_parity_model.probabilities( pygsti.circuits.Circuit([('Gxpi2', 0), ('Gxpi2', 0)], line_labels=(0,1,2)) ))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Alternatively we can flip the last qubit to get a 0 but odd outcome\n", + "dict(Z_parity_model.probabilities( pygsti.circuits.Circuit([('Gxpi2', 2), ('Gxpi2', 2)], line_labels=(0,1,2)) ))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# And we can do partial flip of qubits 0 and 1 to get a uniform spread over all outcome possibilities\n", + "dict(Z_parity_model.probabilities( pygsti.circuits.Circuit([('Gxpi2', 0), ('Gxpi2', 1)], line_labels=(0,1,2)) ))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Multiple custom measurements\n", + "\n", + "The above works nicely if there is only one type of mixed measurement, but what if you have multiple? For example, what if you could measure parity on either pair of neighboring qubits, and also computational basis measurements on all qubits?\n", + "\n", + "In this case, we can just add both POVMs to the model. However, we have to be careful about the \"default\" measurement of the system. For this example, we will use the computational basis POVM as the default measurement and assign the two parity-containing measurements to other keys. We just have to be careful that we explicitly use the correct POVM key when we want to do a different measurement." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Get a basic 3-qubit model\n", + "mult_meas_model = pygsti.models.create_explicit_model(pspec)\n", + "\n", + "# Note that Mdefault is the 3-qubit computational basis measurement already\n", + "print(mult_meas_model['Mdefault'])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Now let's build our two other custom measurements and assign them to other keys\n", + "Z_parity_povm = pygsti.modelmembers.povms.TensorProductPOVM([computational_povm, parity_povm])\n", + "parity_Z_povm = pygsti.modelmembers.povms.TensorProductPOVM([parity_povm, computational_povm])\n", + "\n", + "mult_meas_model['M_Z_par'] = Z_parity_povm\n", + "mult_meas_model['M_par_Z'] = parity_Z_povm\n", + "\n", + "print(mult_meas_model)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As usual, let's test with some circuits to see if this has our expected behavior." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Let's try to run a circuit with a bitflip on qubit 1...\n", + "try:\n", + " dict(mult_meas_model.probabilities( pygsti.circuits.Circuit([('Gxpi2', 0), ('Gxpi2', 0)], line_labels=(0,1,2)) ))\n", + "except Exception as e:\n", + " print(e)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notice that this fails! In particular, it tells us that there is not POVM label in the Circuit, and the model does not have a default. This is expected behavior - when models have multiple measurements, pyGSTi does not automatically assume that one is default.\n", + "\n", + "We can fix this by just explicitly adding the Mdefault key." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "dict(mult_meas_model.probabilities( pygsti.circuits.Circuit([('Gxpi2', 0), ('Gxpi2', 0), \"Mdefault\"], line_labels=(0,1,2)) ))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, let's run the same circuit but use our other measurements." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Using the Z-parity should give us 1 on qubit 0 and even for qubits 2 & 3...\n", + "dict(mult_meas_model.probabilities( pygsti.circuits.Circuit([('Gxpi2', 0), ('Gxpi2', 0), \"M_Z_par\"], line_labels=(0,1,2)) ))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# ... while using parity-Z should give us odd for qubits 0 & 1 and 0 for qubit 2\n", + "dict(mult_meas_model.probabilities( pygsti.circuits.Circuit([('Gxpi2', 0), ('Gxpi2', 0), \"M_par_Z\"], line_labels=(0,1,2)) ))" + ] + }, + { + "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.11.5" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/jupyter_notebooks/Tutorials/reporting/ProceduralErrorBars.ipynb b/jupyter_notebooks/Tutorials/reporting/ProceduralErrorBars.ipynb new file mode 100644 index 000000000..54dbad14d --- /dev/null +++ b/jupyter_notebooks/Tutorials/reporting/ProceduralErrorBars.ipynb @@ -0,0 +1,174 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Procedural Error Bars\n", + "\n", + "One other way we can use the `pygsti.report.reportables` module described in the [ModelAnalysisMetrics tutorial](ModelAnalysisMetrics.ipynb) is to procedurally generate error bars for any quantity you want.\n", + "\n", + "First, let's simulate a noisy GST experiment" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pygsti\n", + "from pygsti.modelpacks import smq1Q_XY\n", + "from pygsti.report import reportables as rptbl, modelfunction as modelfn" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "target_model = smq1Q_XY.target_model()\n", + "\n", + "L=128\n", + "edesign = smq1Q_XY.create_gst_experiment_design(L)\n", + "\n", + "noisy_model = target_model.randomize_with_unitary(.1)\n", + "noisy_model = noisy_model.depolarize(.05)\n", + "\n", + "N=64\n", + "dataset = pygsti.data.simulate_data(noisy_model,edesign,N)\n", + "\n", + "\n", + "gst_proto = pygsti.protocols.StandardGST(modes=['full TP','CPTPLND','Target'],verbosity=2)\n", + "data = pygsti.protocols.ProtocolData(edesign,dataset)\n", + "results = gst_proto.run(data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now let's compute error bars on the CPTP estimate, and then get a 95% confidence interval \"view\" from the `ConfidenceRegionFactory`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "crfact = results.estimates['CPTPLND'].add_confidence_region_factory('stdgaugeopt', 'final')\n", + "crfact.compute_hessian(comm=None, mem_limit=3.0*(1024.0)**3) #optionally use multiple processors & set memlimit\n", + "crfact.project_hessian('intrinsic error')\n", + "\n", + "crf_view = results.estimates['CPTPLND'].confidence_region_factories['stdgaugeopt','final'].view(95)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, we can construct `pygsti.report.ModelFunction` objects that take a function which computes some observable from a model and the extracted view from above to compute error bars on that quantity of interest.\n", + "\n", + "One common thing to check is error bars on the process matrices. The `ModelFunction` in this case only needs to return the operation:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "final_model = results.estimates['CPTPLND'].models['stdgaugeopt'].copy()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def get_op(model, lbl):\n", + " return model[lbl]\n", + "get_op_modelfn = modelfn.modelfn_factory(get_op)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "rptbl.evaluate(get_op_modelfn(final_model, (\"Gxpi2\", 0)), crf_view)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "rptbl.evaluate(get_op_modelfn(final_model, (\"Gypi2\", 0)), crf_view)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "But we can also create model functions that perform more complicated actions, such as computing other reportables." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Note that when creating ModelFunctions in this way, the model where you want the quantity evaluated must be the first argument\n", + "def ddist(model, ideal_model, lbl, basis):\n", + " return rptbl.half_diamond_norm(model[lbl], ideal_model[lbl], basis)\n", + "ddist_modelfn = modelfn.modelfn_factory(ddist)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "rptbl.evaluate(ddist_modelfn(final_model, target_model, (\"Gxpi2\", 0), 'pp'), crf_view)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "rptbl.evaluate(ddist_modelfn(final_model, target_model, (\"Gypi2\", 0), 'pp'), crf_view)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "pygsti", + "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.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/jupyter_notebooks/Tutorials/reporting/ReportGeneration.ipynb b/jupyter_notebooks/Tutorials/reporting/ReportGeneration.ipynb index 514083463..20b9f1682 100644 --- a/jupyter_notebooks/Tutorials/reporting/ReportGeneration.ipynb +++ b/jupyter_notebooks/Tutorials/reporting/ReportGeneration.ipynb @@ -326,6 +326,8 @@ "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\n", "by `Workspace` objects, which are factories for figures and tables (see previous tutorials). By calling `Report.write_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.\n", "\n", + "Note that interactive cells in report notebooks require JavaScript, and therefore do not work with JupyterLab. Please continue to use to track this issue, see https://github.com/pyGSTio/pyGSTi/issues/205.\n", + "\n", "The line below demonstrates how to create a report notebook using `write_notebook`. Note that the argument list is very similar to the other `Report` output methods." ] }, @@ -365,7 +367,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.13" + "version": "3.10.10" } }, "nbformat": 4, diff --git a/pygsti/algorithms/core.py b/pygsti/algorithms/core.py index eed9fcddc..f2b749136 100644 --- a/pygsti/algorithms/core.py +++ b/pygsti/algorithms/core.py @@ -53,7 +53,7 @@ def run_lgst(dataset, prep_fiducials, effect_fiducials, target_model, op_labels=None, op_label_aliases=None, - guess_model_for_gauge=None, svd_truncate_to=None, verbosity=0): + guess_model_for_gauge=None, svd_truncate_to=None, verbosity=0, check=True): """ Performs Linear-inversion Gate Set Tomography on the dataset. @@ -102,6 +102,10 @@ def run_lgst(dataset, prep_fiducials, effect_fiducials, target_model, op_labels= verbosity : int, optional How much detail to send to stdout. + check : bool, optional + Specifies whether we perform computationally expensive assertion checks. + Computationally cheap assertions will always be checked. + Returns ------- Model @@ -193,8 +197,8 @@ def run_lgst(dataset, prep_fiducials, effect_fiducials, target_model, op_labels= "or decrease svd_truncate_to" % (rankAB, ABMat_p.shape[0])) invABMat_p = _np.dot(Pjt, _np.dot(_np.diag(1.0 / s), Pj)) # (trunc,trunc) - # check inverse is correct (TODO: comment out later) - assert(_np.linalg.norm(_np.linalg.inv(ABMat_p) - invABMat_p) < 1e-8) + if check: + assert(_np.linalg.norm(_np.linalg.inv(ABMat_p) - invABMat_p) < 1e-8) assert(len((_np.isnan(invABMat_p)).nonzero()[0]) == 0) if svd_truncate_to is None or svd_truncate_to == target_model.dim: # use target sslbls and basis @@ -231,10 +235,6 @@ def run_lgst(dataset, prep_fiducials, effect_fiducials, target_model, op_labels= assert(len(X_ps) == 1); X_p = X_ps[0] # shape (nESpecs, nRhoSpecs) lgstModel.operations[opLabel] = _op.FullArbitraryOp(_np.dot(invABMat_p, X_p)) # shape (trunc,trunc) - #print "DEBUG: X(%s) = \n" % opLabel,X - #print "DEBUG: Evals(X) = \n",_np.linalg.eigvals(X) - #print "DEBUG: %s = \n" % opLabel,lgstModel[ opLabel ] - #Form POVMs for povmLabel in povmLabelsToEstimate: povm_effects = [] @@ -247,7 +247,10 @@ def run_lgst(dataset, prep_fiducials, effect_fiducials, target_model, op_labels= circuit = rhostr dsRow_fractions = dataset[circuit].fractions # outcome labels should just be effect labels (no instruments!) - EVec[0, i] = dsRow_fractions[(effectLabel,)] + # when using a sparse data set format it might not be the case + # that all effect labels are present (only ones with non-zero counts are) + # so return 0 for the fraction in that case. + EVec[0, i] = dsRow_fractions.get((effectLabel,), 0) EVec_p = _np.dot(_np.dot(EVec, Vd), Pj) # truncate Evec => Evec', shape (1,trunc) povm_effects.append((effectLabel, _np.transpose(EVec_p))) lgstModel.povms[povmLabel] = _povm.UnconstrainedPOVM(povm_effects, evotype='default') @@ -262,7 +265,10 @@ def run_lgst(dataset, prep_fiducials, effect_fiducials, target_model, op_labels= # try without prepLabel since it will be the default circuit = estr dsRow_fractions = dataset[circuit].fractions - rhoVec[eoff:eoff + povmLen, 0] = [dsRow_fractions[(ol,)] for ol in target_model.povms[povmLbl]] + # when using a sparse data set format it might not be the case + # that all effect labels are present (only ones with non-zero counts are) + # so return 0 for the fraction in that case. + rhoVec[eoff:eoff + povmLen, 0] = [dsRow_fractions.get((ol,),0) for ol in target_model.povms[povmLbl]] eoff += povmLen rhoVec_p = _np.dot(Pjt, _np.dot(Ud, rhoVec)) # truncate rhoVec => rhoVec', shape (trunc, 1) rhoVec_p = _np.dot(invABMat_p, rhoVec_p) @@ -444,6 +450,10 @@ def _construct_a(effect_fiducials, model): dim = model.dim A = _np.empty((n, dim)) # st = _np.empty(dim, 'd') + + # Remove restrictions on state param types for computation + old_default_param = model.preps.default_param + model.preps.default_param = "full" basis_st = _np.zeros((dim, 1), 'd'); eoff = 0 for k, (estr, povmLbl, povmLen) in enumerate(zip(effect_fiducials, povmLbls, povmLens)): @@ -459,6 +469,9 @@ def _construct_a(effect_fiducials, model): basis_st[i] = 0.0 eoff += povmLen + + model.preps.default_param = old_default_param + return A @@ -468,6 +481,10 @@ def _construct_b(prep_fiducials, model): B = _np.empty((dim, n)) # st = _np.empty(dim, 'd') + # Remove restrictions on POVM param types for computation + old_default_param = model.povms.default_param + model.povms.default_param = "full" + #Create POVM of vector units basis_Es = [] for i in range(dim): # propagate each basis initial state @@ -484,6 +501,8 @@ def _construct_b(prep_fiducials, model): B[:, k] = [probs[("E%d" % i,)] for i in range(dim)] # CHECK will this work? del model.povms['M_LGST_tmp_povm'] + model.povms.default_param = old_default_param + return B diff --git a/pygsti/algorithms/fiducialpairreduction.py b/pygsti/algorithms/fiducialpairreduction.py index 438e82ee8..80956fd2e 100644 --- a/pygsti/algorithms/fiducialpairreduction.py +++ b/pygsti/algorithms/fiducialpairreduction.py @@ -153,12 +153,7 @@ def find_sufficient_fiducial_pairs(target_model, prep_fiducials, meas_fiducials, #like) #tol = 0.5 #fraction of expected amplification that must be observed to call a parameter "amplified" - if prep_povm_tuples == "first": - firstRho = list(target_model.preps.keys())[0] - firstPOVM = list(target_model.povms.keys())[0] - prep_povm_tuples = [(firstRho, firstPOVM)] - prep_povm_tuples = [(_circuits.Circuit((prepLbl,)), _circuits.Circuit((povmLbl,))) - for prepLbl, povmLbl in prep_povm_tuples] + prep_povm_tuples = _set_up_prep_POVM_tuples(target_model, prep_povm_tuples, return_meas_dofs = False) def _get_derivs(length): """ Compute all derivative info: get derivative of each `` @@ -305,7 +300,7 @@ def _get_number_amplified(m0, m1, len0, len1, verb): return listOfAllPairs def find_sufficient_fiducial_pairs_per_germ(target_model, prep_fiducials, meas_fiducials, - germs, pre_povm_tuples="first", + germs, prep_povm_tuples="first", search_mode="random", constrain_to_tp=True, n_random=100, min_iterations=None, base_loweig_tol= 1e-1, seed=None ,verbosity=0, num_soln_returned=1, type_soln_returned='best', retry_for_smaller=True, @@ -350,7 +345,7 @@ def find_sufficient_fiducial_pairs_per_germ(target_model, prep_fiducials, meas_f germs : list of Circuits The germ circuits that are repeated to amplify errors. - pre_povm_tuples : list or "first", optional + prep_povm_tuples : list or "first", optional A list of `(prepLabel, povmLabel)` tuples to consider when checking for completeness. Usually this should be left as the special (and default) value "first", which considers the first prep and POVM @@ -414,20 +409,9 @@ def find_sufficient_fiducial_pairs_per_germ(target_model, prep_fiducials, meas_f """ printer = _baseobjs.VerbosityPrinter.create_printer(verbosity) - - if pre_povm_tuples == "first": - firstRho = list(target_model.preps.keys())[0] - firstPOVM = list(target_model.povms.keys())[0] - pre_povm_tuples = [(firstRho, firstPOVM)] - #brief intercession to calculate the number of degrees of freedom for the povm. - num_effects= len(list(target_model.povms[pre_povm_tuples[0][1]].keys())) - dof_per_povm= num_effects-1 - - pre_povm_tuples = [(_circuits.Circuit((prepLbl,)), _circuits.Circuit((povmLbl,))) - for prepLbl, povmLbl in pre_povm_tuples] - - + prep_povm_tuples, dof_per_povm = _set_up_prep_POVM_tuples(target_model, prep_povm_tuples, return_meas_dofs = True) + pairListDict = {} # dict of lists of 2-tuples: one pair list per germ if min_iterations is None: @@ -449,7 +433,8 @@ def find_sufficient_fiducial_pairs_per_germ(target_model, prep_fiducials, meas_f gsGerm = target_model.copy() gsGerm.set_all_parameterizations("static") germMx = gsGerm.sim.product(germ) - gsGerm.operations["Ggerm"] = _EigenvalueParamDenseOp( + #give this state space labels equal to the line_labels of + gsGerm.operations['Ggerm'] = _EigenvalueParamDenseOp( germMx, True, constrain_to_tp) printer.show_progress(i, len(germs), @@ -458,11 +443,12 @@ def find_sufficient_fiducial_pairs_per_germ(target_model, prep_fiducials, meas_f #Determine which fiducial-pair indices to iterate over #initial run - candidate_solution_list, bestFirstEval = _get_per_germ_power_fidpairs(prep_fiducials, meas_fiducials, pre_povm_tuples, + candidate_solution_list, bestFirstEval = _get_per_germ_power_fidpairs(prep_fiducials, meas_fiducials, prep_povm_tuples, gsGerm, 1, mem_limit, printer, search_mode, seed, n_random, dof_per_povm, min_iterations, base_loweig_tol, candidate_set_seed=None, - num_soln_returned=num_soln_returned, type_soln_returned=type_soln_returned) + num_soln_returned=num_soln_returned, type_soln_returned=type_soln_returned, + germ_circuit=germ) #the algorithm isn't guaranteed to actually find the requested number of solutions, so check how many there actually are #by checking the length of the list of returned eigenvalues. @@ -482,11 +468,12 @@ def find_sufficient_fiducial_pairs_per_germ(target_model, prep_fiducials, meas_f for candidate_solution in candidate_solution_list.values(): #now do a seeded run for each of the candidate solutions returned in the initial run: #for these internal runs just return a single solution. - reducedPairlist, bestFirstEval = _get_per_germ_power_fidpairs(prep_fiducials, meas_fiducials, pre_povm_tuples, + reducedPairlist, bestFirstEval = _get_per_germ_power_fidpairs(prep_fiducials, meas_fiducials, prep_povm_tuples, gsGerm, 1, mem_limit, printer, search_mode, seed, n_random, dof_per_povm, min_iterations, base_loweig_tol, candidate_set_seed=candidate_solution, - num_soln_returned= 1, type_soln_returned='best') + num_soln_returned= 1, type_soln_returned='best', + germ_circuit=germ) #This should now return a dictionary with a single entry. Append that entry to a running list which we'll process at the end. updated_solns.append(list(reducedPairlist.values())[0]) @@ -523,7 +510,7 @@ def find_sufficient_fiducial_pairs_per_germ(target_model, prep_fiducials, meas_f return pairListDict def find_sufficient_fiducial_pairs_per_germ_greedy(target_model, prep_fiducials, meas_fiducials, - germs, pre_povm_tuples="first", constrain_to_tp=True, + germs, prep_povm_tuples="first", constrain_to_tp=True, inv_trace_tol= 10, initial_seed_mode='random', evd_tol=1e-10, sensitivity_threshold=1e-10, seed=None ,verbosity=0, check_complete_fid_set=True, mem_limit=None): @@ -567,7 +554,7 @@ def find_sufficient_fiducial_pairs_per_germ_greedy(target_model, prep_fiducials, germs : list of Circuits The germ circuits that are repeated to amplify errors. - pre_povm_tuples : list or "first", optional + prep_povm_tuples : list or "first", optional A list of `(prepLabel, povmLabel)` tuples to consider when checking for completeness. Usually this should be left as the special (and default) value "first", which considers the first prep and POVM @@ -630,17 +617,7 @@ def find_sufficient_fiducial_pairs_per_germ_greedy(target_model, prep_fiducials, printer = _baseobjs.VerbosityPrinter.create_printer(verbosity) - if pre_povm_tuples == "first": - firstRho = list(target_model.preps.keys())[0] - firstPOVM = list(target_model.povms.keys())[0] - pre_povm_tuples = [(firstRho, firstPOVM)] - - #brief intercession to calculate the number of degrees of freedom for the povm. - num_effects= len(list(target_model.povms[pre_povm_tuples[0][1]].keys())) - dof_per_povm= num_effects-1 - - pre_povm_tuples = [(_circuits.Circuit((prepLbl,)), _circuits.Circuit((povmLbl,))) - for prepLbl, povmLbl in pre_povm_tuples] + prep_povm_tuples, dof_per_povm = _set_up_prep_POVM_tuples(target_model, prep_povm_tuples, return_meas_dofs=True) pairListDict = {} # dict of lists of 2-tuples: one pair list per germ @@ -667,12 +644,13 @@ def find_sufficient_fiducial_pairs_per_germ_greedy(target_model, prep_fiducials, #Determine which fiducial-pair indices to iterate over #initial run - candidate_solution_list, best_score = _get_per_germ_power_fidpairs_greedy(prep_fiducials, meas_fiducials, pre_povm_tuples, + candidate_solution_list, best_score = _get_per_germ_power_fidpairs_greedy(prep_fiducials, meas_fiducials, prep_povm_tuples, gsGerm, 1, mem_limit, printer, seed, dof_per_povm, inv_trace_tol, initial_seed_mode=initial_seed_mode, check_complete_fid_set=check_complete_fid_set, evd_tol=evd_tol, - sensitivity_threshold=sensitivity_threshold) + sensitivity_threshold=sensitivity_threshold, + germ_circuit= germ) #print some output about the minimum eigenvalue acheived. printer.log('Score Achieved: ' + str(best_score), 2) @@ -691,7 +669,7 @@ def find_sufficient_fiducial_pairs_per_germ_greedy(target_model, prep_fiducials, def find_sufficient_fiducial_pairs_per_germ_power(target_model, prep_fiducials, meas_fiducials, germs, max_lengths, - pre_povm_tuples="first", + prep_povm_tuples="first", search_mode="random", constrain_to_tp=True, trunc_scheme="whole germ powers", n_random=100, min_iterations=None, base_loweig_tol= 1e-1, seed=None, @@ -746,7 +724,7 @@ def find_sufficient_fiducial_pairs_per_germ_power(target_model, prep_fiducials, max_lengths: list of int The germ powers (number of repetitions) to be used to amplify errors. - pre_povm_tuples : list or "first", optional + prep_povm_tuples : list or "first", optional A list of `(prepLabel, povmLabel)` tuples to consider when checking for completeness. Usually this should be left as the special (and default) value "first", which considers the first prep and POVM @@ -805,16 +783,9 @@ def find_sufficient_fiducial_pairs_per_germ_power(target_model, prep_fiducials, printer = _baseobjs.VerbosityPrinter.create_printer(verbosity) - if pre_povm_tuples == "first": - firstRho = list(target_model.preps.keys())[0] - firstPOVM = list(target_model.povms.keys())[0] - pre_povm_tuples = [(firstRho, firstPOVM)] - - pre_povm_tuples = [(_circuits.Circuit((prepLbl,)), _circuits.Circuit((povmLbl,))) - for prepLbl, povmLbl in pre_povm_tuples] + prep_povm_tuples = _set_up_prep_POVM_tuples(target_model, prep_povm_tuples, return_meas_dofs=False) + pairListDict = {} # dict of lists of 2-tuples: one pair list per germ - low_eigvals = {} - #base_loweig_threshold = 1e-2 # HARDCODED #Check whether the user has passed in a candidate set as a seed from a previous run of #per-germ FPR. @@ -881,11 +852,11 @@ def find_sufficient_fiducial_pairs_per_germ_power(target_model, prep_fiducials, else: candidate_set_seed= None - goodPairList, _ = _get_per_germ_power_fidpairs(prep_fiducials, meas_fiducials, pre_povm_tuples, + goodPairList, _ = _get_per_germ_power_fidpairs(prep_fiducials, meas_fiducials, prep_povm_tuples, gsGerm, power, mem_limit, printer, search_mode, seed, n_random, min_iterations, base_loweig_tol, candidate_set_seed, - num_soln_returned=1, type_soln_returned='best') + num_soln_returned=1, type_soln_returned='best', germ_circuit = germ) #This should now return a dictionary with a single entry. pull that entry out. goodPairList= list(goodPairList.values())[0] @@ -900,7 +871,7 @@ def find_sufficient_fiducial_pairs_per_germ_power(target_model, prep_fiducials, return pairListDict def test_fiducial_pairs(fid_pairs, target_model, prep_fiducials, meas_fiducials, germs, - test_lengths=(256, 2048), pre_povm_tuples="first", tol=0.75, + test_lengths=(256, 2048), prep_povm_tuples="first", tol=0.75, verbosity=0, mem_limit=None): """ Tests a set of global or per-germ fiducial pairs. @@ -936,7 +907,7 @@ def test_fiducial_pairs(fid_pairs, target_model, prep_fiducials, meas_fiducials, A tuple of integers specifying the germ-power lengths to use when checking for amplificational completeness. - pre_povm_tuples : list or "first", optional + prep_povm_tuples : list or "first", optional A list of `(prepLabel, povmLabel)` tuples to consider when checking for completeness. Usually this should be left as the special (and default) value "first", which considers the first prep and POVM @@ -958,12 +929,7 @@ def test_fiducial_pairs(fid_pairs, target_model, prep_fiducials, meas_fiducials, """ printer = _baseobjs.VerbosityPrinter.create_printer(verbosity) - if pre_povm_tuples == "first": - firstRho = list(target_model.preps.keys())[0] - firstPOVM = list(target_model.povms.keys())[0] - pre_povm_tuples = [(firstRho, firstPOVM)] - pre_povm_tuples = [(_circuits.Circuit((prepLbl,)), _circuits.Circuit((povmLbl,))) - for prepLbl, povmLbl in pre_povm_tuples] + prep_povm_tuples = _set_up_prep_POVM_tuples(target_model, prep_povm_tuples, return_meas_dofs=False) def _get_derivs(length): """ Compute all derivative info: get derivative of each `` @@ -975,7 +941,7 @@ def _get_derivs(length): pairList = fid_pairs[germ] if isinstance(fid_pairs, dict) else fid_pairs circuits += _gsc.create_circuits("pp[0]+p[0]+expGerm+p[1]+pp[1]", p=[(prep_fiducials[i], meas_fiducials[j]) for i, j in pairList], - pp=pre_povm_tuples, expGerm=expGerm, order=['p', 'pp']) + pp=prep_povm_tuples, expGerm=expGerm, order=['p', 'pp']) circuits = _remove_duplicates(circuits) resource_alloc = _baseobjs.ResourceAllocation(comm=None, mem_limit=mem_limit) @@ -1023,10 +989,11 @@ def _get_number_amplified(m0, m1, len0, len1): # Helper function for per_germ and per_germ_power FPR -def _get_per_germ_power_fidpairs(prep_fiducials, meas_fiducials, pre_povm_tuples, +def _get_per_germ_power_fidpairs(prep_fiducials, meas_fiducials, prep_povm_tuples, gsGerm, power, mem_limit, printer, search_mode, seed, n_random, dof_per_povm, min_iterations=1, lowest_eigenval_tol=1e-1, - candidate_set_seed=None, num_soln_returned=1, type_soln_returned='best'): + candidate_set_seed=None, num_soln_returned=1, type_soln_returned='best', + germ_circuit = None): #Get dP-matrix for full set of fiducials, where # P_ij = , i = composite EVec & fiducial index, # j is similar, and derivs are wrt the "eigenvalues" of the germ @@ -1048,17 +1015,18 @@ def _get_per_germ_power_fidpairs(prep_fiducials, meas_fiducials, pre_povm_tuples min_pairs_needed= ceil((gsGerm.num_params/(nPossiblePairs*dof_per_povm))*nPossiblePairs) printer.log('Minimum Number of Pairs Needed for this Germ: %d'%(min_pairs_needed), 2) + line_labels = germ_circuit.line_labels if germ_circuit is not None else 'auto' lst = _gsc.create_circuits( "pp[0]+f0+germ*power+f1+pp[1]", f0=prep_fiducials, f1=meas_fiducials, - germ=_circuits.Circuit('Ggerm'), pp=pre_povm_tuples, power=power, + germ=_circuits.Circuit(['Ggerm'], line_labels=line_labels), pp=prep_povm_tuples, power=power, order=('f0', 'f1', 'pp')) resource_alloc = _baseobjs.ResourceAllocation(comm=None, mem_limit=mem_limit) layout = gsGerm.sim.create_layout(lst, None, resource_alloc, array_types=('ep',), verbosity=0) elIndicesForPair = [[] for i in range(len(prep_fiducials) * len(meas_fiducials))] - nPrepPOVM = len(pre_povm_tuples) + nPrepPOVM = len(prep_povm_tuples) for k in range(len(prep_fiducials) * len(meas_fiducials)): for o in range(k * nPrepPOVM, (k + 1) * nPrepPOVM): # "original" indices into lst for k-th fiducial pair @@ -1249,7 +1217,6 @@ def _get_per_germ_power_fidpairs(prep_fiducials, meas_fiducials, pre_povm_tuples # subset of the total fiducial pairs. elementIndicesToTest = _np.concatenate([elIndicesForPair[i] for i in pairIndicesToTest]) dP = _np.take(dPall, elementIndicesToTest, axis=0) # subset_of_num_elements x num_params - #print('Rank of candidate set: ', _np.linalg.matrix_rank(dP)) spectrum = _np.abs(_np.linalg.eigvalsh(_np.dot(dP, dP.T))) current_rank= _np.count_nonzero(spectrum>1e-10) @@ -1282,8 +1249,8 @@ def _get_per_germ_power_fidpairs(prep_fiducials, meas_fiducials, pre_povm_tuples try: bestPairs.pop(bestFirstEval[-1]) except KeyError as err: - print("trying to drop the element from bestPairs with key: ", bestFirstEval[-1]) - print("current keys in this dictionary: ", bestPairs.keys()) + printer.log(f"Trying to drop the element from bestPairs with key: {bestFirstEval[-1]}", 3) + printer.log(f"Current keys in this dictionary: {bestPairs.keys()}", 3) #This seems to be happening when there are multiple entries with virtually #identical values for the keys. @@ -1328,10 +1295,11 @@ def _get_per_germ_power_fidpairs(prep_fiducials, meas_fiducials, pre_povm_tuples # This version uses a greedy style algorithm and an # alternative objective function which leverages the performance enhancements # utilized for the germ selection algorithm using low-rank updates. -def _get_per_germ_power_fidpairs_greedy(prep_fiducials, meas_fiducials, pre_povm_tuples, +def _get_per_germ_power_fidpairs_greedy(prep_fiducials, meas_fiducials, prep_povm_tuples, gsGerm, power, mem_limit, printer, seed, dof_per_povm, inv_trace_tol=10, initial_seed_mode= 'random', - check_complete_fid_set= True, evd_tol=1e-10, sensitivity_threshold= 1e-10): + check_complete_fid_set= True, evd_tol=1e-10, sensitivity_threshold= 1e-10, + germ_circuit = None): #Get dP-matrix for full set of fiducials, where # P_ij = , i = composite EVec & fiducial index, # j is similar, and derivs are wrt the "eigenvalues" of the germ @@ -1352,17 +1320,18 @@ def _get_per_germ_power_fidpairs_greedy(prep_fiducials, meas_fiducials, pre_povm min_pairs_needed= ceil((gsGerm.num_params/(nPossiblePairs*dof_per_povm))*nPossiblePairs) printer.log('Minimum Number of Pairs Needed for this Germ: %d'%(min_pairs_needed), 2) - + line_labels = germ_circuit.line_labels if germ_circuit is not None else 'auto' + lst = _gsc.create_circuits( "pp[0]+f0+germ*power+f1+pp[1]", f0=prep_fiducials, f1=meas_fiducials, - germ=_circuits.Circuit('Ggerm'), pp=pre_povm_tuples, power=power, + germ=_circuits.Circuit(['Ggerm'], line_labels=line_labels), pp=prep_povm_tuples, power=power, order=('f0', 'f1', 'pp')) resource_alloc = _baseobjs.ResourceAllocation(comm=None, mem_limit=mem_limit) layout = gsGerm.sim.create_layout(lst, None, resource_alloc, array_types=('ep',), verbosity=0) elIndicesForPair = [[] for i in range(len(prep_fiducials) * len(meas_fiducials))] - nPrepPOVM = len(pre_povm_tuples) + nPrepPOVM = len(prep_povm_tuples) for k in range(len(prep_fiducials) * len(meas_fiducials)): for o in range(k * nPrepPOVM, (k + 1) * nPrepPOVM): # "original" indices into lst for k-th fiducial pair @@ -1586,7 +1555,7 @@ def filter_useless_fid_pairs(fiducial_indices, element_map, complete_jacobian, s #about the amplificational properties of the germ set as a whole. def find_sufficient_fiducial_pairs_per_germ_global(target_model, prep_fiducials, meas_fiducials, - germ_vector_spanning_set=None, germs=None, pre_povm_tuples="first", + germ_vector_spanning_set=None, germs=None, prep_povm_tuples="first", mem_limit=None, inv_trace_tol= 10, initial_seed_mode='greedy', evd_tol=1e-10, seed=None ,verbosity=0, float_type = _np.cdouble, germ_set_spanning_kwargs = None, precomputed_jacobians = None): @@ -1633,7 +1602,7 @@ def find_sufficient_fiducial_pairs_per_germ_global(target_model, prep_fiducials, If passed in and germ_vector_spanning_set is None then we'll use this in the calculation of the germ vector spanning set. - pre_povm_tuples : list or "first", optional + prep_povm_tuples : list or "first", optional A list of `(prepLabel, povmLabel)` tuples to consider when checking for completeness. Usually this should be left as the special (and default) value "first", which considers the first prep and POVM @@ -1711,17 +1680,7 @@ def find_sufficient_fiducial_pairs_per_germ_global(target_model, prep_fiducials, verbosity=verbosity, **used_kwargs) - if pre_povm_tuples == "first": - firstRho = list(target_model.preps.keys())[0] - firstPOVM = list(target_model.povms.keys())[0] - pre_povm_tuples = [(firstRho, firstPOVM)] - - #brief intercession to calculate the number of degrees of freedom for the povm. - num_effects= len(list(target_model.povms[pre_povm_tuples[0][1]].keys())) - dof_per_povm= num_effects-1 - - pre_povm_tuples = [(_circuits.Circuit((prepLbl,)), _circuits.Circuit((povmLbl,))) - for prepLbl, povmLbl in pre_povm_tuples] + prep_povm_tuples, dof_per_povm = _set_up_prep_POVM_tuples(target_model, prep_povm_tuples, return_meas_dofs=True) pairListDict = {} # dict of lists of 2-tuples: one pair list per germ @@ -1733,7 +1692,7 @@ def find_sufficient_fiducial_pairs_per_germ_global(target_model, prep_fiducials, printer.log("------ Per Germ Global Fiducial Pair Reduction --------") with printer.progress_logging(1): for i, (germ, germ_vector_list) in enumerate(germ_vector_spanning_set.items()): - candidate_solution_list, best_score = get_per_germ_fid_pairs_global(prep_fiducials, meas_fiducials, pre_povm_tuples, + candidate_solution_list, best_score = get_per_germ_fid_pairs_global(prep_fiducials, meas_fiducials, prep_povm_tuples, target_model, germ, germ_vector_list, mem_limit, printer, dof_per_povm, inv_trace_tol, initial_seed_mode=initial_seed_mode, evd_tol=evd_tol, @@ -1754,7 +1713,7 @@ def find_sufficient_fiducial_pairs_per_germ_global(target_model, prep_fiducials, return pairListDict -def get_per_germ_fid_pairs_global(prep_fiducials, meas_fiducials, pre_povm_tuples, +def get_per_germ_fid_pairs_global(prep_fiducials, meas_fiducials, prep_povm_tuples, target_model, germ, germ_vector_list, mem_limit, printer, dof_per_povm, inv_trace_tol=10, initial_seed_mode= 'greedy', evd_tol=1e-10, float_type = _np.cdouble, dprobs_dict = None): @@ -1782,8 +1741,7 @@ def get_per_germ_fid_pairs_global(prep_fiducials, meas_fiducials, pre_povm_tuple allPairIndices = list(range(nPossiblePairs)) - print('Current Germ: ') - print(germ) + printer.log(f'Current Germ: {germ}', 2) printer.log('Number of possible pairs: %d'%(nPossiblePairs), 3) @@ -1797,10 +1755,10 @@ def get_per_germ_fid_pairs_global(prep_fiducials, meas_fiducials, pre_povm_tuple #loops over a number of pairs between min_pairs_needed and up to and not including the number of possible pairs min_pairs_needed= ceil((num_germ_vecs/(nPossiblePairs*dof_per_povm))*nPossiblePairs) printer.log('Minimum Number of Pairs Needed for this Germ: %d'%(min_pairs_needed), 2) - + lst = _gsc.create_circuits( "pp[0]+f0+germ*power+f1+pp[1]", f0=prep_fiducials, f1=meas_fiducials, - germ=germ, pp=pre_povm_tuples, power=1, + germ=germ, pp=prep_povm_tuples, power=1, order=('f0', 'f1', 'pp')) printer.log('Constructing Directional Derivatives for Full Fiducial Set' , 2) @@ -2054,9 +2012,7 @@ def _compute_bulk_directional_ddd_compact(model, circuits, vec_mat, eps, #now calculate the direction derivative matrix. directional_deriv = jac@vec_mat - #print('directional deriv shape: ' + str(directional_deriv.shape)) - direc_deriv_gram = directional_deriv.T@directional_deriv - #print('directional deriv gram shape: ' + str(direc_deriv_gram.shape)) + direc_deriv_gram = directional_deriv.T@directional_deriv #now take twirledDerivDerivDagger and construct its compact EVD. e, U= compact_EVD(direc_deriv_gram, evd_tol) e_list.append(e) @@ -2117,7 +2073,8 @@ def _make_spam_static(model): #write a helper function for precomputing the jacobian dictionaries from bulk_dprobs #which can then be passed into the construction of the compactEVD caches. -def compute_jacobian_dicts(model, germs, prep_fiducials, meas_fiducials, pre_povm_tuples = 'first', comm=None, mem_limit=None): +def compute_jacobian_dicts(model, germs, prep_fiducials, meas_fiducials, prep_povm_tuples = 'first', comm=None, + mem_limit=None, verbosity = 0): """ Function for precomputing the jacobian dictionaries from bulk_dprobs for a model with its SPAM parameters frozen, as needed for certain @@ -2136,7 +2093,7 @@ def compute_jacobian_dicts(model, germs, prep_fiducials, meas_fiducials, pre_pov meas_fiducials : list of Circuits A list of measurement fiducial circuits. - pre_povm_tuples : str or list of tuples (default 'first') + prep_povm_tuples : str or list of tuples (default 'first') Either a string or list of tuples. When a list of tuples these correspond to native state prep and native POVM pairs. When the special keyword argument 'first' is passed in the first @@ -2160,14 +2117,10 @@ def compute_jacobian_dicts(model, germs, prep_fiducials, meas_fiducials, pre_pov """ resource_alloc = _baseobjs.ResourceAllocation(comm= comm, mem_limit = mem_limit) + printer = _baseobjs.VerbosityPrinter.create_printer(verbosity, comm= comm) + #construct the list of circuits - if pre_povm_tuples == "first": - firstRho = list(model.preps.keys())[0] - firstPOVM = list(model.povms.keys())[0] - pre_povm_tuples = [(firstRho, firstPOVM)] - - pre_povm_tuples = [(_circuits.Circuit((prepLbl,)), _circuits.Circuit((povmLbl,))) - for prepLbl, povmLbl in pre_povm_tuples] + prep_povm_tuples = _set_up_prep_POVM_tuples(model, prep_povm_tuples, return_meas_dofs=False) #freeze the SPAM model parameters: static_spam_model = _make_spam_static(model) @@ -2175,16 +2128,48 @@ def compute_jacobian_dicts(model, germs, prep_fiducials, meas_fiducials, pre_pov jacobian_dicts = {} for germ in germs: - if comm is None or comm.Get_rank() ==0: - print('Current germ:', germ, flush=True) + printer.log(f'Current germ: {germ}', 1) lst = _gsc.create_circuits( "pp[0]+f0+germ*power+f1+pp[1]", f0=prep_fiducials, f1=meas_fiducials, - germ=germ, pp=pre_povm_tuples, power=1, + germ=germ, pp=prep_povm_tuples, power=1, order=('f0', 'f1', 'pp')) #calculate the dprobs dictionary in bulk. dprobs_dict = static_spam_model.sim.bulk_dprobs(lst, resource_alloc) jacobian_dicts[germ] = dprobs_dict - return jacobian_dicts \ No newline at end of file + return jacobian_dicts + +#helper function for configuring the list of circuit tuples needed for prep-POVM pairs used in FPR. +def _set_up_prep_POVM_tuples(target_model, prep_povm_tuples, return_meas_dofs= False): + + if prep_povm_tuples == "first": + firstRho = list(target_model.preps.keys())[0] + prep_ssl = [target_model.preps[firstRho].state_space.state_space_labels] + firstPOVM = list(target_model.povms.keys())[0] + POVM_ssl = [target_model.povms[firstPOVM].state_space.state_space_labels] + prep_povm_tuples = [(firstRho, firstPOVM)] + #I think using the state space labels for firstRho and firstPOVM as the + #circuit labels should work most of the time (new stricter line_label enforcement means + # we need to enforce compatibility here), but this might break for + #ImplicitModels? Not sure how those handle the state space labels for preps and povms + #Time will tell... + #if not we still need to extract state space labels for all of these to meet new circuit + #label handling requirements. + else: + prep_ssl = [target_model.preps[lbl_tup[0]].state_space.state_space_labels for lbl_tup in prep_povm_tuples] + POVM_ssl = [target_model.povms[lbl_tup[1]].state_space.state_space_labels for lbl_tup in prep_povm_tuples] + + #brief intercession to calculate the number of degrees of freedom for the povm. + num_effects= len(list(target_model.povms[prep_povm_tuples[0][1]].keys())) + dof_per_povm= num_effects-1 + + prep_povm_tuples = [(_circuits.Circuit([prepLbl], line_labels=prep_ssl[i]), + _circuits.Circuit([povmLbl], line_labels=POVM_ssl[i])) + for i, (prepLbl, povmLbl) in enumerate(prep_povm_tuples)] + + if return_meas_dofs: + return prep_povm_tuples, dof_per_povm + else: + return prep_povm_tuples \ No newline at end of file diff --git a/pygsti/algorithms/fiducialselection.py b/pygsti/algorithms/fiducialselection.py index 39ff8d6de..536db2847 100644 --- a/pygsti/algorithms/fiducialselection.py +++ b/pygsti/algorithms/fiducialselection.py @@ -2013,7 +2013,23 @@ def create_candidate_fiducial_list(target_model, omit_identity= True, ops_to_omi else: availableFidList.extend(_circuits.list_random_circuits_onelen( fidOps, fidLength, count, seed=candidate_seed)) - return availableFidList + + #force the line labels on each circuit to match the state space labels for the target model. + #this is suboptimal for many-qubit models, so will probably want to revisit this. #TODO + finalFidList = [] + for ckt in availableFidList: + if ckt._static: + new_ckt = ckt.copy(editable=True) + new_ckt.line_labels = target_model.state_space.state_space_labels + new_ckt.done_editing() + + finalFidList.append(new_ckt) + else: + ckt.line_labels = target_model.state_space.state_space_labels + + finalFidList.append(ckt) + + return finalFidList diff --git a/pygsti/baseobjs/opcalc/fastopcalc.pyx b/pygsti/baseobjs/opcalc/fastopcalc.pyx index b55cc7f37..110c1f865 100644 --- a/pygsti/baseobjs/opcalc/fastopcalc.pyx +++ b/pygsti/baseobjs/opcalc/fastopcalc.pyx @@ -69,7 +69,7 @@ def bulk_eval_compact_polynomials_real(np.ndarray[np.int64_t, ndim=1, mode="c"] np.ndarray[double, ndim=1, mode="c"] ctape, np.ndarray[double, ndim=1, mode="c"] paramvec, dest_shape): - cdef INT dest_size = np.product(dest_shape) + cdef INT dest_size = np.prod(dest_shape) cdef np.ndarray[np.float64_t, ndim=1, mode="c"] res = np.empty(dest_size, np.float64) cdef INT c = 0 @@ -108,7 +108,7 @@ def bulk_eval_compact_polynomials_complex(np.ndarray[np.int64_t, ndim=1, mode="c np.ndarray[double, ndim=1, mode="c"] paramvec, dest_shape): cdef INT k - cdef INT dest_size = 1 # np.product(dest_shape) #SLOW! + cdef INT dest_size = 1 # np.prod(dest_shape) #SLOW! for k in range(len(dest_shape)): dest_size *= dest_shape[k] cdef np.ndarray[np.complex128_t, ndim=1, mode="c"] res = np.empty(dest_size, np.complex128) diff --git a/pygsti/baseobjs/protectedarray.py b/pygsti/baseobjs/protectedarray.py index 59d7eca72..1a3a3b481 100644 --- a/pygsti/baseobjs/protectedarray.py +++ b/pygsti/baseobjs/protectedarray.py @@ -15,7 +15,6 @@ from pygsti.baseobjs import _compatibility as _compat - class ProtectedArray(object): """ A numpy ndarray-like class that allows certain elements to be treated as read-only. @@ -25,39 +24,63 @@ class ProtectedArray(object): input_array : numpy.ndarray The base array. - indices_to_protect : tuple or list, optional - A list or tuple of length `input_array.shape`, specifying + indices_to_protect : int or list of tuples, optional + A list of length `input_array.shape`, specifying the indices to protect along each axis. Values may be integers, slices, or lists of integers, e.g. `(0, slice(None, None, None))`. + Also supported are iterables over tuples/lists, each + of length `input_array.shape`, specifying + the indices to protect along each axis. + + protected_index_mask : numpy.ndarray, optional + An optional array with the same shape as `input_array` which if + specified is used to initialize the mask for protected indices + used by this array. Note that is specified the value overrides + any specification given in indices_to_protect, meaning that argument + is ignored. """ - def __init__(self, input_array, indices_to_protect=None): + def __init__(self, input_array, indices_to_protect=None, protected_index_mask= None): self.base = input_array - #Get protected indices, a specified as: - self.indicesToProtect = [] - if indices_to_protect is not None: - if not isinstance(indices_to_protect, (list, tuple)): - indices_to_protect = (indices_to_protect,) - - assert(len(indices_to_protect) <= len(self.base.shape)) - for ky, L in zip(indices_to_protect, self.base.shape): - if isinstance(ky, slice): - pindices = range(*ky.indices(L)) - elif _compat.isint(ky): - i = ky + L if ky < 0 else ky - if i < 0 or i > L: - raise IndexError("index (%d) is out of range." % ky) - pindices = (i,) - elif isinstance(ky, list): - pindices = ky - else: raise TypeError("Invalid index type: %s" % type(ky)) - self.indicesToProtect.append(pindices) - - if len(self.indicesToProtect) == 0: - self.indicesToProtect = None - + if protected_index_mask is not None: + #check this has the correct shape + assert protected_index_mask.shape == input_array.shape + + #Cast this to a binary dtype (to save space since we only + #need boolean values). + self.protected_index_mask = protected_index_mask.astype(_np.bool_) + + #otherwise use the value passed into indices to protect to construct + #a mask. + #add in support for multiple sets of indices to protect + #by allowing a nested iterable format. Do this by forcing + #everything into this format and then looping over the nested + #submembers. + elif indices_to_protect is not None: + if isinstance(indices_to_protect, int): + indices_to_protect= [(indices_to_protect,)] + #if this is a list go through and wrap any integers + #at the top level in a tuple. + elif isinstance(indices_to_protect, (list, tuple)): + #check whether this is a single-level tuple/list corresponding + #containing only ints and/or slices. If so wrap this in a list. + if all([isinstance(idx, (int, slice)) for idx in indices_to_protect]): + indices_to_protect = [indices_to_protect] + + #add some logic for mixing of unwrapped top-level ints and tuples/lists. + indices_to_protect = [tuple(indices) if isinstance(indices, (list, tuple)) else (indices,) for indices in indices_to_protect] + #initialize an empty mask + self.protected_index_mask = _np.zeros(input_array.shape , dtype= _np.bool_) + + #now loop over the nested subelements and add them to the mask: + for indices in indices_to_protect: + assert(len(indices) <= len(self.base.shape)) + self.protected_index_mask[indices]=1 + #otherwise set the mask to all zeros. + else: + self.protected_index_mask = _np.zeros(input_array.shape , dtype= _np.bool_) #Note: no need to set self.base.flags.writeable = True anymore, # since this flag can only apply to a data owner as of numpy 1.16 or so. # Instead, we just copy the data whenever we return a readonly array. @@ -102,7 +125,7 @@ def __setstate__(self, state): self.__dict__.update(state) #Access to underlying ndarray - + def __getattr__(self, attr): # set references to our memory as (entirely) read-only ret = getattr(self.__dict__['base'], attr) @@ -116,115 +139,32 @@ def __getslice__(self, i, j): return self.__getitem__(slice(i, j)) def __getitem__(self, key): + #Use key to extract subarray of self.base and self.protected_index_mask + ret = self.base[key] + new_protected_mask = self.protected_index_mask[key] - writeable = True - - #check if key matches/overlaps protected region - if self.indicesToProtect is not None: - new_indicesToProtect = []; nUnprotectedIndices = 0 - tup_key = key if isinstance(key, tuple) else (key,) - - while len(tup_key) < len(self.base.shape): - tup_key = tup_key + (slice(None, None, None),) - - for ky, pindices, L in zip(tup_key, self.indicesToProtect, self.base.shape): - - #Get requested indices - if isinstance(ky, slice): - indices = range(*ky.indices(L)) - - new_pindices = [] - for ii, i in enumerate(indices): - if i in pindices: - new_pindices.append(ii) # index of i within indices - new_pindices = sorted(list(set(new_pindices))) - new_indicesToProtect.append(new_pindices) - - #tally how many indices in this dimension are unprotected - nTotalInDim = len(indices) - nUnprotectedInCurDim = (len(indices) - len(new_pindices)) - - elif _compat.isint(ky): - i = ky + L if ky < 0 else ky - if i > L: - raise IndexError("The index (%d) is out of range." % ky) - - nTotalInDim = 1 - if i not in pindices: # single index that is unprotected => all unprotected - nUnprotectedInCurDim = 1 # a single unprotected index - else: - nUnprotectedInCurDim = 0 - - else: raise TypeError("Invalid index type: %s" % type(ky)) - - nUnprotectedIndices += nUnprotectedInCurDim - - #if there exists a single dimension with no protected indices, then - # the whole array is writeable. - if nTotalInDim == nUnprotectedInCurDim: - writeable = True - new_indicesToProtect = None - break - - else: - # if we didn't break b/c of above block, which means each dim has - # at least one protected index - - #if there are no unprotected indices, then just set writeable == False - if nUnprotectedIndices == 0: - writeable = False - new_indicesToProtect = None - else: - #There is at least one writeable (unprotected) index in some dimension - # and at least one protected index in *every* dimension. We need to - # set indicesToProtect to describe what to protect - assert(len(new_indicesToProtect) > 0) # b/c otherwise another case would hold - writeable = True - new_indicesToProtect = tuple(new_indicesToProtect) - - else: # (if nothing is protected) - writeable = True - new_indicesToProtect = None - - ret = _np.ndarray.__getitem__(self.base, key) - + #If ret is not a scalar return a new ProtectedArray corresponding to the + #selected subarray with the set of protected indices inherited over from the + #original. if not _np.isscalar(ret): - if writeable: # then some of the indices are writeable - ret = ProtectedArray(ret) - ret.indicesToProtect = new_indicesToProtect - else: + if not _np.all(new_protected_mask): # then some of the indices are writeable + ret = ProtectedArray(ret, protected_index_mask= new_protected_mask) + else: #otherwise all of the values are masked off. ret = _np.require(ret.copy(), requirements=['OWNDATA']) # copy to a new read-only array ret.flags.writeable = False # a read-only array - ret = ProtectedArray(ret) # return a ProtectedArray that is read-only - - #print " writeable = ",ret.flags.writeable - #print " new_toProtect = ",ret.indicesToProtect - #print "<< END getitem" + ret = ProtectedArray(ret, protected_index_mask=new_protected_mask) # return a ProtectedArray that is read-only return ret def __setitem__(self, key, val): - #print "In setitem with key = ", key, "val = ",val - - protectionViolation = [] # per dimension - if self.indicesToProtect is not None: - tup_key = key if isinstance(key, tuple) else (key,) - for ky, pindices, L in zip(tup_key, self.indicesToProtect, self.base.shape): - - #Get requested indices - if isinstance(ky, slice): - indices = range(*ky.indices(L)) - if any(i in pindices for i in indices): - protectionViolation.append(True) - else: protectionViolation.append(False) - - elif _compat.isint(ky): - i = ky + L if ky < 0 else ky - if i > L: - raise IndexError("The index (%d) is out of range." % ky) - protectionViolation.append(i in pindices) - - else: raise TypeError("Invalid index type: %s" % type(ky)) - - if all(protectionViolation): # assigns to a protected index in each dim - raise ValueError("**assignment destination is read-only") + #check if any of the indices in key have been masked off. + if _np.any(self.protected_index_mask[key]): # assigns to a protected index in each dim + raise ValueError("**some or all of assignment destination is read-only") + #not sure what the original logic was for this return statement, but I don't see any + #harm in keeping it. return self.base.__setitem__(key, val) + + #add a repr method that prints the base array, which is typically what + #we want. + def __repr__(self): + return _np.array2string(self.base) + \ No newline at end of file diff --git a/pygsti/circuits/circuit.py b/pygsti/circuits/circuit.py index bdb5a88d3..4ea29578b 100644 --- a/pygsti/circuits/circuit.py +++ b/pygsti/circuits/circuit.py @@ -43,6 +43,11 @@ # c[1:3,'Q0'] = ('Gx','Gy') # assigns to a part of the Q0 line +#Add warning filter +msg = 'Could not find matching standard gate name in provided dictionary. Falling back to try and find a'\ + +' unitary from standard_gatename_unitaries which matches up to a global phase.' +_warnings.filterwarnings('module', message=msg, category=UserWarning) + def _np_to_quil_def_str(name, input_array): """ Write a DEFGATE block for RQC quil for an arbitrary one- or two-qubit unitary gate. @@ -75,7 +80,7 @@ def _np_to_quil_def_str(name, input_array): def _num_to_rqc_str(num): """Convert float to string to be included in RQC quil DEFGATE block (as written by _np_to_quil_def_str).""" - num = _np.complex_(_np.real_if_close(num)) + num = _np.complex128(_np.real_if_close(num)) if _np.imag(num) == 0: output = str(_np.real(num)) return output @@ -843,9 +848,57 @@ def __radd__(self, x): return x.__add__(self) def __add__(self, x): + """ + Method for adding circuits, or labels to circuits. + + Parameters + ---------- + x : `Circuit` or tuple of `Label` objects + `Circuit` to add to this `Circuit`, or a tuple of Labels to add to this + Circuit. Note: If `x` is a `Circuit` it must have line labels that are + compatible with this it is being added to. In other words, if `x` uses + the default '*' placeholder as its line label and this Circuit does not, + and vice versa, a ValueError will be raised. + + Returns + ------- + Circuit + """ + if not isinstance(x, Circuit): assert(all([isinstance(l, _Label) for l in x])), "Only Circuits and Label-tuples can be added to Circuits!" return Circuit._fastinit(self.layertup + x, self.line_labels, editable=False) + + #Add special line label handling to deal with the special global idle circuits (which have no line labels + # associated with them typically). + #Check if a the circuit or labels being added are all global idles, if so inherit the + #line labels from the circuit being added to. Otherwise, enforce compatibility. + layertup_x = x.layertup if isinstance(x, Circuit) else x + gbl_idle_x= all([lbl == _Label(()) for lbl in layertup_x]) + gbl_idle_self= all([lbl == _Label(()) for lbl in self.layertup]) + + if not (gbl_idle_x or gbl_idle_self): + combined_labels = {x.line_labels, self.line_labels} + elif not gbl_idle_x and gbl_idle_self: + combined_labels = {x.line_labels} + elif gbl_idle_x and not gbl_idle_self: + combined_labels = {self.line_labels} + else: #both are all global idles so it doesn't matter which we take. + combined_labels = {self.line_labels} + + #check that the line labels are compatible between circuits. + #i.e. raise error if adding circuit with * line label to one with + #standard line labels. + if ('*',) in combined_labels and len(combined_labels) > 1: + # raise the error + msg = f"Adding circuits with incompatible line labels: {combined_labels}." \ + +" The problem is that one of these labels uses the placeholder value of '*', while the other label does not."\ + +" The placeholder value arises when when a Circuit is initialized without specifying the line labels,"\ + +" either explicitly by setting the line_labels or by num_lines kwarg, or implicitly from specifying"\ + +" layer labels with non-None state-space labels. Circuits with '*' line labels can be used, but"\ + +" only in conjunction with other circuits with '*' line labels (and vice-versa for circuits with"\ + +" standard line labels)." + raise ValueError(msg) if self._str is None or x._str is None: s = None @@ -857,8 +910,18 @@ def __add__(self, x): s = (mystr + xstr) if xstr != "{}" else mystr else: s = xstr - added_labels = tuple([l for l in x.line_labels if l not in self.line_labels]) - new_line_labels = self.line_labels + added_labels + #try to return the line labels as the contents of combined labels in + #sorted order. If there is a TypeError raised this is probably because + #we're mixing integer and string labels, in which case we'll just return + #the new labels in whatever arbirary order is obtained by casting a set to + #a tuple. + #unpack all of the different sets of labels and make sure there are no duplicates + combined_labels_unpacked = {el for tup in combined_labels for el in tup} + try: + new_line_labels = tuple(sorted(list(combined_labels_unpacked))) + except TypeError: + new_line_labels = tuple(combined_labels_unpacked) + if s is not None: s += _op_seq_str_suffix(new_line_labels, occurrence_id=None) # don't maintain occurrence_id @@ -3739,6 +3802,12 @@ def convert_to_cirq(self, gatename_conversion = _itgs.standard_gatenames_cirq_conversions() if wait_duration is not None: gatename_conversion[idle_gate_name] = cirq.WaitGate(wait_duration) + #conversion does not work is the line labels are none, or the line labels are not a subset + #of the keys for qubit_conversion (indicating there isn't a corresponding mapping into cirq objects). + msg1 = 'Conversion to cirq does not work with circuits w/placeholder * line label.' + msg2 = 'Missing qubit conversions, some line labels have no corresponding cirq conversion in qubit_conversions.' + assert self.line_labels != ('*',), msg1 + assert set(self.line_labels).issubset(set(qubit_conversion.keys())), msg2 moments = [] for i in range(self.num_layers): @@ -3746,15 +3815,193 @@ def convert_to_cirq(self, operations = [] for gate in layer: operation = gatename_conversion[gate.name] - if operation is None: - # This happens if no idle gate it specified because - # standard_gatenames_cirq_conversions maps 'Gi' to `None` - continue qubits = map(qubit_conversion.get, gate.qubits) operations.append(operation.on(*qubits)) moments.append(cirq.Moment(operations)) return cirq.Circuit(moments) + + @classmethod + def from_cirq(cls, circuit, qubit_conversion=None, cirq_gate_conversion= None, + remove_implied_idles = True, global_idle_replacement_label = 'auto'): + """ + Converts and instantiates a pyGSTi Circuit object from a Cirq Circuit object. + + Parameters + ---------- + circuit : cirq Circuit + The cirq Circuit object to parse into a pyGSTi circuit. + + qubit_conversion : dict, optional (default None) + A dictionary specifying a mapping between cirq qubit objects and + pyGSTi qubit labels (either integers or strings). + If None, then a default mapping is created. + + cirq_gate_conversion : dict, optional (default None) + If specified a dictionary with keys given by cirq gate objects, + and values given by pygsti gate names which overrides the built-in + conversion dictionary used by default. + + remove_implied_idles : bool, optional (default True) + A flag indicating whether to remove explicit idles + that are part of a circuit layer containing + other explicitly specified gates + (i.e., whether to abide by the normal pyGSTi implicit idle convention). + + global_idle_replacement_label : string or Label or None, optional (default 'auto') + An option specified for the handling of global idle layers. + If None, no replacement of global idle layers is performed and a verbatim + conversion from the cirq layer is performed. + If the string 'auto', then the behavior is to replace global idle layers with + the gate label Label(()), which is the special syntax for the global + idle layer, stylized typically as '[]'. If another string then replace with a + gate label with the specified name acting on all of the qubits + appearing in the cirq circuit. If a Label object, use this directly, + this does not check for compatibility so it is up to the user to ensure + the labels are compatible. + + Returns + ------- + pygsti_circuit + A pyGSTi Circuit instance equivalent to the specified Cirq one. + """ + + try: + import cirq + except ImportError: + raise ImportError("Cirq is required for this operation, and it does not appear to be installed.") + + #mapping between cirq gates and pygsti gate names: + if cirq_gate_conversion is not None: + cirq_to_gate_name_mapping = cirq_gate_conversion + else: + cirq_to_gate_name_mapping = _itgs.cirq_gatenames_standard_conversions() + + #get all of the qubits in the cirq Circuit + all_cirq_qubits = circuit.all_qubits() + + #ensure all of these have a conversion available. + if qubit_conversion is not None: + assert set(all_cirq_qubits).issubset(set(qubit_conversion.keys())), 'Missing cirq to pygsti conversions for some qubit label(s).' + #if it is None, build a default mapping. + else: + #default mapping is currently hardcoded for the conventions of either cirwq's + #NamedQubit, LineQubit or GridQubit classes, other types will raise an error. + qubit_conversion = {} + for qubit in all_cirq_qubits: + if isinstance(qubit, cirq.NamedQubit): + qubit_conversion[qubit] = f'Q{qubit.name}' + elif isinstance(qubit, cirq.LineQubit): + qubit_conversion[qubit] = f'Q{qubit.x}' + elif isinstance(qubit, cirq.GridQubit): + qubit_conversion[qubit] = f'Q{qubit.row}_{qubit.col}' + else: + msg = 'Unsupported cirq qubit type. Currently only support for automatically creating'\ + +'a default cirq qubit to pygsti qubit label mapping for NamedQubit, LineQubit and GridQubit.' + raise ValueError(msg) + + #In cirq the equivalent concept to a layer in a pygsti circuit is a Moment. + #Circuits consist of ordered lists of moments corresponding to a set of + #operations applied at that abstract time slice. + #cirq Circuits can be sliced and iterated over. Iterating returns each contained + #Moment in sequence. Slicing returns a new circuit corresponding to the + #selected layers. + + #initialize empty list of pygsti circuit layers + circuit_layers = [] + + #initialize a flag for indicating that we've seen a global idle to use later. + seen_global_idle = False + + #Iterate through each of the moments and build up layers Moment by Moment. + for moment in circuit: + #if the length of the tuple of operations for this moment in + #moment.operations is length 1, then we'll add the operation to + #the pygsti circuit as a bare gate label (i.e. not wrapped in a layer label + #indicating parallel gates). Otherwise, we'll iterate through and add them + #as a layer label. + if len(moment.operations) == 1: + op = moment.operations[0] + try: + name = cirq_to_gate_name_mapping[op.gate] + except KeyError: + msg = 'Could not find matching standard gate name in provided dictionary. Falling back to try and find a'\ + +' unitary from standard_gatename_unitaries which matches up to a global phase.' + _warnings.warn(msg) + name = _itgs.unitary_to_standard_gatename(op.gate._unitary_(), up_to_phase=True) + assert name is not None, 'Could not find a matching standard gate name for conversion.' + sslbls = tuple(qubit_conversion[qubit] for qubit in op.qubits) + #global idle handling: + if name == 'Gi' and global_idle_replacement_label: + #set a flag indicating that we've seen a global idle to use later. + seen_global_idle = True + if isinstance(global_idle_replacement_label, str): + if global_idle_replacement_label == 'auto': + #append the default. + circuit_layers.append(_Label(())) + else: + circuit_layers.append(_Label(global_idle_replacement_label, tuple(sorted([qubit_conversion[qubit] for qubit in all_cirq_qubits])))) + elif isinstance(global_idle_replacement_label, _Label): + circuit_layers.append(global_idle_replacement_label) + else: + circuit_layers.append(_Label(name, state_space_labels = sslbls)) + + else: + #initialize sublist for layer label elements + layer_label_elems = [] + #iterate through each of the operations in this moment + for op in moment.operations: + try: + name = cirq_to_gate_name_mapping[op.gate] + except KeyError: + msg = 'Could not find matching standard gate name in provided dictionary. Falling back to try and find a'\ + +' unitary from standard_gatename_unitaries which matches up to a global phase.' + _warnings.warn(msg) + name = _itgs.unitary_to_standard_gatename(op.gate._unitary_(), up_to_phase=True) + assert name is not None, 'Could not find a matching standard gate name for conversion.' + sslbls = tuple(qubit_conversion[qubit] for qubit in op.qubits) + layer_label_elems.append(_Label(name, state_space_labels = sslbls)) + + #add special handling for global idle circuits and implied idels based on flags. + layer_label_elem_names = [elem.name for elem in layer_label_elems] + all_idles = all([name == 'Gi' for name in layer_label_elem_names]) + + if global_idle_replacement_label and all_idles: + #set a flag indicating that we've seen a global idle to use later. + seen_global_idle = True + #if global idle is a string, replace this layer with the user specified one: + if isinstance(global_idle_replacement_label, str): + if global_idle_replacement_label == 'auto': + #append the default. + circuit_layers.append(_Label(())) + else: + circuit_layers.append(_Label(global_idle_replacement_label, tuple(sorted([qubit_conversion[qubit] for qubit in all_cirq_qubits])))) + elif isinstance(global_idle_replacement_label, _Label): + circuit_layers.append(global_idle_replacement_label) + #check whether any of the elements are implied idles, and if so use flag + #to determine whether to include them. We have already checked if this layer + #is a global idle, so if not then we only need to check if any of the layer + #elements are implied idles. + elif remove_implied_idles and 'Gi' in layer_label_elem_names and not all_idles: + stripped_layer_label_elems = [elem for elem in layer_label_elems + if not elem.name == 'Gi'] + #if this is length one then add this to the circuit as a bare label, otherwise + #add as a layer label. + if len(stripped_layer_label_elems)==1: + circuit_layers.append(stripped_layer_label_elems[0]) + else: + circuit_layers.append(_Label(stripped_layer_label_elems)) + #otherwise, just add this layer as-is. + else: + circuit_layers.append(_Label(layer_label_elems)) + + #if any of the circuit layers are global idles, then we'll force the circuit line + #labels to include all of the qubits appearing in the cirq circuit, otherwise + #we'll let the Circuit constructor figure this out. + if seen_global_idle: + return cls(circuit_layers, line_labels = tuple(sorted([qubit_conversion[qubit] for qubit in all_cirq_qubits]))) + else: + return cls(circuit_layers) def convert_to_quil(self, num_qubits=None, @@ -3928,6 +4175,7 @@ def convert_to_openqasm(self, num_qubits=None, gatename_conversion=None, qubit_conversion=None, block_between_layers=True, block_between_gates=False, + include_delay_on_idle=True, gateargs_map=None): # TODO """ Converts this circuit to an openqasm string. @@ -3964,6 +4212,17 @@ def convert_to_openqasm(self, num_qubits=None, When `True`, add in a barrier after every circuit layer. Including such barriers can be important for QCVV testing, as this can help reduce the "behind-the-scenes" compilation (beyond necessary conversion to native instructions) experience by the circuit. + + block_between_gates: bool, optional + When `True`, add in a barrier after every gate (effectively serializing the circuit). + Defaults to False. + + include_delay_on_idle: bool, optional + When `True`, includes a delay operation on implicit idles in each layer, as per + Qiskit's OpenQASM 2.0 convention after the deprecation of the id operation. + Defaults to True, which is commensurate with legacy usage of this function. + However, this can now be set to False to avoid this behaviour if generating + actually valid OpenQASM (with no opaque delay instruction) is desired. gateargs_map : dict, optional If not None, a dict that maps strings (representing pyGSTi standard gate names) to @@ -4015,8 +4274,10 @@ def convert_to_openqasm(self, num_qubits=None, # Init the openqasm string. openqasm = 'OPENQASM 2.0;\ninclude "qelib1.inc";\n\n' - # Include a delay instruction - openqasm += 'opaque delay(t) q;\n\n' + + if include_delay_on_idle: + # Include a delay instruction + openqasm += 'opaque delay(t) q;\n\n' openqasm += 'qreg q[{0}];\n'.format(str(num_qubits)) # openqasm += 'creg cr[{0}];\n'.format(str(num_qubits)) @@ -4092,7 +4353,7 @@ def convert_to_openqasm(self, num_qubits=None, qubits_used.extend(gate_qubits) # All gates that don't have a non-idle gate acting on them get an idle in the layer. - if not block_between_gates: + if not block_between_gates and include_delay_on_idle: for q in self.line_labels: if q not in qubits_used: # Delay 0 works because of the barrier diff --git a/pygsti/circuits/circuitlist.py b/pygsti/circuits/circuitlist.py index 6e275044d..3c9345269 100644 --- a/pygsti/circuits/circuitlist.py +++ b/pygsti/circuits/circuitlist.py @@ -205,3 +205,49 @@ def __setstate__(self, state_dict): self.__dict__.update(state_dict) if 'uuid' not in state_dict: # backward compatibility self.uuid = _uuid.uuid4() # create a new uuid + + def elementvec_to_array(self, elementvec, layout, mergeop="sum"): + """ + Form an array of values corresponding to this CircuitList from an element vector. + + An element vector holds individual-outcome elements (e.g. the bulk probabilities + computed by a model). + + Parameters + ---------- + elementvec : numpy array + An array containting the values to use when constructing a + matrix of values for this CircuitList. This array may contain more + values than are needed by this CircuitList. Indices into this array + are given by `elindices_lookup`. + + layout : CircuitOutcomeProbabilityArrayLayout + The layout of `elementvec`, giving the mapping between its elements and + circuit outcomes. + + mergeop : "sum" or format string, optional + Dictates how to combine the `elementvec` components corresponding to a single + plaquette entry (circuit). If "sum", the returned array contains summed + values. If a format string, e.g. `"%.2f"`, then the so-formatted components + are joined together with separating commas, and the resulting array contains + string (object-type) entries. + + Returns + ------- + numpy array + """ + + if mergeop == "sum": + ret = _np.nan * _np.ones(len(self), 'd') + for i,ckt in enumerate(self._circuits): + ret[i] = sum(elementvec[layout.indices(ckt)]) + elif '%' in mergeop: + fmt = mergeop + ret = _np.nan * _np.ones(len(self), dtype=_np.object_) + for i,ckt in enumerate(self._circuits): + ret[i] = ", ".join(["NaN" if _np.isnan(x) else + (fmt % x) for x in elementvec[layout.indices(ckt)]]) + else: + raise ValueError("Invalid `mergeop` arg: %s" % str(mergeop)) + + return ret \ No newline at end of file diff --git a/pygsti/circuits/circuitstructure.py b/pygsti/circuits/circuitstructure.py index 6b3916b09..cf9adcc93 100644 --- a/pygsti/circuits/circuitstructure.py +++ b/pygsti/circuits/circuitstructure.py @@ -117,9 +117,9 @@ def __iter__(self): def __len__(self): return len(self.elements) - def elementvec_to_matrix(self, elementvec, layout, mergeop="sum"): + def elementvec_to_array(self, elementvec, layout, mergeop="sum"): """ - Form a matrix of values corresponding to this plaquette from an element vector. + Form a array of values corresponding to this plaquette from an element vector. An element vector holds individual-outcome elements (e.g. the bulk probabilities computed by a model). @@ -644,7 +644,7 @@ def cast(cls, circuits_or_structure): else: op_label_aliases = weights_dict = name = None - return cls({}, [], [], circuits_or_structure, + return cls({}, [], [], '', '', circuits_or_structure, op_label_aliases, weights_dict, name) def __init__(self, plaquettes, x_values, y_values, xlabel, ylabel, additional_circuits=None, op_label_aliases=None, diff --git a/pygsti/circuits/cloudcircuitconstruction.py b/pygsti/circuits/cloudcircuitconstruction.py index 999259361..d8a39f80f 100644 --- a/pygsti/circuits/cloudcircuitconstruction.py +++ b/pygsti/circuits/cloudcircuitconstruction.py @@ -261,9 +261,12 @@ def _find_amped_polynomials_for_syntheticidle(qubit_filter, idle_str, model, sin #print("DB: Rank %d: running itr=%d" % (comm.Get_rank(), itr)) printer.show_progress(loc_itr - 1, nLocIters, prefix='--- Finding amped-polys for idle: ') - prepFid = _Circuit((), line_labels=idle_str.line_labels) + for i, el in enumerate(prep): - prepFid = prepFid + _onqubit(el, qubit_filter[i]) + if i==0: + prepFid = _onqubit(el, qubit_filter[i]) + else: + prepFid = prepFid + _onqubit(el, qubit_filter[i]) for meas in _itertools.product(*([single_q_meas_fiducials] * nQubits)): @@ -278,9 +281,11 @@ def _find_amped_polynomials_for_syntheticidle(qubit_filter, idle_str, model, sin # if all are not the same or all are not different, skip if not (all(cmp) or not any(cmp)): continue - measFid = _Circuit((), line_labels=idle_str.line_labels) for i, el in enumerate(meas): - measFid = measFid + _onqubit(el, qubit_filter[i]) + if i==0: + measFid = _onqubit(el, qubit_filter[i]) + else: + measFid = measFid + _onqubit(el, qubit_filter[i]) gatename_fidpair_list = [(prep[i], meas[i]) for i in range(nQubits)] if gatename_fidpair_list in selected_gatename_fidpair_lists: @@ -673,9 +678,11 @@ def _find_amped_polynomials_for_clifford_syntheticidle(qubit_filter, core_filter # prep[ qubit_filter.index(core_ql) ] = prep_core[i] # prep = tuple(prep) - prepFid = _Circuit(()) for i, el in enumerate(prep): - prepFid = prepFid + _onqubit(el, qubit_filter[i]) + if i==0: + prepFid = _onqubit(el, qubit_filter[i]) + else: + prepFid = prepFid + _onqubit(el, qubit_filter[i]) #OLD: back when we tried iterating over *all* core fiducial pairs # (now we think/know this is unnecessary - the "true idle" fidpairs suffice) @@ -687,9 +694,11 @@ def _find_amped_polynomials_for_clifford_syntheticidle(qubit_filter, core_filter # # meas[ qubit_filter.index(core_ql) ] = meas_core[i] # meas = tuple(meas) - measFid = _Circuit(()) for i, el in enumerate(meas): - measFid = measFid + _onqubit(el, qubit_filter[i]) + if i==0: + measFid = _onqubit(el, qubit_filter[i]) + else: + measFid = measFid + _onqubit(el, qubit_filter[i]) #print("PREPMEAS = ",prepFid,measFid) @@ -891,9 +900,11 @@ def _get_fidpairs_needed_to_access_amped_polynomials(qubit_filter, core_filter, prep[qubit_filter.index(core_ql)] = prep_core[i] prep = tuple(prep) - prepFid = _Circuit(()) for i, el in enumerate(prep): - prepFid = prepFid + _onqubit(el, qubit_filter[i]) + if i==0: + prepFid = _onqubit(el, qubit_filter[i]) + else: + prepFid = prepFid + _onqubit(el, qubit_filter[i]) #for meas in _itertools.product(*([single_q_fiducials]*nQubits) ): #for meas_core in _itertools.product(*([single_q_fiducials]*nCore) ): @@ -908,9 +919,11 @@ def _get_fidpairs_needed_to_access_amped_polynomials(qubit_filter, core_filter, meas[qubit_filter.index(core_ql)] = meas_core[i] meas = tuple(meas) - measFid = _Circuit(()) for i, el in enumerate(meas): - measFid = measFid + _onqubit(el, qubit_filter[i]) + if i==0: + measFid = _onqubit(el, qubit_filter[i]) + else: + measFid = measFid + _onqubit(el, qubit_filter[i]) #print("CONSIDER: ",prep,"-",meas) opstr = prepFid + germ_power_str + measFid # should be a Circuit @@ -1324,7 +1337,7 @@ def _get_candidates_for_core(model, core_qubits, candidate_counts, seed_start): return candidate_germs -@_deprecated_fn("Use pygsti.circuits.create_standard_cloudnoise_circuits(...).") +@_deprecated_fn("Use pygsti.circuits.create_cloudnoise_circuits(...).") def _create_xycnot_cloudnoise_circuits(num_qubits, max_lengths, geometry, cnot_edges, max_idle_weight=1, maxhops=0, extra_weight_1_hops=0, extra_gate_weight=0, parameterization="H+S", verbosity=0, cache=None, idle_only=False, diff --git a/pygsti/data/datacomparator.py b/pygsti/data/datacomparator.py index 83b70481a..5b8f38b99 100644 --- a/pygsti/data/datacomparator.py +++ b/pygsti/data/datacomparator.py @@ -75,11 +75,11 @@ def _loglikelihood_ratio(n_list_list): The log-likehood ratio for this model comparison. """ nListC = _np.sum(n_list_list, axis=0) - pListC = nListC / _np.float_(_np.sum(nListC)) + pListC = nListC / _np.float64(_np.sum(nListC)) lC = _loglikelihood(pListC, nListC) li_list = [] for nList in n_list_list: - pList = _np.array(nList) / _np.float_(_np.sum(nList)) + pList = _np.array(nList) / _np.float64(_np.sum(nList)) li_list.append(_loglikelihood(pList, nList)) lS = _np.sum(li_list) return -2 * (lC - lS) @@ -647,9 +647,9 @@ def run(self, significance=0.05, per_circuit_correction='Hochberg', if self.inconsistent_datasets_detected: print("The data are INCONSISTENT at {0:.2f}% significance.".format(self.significance * 100)) print(" - Details:") - print(" - The aggregate log-_likelihood ratio test is " + print(" - The aggregate log-likelihood ratio test is " "significant at {0:.2f} standard deviations.".format(self._aggregate_nsigma)) - print(" - The aggregate log-_likelihood ratio test " + print(" - The aggregate log-likelihood ratio test " "standard deviations signficance threshold is {0:.2f}".format(self._aggregate_nsigma_threshold)) print( " - The number of sequences with data that is " diff --git a/pygsti/data/dataset.py b/pygsti/data/dataset.py index 8d8658ec8..2278c2297 100644 --- a/pygsti/data/dataset.py +++ b/pygsti/data/dataset.py @@ -11,6 +11,7 @@ #*************************************************************************************************** import bisect as _bisect +from collections.abc import Iterable as _Iterable import copy as _copy import itertools as _itertools import numbers as _numbers @@ -1031,12 +1032,13 @@ def __init__(self, oli_data=None, time_data=None, rep_data=None, self.olIndex = outcome_label_indices self.olIndex_max = max(self.olIndex.values()) if len(self.olIndex) > 0 else -1 elif outcome_labels is not None: - if isinstance(outcome_labels, _np.int64): - nqubits = outcome_labels - tup_outcomeLabels = [("".join(x),) for x in _itertools.product(*([('0', '1')] * nqubits))] - else: + if isinstance(outcome_labels, _Iterable): tup_outcomeLabels = [_ld.OutcomeLabelDict.to_outcome(ol) for ol in outcome_labels] # strings -> tuple outcome labels + else: # Given an int which signifies how many qubits + nqubits = outcome_labels + tup_outcomeLabels = [("".join(x),) for x in _itertools.product(*([('0', '1')] * nqubits))] + self.olIndex = _OrderedDict([(ol, i) for (i, ol) in enumerate(tup_outcomeLabels)]) self.olIndex_max = len(tup_outcomeLabels) - 1 else: @@ -1601,7 +1603,7 @@ def add_count_arrays(self, circuit, outcome_index_array, count_array, self._add_raw_arrays(circuit, outcome_index_array, time_array, count_array, overwriteExisting, record_zero_counts, aux) - def add_cirq_trial_result(self, circuit, trial_result, key): + def add_cirq_trial_result(self, circuit, trial_result, key, convert_int_to_binary = True, num_qubits = None): """ Add a single circuit's counts --- stored in a Cirq TrialResult --- to this DataSet @@ -1617,6 +1619,16 @@ def add_cirq_trial_result(self, circuit, trial_result, key): key : str The string key of the measurement. Set by cirq.measure. + convert_int_to_binary : bool, optional (defaut True) + By default the keys in the cirq Results object are the integers representing + the bitstrings of the measurements on a set of qubits, in big-endian convention. + If True this converts back to a binary string before adding the counts as a + entry into the pygsti dataset. + + num_qubits : int, optional (default None) + Number of qubits used in the conversion from integers to binary when convert_int_to_binary + is True. If None, then the number of line_labels on the input circuit is used. + Returns ------- None @@ -1629,8 +1641,17 @@ def add_cirq_trial_result(self, circuit, trial_result, key): # TrialResult.histogram returns a collections.Counter object, which is a subclass of dict. histogram_counter = trial_result.histogram(key=key) + + if num_qubits is None: + num_qubits = len(circuit.line_labels) + # The keys in histogram_counter are integers, but pyGSTi likes dictionary keys to be strings. - count_dict = {str(key): value for key, value in histogram_counter.items()} + count_dict = {} + for key, value in histogram_counter.items(): + if convert_int_to_binary: + count_dict[_np.binary_repr(key, width= num_qubits)] = value + else: + count_dict[str(key)] = value self.add_count_dict(circuit, count_dict) def add_raw_series_data(self, circuit, outcome_label_list, time_stamp_list, @@ -1716,7 +1737,9 @@ def add_raw_series_data(self, circuit, outcome_label_list, time_stamp_list, def _add_raw_arrays(self, circuit, oli_array, time_array, rep_array, overwrite_existing, record_zero_counts, aux): - + assert not self.bStatic, "Attempting to add arrays to a static DataSet. " + \ + "Consider using .copy_nonstatic() to get a mutable DataSet first." + if rep_array is None: if self.repData is not None: rep_array = _np.ones(len(oli_array), self.repType) @@ -2114,7 +2137,8 @@ def add_series_from_dataset(self, other_data_set): ------- None """ - if self.bStatic: raise ValueError("Cannot add data to a static DataSet object") + if self.bStatic: raise ValueError("Cannot add data to a static DataSet object." + \ + "Consider using .copy_nonstatic() to get a mutable DataSet first.") for circuit, dsRow in other_data_set.items(): self.add_raw_series_data(circuit, dsRow.outcomes, dsRow.time, dsRow.reps, False) diff --git a/pygsti/drivers/longsequence.py b/pygsti/drivers/longsequence.py index b1caabd0b..e6de76803 100644 --- a/pygsti/drivers/longsequence.py +++ b/pygsti/drivers/longsequence.py @@ -24,6 +24,8 @@ from pygsti.models.model import Model as _Model from pygsti.models.modelconstruction import _create_explicit_model, create_explicit_model from pygsti.protocols.gst import _load_pspec_or_model +from pygsti.forwardsims import ForwardSimulator +from typing import Optional ROBUST_SUFFIX_LIST = [".robust", ".Robust", ".robust+", ".Robust+"] DEFAULT_BAD_FIT_THRESHOLD = 2.0 @@ -35,7 +37,8 @@ def run_model_test(model_filename_or_object, germs_list_or_filename, max_lengths, gauge_opt_params=None, advanced_options=None, comm=None, mem_limit=None, output_pkl=None, verbosity=2, checkpoint=None, checkpoint_path=None, - disable_checkpointing= False): + disable_checkpointing=False, + simulator: Optional[ForwardSimulator.Castable]=None): """ Compares a :class:`Model`'s predictions to a `DataSet` using GST-like circuits. @@ -138,6 +141,11 @@ def run_model_test(model_filename_or_object, to disk during the course of this protocol. It is strongly recommended that this be kept set to False without good reason to disable the checkpoints. + simulator : ForwardSimulator.Castable or None + Ignored if None. If not None, then we call + fwdsim = ForwardSimulator.cast(simulator), + and we set the .sim attribute of every Model we encounter to fwdsim. + Returns ------- Results @@ -170,6 +178,7 @@ def run_model_test(model_filename_or_object, if isinstance(pspec_or_model, _Model): target_model= pspec_or_model elif isinstance(pspec_or_model, _ProcessorSpec): + target_model= create_explicit_model(pspec_or_model, basis= _load_model(model_filename_or_object).basis) @@ -185,7 +194,9 @@ def run_model_test(model_filename_or_object, proto.circuit_weights = advanced_options.get('circuit_weights', None) proto.unreliable_ops = advanced_options.get('unreliable_ops', ['Gcnot', 'Gcphase', 'Gms', 'Gcn', 'Gcx', 'Gcz']) - results = proto.run(data, mem_limit, comm, checkpoint=checkpoint, checkpoint_path=checkpoint_path, disable_checkpointing=disable_checkpointing) + results = proto.run(data, mem_limit, comm, + checkpoint=checkpoint, checkpoint_path=checkpoint_path, disable_checkpointing=disable_checkpointing, + simulator=simulator) _output_to_pickle(results, output_pkl, comm) return results @@ -306,7 +317,8 @@ def run_long_sequence_gst(data_filename_or_set, target_model_filename_or_object, germs_list_or_filename, max_lengths, gauge_opt_params=None, advanced_options=None, comm=None, mem_limit=None, output_pkl=None, verbosity=2, checkpoint=None, checkpoint_path=None, - disable_checkpointing = False): + disable_checkpointing=False, + simulator: Optional[ForwardSimulator.Castable]=None): """ Perform long-sequence GST (LSGST). @@ -439,11 +451,17 @@ def run_long_sequence_gst(data_filename_or_set, target_model_filename_or_object, completed iteration number appended to it before writing it to disk. If none, the value of {name} will be set to the name of the protocol being run. + disable_checkpointing : bool, optional (default False) When set to True checkpoint objects will not be constructed and written to disk during the course of this protocol. It is strongly recommended that this be kept set to False without good reason to disable the checkpoints. + simulator : ForwardSimulator.Castable or None + Ignored if None. If not None, then we call + fwdsim = ForwardSimulator.cast(simulator), + and we set the .sim attribute of every Model we encounter to fwdsim. + Returns ------- Results @@ -488,7 +506,9 @@ def run_long_sequence_gst(data_filename_or_set, target_model_filename_or_object, proto.circuit_weights = advanced_options.get('circuit_weights', None) proto.unreliable_ops = advanced_options.get('unreliable_ops', ['Gcnot', 'Gcphase', 'Gms', 'Gcn', 'Gcx', 'Gcz']) - results = proto.run(data, mem_limit, comm, checkpoint=checkpoint, checkpoint_path= checkpoint_path, disable_checkpointing=disable_checkpointing) + results = proto.run(data, mem_limit, comm, + checkpoint=checkpoint, checkpoint_path= checkpoint_path, disable_checkpointing=disable_checkpointing, + simulator=simulator) _output_to_pickle(results, output_pkl, comm) return results @@ -497,7 +517,8 @@ def run_long_sequence_gst_base(data_filename_or_set, target_model_filename_or_ob lsgst_lists, gauge_opt_params=None, advanced_options=None, comm=None, mem_limit=None, output_pkl=None, verbosity=2, checkpoint=None, checkpoint_path=None, - disable_checkpointing = False): + disable_checkpointing=False, + simulator: Optional[ForwardSimulator.Castable]=None): """ A more fundamental interface for performing end-to-end GST. @@ -582,7 +603,12 @@ def run_long_sequence_gst_base(data_filename_or_set, target_model_filename_or_ob When set to True checkpoint objects will not be constructed and written to disk during the course of this protocol. It is strongly recommended that this be kept set to False without good reason to disable the checkpoints. - + + simulator : ForwardSimulator.Castable or None + Ignored if None. If not None, then we call + fwdsim = ForwardSimulator.cast(simulator), + and we set the .sim attribute of every Model we encounter to fwdsim. + Returns ------- Results @@ -615,7 +641,9 @@ def run_long_sequence_gst_base(data_filename_or_set, target_model_filename_or_ob proto.circuit_weights = advanced_options.get('circuit_weights', None) proto.unreliable_ops = advanced_options.get('unreliable_ops', ['Gcnot', 'Gcphase', 'Gms', 'Gcn', 'Gcx', 'Gcz']) - results = proto.run(data, mem_limit, comm, checkpoint=checkpoint, checkpoint_path=checkpoint_path, disable_checkpointing=disable_checkpointing) + results = proto.run(data, mem_limit, comm, + checkpoint=checkpoint, checkpoint_path=checkpoint_path, disable_checkpointing=disable_checkpointing, + simulator=simulator) _output_to_pickle(results, output_pkl, comm) return results @@ -624,7 +652,8 @@ def run_stdpractice_gst(data_filename_or_set, target_model_filename_or_object, p meas_fiducial_list_or_filename, germs_list_or_filename, max_lengths, modes=('full TP','CPTPLND','Target'), gaugeopt_suite='stdgaugeopt', gaugeopt_target=None, models_to_test=None, comm=None, mem_limit=None, advanced_options=None, output_pkl=None, - verbosity=2, checkpoint=None, checkpoint_path=None, disable_checkpointing = False): + verbosity=2, checkpoint=None, checkpoint_path=None, disable_checkpointing=False, + simulator: Optional[ForwardSimulator.Castable]=None): """ Perform end-to-end GST analysis using standard practices. @@ -748,6 +777,11 @@ def run_stdpractice_gst(data_filename_or_set, target_model_filename_or_object, p to disk during the course of this protocol. It is strongly recommended that this be kept set to False without good reason to disable the checkpoints. + simulator : ForwardSimulator.Castable or None + Ignored if None. If not None, then we call + fwdsim = ForwardSimulator.cast(simulator), + and we set the .sim attribute of every Model we encounter to fwdsim. + Returns ------- Results @@ -791,7 +825,9 @@ def run_stdpractice_gst(data_filename_or_set, target_model_filename_or_object, p badfit_options=_get_badfit_options(advanced_options), verbosity=printer, name=advanced_options.get('estimate_label', None)) - results = proto.run(data, mem_limit, comm, checkpoint=checkpoint, checkpoint_path= checkpoint_path, disable_checkpointing=disable_checkpointing) + results = proto.run(data, mem_limit, comm, + checkpoint=checkpoint, checkpoint_path= checkpoint_path, disable_checkpointing=disable_checkpointing, + simulator=simulator) _output_to_pickle(results, output_pkl, comm) return results @@ -895,7 +931,7 @@ def _get_optimizer(advanced_options, model_being_optimized): from pygsti.forwardsims.matrixforwardsim import MatrixForwardSimulator as _MatrixFSim advanced_options = advanced_options or {} default_fditer = 1 if isinstance(model_being_optimized.sim, _MatrixFSim) else 0 - optimizer = {'maxiter': advanced_options.get('max_iterations', 100000), + optimizer = {'maxiter': advanced_options.get('max_iterations', 100), 'tol': advanced_options.get('tolerance', 1e-6), 'fditer': advanced_options.get('finitediff_iterations', default_fditer)} optimizer.update(advanced_options.get('extra_lm_opts', {})) diff --git a/pygsti/evotypes/densitymx/effectreps.pyx b/pygsti/evotypes/densitymx/effectreps.pyx index 3987325c6..3c5a62c54 100644 --- a/pygsti/evotypes/densitymx/effectreps.pyx +++ b/pygsti/evotypes/densitymx/effectreps.pyx @@ -108,7 +108,7 @@ cdef class EffectRepTensorProduct(EffectRep): cdef _np.ndarray[_np.int64_t, ndim=1, mode='c'] factor_dims = \ _np.ascontiguousarray(_np.array([fct.state_space.dim for fct in povm_factors], _np.int64)) - cdef INT dim = _np.product(factor_dims) + cdef INT dim = _np.prod(factor_dims) cdef INT nfactors = len(povm_factors) self.povm_factors = povm_factors self.effect_labels = effect_labels diff --git a/pygsti/evotypes/densitymx/opreps.pyx b/pygsti/evotypes/densitymx/opreps.pyx index 87b6571a7..d3c05586a 100644 --- a/pygsti/evotypes/densitymx/opreps.pyx +++ b/pygsti/evotypes/densitymx/opreps.pyx @@ -540,7 +540,7 @@ def _compute_embedding_quantities_cachekey(state_space, target_labels, embedded_ # final map just acts as identity w.r.t. labelIndices = [tensorProdBlkLabels.index(label) for label in target_labels] cdef _np.ndarray[_np.int64_t, ndim=1, mode='c'] action_inds = _np.array(labelIndices, _np.int64) - assert(_np.product([num_basis_els[i] for i in action_inds]) == embedded_rep_dim), \ + assert(_np.prod([num_basis_els[i] for i in action_inds]) == embedded_rep_dim), \ "Embedded operation has dimension (%d) inconsistent with the given target labels (%s)" % ( embedded_rep_dim, str(target_labels)) @@ -550,7 +550,7 @@ def _compute_embedding_quantities_cachekey(state_space, target_labels, embedded_ cdef INT ncomponents_in_active_block = len(state_space.tensor_product_block_labels(active_block_index)) cdef INT embedded_dim = embedded_rep_dim cdef _np.ndarray[_np.int64_t, ndim=1, mode='c'] blocksizes = \ - _np.array([_np.product(state_space.tensor_product_block_dimensions(k)) + _np.array([_np.prod(state_space.tensor_product_block_dimensions(k)) for k in range(nblocks)], _np.int64) cdef INT i, j diff --git a/pygsti/evotypes/densitymx/statereps.pyx b/pygsti/evotypes/densitymx/statereps.pyx index 32e6e2319..16da7a247 100644 --- a/pygsti/evotypes/densitymx/statereps.pyx +++ b/pygsti/evotypes/densitymx/statereps.pyx @@ -163,7 +163,7 @@ cdef class StateRepTensorProduct(StateRep): def __cinit__(self, factor_state_reps, state_space): self.factor_reps = factor_state_reps - dim = _np.product([fct.dim for fct in self.factor_reps]) + dim = _np.prod([fct.dim for fct in self.factor_reps]) self._cinit_base(_np.zeros(dim, 'd'), state_space) self.reps_have_changed() diff --git a/pygsti/evotypes/stabilizer/statereps.pyx b/pygsti/evotypes/stabilizer/statereps.pyx index 47e8d64db..13cb6b0c9 100644 --- a/pygsti/evotypes/stabilizer/statereps.pyx +++ b/pygsti/evotypes/stabilizer/statereps.pyx @@ -129,7 +129,7 @@ cdef class StateRepTensorProduct(StateRep): def __cinit__(self, factor_state_reps, state_space): self.factor_reps = factor_state_reps n = sum([sf.nqubits for sf in self.factor_reps]) # total number of qubits - np = int(_np.product([len(sf.pvectors) for sf in self.factor_reps])) + np = int(_np.prod([len(sf.pvectors) for sf in self.factor_reps])) self._cinit_base(_np.zeros((2 * n, 2 * n), _np.int64), _np.zeros((np, 2 * n), _np.int64), _np.ones(np, complex), diff --git a/pygsti/evotypes/statevec/effectreps.pyx b/pygsti/evotypes/statevec/effectreps.pyx index 4c12ce54d..6645c30a2 100644 --- a/pygsti/evotypes/statevec/effectreps.pyx +++ b/pygsti/evotypes/statevec/effectreps.pyx @@ -111,7 +111,7 @@ cdef class EffectRepTensorProduct(EffectRep): cdef _np.ndarray[_np.int64_t, ndim=1, mode='c'] factor_dims = \ _np.ascontiguousarray(_np.array([fct.state_space.udim for fct in povm_factors], _np.int64)) - cdef INT dim = _np.product(factor_dims) + cdef INT dim = _np.prod(factor_dims) cdef INT nfactors = len(self.povm_factors) self.povm_factors = povm_factors self.effect_labels = effect_labels diff --git a/pygsti/evotypes/statevec/opreps.pyx b/pygsti/evotypes/statevec/opreps.pyx index 7594d90a5..8fa3d2dc8 100644 --- a/pygsti/evotypes/statevec/opreps.pyx +++ b/pygsti/evotypes/statevec/opreps.pyx @@ -246,7 +246,7 @@ cdef class OpRepEmbedded(OpRep): # final map just acts as identity w.r.t. labelIndices = [tensorProdBlkLabels.index(label) for label in target_labels] cdef _np.ndarray[_np.int64_t, ndim=1, mode='c'] action_inds = _np.array(labelIndices, _np.int64) - assert(_np.product([num_basis_els[i] for i in action_inds]) == embedded_rep.dim), \ + assert(_np.prod([num_basis_els[i] for i in action_inds]) == embedded_rep.dim), \ "Embedded operation has dimension (%d) inconsistent with the given target labels (%s)" % ( embedded_rep.dim, str(target_labels)) @@ -256,7 +256,7 @@ cdef class OpRepEmbedded(OpRep): cdef INT ncomponents_in_active_block = len(state_space.tensor_product_block_labels(active_block_index)) cdef INT embedded_dim = embedded_rep.dim cdef _np.ndarray[_np.int64_t, ndim=1, mode='c'] blocksizes = \ - _np.array([_np.product(state_space.tensor_product_block_udimensions(k)) + _np.array([_np.prod(state_space.tensor_product_block_udimensions(k)) for k in range(nblocks)], _np.int64) cdef INT i, j diff --git a/pygsti/evotypes/statevec/statereps.pyx b/pygsti/evotypes/statevec/statereps.pyx index 7fd404d57..d1304a5b1 100644 --- a/pygsti/evotypes/statevec/statereps.pyx +++ b/pygsti/evotypes/statevec/statereps.pyx @@ -150,7 +150,7 @@ cdef class StateRepTensorProduct(StateRep): def __init__(self, factor_state_reps, state_space): self.factor_reps = factor_state_reps - dim = _np.product([fct.dim for fct in self.factor_reps]) + dim = _np.prod([fct.dim for fct in self.factor_reps]) self._cinit_base(_np.zeros(dim, complex), state_space, None) # TODO: compute a tensorprod basis? self.reps_have_changed() diff --git a/pygsti/extras/drift/signal.py b/pygsti/extras/drift/signal.py index 961f0a5f8..e24135d8f 100644 --- a/pygsti/extras/drift/signal.py +++ b/pygsti/extras/drift/signal.py @@ -10,7 +10,7 @@ import numpy as _np import numpy.random as _rnd -from scipy import convolve as _convolve +from numpy import convolve as _convolve from scipy.fftpack import dct as _dct from scipy.fftpack import fft as _fft from scipy.fftpack import idct as _idct diff --git a/pygsti/forwardsims/forwardsim.py b/pygsti/forwardsims/forwardsim.py index d5af0937d..c5e61b057 100644 --- a/pygsti/forwardsims/forwardsim.py +++ b/pygsti/forwardsims/forwardsim.py @@ -9,7 +9,7 @@ # in compliance with the License. You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 or in the LICENSE file in the root pyGSTi directory. #*************************************************************************************************** - +from __future__ import annotations import collections as _collections import warnings as _warnings @@ -21,6 +21,7 @@ from pygsti.baseobjs.resourceallocation import ResourceAllocation as _ResourceAllocation from pygsti.baseobjs.nicelyserializable import NicelySerializable as _NicelySerializable from pygsti.tools import slicetools as _slct +from typing import Union, Callable, Literal class ForwardSimulator(_NicelySerializable): @@ -44,22 +45,40 @@ class ForwardSimulator(_NicelySerializable): The model this forward simulator will use to compute circuit outcome probabilities. """ + Castable = Union[ + 'ForwardSimulator', + Callable[[], 'ForwardSimulator'], + Literal['map'], + Literal['matrix'], + Literal['auto'] + ] + # ^ Define a type alias we can reference elsewhere in our code. + @classmethod - def cast(cls, obj, num_qubits=None): + def cast(cls, obj : ForwardSimulator.Castable, num_qubits=None): """ num_qubits only used if `obj == 'auto'` """ from .matrixforwardsim import MatrixForwardSimulator as _MatrixFSim from .mapforwardsim import MapForwardSimulator as _MapFSim if isinstance(obj, ForwardSimulator): return obj - elif obj == "auto": - return _MapFSim() if (num_qubits is None or num_qubits > 2) else _MatrixFSim() - elif obj == "map": - return _MapFSim() - elif obj == "matrix": - return _MatrixFSim() + elif isinstance(obj, str): + if obj == "auto": + return _MapFSim() if (num_qubits is None or num_qubits > 2) else _MatrixFSim() + elif obj == "map": + return _MapFSim() + elif obj == "matrix": + return _MatrixFSim() + else: + raise ValueError(f'Unrecognized string argument, {obj}') + elif isinstance(obj, Callable): + out_obj = obj() + if isinstance(out_obj, ForwardSimulator): + return out_obj + else: + raise ValueError(f'Argument {obj} cannot be cast to a ForwardSimulator.') else: - raise ValueError("Cannot convert %s to a forward simulator!" % str(obj)) + raise ValueError(f'Argument {obj} cannot be cast to a ForwardSimulator.') @classmethod def _array_types_for_method(cls, method_name): @@ -337,9 +356,10 @@ def create_layout(self, circuits, dataset=None, resource_alloc=None, derivative_dimensions : tuple, optional A tuple containing, optionally, the parameter-space dimension used when taking first - and second derivatives with respect to the cirucit outcome probabilities. This must be + and second derivatives with respect to the cirucit outcome probabilities. This should have minimally 1 or 2 elements when `array_types` contains `'ep'` or `'epp'` types, - respectively. + respectively. If `array_types` contains either of these strings and derivative_dimensions + is None on input then we automatically set derivative_dimensions based on self.model. verbosity : int or VerbosityPrinter Determines how much output to send to stdout. 0 means no output, higher @@ -349,38 +369,16 @@ def create_layout(self, circuits, dataset=None, resource_alloc=None, ------- CircuitOutcomeProbabilityArrayLayout """ + if derivative_dimensions is None: + if 'epp' in array_types: + derivative_dimensions = (self.model.num_params, self.model.num_params) + elif 'ep' in array_types: + derivative_dimensions = (self.model.num_params,) + else: + derivative_dimensions = tuple() return _CircuitOutcomeProbabilityArrayLayout.create_from(circuits, self.model, dataset, derivative_dimensions, resource_alloc=resource_alloc) - #TODO UPDATE - #def bulk_prep_probs(self, eval_tree, comm=None, mem_limit=None): - # """ - # Performs initial computation needed for bulk_fill_probs and related calls. - # - # For example, as computing probability polynomials. This is usually coupled with - # the creation of an evaluation tree, but is separated from it because this - # "preparation" may use `comm` to distribute a computationally intensive task. - # - # Parameters - # ---------- - # eval_tree : EvalTree - # The evaluation tree used to define a list of circuits and hold (cache) - # any computed quantities. - # - # comm : mpi4py.MPI.Comm, optional - # When not None, an MPI communicator for distributing the computation - # across multiple processors. Distribution is performed over - # subtrees of `eval_tree` (if it is split). - # - # mem_limit : int - # Rough memory limit in bytes. - # - # Returns - # ------- - # None - # """ - # pass # default is to have no pre-computed quantities (but not an error to call this fn) - def bulk_probs(self, circuits, clip_to=None, resource_alloc=None, smartc=None): """ Construct a dictionary containing the probabilities for an entire list of circuits. @@ -642,7 +640,7 @@ def _bulk_fill_dprobs_block(self, array_to_fill, dest_param_slice, layout, param iFinal = iParamToFinal[i] vec = orig_vec.copy(); vec[i] += eps self.model.from_vector(vec, close=True) - self._bulk_fill_probs_block(probs2, layout, resource_alloc) + self._bulk_fill_probs_block(probs2, layout) array_to_fill[:, iFinal] = (probs2 - probs) / eps self.model.from_vector(orig_vec, close=True) diff --git a/pygsti/forwardsims/mapforwardsim.py b/pygsti/forwardsims/mapforwardsim.py index 1d0c073db..6b19e8d39 100644 --- a/pygsti/forwardsims/mapforwardsim.py +++ b/pygsti/forwardsims/mapforwardsim.py @@ -193,7 +193,7 @@ def copy(self): self._processor_grid, self._pblk_sizes) def create_layout(self, circuits, dataset=None, resource_alloc=None, array_types=('E',), - derivative_dimension=None, verbosity=0): + derivative_dimensions=None, verbosity=0): """ Constructs an circuit-outcome-probability-array (COPA) layout for a list of circuits. @@ -214,10 +214,11 @@ def create_layout(self, circuits, dataset=None, resource_alloc=None, array_types array_types : tuple, optional A tuple of string-valued array types. See :meth:`ForwardSimulator.create_layout`. - derivative_dimension : int, optional + derivative_dimensions : int or tuple[int], optional Optionally, the parameter-space dimension used when taking first and second derivatives with respect to the cirucit outcome probabilities. This must be non-None when `array_types` contains `'ep'` or `'epp'` types. + If a tuple, then must be length 1. verbosity : int or VerbosityPrinter Determines how much output to send to stdout. 0 means no output, higher @@ -233,7 +234,13 @@ def create_layout(self, circuits, dataset=None, resource_alloc=None, array_types if (resource_alloc.mem_limit is not None) else None # *per-processor* memory limit nprocs = resource_alloc.comm_size comm = resource_alloc.comm - num_params = derivative_dimension if (derivative_dimension is not None) else self.model.num_params + if isinstance(derivative_dimensions, int): + num_params = derivative_dimensions + elif isinstance(derivative_dimensions, tuple): + assert len(derivative_dimensions) == 1 + num_params = derivative_dimensions[0] + else: + num_params = self.model.num_params C = 1.0 / (1024.0**3) if mem_limit is not None: diff --git a/pygsti/forwardsims/matrixforwardsim.py b/pygsti/forwardsims/matrixforwardsim.py index fda58668b..ddc18270a 100644 --- a/pygsti/forwardsims/matrixforwardsim.py +++ b/pygsti/forwardsims/matrixforwardsim.py @@ -1025,7 +1025,7 @@ def _compute_hproduct_cache(self, layout_atom_tree, prod_cache, d_prod_cache1, return hProdCache def create_layout(self, circuits, dataset=None, resource_alloc=None, array_types=('E',), - derivative_dimension=None, verbosity=0): + derivative_dimensions=None, verbosity=0): """ Constructs an circuit-outcome-probability-array (COPA) layout for a list of circuits. @@ -1046,10 +1046,11 @@ def create_layout(self, circuits, dataset=None, resource_alloc=None, array_types array_types : tuple, optional A tuple of string-valued array types. See :meth:`ForwardSimulator.create_layout`. - derivative_dimension : int, optional + derivative_dimensions : int or tuple[int], optional Optionally, the parameter-space dimension used when taking first and second derivatives with respect to the cirucit outcome probabilities. This must be non-None when `array_types` contains `'ep'` or `'epp'` types. + If a tuple, then must be length 1. verbosity : int or VerbosityPrinter Determines how much output to send to stdout. 0 means no output, higher @@ -1075,7 +1076,13 @@ def create_layout(self, circuits, dataset=None, resource_alloc=None, array_types printer = _VerbosityPrinter.create_printer(verbosity, resource_alloc) nprocs = resource_alloc.comm_size comm = resource_alloc.comm - num_params = derivative_dimension if (derivative_dimension is not None) else self.model.num_params + if isinstance(derivative_dimensions, int): + num_params = derivative_dimensions + elif isinstance(derivative_dimensions, tuple): + assert len(derivative_dimensions) == 1 + num_params = derivative_dimensions[0] + else: + num_params = self.model.num_params C = 1.0 / (1024.0**3) if mem_limit is not None: diff --git a/pygsti/forwardsims/termforwardsim.py b/pygsti/forwardsims/termforwardsim.py index 1dd7c92b4..3d4669d2a 100644 --- a/pygsti/forwardsims/termforwardsim.py +++ b/pygsti/forwardsims/termforwardsim.py @@ -214,7 +214,7 @@ def _to_nice_serialization(self): @classmethod def _from_nice_serialization(cls, state): #Note: resets processor-distribution information - return cls(state['mode'], state['max_taylor_order'], + return cls(None, state['mode'], state['max_taylor_order'], state['desired_pathintegral_approximation_error'], state['allowed_pathintegral_approximation_error'], state['minimum_retained_term_magnitude'], diff --git a/pygsti/modelmembers/operations/__init__.py b/pygsti/modelmembers/operations/__init__.py index 1b479a53f..8c00f4aab 100644 --- a/pygsti/modelmembers/operations/__init__.py +++ b/pygsti/modelmembers/operations/__init__.py @@ -38,6 +38,7 @@ from .staticunitaryop import StaticUnitaryOp from .stochasticop import StochasticNoiseOp from .lindbladcoefficients import LindbladCoefficientBlock as _LindbladCoefficientBlock +from .affineshiftop import AffineShiftOp from pygsti.baseobjs import statespace as _statespace from pygsti.tools import basistools as _bt from pygsti.tools import optools as _ot diff --git a/pygsti/modelmembers/operations/affineshiftop.py b/pygsti/modelmembers/operations/affineshiftop.py new file mode 100644 index 000000000..9aaacb120 --- /dev/null +++ b/pygsti/modelmembers/operations/affineshiftop.py @@ -0,0 +1,205 @@ +""" +The AffineShiftOp class and supporting functionality. +""" +#*************************************************************************************************** +# Copyright 2015, 2019 National Technology & Engineering Solutions of Sandia, LLC (NTESS). +# Under the terms of Contract DE-NA0003525 with NTESS, the U.S. Government retains certain rights +# in this software. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 or in the LICENSE file in the root pyGSTi directory. +#*************************************************************************************************** + +import numpy as _np + +from pygsti.modelmembers.operations.denseop import DenseOperator as _DenseOperator +from pygsti.modelmembers.operations.linearop import LinearOperator as _LinearOperator +from pygsti.baseobjs.protectedarray import ProtectedArray as _ProtectedArray + + +class AffineShiftOp(_DenseOperator): + """ + An operation matrix that induces an affine shift. + + An operation matrix with ones on the diagonal and nonzero values in + the first columns. + + Meant to work in the Pauli basis for now. + + Parameters + ---------- + m : array_like or LinearOperator + a square 2D array-like or LinearOperator object representing the operation action. + The shape of m sets the dimension of the operation. + + basis : Basis or {'pp','gm','std'} or None + The basis used to construct the Hilbert-Schmidt space representation + of this state as a super-operator. If None, certain functionality, + such as access to Kraus operators, will be unavailable. + + evotype : Evotype or str, optional + The evolution type. The special value `"default"` is equivalent + to specifying the value of `pygsti.evotypes.Evotype.default_evotype`. + + state_space : StateSpace, optional + The state space for this operation. If `None` a default state space + with the appropriate number of qubits is used. + + Attributes + ---------- + base : numpy.ndarray + Direct access to the underlying process matrix data. + """ + + def __init__(self, m, basis=None, evotype="default", state_space=None): + #LinearOperator.__init__(self, LinearOperator.convert_to_matrix(m)) + mx = _LinearOperator.convert_to_matrix(m) + assert(_np.isrealobj(mx)), "FullTPOp must have *real* values!" + + #this line checks whether the input matrix has the correct + #arrowhead structure. + if not (_np.allclose(_np.diag(mx), 1) and _np.allclose((mx-_np.eye(mx.shape[0]))[:, 1:], 0.0)): + raise ValueError("Cannot create AffineShiftOp: " + "Matrix does not have the correct arrowhead structure") + _DenseOperator.__init__(self, mx, basis, evotype, state_space) + assert(self._rep.base.flags['C_CONTIGUOUS'] and self._rep.base.flags['OWNDATA']) + assert(isinstance(self._ptr, _ProtectedArray)) + + self._paramlbls = _np.array(["MxElement %d,0" % (i) for i in range(1, self.dim)], + dtype=object) + + @property + def _ptr(self): + """ + The underlying dense process matrix. + """ + return _ProtectedArray(self._rep.base, indices_to_protect=[(0,slice(None,None,None)), + (slice(1,None, None), slice(1, None, None))]) + + def set_dense(self, m): + """ + Set the dense-matrix value of this operation. + + Attempts to modify operation parameters so that the specified raw + operation matrix becomes m. Will raise ValueError if this operation + is not possible. + + Parameters + ---------- + m : array_like or LinearOperator + An array of shape (dim, dim) or LinearOperator representing the operation action. + + Returns + ------- + None + """ + mx = _LinearOperator.convert_to_matrix(m) + if(mx.shape != (self.dim, self.dim)): + raise ValueError("Argument must be a (%d,%d) matrix!" + % (self.dim, self.dim)) + if not (_np.allclose(_np.diag(mx), 1) and _np.allclose((mx-_np.eye(mx.shape[0]))[:, 1:], 0.0)): + raise ValueError("Cannot create AffineShiftOp: " + "Matrix does not have the correct arrowhead structure") + #For further debugging: + "\n".join([str(e) for e in mx[0,:]]) + self._ptr[1:, 0] = mx[1:, 0] + self._ptr_has_changed() + self.dirty = True + + @property + def num_params(self): + """ + Get the number of independent parameters which specify this operation. + + Returns + ------- + int + the number of independent parameters. + """ + return self.dim-1 + + def to_vector(self): + """ + Get the operation parameters as an array of values. + + Returns + ------- + numpy array + The operation parameters as a 1D array with length num_params(). + """ + return self._ptr[1:,0].flatten() # .real in case of complex matrices? + + def from_vector(self, v, close=False, dirty_value=True): + """ + Initialize the operation using a vector of parameters. + + Parameters + ---------- + v : numpy array + The 1D vector of operation parameters. Length + must == num_params() + + close : bool, optional + Whether `v` is close to this operation's current + set of parameters. Under some circumstances, when this + is true this call can be completed more quickly. + + dirty_value : bool, optional + The value to set this object's "dirty flag" to before exiting this + call. This is passed as an argument so it can be updated *recursively*. + Leave this set to `True` unless you know what you're doing. + + Returns + ------- + None + """ + #TODO: Circle back to comments about it being faster to directly + #operate on the rep. + #assert(self._ptr.shape == (self.dim, self.dim)) + assert (len(v) == self.dim-1) + self._ptr[1:, 0] = v + #self._rep.base[1:, :] = v.reshape((self.dim - 1, self.dim)) # faster than line above + #self._rep.base.flat[self.dim:] = v # faster still + self._ptr_has_changed() # because _rep.base == _ptr (same memory) + self.dirty = dirty_value + + def deriv_wrt_params(self, wrt_filter=None): + """ + The element-wise derivative this operation. + + Construct a matrix whose columns are the vectorized + derivatives of the flattened operation matrix with respect to a + single operation parameter. Thus, each column is of length + op_dim^2 and there is one column per operation parameter. + + Parameters + ---------- + wrt_filter : list or numpy.ndarray + List of parameter indices to take derivative with respect to. + (None means to use all the this operation's parameters.) + + Returns + ------- + numpy array + Array of derivatives with shape (dimension^2, num_params) + """ + derivMx = _np.identity(self.dim**2, 'd') # TP operations are assumed to be real + + derivMx = derivMx[:, self.dim::self.dim] # Extract only columns of derivMx matrix + #corresponding to the first column of the PTR less the first row. + + if wrt_filter is None: + return derivMx + else: + return _np.take(derivMx, wrt_filter, axis=1) + + def has_nonzero_hessian(self): + """ + Whether this operation has a non-zero Hessian with respect to its parameters. + + (i.e. whether it only depends linearly on its parameters or not) + + Returns + ------- + bool + """ + return False diff --git a/pygsti/modelmembers/operations/denseop.py b/pygsti/modelmembers/operations/denseop.py index bef7c2f65..eb798ecb8 100644 --- a/pygsti/modelmembers/operations/denseop.py +++ b/pygsti/modelmembers/operations/denseop.py @@ -416,11 +416,11 @@ def kraus_operators(self): #CHECK 1 (to unit test?) REMOVE #tmp_std = _bt.change_basis(superop_mx, self._basis, 'std') #B = _bt.basis_matrices('std', superop_mx.shape[0]) - #check_superop = sum([ choi_mx[i,j] * _np.kron(B[i], B[j].T) for i in range(d*d) for j in range(d*d)]) + #check_superop = sum([ choi_mx[i,j] * _np.kron(B[i], B[j].conjugate()) for i in range(d*d) for j in range(d*d)]) #assert(_np.allclose(check_superop, tmp_std)) - evals, evecs = _np.linalg.eig(choi_mx) - #assert(_np.allclose(evecs @ _np.diag(evals) @ (evecs.conjugate().T), choi_mx)) + evals, evecs = _np.linalg.eigh(choi_mx) + assert(_np.allclose(evecs @ _np.diag(evals) @ (evecs.conjugate().T), choi_mx)) TOL = 1e-7 # consider lowering this tolerance as it leads to errors of this order in the Kraus decomp if any([ev <= -TOL for ev in evals]): raise ValueError("Cannot compute Kraus decomposition of non-positive-definite superoperator!") diff --git a/pygsti/modelmembers/operations/experrorgenop.py b/pygsti/modelmembers/operations/experrorgenop.py index f9b6b5840..142ee2c21 100644 --- a/pygsti/modelmembers/operations/experrorgenop.py +++ b/pygsti/modelmembers/operations/experrorgenop.py @@ -703,6 +703,9 @@ def spam_transform_inplace(self, s, typ): else: mx = _mt.safe_dot(mx, U) self.set_dense(mx) # calls _update_rep() and sets dirty flag + else: + raise ValueError("Invalid transform for this LindbladErrorgen: type %s" + % str(type(s))) def __str__(self): s = "Exponentiated operation map with dim = %d, num params = %d\n" % \ diff --git a/pygsti/modelmembers/povms/marginalizedpovm.py b/pygsti/modelmembers/povms/marginalizedpovm.py index f6c22f81d..a56595287 100644 --- a/pygsti/modelmembers/povms/marginalizedpovm.py +++ b/pygsti/modelmembers/povms/marginalizedpovm.py @@ -14,6 +14,7 @@ # from .. import modelmember as _mm from pygsti.modelmembers.povms.povm import POVM as _POVM +from pygsti.modelmembers.povms import ComposedPOVMEffect as _ComposedPOVMEffect from pygsti.modelmembers.povms.staticeffect import StaticPOVMEffect as _StaticPOVMEffect from pygsti.baseobjs.statespace import StateSpace as _StateSpace from pygsti.baseobjs.label import Label as _Label @@ -193,8 +194,8 @@ def __getitem__(self, key): effect_vec = e.to_dense() else: effect_vec += e.to_dense() - effect = _StaticPOVMEffect(effect_vec, e._basis, self._evotype) - # UNSPECIFIED BASIS -- may need to rename e._basis -> e._rep.basis above if that's the std attribute name? + rep = e.effect_vec._rep if isinstance(e, _ComposedPOVMEffect) else e._rep + effect = _StaticPOVMEffect(effect_vec, rep.basis, self._evotype) assert(effect.allocate_gpindices(0, self.parent) == 0) # functional! (do not remove) _collections.OrderedDict.__setitem__(self, key, effect) return effect diff --git a/pygsti/modelmembers/states/densestate.py b/pygsti/modelmembers/states/densestate.py index 40bb3b246..6a0ef6411 100644 --- a/pygsti/modelmembers/states/densestate.py +++ b/pygsti/modelmembers/states/densestate.py @@ -265,13 +265,14 @@ def __init__(self, purevec, basis, evotype, state_space): else _statespace.StateSpace.cast(state_space) evotype = _Evotype.cast(evotype) basis = _Basis.cast(basis, state_space.dim) # basis for Hilbert-Schmidt (superop) space - - #Try to create a dense pure rep. If this fails, see if a dense superkey rep + + #Try to create a dense pure rep. If this fails, see if a dense superket rep # can be created, as this type of rep can also hold arbitrary pure states. try: rep = evotype.create_pure_state_rep(purevec, basis, state_space) self._reptype = 'pure' - self._purevec = self._basis = None + self._purevec = None + self._basis = basis #this was previously being set as None, not sure why. except Exception: if len(purevec) == basis.dim and _np.linalg.norm(purevec.imag) < 1e-10: # Special case when a *superket* was provided instead of a purevec @@ -350,7 +351,6 @@ def to_memoized_dict(self, mmg_memo): mm_dict['dense_state_vector'] = self._encodemx(self.to_dense('Hilbert')) mm_dict['basis'] = self._basis.to_nice_serialization() if (self._basis is not None) else None - return mm_dict @classmethod diff --git a/pygsti/modelpacks/smq1Q_ZN.py b/pygsti/modelpacks/smq1Q_ZN.py index 778455011..c2459502a 100644 --- a/pygsti/modelpacks/smq1Q_ZN.py +++ b/pygsti/modelpacks/smq1Q_ZN.py @@ -1,7 +1,9 @@ """ A standard multi-qubit gate set module. -Variables for working with the a model containing Idle, Z(pi/2) and rot(X=pi/2, Y=sqrt(3)/2) gates. +Variables for working with the a model containing Idle, Z(pi/2) and N gate, where the N gate is a +pi/2 rotation about the (np.sqrt(3)/2, 0, -1/2) axis of the Bloch sphere. +gates. """ #*************************************************************************************************** # Copyright 2015, 2019 National Technology & Engineering Solutions of Sandia, LLC (NTESS). diff --git a/pygsti/modelpacks/smq2Q_XXYYII.py b/pygsti/modelpacks/smq2Q_XXYYII.py index 00ee24010..7cae4f249 100644 --- a/pygsti/modelpacks/smq2Q_XXYYII.py +++ b/pygsti/modelpacks/smq2Q_XXYYII.py @@ -2,7 +2,8 @@ A standard multi-qubit gate set module. Variables for working with the 2-qubit model containing the gates -I*X(pi/2), I*Y(pi/2), X(pi/2)*I, Y(pi/2)*I, and CPHASE. +I*I, I*X(pi/2), I*Y(pi/2), X(pi/2)*I, Y(pi/2)*I, X(pi/2)*X(pi/2), +Y(pi/2)*Y(pi/2), X(pi/2)*Y(pi/2), and Y(pi/2)*X(pi/2) gates. """ #*************************************************************************************************** # Copyright 2015, 2019 National Technology & Engineering Solutions of Sandia, LLC (NTESS). diff --git a/pygsti/modelpacks/smq2Q_XYXX.py b/pygsti/modelpacks/smq2Q_XYXX.py index 2dadb2dcf..86691899a 100644 --- a/pygsti/modelpacks/smq2Q_XYXX.py +++ b/pygsti/modelpacks/smq2Q_XYXX.py @@ -2,7 +2,7 @@ A standard multi-qubit gate set module. Variables for working with the 2-qubit model containing the gates -I*X(pi/2), I*Y(pi/2), X(pi/2)*I, Y(pi/2)*I, and CNOT. +I*X(pi/2), I*Y(pi/2), X(pi/2)*I, Y(pi/2)*I, and XX gates """ #*************************************************************************************************** # Copyright 2015, 2019 National Technology & Engineering Solutions of Sandia, LLC (NTESS). diff --git a/pygsti/modelpacks/smq2Q_XYZZ.py b/pygsti/modelpacks/smq2Q_XYZZ.py index d8d49510a..65438eeee 100644 --- a/pygsti/modelpacks/smq2Q_XYZZ.py +++ b/pygsti/modelpacks/smq2Q_XYZZ.py @@ -2,7 +2,7 @@ A standard multi-qubit gate set module. Variables for working with the 2-qubit model containing the gates -I*X(pi/2), I*Y(pi/2), X(pi/2)*I, Y(pi/2)*I, and CNOT. +I*X(pi/2), I*Y(pi/2), X(pi/2)*I, Y(pi/2)*I, and ZZ gates. """ #*************************************************************************************************** # Copyright 2015, 2019 National Technology & Engineering Solutions of Sandia, LLC (NTESS). diff --git a/pygsti/models/model.py b/pygsti/models/model.py index b16b53e70..dbc799a29 100644 --- a/pygsti/models/model.py +++ b/pygsti/models/model.py @@ -25,8 +25,6 @@ from pygsti.models.modelparaminterposer import LinearInterposer as _LinearInterposer from pygsti.evotypes import Evotype as _Evotype from pygsti.forwardsims import forwardsim as _fwdsim -from pygsti.forwardsims import mapforwardsim as _mapfwdsim -from pygsti.forwardsims import matrixforwardsim as _matrixfwdsim from pygsti.modelmembers import modelmember as _gm from pygsti.modelmembers import operations as _op from pygsti.baseobjs.basis import Basis as _Basis, TensorProdBasis as _TensorProdBasis @@ -505,7 +503,7 @@ def sim(self, simulator): except: nqubits = None # TODO: This should probably also take evotype (e.g. 'chp' should probably use a CHPForwardSim, etc) - self._sim = simulator = _fwdsim.ForwardSimulator.cast(simulator, nqubits) + self._sim = _fwdsim.ForwardSimulator.cast(simulator, nqubits) self._sim.model = self # ensure the simulator's `model` is set to this object @property diff --git a/pygsti/models/modelnoise.py b/pygsti/models/modelnoise.py index ae02b7126..a4cc2c869 100644 --- a/pygsti/models/modelnoise.py +++ b/pygsti/models/modelnoise.py @@ -799,7 +799,7 @@ def create_errorgen(self, evotype, state_space): # LindbladErrorgen with "depol" or "diagonal" param basis_size = state_space.dim # e.g. 4 for a single qubit - basis = _BuiltinBasis('pp', basis_size) + basis = _BuiltinBasis('PP', basis_size) rate_per_pauli = self.depolarization_rate / (basis_size - 1) errdict = {('S', bl): rate_per_pauli for bl in basis.labels[1:]} return _op.LindbladErrorgen.from_elementary_errorgens( @@ -896,7 +896,7 @@ def create_errorgen(self, evotype, state_space): raise ValueError("Stochastic noise parameterization must be one of %s" % str(allowed_values)) basis_size = state_space.dim # e.g. 4 for a single qubit - basis = _BuiltinBasis('pp', basis_size) + basis = _BuiltinBasis('PP', basis_size) errdict = {('S', bl): rate for bl, rate in zip(basis.labels[1:], sto_rates)} return _op.LindbladErrorgen.from_elementary_errorgens( errdict, "S", basis, mx_basis='pp', diff --git a/pygsti/models/qutrit.py b/pygsti/models/qutrit.py index 7edef3adc..804c3a4cb 100644 --- a/pygsti/models/qutrit.py +++ b/pygsti/models/qutrit.py @@ -14,9 +14,10 @@ from scipy import linalg as _linalg from pygsti.baseobjs import Basis as _Basis, statespace as _statespace -from pygsti.models.gaugegroup import FullGaugeGroup as _FullGaugeGroup -from pygsti.modelmembers.operations import FullArbitraryOp as _FullArbitraryOp -from pygsti.modelmembers.povms import UnconstrainedPOVM as _UnconstrainedPOVM +from pygsti.models.gaugegroup import TPGaugeGroup as _TPGaugeGroup +from pygsti.modelmembers.operations import FullTPOp as _FullTPOp +from pygsti.modelmembers.povms import TPPOVM as _TPPOVM +from pygsti.modelmembers.states import TPState as _TPState from pygsti.models import ExplicitOpModel as _ExplicitOpModel from pygsti.tools import unitary_to_superop, change_basis @@ -282,14 +283,14 @@ def create_qutrit_model(error_scale, x_angle=_np.pi / 2, y_angle=_np.pi / 2, state_space = _statespace.ExplicitStateSpace(['QT'], [3]) qutritMDL = _ExplicitOpModel(state_space, _Basis.cast(basis, 9), evotype=evotype) - qutritMDL.preps['rho0'] = rho0final - qutritMDL.povms['Mdefault'] = _UnconstrainedPOVM([('0bright', E0final), - ('1bright', E1final), - ('2bright', E2final)], evotype=evotype) - qutritMDL.operations['Gi'] = _FullArbitraryOp(arrType(gateISOfinal), basis, evotype, state_space) - qutritMDL.operations['Gx'] = _FullArbitraryOp(arrType(gateXSOfinal), basis, evotype, state_space) - qutritMDL.operations['Gy'] = _FullArbitraryOp(arrType(gateYSOfinal), basis, evotype, state_space) - qutritMDL.operations['Gm'] = _FullArbitraryOp(arrType(gateMSOfinal), basis, evotype, state_space) - qutritMDL.default_gauge_group = _FullGaugeGroup(state_space, qutritMDL.basis, evotype) + qutritMDL.preps['rho0'] = _TPState(rho0final, evotype=evotype) + qutritMDL.povms['Mdefault'] = _TPPOVM([('0bright', E0final), + ('1bright', E1final), + ('2bright', E2final)], evotype=evotype) + qutritMDL.operations['Gi', 'QT'] = _FullTPOp(arrType(gateISOfinal), basis, evotype, state_space) + qutritMDL.operations['Gx', 'QT'] = _FullTPOp(arrType(gateXSOfinal), basis, evotype, state_space) + qutritMDL.operations['Gy', 'QT'] = _FullTPOp(arrType(gateYSOfinal), basis, evotype, state_space) + qutritMDL.operations['Gm', 'QT'] = _FullTPOp(arrType(gateMSOfinal), basis, evotype, state_space) + qutritMDL.default_gauge_group = _TPGaugeGroup(state_space, qutritMDL.basis, evotype) return qutritMDL diff --git a/pygsti/objectivefns/objectivefns.py b/pygsti/objectivefns/objectivefns.py index f7195235e..191fd736b 100644 --- a/pygsti/objectivefns/objectivefns.py +++ b/pygsti/objectivefns/objectivefns.py @@ -859,8 +859,8 @@ def __init__(self, model, dataset, circuits=None, resource_alloc=None, array_typ # probabilities (and other results) are stored in arrays - this makes sense # because it understands how to make this layout amenable to fast computation. if precomp_layout is None: - self.layout = model.sim.create_layout(bulk_circuit_list, dataset, self.resource_alloc, - array_types, verbosity=verbosity) # a CircuitProbabilityArrayLayout + self.layout = model.sim.create_layout(bulk_circuit_list, dataset, self.resource_alloc, array_types, + derivative_dimensions=None, verbosity=verbosity) # a CircuitProbabilityArrayLayout else: self.layout = precomp_layout self.array_types = array_types diff --git a/pygsti/protocols/estimate.py b/pygsti/protocols/estimate.py index 244a8bc3b..b478de2a3 100644 --- a/pygsti/protocols/estimate.py +++ b/pygsti/protocols/estimate.py @@ -277,7 +277,10 @@ def retrieve_start_model(self, goparams): Model """ goparams_list = [goparams] if hasattr(goparams, 'keys') else goparams - return goparams_list[0].get('model', self.models['final iteration estimate']) + if goparams_list: + return goparams_list[0].get('model', self.models['final iteration estimate']) + else: + return None def add_gaugeoptimized(self, goparams, model=None, label=None, comm=None, verbosity=None): """ @@ -331,8 +334,14 @@ def add_gaugeoptimized(self, goparams, model=None, label=None, comm=None, verbos label = "go%d" % i; i += 1 if (label not in self._gaugeopt_suite.gaugeopt_argument_dicts) and \ (label not in self.models): break - - goparams_list = [goparams] if hasattr(goparams, 'keys') else goparams + if hasattr(goparams, 'keys'): + goparams_list = [goparams] + elif goparams is None: + goparams_list = [] + #since this will be empty much of the code/iteration below will + #be skipped. + else: + goparams_list = goparams ordered_goparams = [] last_gs = None @@ -350,11 +359,14 @@ def add_gaugeoptimized(self, goparams, model=None, label=None, comm=None, verbos printer = _VerbosityPrinter.create_printer(max_vb, printer_comm) printer.log("-- Adding Gauge Optimized (%s) --" % label) - for i, gop in enumerate(goparams_list): - - if model is not None: - last_gs = model # just use user-supplied result - else: + if model is not None: + last_gs = model # just use user-supplied result + #sort the parameters by name for consistency + for gop in goparams_list: + ordered_goparams.append(_collections.OrderedDict( + [(k, gop[k]) for k in sorted(list(gop.keys()))])) + else: + for i, gop in enumerate(goparams_list): from ..algorithms import gaugeopt_to_target as _gaugeopt_to_target default_model = default_target_model = False gop = gop.copy() # so we don't change the caller's dict @@ -398,14 +410,20 @@ def add_gaugeoptimized(self, goparams, model=None, label=None, comm=None, verbos if default_model: del gop['model'] if default_target_model: del gop['target_model'] - #sort the parameters by name for consistency - ordered_goparams.append(_collections.OrderedDict( - [(k, gop[k]) for k in sorted(list(gop.keys()))])) + #sort the parameters by name for consistency + ordered_goparams.append(_collections.OrderedDict( + [(k, gop[k]) for k in sorted(list(gop.keys()))])) assert(last_gs is not None) self.models[label] = last_gs - self._gaugeopt_suite.gaugeopt_argument_dicts[label] = ordered_goparams \ - if len(goparams_list) > 1 else ordered_goparams[0] + + if goparams_list: #only do this if goparams_list wasn't empty to begin with. + #which would be the case except for the special case where the label is 'none'. + self._gaugeopt_suite.gaugeopt_argument_dicts[label] = ordered_goparams \ + if len(goparams_list) > 1 else ordered_goparams[0] + else: + self._gaugeopt_suite.gaugeopt_argument_dicts[label] = None + def add_confidence_region_factory(self, model_label='final iteration estimate', diff --git a/pygsti/protocols/gst.py b/pygsti/protocols/gst.py index e606c670b..9baf53c28 100644 --- a/pygsti/protocols/gst.py +++ b/pygsti/protocols/gst.py @@ -20,6 +20,7 @@ import numpy as _np from scipy.stats import chi2 as _chi2 +from typing import Optional from pygsti.baseobjs.profiler import DummyProfiler as _DummyProfiler from pygsti.baseobjs.nicelyserializable import NicelySerializable as _NicelySerializable @@ -44,6 +45,7 @@ from pygsti.modelmembers import states as _states, povms as _povms from pygsti.tools.legacytools import deprecate as _deprecated_fn from pygsti.circuits import Circuit +from pygsti.forwardsims import ForwardSimulator #For results object: @@ -535,7 +537,7 @@ def retrieve_model(self, edesign, gaugeopt_target, dataset, comm): if comm is None or comm.Get_rank() == 0: #Advanced Options can specify further manipulation of starting model if self.contract_start_to_cptp: - mdl_start = _alg.contract(mdl_start, "CPTP") + mdl_start = _alg.contract(mdl_start, "CPTPLND") raise ValueError( "'contractStartToCPTP' has been removed b/c it can change the parameterization of a model") if self.depolarize_start > 0: @@ -593,7 +595,7 @@ class GSTBadFitOptions(_NicelySerializable): Actions to take when a GST fit is unsatisfactory. Allowed actions include: * 'wildcard': Find an admissable wildcard model. - * 'ddist_wildcard': Fits a single parameter wildcard model in which + * 'wildcard1d': Fits a single parameter wildcard model in which the amount of wildcard error added to an operation is proportional to the diamond distance between that operation and the target. * 'robust': scale data according out "robust statistics v1" algorithm, @@ -839,7 +841,9 @@ class GSTGaugeOptSuite(_NicelySerializable): - "varyValidSpamWt" : varies spam weight with SPAM penalty == 1. - "toggleValidSpam" : toggles spame penalty (0 or 1); fixed SPAM wt. - "unreliable2Q" : adds branch to a spam suite that weights 2Q gates less - - "none" : no gauge optimizations are performed. + - "none" : no gauge optimizations are performed. When passed individually + (not in a list with other suite names) then this results in an empty + GSTGaugeOptSuite object (w/gaugeopt_suite_names set to None). gaugeopt_argument_dicts : dict, optional A dictionary whose string-valued keys label different gauge optimizations (e.g. within a @@ -870,8 +874,11 @@ def cast(cls, obj): def __init__(self, gaugeopt_suite_names=None, gaugeopt_argument_dicts=None, gaugeopt_target=None): super().__init__() if gaugeopt_suite_names is not None: - self.gaugeopt_suite_names = (gaugeopt_suite_names,) \ - if isinstance(gaugeopt_suite_names, str) else tuple(gaugeopt_suite_names) + if gaugeopt_suite_names == 'none': + self.gaugeopt_suite_names = None + else: + self.gaugeopt_suite_names = (gaugeopt_suite_names,) \ + if isinstance(gaugeopt_suite_names, str) else tuple(gaugeopt_suite_names) else: self.gaugeopt_suite_names = None @@ -949,6 +956,8 @@ def to_dictionary(self, model, unreliable_ops=(), verbosity=0): if hasattr(goparams, 'keys'): # goparams is a simple dict gaugeopt_suite_dict[lbl] = goparams.copy() gaugeopt_suite_dict[lbl].update({'verbosity': printer}) + elif goparams is None: + gaugeopt_suite_dict[lbl] = None else: # assume goparams is an iterable assert(isinstance(goparams, (list, tuple))), \ "If not a dictionary, gauge opt params should be a list or tuple of dicts!" @@ -961,7 +970,13 @@ def to_dictionary(self, model, unreliable_ops=(), verbosity=0): if self.gaugeopt_target is not None: assert(isinstance(self.gaugeopt_target, _Model)), "`gaugeopt_target` must be None or a Model" for goparams in gaugeopt_suite_dict.values(): - goparams_list = [goparams] if hasattr(goparams, 'keys') else goparams + if hasattr(goparams, 'keys'): + goparams_list = [goparams] + elif goparams is None: #edge case for 'none' suite + continue + else: + goparams_list = goparams + for goparams_dict in goparams_list: if 'target_model' in goparams_dict: _warnings.warn(("`gaugeOptTarget` argument is overriding" @@ -1086,8 +1101,8 @@ def _update_gaugeopt_dict_from_suitename(self, gaugeopt_suite_dict, root_lbl, su elif suite_name == "unreliable2Q": raise ValueError(("unreliable2Q is no longer a separate 'suite'. You should precede it with the suite" " name, e.g. 'stdgaugeopt-unreliable2Q' or 'varySpam-unreliable2Q'")) - elif suite_name == "none": - pass # add nothing + elif suite_name == 'none': + gaugeopt_suite_dict[root_lbl] = None else: raise ValueError("Unknown gauge-optimization suite '%s'" % suite_name) @@ -1257,20 +1272,8 @@ def __init__(self, initial_model=None, gaugeopt_suite='stdgaugeopt', self.circuit_weights = None self.unreliable_ops = ('Gcnot', 'Gcphase', 'Gms', 'Gcn', 'Gcx', 'Gcz') - #TODO: Maybe make methods like this separate functions?? - #def run_using_germs_and_fiducials(self, dataset, target_model, prep_fiducials, meas_fiducials, germs, max_lengths): - # design = StandardGSTDesign(target_model, prep_fiducials, meas_fiducials, germs, max_lengths) - # return self.run(_proto.ProtocolData(design, dataset)) - # - #def run_using_circuit_structures(self, target_model, circuit_structs, dataset): - # design = StructuredGSTDesign(target_model, circuit_structs) - # return self.run(_proto.ProtocolData(design, dataset)) - # - #def run_using_circuit_lists(self, target_model, circuit_lists, dataset): - # design = GateSetTomographyDesign(target_model, circuit_lists) - # return self.run(_proto.ProtocolData(design, dataset)) - - def run(self, data, memlimit=None, comm=None, checkpoint=None, checkpoint_path=None, disable_checkpointing = False): + def run(self, data, memlimit=None, comm=None, checkpoint=None, checkpoint_path=None, disable_checkpointing=False, + simulator: Optional[ForwardSimulator.Castable]=None): """ Run this protocol on `data`. @@ -1303,6 +1306,11 @@ def run(self, data, memlimit=None, comm=None, checkpoint=None, checkpoint_path=N to disk during the course of this protocol. It is strongly recommended that this be kept set to False without good reason to disable the checkpoints. + simulator : ForwardSimulator.Castable or None + Ignored if None. If not None, then we call + fwdsim = ForwardSimulator.cast(simulator), + and we set the .sim attribute of every Model we encounter to fwdsim. + Returns ------- ModelEstimateResults @@ -1337,54 +1345,56 @@ def run(self, data, memlimit=None, comm=None, checkpoint=None, checkpoint_path=N tnxt = _time.time(); profiler.add_time('GST: loading', tref); tref = tnxt mdl_start = self.initial_model.retrieve_model(data.edesign, self.gaugeopt_suite.gaugeopt_target, data.dataset, comm) - - if not disable_checkpointing: - #Set the checkpoint_path variable if None + if simulator is not None: + mdl_start.sim = simulator + + if disable_checkpointing: + seed_model = mdl_start.copy() + mdl_lsgst_list = [] + starting_idx = 0 + else: + # Set the checkpoint_path variable if None if checkpoint_path is None: checkpoint_path = _pathlib.Path('./gst_checkpoints/' + self.name) else: - #cast this to a pathlib path with the file extension (suffix) dropped + # cast this to a pathlib path with the file extension (suffix) dropped checkpoint_path = _pathlib.Path(checkpoint_path).with_suffix('') - - #create the parent directory of the checkpoint if needed: + + # create the parent directory of the checkpoint if needed: checkpoint_path.parent.mkdir(parents=True, exist_ok=True) - - #If there is no checkpoint we should start from with the seed model, - #otherwise we should seed the next iteration with the last iteration's result. - #If there is no checkpoint initialize mdl_lsgst_list and final_objfn to be empty, - #otherwise re-initialize their values from the checkpoint + + # If there is no checkpoint we should start from with the seed model, + # otherwise we should seed the next iteration with the last iteration's result. + # If there is no checkpoint initialize mdl_lsgst_list and final_objfn to be empty, + # otherwise re-initialize their values from the checkpoint if checkpoint is None: seed_model = mdl_start.copy() mdl_lsgst_list = [] checkpoint = GateSetTomographyCheckpoint() elif isinstance(checkpoint, GateSetTomographyCheckpoint): - #if the checkpoint's last completed iteration is non-negative - #(i.e. the checkpoint actually has data in it) + # if the checkpoint's last completed iteration is non-negative + # (i.e. the checkpoint actually has data in it) if checkpoint.last_completed_iter >= 0: seed_model = checkpoint.mdl_list[-1] - #otherwise seed with target + # otherwise seed with target else: seed_model = mdl_start.copy() mdl_lsgst_list = checkpoint.mdl_list final_objfn = checkpoint.final_objfn - #final_objfn initialized to None in the GateSetTomographyCheckpoint and will be overwritten - #during the loop below unless the last completed iteration is the final iteration - #in which case the loop should be skipped. If so I think it is ok that this gets - #left set to None. There looks to be some logic for handling this and it looks - #like the serialization routines effectively do this already, as the value - #of this is lost between writing and reading. + # final_objfn initialized to None in the GateSetTomographyCheckpoint and will be overwritten + # during the loop below unless the last completed iteration is the final iteration + # in which case the loop should be skipped. If so I think it is ok that this gets + # left set to None. There looks to be some logic for handling this and it looks + # like the serialization routines effectively do this already, as the value + # of this is lost between writing and reading. else: - NotImplementedError('The only currently valid checkpoint inputs are None and GateSetTomographyCheckpoint.') - - #note the last_completed_iter value is initialized to -1 so the below line + NotImplementedError( + 'The only currently valid checkpoint inputs are None and GateSetTomographyCheckpoint.') + + # note the last_completed_iter value is initialized to -1 so the below line # will have us correctly starting at 0 if this is a fresh checkpoint. starting_idx = checkpoint.last_completed_iter + 1 - else: - seed_model = mdl_start.copy() - mdl_lsgst_list = [] - starting_idx = 0 - tnxt = _time.time(); profiler.add_time('GST: Prep Initial seed', tref); tref = tnxt #Run Long-sequence GST on data @@ -1404,18 +1414,18 @@ def run(self, data, memlimit=None, comm=None, checkpoint=None, checkpoint_path=N #then do the final iteration slightly differently since the generator should #give three return values. if i==len(bulk_circuit_lists)-1: - mdl_iter, opt_iter, final_objfn = next(gst_iter_generator) + mdl_iter, opt_iter, final_objfn = next(gst_iter_generator) else: mdl_iter, opt_iter = next(gst_iter_generator) mdl_lsgst_list.append(mdl_iter) optima_list.append(opt_iter) if not disable_checkpointing: - #update the checkpoint along the way: + # update the checkpoint along the way: checkpoint.mdl_list = mdl_lsgst_list checkpoint.last_completed_iter += 1 checkpoint.last_completed_circuit_list = bulk_circuit_lists[i] - #write the updated checkpoint to disk: + # write the updated checkpoint to disk: if resource_alloc.comm_rank == 0: checkpoint.write(f'{checkpoint_path}_iteration_{i}.json') @@ -1442,19 +1452,37 @@ def run(self, data, memlimit=None, comm=None, checkpoint=None, checkpoint_path=N target_model = self.gaugeopt_suite.gaugeopt_target elif self.initial_model.target_model is not None: target_model = self.initial_model.target_model.copy() - elif self.initial_model.model is not None and self.gaugeopt_suite.is_empty() is False: + elif self.initial_model.model is not None: # when we desparately need a target model but none have been specifically given: use initial model target_model = self.initial_model.model.copy() else: + msg = 'Could not identify a suitable target model, this may result'\ + +' in unexpected behavior or missing plots in reports.' + _warnings.warn(msg) target_model = None + if target_model is not None and simulator is not None: + target_model.sim = simulator + estimate = _Estimate.create_gst_estimate(ret, target_model, mdl_start, mdl_lsgst_list, parameters) ret.add_estimate(estimate, estimate_key=self.name) - return _add_gaugeopt_and_badfit(ret, self.name, target_model, - self.gaugeopt_suite, self.unreliable_ops, - self.badfit_options, self.optimizer, resource_alloc, printer) - + #Add some better handling for when gauge optimization is turned off (current code path isn't working.) + if not self.gaugeopt_suite.is_empty(): + ret = _add_gaugeopt_and_badfit(ret, self.name, target_model, + self.gaugeopt_suite, self.unreliable_ops, + self.badfit_options, self.optimizer, + resource_alloc, printer) + else: + #add a model to the estimate that we'll call the trivial gauge optimized model which + #will be set to be equal to the final iteration estimate. + ret.estimates[self.name].models['trivial_gauge_opt'] = mdl_lsgst_list[-1] + #and add a key for this to the goparameters dict (this is what the report + #generation looks at to determine the names of the gauge optimized models). + #Set the value to None as a placeholder. + ret.estimates[self.name].goparameters['trivial_gauge_opt'] = None + + return ret class LinearGateSetTomography(_proto.Protocol): """ @@ -1504,6 +1532,10 @@ def __init__(self, target_model=None, gaugeopt_suite='stdgaugeopt', self.oplabel_aliases = None self.unreliable_ops = ('Gcnot', 'Gcphase', 'Gms', 'Gcn', 'Gcx', 'Gcz') + self.auxfile_types['target_model'] = 'serialized-object' + self.auxfile_types['gaugeopt_suite'] = 'serialized-object' + self.auxfile_types['badfit_options'] = 'serialized-object' + def check_if_runnable(self, data): """ Raises a ValueError if LGST cannot be run on data @@ -1612,9 +1644,22 @@ def run(self, data, memlimit=None, comm=None): 'final iteration estimate': mdl_lgst}, parameters) ret.add_estimate(estimate, estimate_key=self.name) - return _add_gaugeopt_and_badfit(ret, self.name, target_model, self.gaugeopt_suite, + + #Add some better handling for when gauge optimization is turned off (current code path isn't working.) + if not self.gaugeopt_suite.is_empty(): + ret = _add_gaugeopt_and_badfit(ret, self.name, target_model, self.gaugeopt_suite, self.unreliable_ops, self.badfit_options, None, resource_alloc, printer) + else: + #add a model to the estimate that we'll call the trivial gauge optimized model which + #will be set to be equal to the final iteration estimate. + ret.estimates[self.name].models['trivial_gauge_opt'] = mdl_lgst + #and add a key for this to the goparameters dict (this is what the report + #generation looks at to determine the names of the gauge optimized models). + #Set the value to None as a placeholder. + ret.estimates[self.name].goparameters['trivial_gauge_opt'] = None + + return ret class StandardGST(_proto.Protocol): @@ -1629,13 +1674,13 @@ class StandardGST(_proto.Protocol): parameterizations/constraints to apply to the estimated model. The default value is usually fine. Allowed values are: - - "full" : full (completely unconstrained) - - "TP" : TP-constrained - - "CPTP" : Lindbladian CPTP-constrained - - "H+S" : Only Hamiltonian + Stochastic errors allowed (CPTP) - - "S" : Only Stochastic errors allowed (CPTP) - - "Target" : use the target (ideal) gates as the estimate - - : any key in the `models_to_test` argument + - "full" : full (completely unconstrained) + - "TP" : TP-constrained + - "CPTPLND" : Lindbladian CPTP-constrained + - "H+S" : Only Hamiltonian + Stochastic errors allowed (CPTP) + - "S" : Only Stochastic errors allowed (CPTP) + - "Target" : use the target (ideal) gates as the estimate + - : any key in the `models_to_test` argument gaugeopt_suite : GSTGaugeOptSuite, optional Specifies which gauge optimizations to perform on each estimate. Can also @@ -1646,6 +1691,14 @@ class StandardGST(_proto.Protocol): optimization (only), and is useful when you want to gauge optimize toward something other than the *ideal* target gates. + target_model : Model, optional (default None) + If specified use this Model as the target model. Depending on other + specified keyword arguments this model may be used as the target for + the purposes of gauge optimization, report generation/analysis, and + initial seeding for optimization. (For almost all of these it may be the + case that other keyword argument values override this for certain + tasks). + models_to_test : dict, optional A dictionary of Model objects representing (gate-set) models to test against the data. These Models are essentially hypotheses for @@ -1718,7 +1771,8 @@ def __init__(self, modes=('full TP','CPTPLND','Target'), gaugeopt_suite='stdgaug # data = _proto.ProtocolData(design, dataset) # return self.run(data) - def run(self, data, memlimit=None, comm=None, checkpoint= None, checkpoint_path=None, disable_checkpointing = False): + def run(self, data, memlimit=None, comm=None, checkpoint=None, checkpoint_path=None, + disable_checkpointing=False, simulator: Optional[ForwardSimulator.Castable]=None): """ Run this protocol on `data`. @@ -1751,6 +1805,11 @@ def run(self, data, memlimit=None, comm=None, checkpoint= None, checkpoint_path= to disk during the course of this protocol. It is strongly recommended that this be kept set to False without good reason to disable the checkpoints. + simulator : ForwardSimulator.Castable or None + Ignored if None. If not None, then we call + fwdsim = ForwardSimulator.cast(simulator), + and we set the .sim attribute of every Model we encounter to fwdsim. + Returns ------- ProtocolResults @@ -1780,6 +1839,10 @@ def run(self, data, memlimit=None, comm=None, checkpoint= None, checkpoint_path= else: target_model = None # Usually this path leads to an error being raised below. + if target_model is not None: + if simulator is not None: + target_model.sim = simulator + if not disable_checkpointing: #Set the checkpoint_path variable if None if checkpoint_path is None: @@ -1813,8 +1876,12 @@ def run(self, data, memlimit=None, comm=None, checkpoint= None, checkpoint_path= with printer.progress_logging(1): for i, mode in enumerate(modes): printer.show_progress(i, len(modes), prefix='-- Std Practice: ', suffix=' (%s) --' % mode) - if not disable_checkpointing: - #pre python 3.9 compatible version. + if disable_checkpointing: + checkpoint_path = None + child_checkpoint = None + else: + child_checkpoint = checkpoint.children[mode] + #The line below is for compatibility with Python 3.8 and lower. checkpoint_path = checkpoint_path_base.with_name(f"{checkpoint_path_base.stem}_{mode.replace(' ', '_')}") #The line below only works for python 3.9+ #checkpoint_path = checkpoint_path_base.with_stem(f"{checkpoint_path_base.stem}_{mode.replace(' ', '_')}") @@ -1825,21 +1892,22 @@ def run(self, data, memlimit=None, comm=None, checkpoint= None, checkpoint_path= mdltest = _ModelTest(target_model, target_model, self.gaugeopt_suite, mt_builder, self.badfit_options, verbosity=printer - 1, name=mode) - if not disable_checkpointing: - result = mdltest.run(data, memlimit, comm, checkpoint = checkpoint.children[mode], - checkpoint_path=checkpoint_path) - else: - result = mdltest.run(data, memlimit, comm, disable_checkpointing=True) + result = mdltest.run(data, memlimit, comm, + disable_checkpointing=disable_checkpointing, + checkpoint=child_checkpoint, + checkpoint_path=checkpoint_path) ret.add_estimates(result) elif mode in models_to_test: - mdltest = _ModelTest(models_to_test[mode], target_model, self.gaugeopt_suite, + mdl = models_to_test[mode] + if simulator is not None: + mdl.sim = simulator + mdltest = _ModelTest(mdl, target_model, self.gaugeopt_suite, None, self.badfit_options, verbosity=printer - 1, name=mode) - if not disable_checkpointing: - result = mdltest.run(data, memlimit, comm, checkpoint = checkpoint.children[mode], - checkpoint_path=checkpoint_path) - else: - result = mdltest.run(data, memlimit, comm, disable_checkpointing=True) + result = mdltest.run(data, memlimit, comm, + disable_checkpointing=disable_checkpointing, + checkpoint=child_checkpoint, + checkpoint_path=checkpoint_path) ret.add_estimates(result) else: @@ -1849,7 +1917,7 @@ def run(self, data, memlimit=None, comm=None, checkpoint= None, checkpoint_path= #Try to interpret `mode` as a parameterization parameterization = mode # for now, 1-1 correspondence - initial_model = target_model + initial_model = target_model.copy() try: initial_model.set_all_parameterizations(parameterization) @@ -1858,13 +1926,14 @@ def run(self, data, memlimit=None, comm=None, checkpoint= None, checkpoint_path= % (mode, str(e))) initial_model = GSTInitialModel(initial_model, self.starting_point.get(mode, None)) + if simulator is not None: + initial_model.sim = simulator gst = GST(initial_model, self.gaugeopt_suite, self.objfn_builders, self.optimizer, self.badfit_options, verbosity=printer - 1, name=mode) - if not disable_checkpointing: - result = gst.run(data, memlimit, comm, checkpoint = checkpoint.children[mode], - checkpoint_path=checkpoint_path) - else: - result = gst.run(data, memlimit, comm, disable_checkpointing=True) + result = gst.run(data, memlimit, comm, + disable_checkpointing=disable_checkpointing, + checkpoint=child_checkpoint, + checkpoint_path=checkpoint_path) ret.add_estimates(result) return ret @@ -2023,26 +2092,31 @@ def _add_gauge_opt(results, base_est_label, gaugeopt_suite, starting_model, printer.log("-- Performing '%s' gauge optimization on %s estimate --" % (go_label, base_est_label), 2) - #Get starting model - results.estimates[base_est_label].add_gaugeoptimized(goparams, None, go_label, comm, printer - 3) + #add logic for the case where no gauge optimization is performed. + if go_label == 'none': + results.estimates[base_est_label].add_gaugeoptimized(goparams, starting_model, go_label, comm, printer - 3) + else: + results.estimates[base_est_label].add_gaugeoptimized(goparams, None, go_label, comm, printer - 3) + + #Get starting model for next stage mdl_start = results.estimates[base_est_label].retrieve_start_model(goparams) - - #Gauge optimize data-scaled estimate also - for suffix in ROBUST_SUFFIX_LIST: - robust_est_label = base_est_label + suffix - if robust_est_label in results.estimates: - mdl_start_robust = results.estimates[robust_est_label].retrieve_start_model(goparams) - - if mdl_start_robust.frobeniusdist(mdl_start) < 1e-8: - printer.log("-- Conveying '%s' gauge optimization from %s to %s estimate --" % - (go_label, base_est_label, robust_est_label), 2) - params = results.estimates[base_est_label].goparameters[go_label] # no need to copy here - gsopt = results.estimates[base_est_label].models[go_label].copy() - results.estimates[robust_est_label].add_gaugeoptimized(params, gsopt, go_label, comm, printer - 3) - else: - printer.log("-- Performing '%s' gauge optimization on %s estimate --" % - (go_label, robust_est_label), 2) - results.estimates[robust_est_label].add_gaugeoptimized(goparams, None, go_label, comm, printer - 3) + if mdl_start is not None: + #Gauge optimize data-scaled estimate also + for suffix in ROBUST_SUFFIX_LIST: + robust_est_label = base_est_label + suffix + if robust_est_label in results.estimates: + mdl_start_robust = results.estimates[robust_est_label].retrieve_start_model(goparams) + + if mdl_start_robust.frobeniusdist(mdl_start) < 1e-8: + printer.log("-- Conveying '%s' gauge optimization from %s to %s estimate --" % + (go_label, base_est_label, robust_est_label), 2) + params = results.estimates[base_est_label].goparameters[go_label] # no need to copy here + gsopt = results.estimates[base_est_label].models[go_label].copy() + results.estimates[robust_est_label].add_gaugeoptimized(params, gsopt, go_label, comm, printer - 3) + else: + printer.log("-- Performing '%s' gauge optimization on %s estimate --" % + (go_label, robust_est_label), 2) + results.estimates[robust_est_label].add_gaugeoptimized(goparams, None, go_label, comm, printer - 3) def _add_badfit_estimates(results, base_estimate_label, badfit_options, @@ -2983,7 +3057,8 @@ def add_estimate(self, estimate, estimate_key='default'): self.estimates[estimate_key] = estimate def add_model_test(self, target_model, themodel, - estimate_key='test', gaugeopt_keys="auto", verbosity=2): + estimate_key='test', gaugeopt_keys="auto", verbosity=2, + simulator: Optional[ForwardSimulator.Castable]=None): """ Add a new model-test (i.e. non-optimized) estimate to this `Results` object. @@ -3010,6 +3085,11 @@ def add_model_test(self, target_model, themodel, verbosity : int, optional Level of detail printed to stdout. + simulator : ForwardSimulator.Castable or None + Ignored if None. If not None, then we call + fwdsim = ForwardSimulator.cast(simulator), + and we set the .sim attribute of every Model we encounter to fwdsim. + Returns ------- None @@ -3030,7 +3110,7 @@ def add_model_test(self, target_model, themodel, from .modeltest import ModelTest as _ModelTest mdltest = _ModelTest(themodel, target_model, gaugeopt_suite, objfn_builder, badfit_options, name=estimate_key, verbosity=verbosity) - test_result = mdltest.run(self.data) + test_result = mdltest.run(self.data, simulator=simulator) self.add_estimates(test_result) def view(self, estimate_keys, gaugeopt_keys=None): diff --git a/pygsti/protocols/modeltest.py b/pygsti/protocols/modeltest.py index dee9ae860..b29b1b735 100644 --- a/pygsti/protocols/modeltest.py +++ b/pygsti/protocols/modeltest.py @@ -13,6 +13,7 @@ import collections as _collections import warnings as _warnings import pathlib as _pathlib +from typing import Optional from pygsti.baseobjs.profiler import DummyProfiler as _DummyProfiler from pygsti.objectivefns.objectivefns import ModelDatasetCircuitsStore as _ModelDatasetCircuitStore from pygsti.protocols.estimate import Estimate as _Estimate @@ -23,6 +24,7 @@ from pygsti.circuits import Circuit from pygsti.circuits.circuitlist import CircuitList as _CircuitList from pygsti.baseobjs.resourceallocation import ResourceAllocation as _ResourceAllocation +from pygsti.forwardsims import ForwardSimulator class ModelTest(_proto.Protocol): @@ -98,6 +100,7 @@ def __init__(self, model_to_test, target_model=None, gaugeopt_suite=None, set_trivial_gauge_group=True, verbosity=2, name=None): from .gst import GSTBadFitOptions as _GSTBadFitOptions + from .gst import GSTGaugeOptSuite as _GSTGaugeOptSuite if set_trivial_gauge_group: model_to_test = model_to_test.copy() @@ -107,7 +110,7 @@ def __init__(self, model_to_test, target_model=None, gaugeopt_suite=None, super().__init__(name) self.model_to_test = model_to_test self.target_model = target_model - self.gaugeopt_suite = gaugeopt_suite + self.gaugeopt_suite = _GSTGaugeOptSuite.cast(gaugeopt_suite) self.badfit_options = _GSTBadFitOptions.cast(badfit_options) self.verbosity = verbosity @@ -131,7 +134,8 @@ def __init__(self, model_to_test, target_model=None, gaugeopt_suite=None, # design = _StandardGSTDesign(target_model, prep_fiducials, meas_fiducials, germs, maxLengths) # return self.run(_proto.ProtocolData(design, dataset)) - def run(self, data, memlimit=None, comm=None, checkpoint=None, checkpoint_path=None, disable_checkpointing= False): + def run(self, data, memlimit=None, comm=None, checkpoint=None, checkpoint_path=None, disable_checkpointing=False, + simulator: Optional[ForwardSimulator.Castable]=None): """ Run this protocol on `data`. @@ -164,12 +168,19 @@ def run(self, data, memlimit=None, comm=None, checkpoint=None, checkpoint_path=N to disk during the course of this protocol. It is strongly recommended that this be kept set to False without good reason to disable the checkpoints. + simulator : ForwardSimulator.Castable or None + Ignored if None. If not None, then we call + fwdsim = ForwardSimulator.cast(simulator), + and we set the .sim attribute of every Model we encounter to fwdsim. + Returns ------- ModelEstimateResults """ the_model = self.model_to_test - + if simulator is not None: + the_model.sim = simulator + target_model = self.target_model # can be None; target model isn't necessary #Create profiler @@ -267,11 +278,13 @@ def run(self, data, memlimit=None, comm=None, checkpoint=None, checkpoint_path=N models.update({('iteration %d estimate' % k): the_model for k in range(len(bulk_circuit_lists))}) # TODO: come up with better key names? and must we have iteration_estimates? if target_model is not None: + if simulator is not None: + target_model.sim = simulator models['target'] = target_model ret.add_estimate(_Estimate(ret, models, parameters, extra_parameters=extra_parameters), estimate_key=self.name) - #Add some better handling for when gauge optimization is turned off (current code path isn't working. - if self.gaugeopt_suite is not None: + #Add some better handling for when gauge optimization is turned off (current code path isn't working.) + if not self.gaugeopt_suite.is_empty(): ret= _add_gaugeopt_and_badfit(ret, self.name, target_model, self.gaugeopt_suite, self.unreliable_ops, self.badfit_options, None, resource_alloc, printer) @@ -282,8 +295,8 @@ def run(self, data, memlimit=None, comm=None, checkpoint=None, checkpoint_path=N #and add a key for this to the goparameters dict (this is what the report #generation looks at to determine the names of the gauge optimized models). #Set the value to None as a placeholder. - from .gst import GSTGaugeOptSuite ret.estimates[self.name].goparameters['trivial_gauge_opt']= None + return ret diff --git a/pygsti/protocols/vbdataframe.py b/pygsti/protocols/vbdataframe.py index 6c7bbeb57..1c007dc1c 100644 --- a/pygsti/protocols/vbdataframe.py +++ b/pygsti/protocols/vbdataframe.py @@ -19,7 +19,7 @@ def _calculate_summary_statistic(x, statistic, lower_cutoff=None): Utility function that returns statistic(x), or the maximum of statistic(x) and lower_cutoff if lower_cutoff is not None. """ - if len(x) == 0 or _np.all(_np.isnan(x)): return _np.NaN + if len(x) == 0 or _np.all(_np.isnan(x)): return _np.nan if statistic == 'mean': func = _np.nanmean elif statistic == 'max' or statistic == 'monotonic_max': func = _np.nanmax elif statistic == 'min' or statistic == 'monotonic_min': func = _np.nanmin diff --git a/pygsti/report/fogidiagram.py b/pygsti/report/fogidiagram.py index 8485a371f..a53b1681a 100644 --- a/pygsti/report/fogidiagram.py +++ b/pygsti/report/fogidiagram.py @@ -1038,7 +1038,7 @@ def render(self, detail_level=0, figsize=5, outfile=None, spacing=0.05, nudge=0. for i in range(nOps): for j in range(i, nOps): total_items[i, j] = sum([len(by_qty_items[qty][i, j]) for qty in all_qtys]) - if total_items[i, j] == 0: totals[i, j] = _np.NaN + if total_items[i, j] == 0: totals[i, j] = _np.nan box_size_mode = "condensed" # or "inflated" if detail_level == 2: diff --git a/pygsti/report/plothelpers.py b/pygsti/report/plothelpers.py index 1115d3477..eeba19eec 100644 --- a/pygsti/report/plothelpers.py +++ b/pygsti/report/plothelpers.py @@ -18,6 +18,7 @@ from pygsti.objectivefns import objectivefns as _objfns from pygsti.circuits.circuitlist import CircuitList as _CircuitList from pygsti.baseobjs.smartcache import smart_cached +from pygsti.baseobjs import Label def small_eigenvalue_err_rate(sigma, direct_gst_models): @@ -43,7 +44,8 @@ def small_eigenvalue_err_rate(sigma, direct_gst_models): """ if sigma is None: return _np.nan # in plot processing, "None" circuits = no plot output = nan values mdl_direct = direct_gst_models[sigma] - minEigval = min(abs(_np.linalg.eigvals(mdl_direct.operations["GsigmaLbl"]))) + key = Label('GsigmaLbl') if sigma.line_labels == ('*',) else Label('GsigmaLbl', sigma.line_labels) + minEigval = min(abs(_np.linalg.eigvals(mdl_direct.operations[key]))) # (approximate) per-gate error rate; max averts divide by zero error return 1.0 - minEigval**(1.0 / max(len(sigma), 1)) @@ -156,7 +158,13 @@ def _compute_sub_mxs(gss, model, sub_mx_creation_fn, dataset=None, sub_mx_creati for x in gss.used_xs] for y in gss.used_ys] #Note: subMxs[y-index][x-index] is proper usage return subMxs + +#define a modified version that is meant for working with CircuitList objects of lists of them. +#@smart_cached +def _compute_sub_mxs_circuit_list(circuit_lists, model, sub_mx_creation_fn, dataset=None, sub_mx_creation_fn_extra_arg=None): + subMxs = [sub_mx_creation_fn(circuit_list, sub_mx_creation_fn_extra_arg) for circuit_list in circuit_lists] + return subMxs @smart_cached def dscompare_llr_matrices(gsplaq, dscomparator): diff --git a/pygsti/report/report.py b/pygsti/report/report.py index d51b120db..c1be85a05 100644 --- a/pygsti/report/report.py +++ b/pygsti/report/report.py @@ -206,6 +206,11 @@ def write_notebook(self, path, auto_open=False, connected=False, verbosity=0): who want to tinker with the standard analysis presented in the static HTML or LaTeX format reports. + Note that interactive cells in report notebooks require JavaScript, + and therefore do not work with JupyterLab. Please continue to use + classic Jupyter notebooks for PyGSTi report notebooks. To track this issue, + see https://github.com/pyGSTio/pyGSTi/issues/205. + Parameters ---------- path : str or path-like object @@ -249,6 +254,12 @@ def write_notebook(self, path, auto_open=False, connected=False, verbosity=0): nb = _Notebook() nb.add_markdown('# {title}\n(Created on {date})'.format( title=title, date=_time.strftime("%B %d, %Y"))) + + nb.add_markdown("## JupyterLab Incompatibility Warning\n" + + "Note that interactive cells in report notebooks require JavaScript, " + + "and therefore do not work with JupyterLab. Please continue to use " + + "classic Jupyter notebooks for PyGSTi report notebooks. To track this issue, " + + "see https://github.com/pyGSTio/pyGSTi/issues/205.") nb.add_code("""\ import pickle @@ -353,6 +364,11 @@ def write_notebook(self, path, auto_open=False, connected=False, verbosity=0): printer.log("Report Notebook created as %s" % path) + printer.warning("""Note that interactive cells in report notebooks require JavaScript, + and therefore do not work with JupyterLab. Please continue to use + classic Jupyter notebooks for PyGSTi report notebooks. To track this issue, + see https://github.com/pyGSTio/pyGSTi/issues/205.""") + if auto_open: port = "auto" if auto_open is True else int(auto_open) nb.launch(str(path), port=port) diff --git a/pygsti/report/templates/offline/pygsti_dashboard.css b/pygsti/report/templates/offline/pygsti_dashboard.css index af5b9c9db..a8f64a178 100644 --- a/pygsti/report/templates/offline/pygsti_dashboard.css +++ b/pygsti/report/templates/offline/pygsti_dashboard.css @@ -598,6 +598,12 @@ div.sidenav div.linkgroup a.active { display: block !important; } +.defaultcaptiondetail { + display: none; + font-weight: normal; +} + + #status { color: #777; background:#ccc; diff --git a/pygsti/report/templates/offline/pygsti_dashboard.js b/pygsti/report/templates/offline/pygsti_dashboard.js index f9317b188..4d61eb9f3 100644 --- a/pygsti/report/templates/offline/pygsti_dashboard.js +++ b/pygsti/report/templates/offline/pygsti_dashboard.js @@ -158,10 +158,22 @@ $(document).ready(function() { // Render KaTeX render_katex('body'); + // Iterate through all figure captions and add a default caption detail + const figcaptions = document.getElementsByTagName("figcaption") + for (const figcap of figcaptions) { + const defaultcaption = document.createElement('span') + defaultcaption.className = 'defaultcaptiondetail' + defaultcaption.innerHTML = '(Click to expand details)' + defaultcaption.classList.toggle("showcaption") + figcap.appendChild(defaultcaption) + } + // Enable figure caption toggling $('figcaption').on('click', function() { // captiondetails should be divs, not spans $(this).children('.captiondetail').toggleClass('showcaption') + // Also turn off default caption + $(this).children('.defaultcaptiondetail').toggleClass('showcaption') }); }); diff --git a/pygsti/report/workspaceplots.py b/pygsti/report/workspaceplots.py index 50d4d35a4..5dd53332b 100644 --- a/pygsti/report/workspaceplots.py +++ b/pygsti/report/workspaceplots.py @@ -23,13 +23,14 @@ from pygsti.report import colormaps as _colormaps from pygsti.report import plothelpers as _ph from pygsti.report.figure import ReportFigure -from pygsti.report.workspace import WorkspacePlot +from pygsti.report.workspace import WorkspacePlot, NotApplicable from pygsti import algorithms as _alg from pygsti import baseobjs as _baseobjs from pygsti.objectivefns import objectivefns as _objfns from pygsti.circuits.circuit import Circuit as _Circuit from pygsti.circuits.circuitstructure import PlaquetteGridCircuitStructure as _PlaquetteGridCircuitStructure, \ GermFiducialPairPlaquette as _GermFiducialPairPlaquette +from pygsti.circuits.circuitlist import CircuitList as _CircuitList from pygsti.data import DataSet as _DataSet #Plotly v3 changes heirarchy of graph objects @@ -529,6 +530,40 @@ def hover_label_fn(val, iy, ix, iiy, iix): txt += "
%s: %s" % (lbl, str(addl_subMxs[iy][ix][iiy][iix])) return txt return hover_label_fn + +def _create_hover_info_fn_circuit_list(circuit_structure, sum_up, addl_hover_submxs): + + if sum_up: + pass + else: + if isinstance(circuit_structure, _CircuitList): + def hover_label_fn(val, i): + """ Standard hover labels """ + #Note: in this case, we need to "flip" the iiy index because + # the matrices being plotted are flipped within _summable_color_boxplot(...) + if _np.isnan(val): return "" + ckt = circuit_structure[i].copy(editable=True) + ckt.factorize_repetitions_inplace() + txt = ckt.layerstr # note: *row* index = iiy + txt += ("
value: %g" % val) + for lbl, addl_subMxs in addl_hover_submxs.items(): + txt += "
%s: %s" % (lbl, str(addl_subMxs[i])) + return txt + + elif isinstance(circuit_structure, list) and all([isinstance(el, _CircuitList) for el in circuit_structure]): + def hover_label_fn(val, i, j): + """ Standard hover labels """ + #Note: in this case, we need to "flip" the iiy index because + # the matrices being plotted are flipped within _summable_color_boxplot(...) + if _np.isnan(val): return "" + ckt = circuit_structure[i][j].copy(editable=True) + ckt.factorize_repetitions_inplace() + txt = ckt.layerstr # note: *row* index = iiy + txt += ("
value: %g" % val) + for lbl, addl_subMxs in addl_hover_submxs.items(): + txt += "
%s: %s" % (lbl, str(addl_subMxs[i][j])) + return txt + return hover_label_fn def _circuit_color_boxplot(circuit_structure, sub_mxs, colormap, @@ -662,42 +697,78 @@ def _circuit_color_scatterplot(circuit_structure, sub_mxs, colormap, plotly.Figure """ g = circuit_structure - xvals = g.used_xs - yvals = g.used_ys if addl_hover_submxs is None: addl_hover_submxs = {} if hover_info: - hover_info = _create_hover_info_fn(circuit_structure, xvals, yvals, sum_up, addl_hover_submxs) - + if isinstance(g, _PlaquetteGridCircuitStructure): + hover_info = _create_hover_info_fn(circuit_structure, g.used_xs, g.used_ys, sum_up, addl_hover_submxs) + elif isinstance(g, _CircuitList) or (isinstance(g, list) and all([isinstance(el, _CircuitList) for el in g])): + hover_info = _create_hover_info_fn_circuit_list(circuit_structure, sum_up, addl_hover_submxs) + xs = []; ys = []; texts = [] gstrs = set() # to eliminate duplicate strings - for ix, x in enumerate(g.used_xs): - for iy, y in enumerate(g.used_ys): - plaq = g.plaquette(x, y, empty_if_missing=True) - if sum_up: - if plaq.base not in gstrs: - tot = sum([sub_mxs[iy][ix][iiy][iix] for iiy, iix, _ in plaq]) - xs.append(len(plaq.base)) # x-coord is len of *base* string - ys.append(tot) - gstrs.add(plaq.base) - if hover_info: - if callable(hover_info): - texts.append(hover_info(tot, iy, ix)) - else: - texts.append(str(tot)) + + if isinstance(g, _PlaquetteGridCircuitStructure): + for ix, x in enumerate(g.used_xs): + for iy, y in enumerate(g.used_ys): + plaq = g.plaquette(x, y, empty_if_missing=True) + if sum_up: + if plaq.base not in gstrs: + tot = sum([sub_mxs[iy][ix][iiy][iix] for iiy, iix, _ in plaq]) + xs.append(len(plaq.base)) # x-coord is len of *base* string + ys.append(tot) + gstrs.add(plaq.base) + if hover_info: + if callable(hover_info): + texts.append(hover_info(tot, iy, ix)) + else: + texts.append(str(tot)) + else: + for iiy, iix, opstr in plaq: + if opstr in gstrs: continue # skip duplicates + xs.append(len(opstr)) + ys.append(sub_mxs[iy][ix][iiy][iix]) + gstrs.add(opstr) + if hover_info: + if callable(hover_info): + texts.append(hover_info(sub_mxs[iy][ix][iiy][iix], iy, ix, iiy, iix)) + else: + texts.append(str(sub_mxs[iy][ix][iiy][iix])) + elif isinstance(g, _CircuitList): + for i, ckt in enumerate(g): + if ckt in gstrs: + continue else: - for iiy, iix, opstr in plaq: - if opstr in gstrs: continue # skip duplicates - xs.append(len(opstr)) - ys.append(sub_mxs[iy][ix][iiy][iix]) - gstrs.add(opstr) + if sum_up: + pass + #TODO: Implement sum_up behavior mirroring that above. + gstrs.add(ckt) + ys.append(sub_mxs[i]) + xs.append(len(ckt)) + if hover_info: + if callable(hover_info): + texts.append(hover_info(sub_mxs[i], i)) + else: + texts.append(str(sub_mxs[i])) + elif isinstance(g, list) and all([isinstance(el, _CircuitList) for el in g]): + for i, circuit_list in enumerate(g): + for j, ckt in enumerate(circuit_list): + if ckt in gstrs: + continue + else: + if sum_up: + pass + #TODO: Implement sum_up behavior mirroring that above. + gstrs.add(ckt) + ys.append(sub_mxs[i][j]) + xs.append(len(ckt)) if hover_info: if callable(hover_info): - texts.append(hover_info(sub_mxs[iy][ix][iiy][iix], iy, ix, iiy, iix)) + texts.append(hover_info(sub_mxs[i][j], i, j)) else: - texts.append(str(sub_mxs[iy][ix][iiy][iix])) + texts.append(str(sub_mxs[i][j])) #This GL version works, but behaves badly, sometimes failing to render... #trace = go.Scattergl(x=xs, y=ys, mode="markers", @@ -768,17 +839,42 @@ def _circuit_color_histogram(circuit_structure, sub_mxs, colormap, plotly.Figure """ g = circuit_structure - + + #For all of the fanciness below, this all essentially looks like it just produces + #a flattened list of all of the contents of sub_mxs, so we can still do that with the + #submx structures we get from using CircuitList objects. ys = [] # artificially add minval so gstrs = set() # to eliminate duplicate strings - for ix, x in enumerate(g.used_xs): - for iy, y in enumerate(g.used_ys): - plaq = g.plaquette(x, y, empty_if_missing=True) - #TODO: if sum_up then need to sum before appending... - for iiy, iix, opstr in plaq: - if opstr in gstrs: continue # skip duplicates - ys.append(sub_mxs[iy][ix][iiy][iix]) - gstrs.add(opstr) + + if isinstance(g, _PlaquetteGridCircuitStructure): + for ix, x in enumerate(g.used_xs): + for iy, y in enumerate(g.used_ys): + plaq = g.plaquette(x, y, empty_if_missing=True) + #TODO: if sum_up then need to sum before appending... + for iiy, iix, opstr in plaq: + if opstr in gstrs: continue # skip duplicates + ys.append(sub_mxs[iy][ix][iiy][iix]) + gstrs.add(opstr) + + elif isinstance(g, _CircuitList): + for i, ckt in enumerate(g): + if ckt in gstrs: + continue + else: + gstrs.add(ckt) + ys.append(sub_mxs[i]) + + elif isinstance(g, list) and all([isinstance(el, _CircuitList) for el in g]): + for i, circuit_list in enumerate(g): + for j, ckt in enumerate(circuit_list): + if ckt in gstrs: + continue + else: + gstrs.add(ckt) + ys.append(sub_mxs[i][j]) + else: + raise ValueError('Can only handle PlaquetteGridCircuitStructure, CircuitList or lists of CircuitList objects at present.') + if len(ys) == 0: ys = [0] # case of no data - dummy so max works below minval = 0 @@ -1641,7 +1737,6 @@ def _create(self, plottypes, circuits, dataset, model, prec, sum_up, box_labels, if isinstance(objfn, (_objfns.PoissonPicDeltaLogLFunction, _objfns.DeltaLogLFunction)): terms *= 2.0 # show 2 * deltaLogL values, not just deltaLogL - if isinstance(objfn, _objfns.TVDFunction): colormapType = "blueseq" else: @@ -1649,16 +1744,34 @@ def _create(self, plottypes, circuits, dataset, model, prec, sum_up, box_labels, linlog_color = "red" ytitle = objfn.description # "chi2" OR "2 log(L ratio)" - - mx_fn = _mx_fn_from_elements # use a *global* function so cache can tell it's the same + + if isinstance(circuits, _PlaquetteGridCircuitStructure): + mx_fn = _mx_fn_from_elements # use a *global* function so cache can tell it's the same + elif isinstance(circuits, _CircuitList): + mx_fn = _mx_fn_from_elements_circuit_list + elif isinstance(circuits, list) and all([isinstance(el, _CircuitList) for el in circuits]): + mx_fn = _mx_fn_from_elements_circuit_list + extra_arg = (terms, objfn.layout, "sum") - - # (function, extra_arg) tuples - addl_hover_info_fns['outcomes'] = (_addl_mx_fn_outcomes, objfn.layout) - addl_hover_info_fns['p'] = (_mx_fn_from_elements, (objfn.probs, objfn.layout, "%.5g")) - addl_hover_info_fns['f'] = (_mx_fn_from_elements, (objfn.freqs, objfn.layout, "%.5g")) - addl_hover_info_fns['counts'] = (_mx_fn_from_elements, (objfn.counts, objfn.layout, "%d")) - + + if isinstance(circuits, _PlaquetteGridCircuitStructure): + # (function, extra_arg) tuples + addl_hover_info_fns['outcomes'] = (_addl_mx_fn_outcomes, objfn.layout) + addl_hover_info_fns['p'] = (_mx_fn_from_elements, (objfn.probs, objfn.layout, "%.5g")) + addl_hover_info_fns['f'] = (_mx_fn_from_elements, (objfn.freqs, objfn.layout, "%.5g")) + addl_hover_info_fns['counts'] = (_mx_fn_from_elements, (objfn.counts, objfn.layout, "%d")) + elif isinstance(circuits, _CircuitList): + # (function, extra_arg) tuples + addl_hover_info_fns['outcomes'] = (_addl_mx_fn_outcomes_circuit_list, objfn.layout) + addl_hover_info_fns['p'] = (_mx_fn_from_elements_circuit_list, (objfn.probs, objfn.layout, "%.5g")) + addl_hover_info_fns['f'] = (_mx_fn_from_elements_circuit_list, (objfn.freqs, objfn.layout, "%.5g")) + addl_hover_info_fns['counts'] = (_mx_fn_from_elements_circuit_list, (objfn.counts, objfn.layout, "%d")) + elif isinstance(circuits, list) and all([isinstance(el, _CircuitList) for el in circuits]): + addl_hover_info_fns['outcomes'] = (_addl_mx_fn_outcomes_circuit_list, objfn.layout) + addl_hover_info_fns['p'] = (_mx_fn_from_elements_circuit_list, (objfn.probs, objfn.layout, "%.5g")) + addl_hover_info_fns['f'] = (_mx_fn_from_elements_circuit_list, (objfn.freqs, objfn.layout, "%.5g")) + addl_hover_info_fns['counts'] = (_mx_fn_from_elements_circuit_list, (objfn.counts, objfn.layout, "%d")) + elif ptyp == "blank": colormapType = "trivial" ytitle = "" @@ -1777,23 +1890,116 @@ def _create(self, plottypes, circuits, dataset, model, prec, sum_up, box_labels, colormapType = submatrices.get(ptyp + ".colormap", "seq") else: raise ValueError("Invalid plot type: %s" % ptyp) - - circuit_struct = _PlaquetteGridCircuitStructure.cast(circuits) # , dataset? - + #TODO: propagate mdc_store down into compute_sub_mxs? if (submatrices is not None) and ptyp in submatrices: subMxs = submatrices[ptyp] # "custom" type -- all mxs precomputed by user - else: - subMxs = self._ccompute(_ph._compute_sub_mxs, circuit_struct, model, mx_fn, dataset, extra_arg) - addl_hover_info = _collections.OrderedDict() - for lbl, (addl_mx_fn, addl_extra_arg) in addl_hover_info_fns.items(): - if (submatrices is not None) and lbl in submatrices: - addl_subMxs = submatrices[lbl] # ever useful? + #some of the branches below rely on circuit_struct being defined, which is previously + #wasn't when hitting this condition on the if statement, so add those definitions here. + #also need to built the addl_hover_info as well, based on circuit_struct. + if isinstance(circuits, _PlaquetteGridCircuitStructure): + circuit_struct = circuits + + addl_hover_info = _collections.OrderedDict() + for lbl, (addl_mx_fn, addl_extra_arg) in addl_hover_info_fns.items(): + if (submatrices is not None) and lbl in submatrices: + addl_subMxs = submatrices[lbl] # ever useful? + else: + addl_subMxs = self._ccompute(_ph._compute_sub_mxs, circuit_struct, model, + addl_mx_fn, dataset, addl_extra_arg) + addl_hover_info[lbl] = addl_subMxs + + elif isinstance(circuits, _CircuitList): + circuit_struct = [circuits] + + addl_hover_info = _collections.OrderedDict() + for lbl, (addl_mx_fn, addl_extra_arg) in addl_hover_info_fns.items(): + if (submatrices is not None) and lbl in submatrices: + addl_subMxs = submatrices[lbl] # ever useful? + else: + addl_subMxs = self._ccompute(_ph._compute_sub_mxs_circuit_list, circuit_struct, model, + addl_mx_fn, dataset, addl_extra_arg) + addl_hover_info[lbl] = addl_subMxs + + elif isinstance(circuits, list) and all([isinstance(el, _CircuitList) for el in circuits]): + circuit_struct = circuits + + addl_hover_info = _collections.OrderedDict() + for lbl, (addl_mx_fn, addl_extra_arg) in addl_hover_info_fns.items(): + if (submatrices is not None) and lbl in submatrices: + addl_subMxs = submatrices[lbl] # ever useful? + else: + addl_subMxs = self._ccompute(_ph._compute_sub_mxs_circuit_list, circuit_struct, model, + addl_mx_fn, dataset, addl_extra_arg) + addl_hover_info[lbl] = addl_subMxs + + #Otherwise fall-back to the old casting behavior and proceed else: - addl_subMxs = self._ccompute(_ph._compute_sub_mxs, circuit_struct, model, - addl_mx_fn, dataset, addl_extra_arg) - addl_hover_info[lbl] = addl_subMxs + circuit_struct = _PlaquetteGridCircuitStructure.cast(circuits) + addl_hover_info = _collections.OrderedDict() + for lbl, (addl_mx_fn, addl_extra_arg) in addl_hover_info_fns.items(): + if (submatrices is not None) and lbl in submatrices: + addl_subMxs = submatrices[lbl] # ever useful? + else: + addl_subMxs = self._ccompute(_ph._compute_sub_mxs, circuit_struct, model, + addl_mx_fn, dataset, addl_extra_arg) + addl_hover_info[lbl] = addl_subMxs + + elif isinstance(circuits, _PlaquetteGridCircuitStructure): + circuit_struct= circuits + subMxs = self._ccompute(_ph._compute_sub_mxs, circuit_struct, model, mx_fn, dataset, extra_arg) + + addl_hover_info = _collections.OrderedDict() + for lbl, (addl_mx_fn, addl_extra_arg) in addl_hover_info_fns.items(): + if (submatrices is not None) and lbl in submatrices: + addl_subMxs = submatrices[lbl] # ever useful? + else: + addl_subMxs = self._ccompute(_ph._compute_sub_mxs, circuit_struct, model, + addl_mx_fn, dataset, addl_extra_arg) + addl_hover_info[lbl] = addl_subMxs + + #Add in alternative logic for constructing sub-matrices when we have either a CircuitList or a + #list of circuit lists: + elif isinstance(circuits, _CircuitList): + circuit_struct= [circuits] + subMxs = self._ccompute(_ph._compute_sub_mxs_circuit_list, circuit_struct, model, mx_fn, dataset, extra_arg) + + addl_hover_info = _collections.OrderedDict() + for lbl, (addl_mx_fn, addl_extra_arg) in addl_hover_info_fns.items(): + if (submatrices is not None) and lbl in submatrices: + addl_subMxs = submatrices[lbl] # ever useful? + else: + addl_subMxs = self._ccompute(_ph._compute_sub_mxs_circuit_list, circuit_struct, model, + addl_mx_fn, dataset, addl_extra_arg) + addl_hover_info[lbl] = addl_subMxs + + elif isinstance(circuits, list) and all([isinstance(el, _CircuitList) for el in circuits]): + circuit_struct= circuits + subMxs = self._ccompute(_ph._compute_sub_mxs_circuit_list, circuit_struct, model, mx_fn, dataset, extra_arg) + + addl_hover_info = _collections.OrderedDict() + for lbl, (addl_mx_fn, addl_extra_arg) in addl_hover_info_fns.items(): + if (submatrices is not None) and lbl in submatrices: + addl_subMxs = submatrices[lbl] # ever useful? + else: + addl_subMxs = self._ccompute(_ph._compute_sub_mxs_circuit_list, circuit_struct, model, + addl_mx_fn, dataset, addl_extra_arg) + addl_hover_info[lbl] = addl_subMxs + + #Otherwise fall-back to the old casting behavior and proceed + else: + circuit_struct = _PlaquetteGridCircuitStructure.cast(circuits) # , dataset? + subMxs = self._ccompute(_ph._compute_sub_mxs, circuit_struct, model, mx_fn, dataset, extra_arg) + + addl_hover_info = _collections.OrderedDict() + for lbl, (addl_mx_fn, addl_extra_arg) in addl_hover_info_fns.items(): + if (submatrices is not None) and lbl in submatrices: + addl_subMxs = submatrices[lbl] # ever useful? + else: + addl_subMxs = self._ccompute(_ph._compute_sub_mxs, circuit_struct, model, + addl_mx_fn, dataset, addl_extra_arg) + addl_hover_info[lbl] = addl_subMxs if colormapType == "linlog": if dataset is None: @@ -1827,9 +2033,17 @@ def _create(self, plottypes, circuits, dataset, model, prec, sum_up, box_labels, elif colormapType in ("seq", "revseq", "blueseq", "redseq"): if len(subMxs) > 0: - max_abs = max([_np.max(_np.abs(_np.nan_to_num(subMxs[iy][ix]))) - for ix in range(len(circuit_struct.used_xs)) - for iy in range(len(circuit_struct.used_ys))]) + if isinstance(circuit_struct, _PlaquetteGridCircuitStructure): + max_abs = max([_np.max(_np.abs(_np.nan_to_num(subMxs[iy][ix]))) + for ix in range(len(circuit_struct.used_xs)) + for iy in range(len(circuit_struct.used_ys))]) + #circuit_struct logic above should mean that we always have at least a length 1 list of + #CircuitList objects if not a plaquette circuit structure by this point. + elif isinstance(circuit_struct, list) and all([isinstance(el, _CircuitList) for el in circuit_struct]): + max_abs = max([_np.max(_np.abs(_np.nan_to_num(subMxs[i][j]))) + for i, ckt_list in enumerate(circuit_struct) + for j in range(len(ckt_list))]) + else: max_abs = 0 if max_abs == 0: max_abs = 1e-6 # pick a nonzero value if all entries are zero or nan if colormapType == "seq": color = "whiteToBlack" @@ -1841,7 +2055,15 @@ def _create(self, plottypes, circuits, dataset, model, prec, sum_up, box_labels, else: assert(False), "Internal logic error" # pragma: no cover if typ == "boxes": - newfig = _circuit_color_boxplot(circuit_struct, subMxs, colormap, + if not isinstance(circuit_struct, _PlaquetteGridCircuitStructure): + #if not a plaquette structure then maybe try returning a NotApplicable object + #for the figure? + return NotApplicable(self.ws) + else: + #I am expecting this cast won't do anything at the moment, but + #maybe down the line it will. + circuit_struct= _PlaquetteGridCircuitStructure.cast(circuits) + newfig = _circuit_color_boxplot(circuit_struct, subMxs, colormap, colorbar, box_labels, prec, hover_info, sum_up, invert, scale, bgcolor, addl_hover_info) @@ -1897,16 +2119,33 @@ def _create(self, plottypes, circuits, dataset, model, prec, sum_up, box_labels, #Helper function for ColorBoxPlot matrix computation def _mx_fn_from_elements(plaq, x, y, extra): - return plaq.elementvec_to_matrix(extra[0], extra[1], mergeop=extra[2]) - + return plaq.elementvec_to_array(extra[0], extra[1], mergeop=extra[2]) + +#modified version of the above meant for working with circuit lists +def _mx_fn_from_elements_circuit_list(circuit_list, extra): + #Based on the convention above in the ColorBoxPlot code it looks likelihood + #extra[0] is the thing we want to index into, extra[1] is the layout and extra[2] + #is something called the merge op, which indicated how to combine the elements of extra[0] + #for each circuit in the circuit_list + if isinstance(circuit_list, _CircuitList): + pass + elif isinstance(circuit_list, list) and all([isinstance(el, _CircuitList) for el in circuit_list]): + circuit_list = _CircuitList.cast(circuit_list) + else: + msg = 'Invalid type. _mx_fn_from_elements_circuit_list is only presently implemented for CircuitList'\ + +'objects and lists of Circuit objects.' + raise ValueError(msg) + return circuit_list.elementvec_to_array(extra[0], extra[1], mergeop=extra[2]) + def _mx_fn_blank(plaq, x, y, unused): return _np.nan * _np.zeros((plaq.num_rows, plaq.num_cols), 'd') def _mx_fn_errorrate(plaq, x, y, direct_gst_models): # error rate as 1x1 matrix which we have plotting function sum up base_circuit = plaq.base if isinstance(plaq, _GermFiducialPairPlaquette) \ - else _Circuit(()) + else _Circuit((), line_labels=list(direct_gst_models.keys())[0].line_labels) #Taking the line labels from the first circuit in direct_gst_models will probably work + #most of the time. TODO: Cook up a better scheme. return _np.array([[_ph.small_eigenvalue_err_rate(base_circuit, direct_gst_models)]]) @@ -1957,6 +2196,15 @@ def _addl_mx_fn_outcomes(plaq, x, y, layout): slmx[i, j] = ", ".join([_outcome_to_str(ol) for ol in layout.outcomes(opstr)]) return slmx +#modified version of the above function meant to work for CircuitList objects +def _addl_mx_fn_outcomes_circuit_list(circuit_list, layout): + slmx = _np.empty(len(circuit_list), dtype=_np.object_) + for i,ckt in enumerate(circuit_list): + slmx[i] = ", ".join([_outcome_to_str(ol) for ol in layout.outcomes(ckt)]) + return slmx + + + class GateMatrixPlot(WorkspacePlot): """ diff --git a/pygsti/tools/fastcalc.pyx b/pygsti/tools/fastcalc.pyx index f20b9d0ae..bed8e6c23 100644 --- a/pygsti/tools/fastcalc.pyx +++ b/pygsti/tools/fastcalc.pyx @@ -50,7 +50,7 @@ def embedded_fast_acton_sparse(embedded_gate_acton_fn, cdef np.ndarray[double, ndim=1, mode="c"] slc1 = np.empty(nActionIndices, dtype='d') cdef np.ndarray[double, ndim=1, mode="c"] slc2 = np.empty(nActionIndices, dtype='d') - # nActionIndices = np.product(numBasisEls_action) + # nActionIndices = np.prod(numBasisEls_action) #for i in range(nAction): # nActionIndices *= numBasisEls_action[i] @@ -274,7 +274,7 @@ def embedded_fast_acton_sparse_complex(embedded_gate_acton_fn, cdef np.ndarray[np.complex128_t, ndim=1, mode="c"] slc1 = np.empty(nActionIndices, dtype=np.complex128) cdef np.ndarray[np.complex128_t, ndim=1, mode="c"] slc2 = np.empty(nActionIndices, dtype=np.complex128) - # nActionIndices = np.product(numBasisEls_action) + # nActionIndices = np.prod(numBasisEls_action) #for i in range(nAction): # nActionIndices *= numBasisEls_action[i] diff --git a/pygsti/tools/internalgates.py b/pygsti/tools/internalgates.py index 8f320b93c..b03032768 100644 --- a/pygsti/tools/internalgates.py +++ b/pygsti/tools/internalgates.py @@ -16,6 +16,7 @@ from pygsti.tools import optools as _ot from pygsti.tools import symplectic as _symp from pygsti.baseobjs.unitarygatefunction import UnitaryGateFunction as _UnitaryGateFunction +from pygsti.tools.gatetools import sigmax, sigmay, sigmaz, sigmaxz class Gzr(_UnitaryGateFunction): @@ -192,14 +193,18 @@ def standard_gatename_unitaries(): * 'Gxmpi2','Gympi2','Gzmpi2' : 1Q -pi/2 rotations around X, Y and Z. * 'Gh' : Hadamard. * 'Gp', 'Gpdag' : phase and inverse phase (an alternative notation/name for Gzpi and Gzmpi2). - * 'Gci' where `i = 0, 1, ..., 23` : the 24 1-qubit Cliffor gates (all the gates above are included as one of these). - * 'Gcphase','Gcnot','Gswap' : standard 2Q gates. - + * 'Gci' where `i = 0, 1, ..., 23` : the 24 1-qubit Clifford gates (all the gates above are included as one of these). + * 'Gcphase','Gcnot','Gswap', 'Giswap' : standard 2Q gates. + * 'Gsqrtiswap' : square-root of ISWAP gate, used in some superconducting qubit platforms. + * 'Gxx', 'Gzz' : MS-style parity gates + * 'Gcres', 'Gecres' : Cross-resonance and echoed cross-resonance gates. Native gate operations common on transmon systems (including IBM). + * Non-Clifford gates: * 'Gt', 'Gtdag' : the T and inverse T gates (T is a Z rotation by pi/4). * 'Gzr' : a parameterized gate that is a Z rotation by an angle, where when the angle = pi then it equals Z. - + * 'Gn' : N gate, pi/2 rotation about the (np.sqrt(3)/2, 0, -1/2) axis of the Bloch sphere, native gate in some spin qubit systems. + Mostly, pyGSTi does not assume that a gate with one of these names is indeed the unitary specified here. Instead, these names are intended as short-hand for defining ProcessorSpecs and n-qubit models. Moreover, when these names @@ -212,10 +217,6 @@ def standard_gatename_unitaries(): """ std_unitaries = {} - sigmax = _np.array([[0, 1], [1, 0]]) - sigmay = _np.array([[0, -1.0j], [1.0j, 0]]) - sigmaz = _np.array([[1, 0], [0, -1]]) - def u_op(exp): return _np.array(_spl.expm(-1j * exp / 2), complex) @@ -233,6 +234,11 @@ def u_op(exp): std_unitaries['Gympi2'] = u_op(-1 * _np.pi / 2 * sigmay) std_unitaries['Gzmpi2'] = u_op(-1 * _np.pi / 2 * sigmaz) + std_unitaries['Gxpi4'] = u_op(_np.pi / 4 * sigmax) + std_unitaries['Gypi4'] = u_op(_np.pi / 4 * sigmay) + std_unitaries['Gzpi4'] = u_op(_np.pi / 4 * sigmaz) + + H = (1 / _np.sqrt(2)) * _np.array([[1., 1.], [1., -1.]], complex) P = _np.array([[1., 0.], [0., 1j]], complex) Pdag = _np.array([[1., 0.], [0., -1j]], complex) @@ -245,6 +251,11 @@ def u_op(exp): #std_unitaries['Ghph'] = _np.dot(H,_np.dot(P,H)) std_unitaries['Gt'] = _np.array([[1., 0.], [0., _np.exp(1j * _np.pi / 4)]], complex) std_unitaries['Gtdag'] = _np.array([[1., 0.], [0., _np.exp(-1j * _np.pi / 4)]], complex) + + #N gate, pi/2 rotation about the (np.sqrt(3)/2, 0, -1/2) axis of the Bloch sphere + #native gate in some spin qubit systems. + std_unitaries['Gn'] = _spl.expm(-1j*(_np.pi/4)*((_np.sqrt(3)/2)*sigmax - (.5)*sigmaz)) + # The 1-qubit Clifford group. The labelling is the same as in the the 1-qubit Clifford group generated # in pygsti.extras.rb.group, and also in the internal standard unitary (but with 'Gci' -> 'Ci') std_unitaries['Gc0'] = _np.array([[1, 0], [0, 1]], complex) # This is Gi @@ -273,6 +284,7 @@ def u_op(exp): std_unitaries['Gc21'] = _np.array([[1, -1], [1, 1]], complex) / _np.sqrt(2) # This is Gypi2 (up to phase) std_unitaries['Gc22'] = _np.array([[0.5 + 0.5j, 0.5 - 0.5j], [-0.5 + 0.5j, -0.5 - 0.5j]], complex) std_unitaries['Gc23'] = _np.array([[1, 0], [0, -1j]], complex) # This is Gzmpi2 / Gpdag (up to phase) + # Two-qubit gates std_unitaries['Gcphase'] = _np.array([[1., 0., 0., 0.], [0., 1., 0., 0.], [ 0., 0., 1., 0.], [0., 0., 0., -1.]], complex) @@ -285,10 +297,21 @@ def u_op(exp): std_unitaries['Gswap'] = _np.array([[1., 0., 0., 0.], [0., 0., 1., 0.], [0., 1., 0., 0.], [0., 0., 0., 1.]], complex) + std_unitaries['Giswap'] = _np.array([[1., 0., 0., 0.], [0., 0., 1j, 0.], + [0., 1j, 0., 0.], [0., 0., 0., 1.]], complex) + + std_unitaries['Gsqrtiswap'] = _np.array([[1., 0., 0., 0.], [0., 1/_np.sqrt(2), 1j/_np.sqrt(2), 0.], + [0., 1j/_np.sqrt(2), 1/_np.sqrt(2), 0.], [0., 0., 0., 1.]], complex) + + #cross-resonance gate (exp(-1j*pi/4 sigmaxz)) + std_unitaries['Gcres'] = _spl.expm(-1j*_np.pi/4*sigmaxz) + std_unitaries['Gecres'] = _np.array([[0, 1, 0., 1j], [1., 0, -1j, 0.], + [0., 1j, 0, 1], [-1j, 0., 1, 0]], complex)/_np.sqrt(2) + std_unitaries['Gzr'] = Gzr() std_unitaries['Gczr'] = Gczr() - #Add these at the end, since we don't want unitary_to_standard_gatenemt to return these "shorthand" names + #Add these at the end, since we don't want unitary_to_standard_gatenames to return these "shorthand" names std_unitaries['Gx'] = std_unitaries['Gxpi2'] std_unitaries['Gy'] = std_unitaries['Gypi2'] std_unitaries['Gz'] = std_unitaries['Gzpi2'] @@ -296,7 +319,7 @@ def u_op(exp): return std_unitaries -def unitary_to_standard_gatename(unitary): +def unitary_to_standard_gatename(unitary, up_to_phase = False, return_phase = False): """ Looks up and returns the standard gate name for a unitary gate matrix, if one exists. @@ -305,6 +328,16 @@ def unitary_to_standard_gatename(unitary): unitary : complex np.array The unitary to convert. + up_to_phase : bool, optional (default False) + If true then after checking if the unitary is exactly equivalent to a built-in one, + this then checks if the input unitary is equal to to a built-in one up to a global + phase. + + return_phase : bool, optional (default False) + If true, and up_to_phase is true, then if a unitary is equivalent up to a global + phase to a built-in one, we return that phase (i.e. the phase the built-in one + would need to be multiplied by). + Returns ------- str or None @@ -314,6 +347,28 @@ def unitary_to_standard_gatename(unitary): for std_name, U in standard_gatename_unitaries().items(): if not callable(U) and not callable(unitary) and U.shape == unitary.shape and _np.allclose(unitary, U): return std_name + + #check for equivalence up to a global phase. + if up_to_phase: + for std_name, U in standard_gatename_unitaries().items(): + #I think the callable checks are to avoid doing the check on the continuously parameterized Z + #rotation that is in the built-in dictionary. Follow the original code's lead and do the same here. + if not callable(U) and not callable(unitary) and U.shape == unitary.shape: + + inv_prod = U.conj().T@unitary + inv_prod_diag = _np.diag(inv_prod) + inv_prod_upper = _np.triu(inv_prod, 1) + inv_prod_lower = _np.tril(inv_prod, -1) + + #If all of the diagonals are close to the same value, and all the the off diagonals + #are close to 0 then we should be proportional to the identity. + if _np.allclose(inv_prod_diag, inv_prod_diag[0]) and _np.allclose(inv_prod_upper, 0) and _np.allclose(inv_prod_lower, 0): + if return_phase: + phase = inv_prod_diag[0] + return std_name, phase + else: + return std_name + return None def standard_gatenames_stim_conversions(): """ @@ -366,12 +421,11 @@ def standard_gatenames_cirq_conversions(): Currently there are some standard gate names with no conversion to cirq. - TODO: add Clifford gates with - https://cirq.readthedocs.io/en/latest/generated/cirq.SingleQubitCliffordGate.html - Returns ------- - dict mapping strings to string + std_gatenames_to_cirq + dict mapping strings corresponding to standard built-in pyGSTi names to + corresponding cirq operation objects. """ try: import cirq @@ -379,7 +433,10 @@ def standard_gatenames_cirq_conversions(): raise ImportError("Cirq is required for this operation, and it does not appear to be installed.") std_gatenames_to_cirq = {} - std_gatenames_to_cirq['Gi'] = None + + #single-qubit gates + + std_gatenames_to_cirq['Gi'] = cirq.I std_gatenames_to_cirq['Gxpi2'] = cirq.XPowGate(exponent=1 / 2) std_gatenames_to_cirq['Gxmpi2'] = cirq.XPowGate(exponent=-1 / 2) std_gatenames_to_cirq['Gxpi'] = cirq.X @@ -394,12 +451,87 @@ def standard_gatenames_cirq_conversions(): std_gatenames_to_cirq['Gh'] = cirq.H std_gatenames_to_cirq['Gt'] = cirq.T std_gatenames_to_cirq['Gtdag'] = cirq.T**-1 + std_gatenames_to_cirq['Gn'] = cirq.PhasedXZGate(axis_phase_exponent=0.14758361765043326, + x_exponent=0.4195693767448338, + z_exponent=-0.2951672353008665) + + #two-qubit gates + std_gatenames_to_cirq['Gcphase'] = cirq.CZ std_gatenames_to_cirq['Gcnot'] = cirq.CNOT std_gatenames_to_cirq['Gswap'] = cirq.SWAP + std_gatenames_to_cirq['Gzz'] = cirq.ZZPowGate(exponent=.5, global_shift=-.5) + std_gatenames_to_cirq['Gxx'] = cirq.XXPowGate(exponent=.5, global_shift=-.5) + std_gatenames_to_cirq['Giswap'] = cirq.ISWAP + std_gatenames_to_cirq['Gsqrtiswap'] = cirq.SQRT_ISWAP + #I don't presently see a one-to-one conversion for cross-resonance + + #single-qubit clifford group + + std_gatenames_to_cirq['Gc0'] = cirq.I # This is Gi + std_gatenames_to_cirq['Gc1'] = cirq.PhasedXZGate(axis_phase_exponent=0.0, x_exponent=0.5, z_exponent=0.5) + std_gatenames_to_cirq['Gc2'] = cirq.PhasedXZGate(axis_phase_exponent=0.5, x_exponent=-0.5, z_exponent=-0.5) + std_gatenames_to_cirq['Gc3'] = cirq.X # This is pauli X + std_gatenames_to_cirq['Gc4'] = cirq.PhasedXZGate(axis_phase_exponent=0.0, x_exponent=-0.5, z_exponent=0.5) + std_gatenames_to_cirq['Gc5'] = cirq.PhasedXZGate(axis_phase_exponent=0.5, x_exponent=-0.5, z_exponent=0.5) + std_gatenames_to_cirq['Gc6'] = cirq.Y # This is pauli Y + std_gatenames_to_cirq['Gc7'] = cirq.PhasedXZGate(axis_phase_exponent=0.0, x_exponent=0.5, z_exponent=-0.5) + std_gatenames_to_cirq['Gc8'] = cirq.PhasedXZGate(axis_phase_exponent=0.5, x_exponent=0.5, z_exponent=-0.5) + std_gatenames_to_cirq['Gc9'] = cirq.Z # This is pauli Z + std_gatenames_to_cirq['Gc10'] = cirq.PhasedXZGate(axis_phase_exponent=0.0, x_exponent=-0.5, z_exponent=-0.5) + std_gatenames_to_cirq['Gc11'] = cirq.PhasedXZGate(axis_phase_exponent=0.5, x_exponent=0.5, z_exponent=0.5) + std_gatenames_to_cirq['Gc12'] = cirq.H # This is Gh + std_gatenames_to_cirq['Gc13'] = cirq.PhasedXZGate(axis_phase_exponent=0.0, x_exponent=-0.5, z_exponent=0.0) # This is Gxmpi2 (up to phase) + std_gatenames_to_cirq['Gc14'] = cirq.PhasedXZGate(axis_phase_exponent=0.0, x_exponent=0.0, z_exponent=0.5) # THis is Gzpi2 / Gp (up to phase) + std_gatenames_to_cirq['Gc15'] = cirq.PhasedXZGate(axis_phase_exponent=0.5, x_exponent=-0.5, z_exponent=0.0)# This is Gympi2 (up to phase) + std_gatenames_to_cirq['Gc16'] = cirq.PhasedXZGate(axis_phase_exponent=0.0, x_exponent=0.5, z_exponent=0.0)# This is Gxpi2 (up to phase) + std_gatenames_to_cirq['Gc17'] = cirq.PhasedXZGate(axis_phase_exponent=0.25, x_exponent=1.0, z_exponent=0.0)# This is Gypi2 (up to phase) + std_gatenames_to_cirq['Gc18'] = cirq.PhasedXZGate(axis_phase_exponent=0.5, x_exponent=0.5, z_exponent=1.0) + std_gatenames_to_cirq['Gc19'] = cirq.PhasedXZGate(axis_phase_exponent=0.0, x_exponent=-0.5, z_exponent=1.0) + std_gatenames_to_cirq['Gc20'] = cirq.PhasedXZGate(axis_phase_exponent=-0.25, x_exponent=1.0, z_exponent=0.0) + std_gatenames_to_cirq['Gc21'] = cirq.PhasedXZGate(axis_phase_exponent=0.5, x_exponent=0.5, z_exponent=0.0) # This is Gypi2 (up to phase) + std_gatenames_to_cirq['Gc22'] = cirq.PhasedXZGate(axis_phase_exponent=0.0, x_exponent=0.5, z_exponent=1.0) + std_gatenames_to_cirq['Gc23'] = cirq.PhasedXZGate(axis_phase_exponent=0.0, x_exponent=0.0, z_exponent=-0.5) # This is Gzmpi2 / Gpdag (up to phase) + + #legacy aliasing: + std_gatenames_to_cirq['Gx'] = std_gatenames_to_cirq['Gxpi2'] + std_gatenames_to_cirq['Gy'] = std_gatenames_to_cirq['Gypi2'] + std_gatenames_to_cirq['Gz'] = std_gatenames_to_cirq['Gzpi2'] + return std_gatenames_to_cirq +def cirq_gatenames_standard_conversions(): + + """ + A dictionary converting cirq gates to built-in pyGSTi names for these gates. + Does not currently support conversion of all cirq gate types. + """ + + try: + import cirq + except ImportError: + raise ImportError("Cirq is required for this operation, and it does not appear to be installed.") + + + #reverse the mapping in standard_gatenames_cirq_conversions + cirq_to_standard_mapping = {value: key for key,value in standard_gatenames_cirq_conversions().items()} + + #A direct reversing doesn't quite do what we want since the originally mapping was not + #one-to-one (some pyGSTi gate names refer to the same cirq Circuit, primarily because of the cliffords). + #Manually add back in some preference on the non-one-to-one gates. + cirq_to_standard_mapping[cirq.I] = 'Gi' + cirq_to_standard_mapping[cirq.X] = 'Gxpi' + cirq_to_standard_mapping[cirq.Y] = 'Gypi' + cirq_to_standard_mapping[cirq.PhasedXZGate(axis_phase_exponent=0.5, x_exponent=-1, z_exponent=0)] = 'Gypi' + cirq_to_standard_mapping[cirq.Z] = 'Gzpi' + cirq_to_standard_mapping[cirq.XPowGate(exponent=1 / 2)] = 'Gxpi2' + cirq_to_standard_mapping[cirq.YPowGate(exponent=1 / 2)] = 'Gypi2' + cirq_to_standard_mapping[cirq.ZPowGate(exponent=1 / 2)] = 'Gzpi2' + cirq_to_standard_mapping[cirq.H] = 'Gh' + + return cirq_to_standard_mapping + def standard_gatenames_quil_conversions(): """ diff --git a/pygsti/tools/matrixmod2.py b/pygsti/tools/matrixmod2.py index f3144ea08..4c1854939 100644 --- a/pygsti/tools/matrixmod2.py +++ b/pygsti/tools/matrixmod2.py @@ -468,7 +468,7 @@ def fix_top(a): found_B = False for ind in range(t): aa, P = permute_top(a, ind) - B = _np.round_(aa[1:, 1:]) + B = _np.round(aa[1:, 1:]) if det_mod2(B) == 0: continue diff --git a/pygsti/tools/optools.py b/pygsti/tools/optools.py index e4a84aec2..fab37e8a0 100644 --- a/pygsti/tools/optools.py +++ b/pygsti/tools/optools.py @@ -402,11 +402,13 @@ def entanglement_fidelity(a, b, mx_basis='pp', is_tp=None, is_unitary=None): Parameters ---------- - a : numpy array - First matrix. + a : array or gate + The gate to compute the entanglement fidelity to b of. E.g., an + imperfect implementation of b. - b : numpy array - Second matrix. + b : array or gate + The gate to compute the entanglement fidelity to a of. E.g., the + target gate corresponding to a. mx_basis : {'std', 'gm', 'pp', 'qt'} or Basis object The basis of the matrices. Allowed values are Matrix-unit (std), @@ -430,6 +432,15 @@ def entanglement_fidelity(a, b, mx_basis='pp', is_tp=None, is_unitary=None): ------- float """ + from pygsti.modelmembers.operations.linearop import LinearOperator as _LinearOperator + + # Attempt to cast to dense array. If this is already an array, the AttributeError + # will be suppressed. + if isinstance(a, _LinearOperator): + a = a.to_dense() + if isinstance(b, _LinearOperator): + b = b.to_dense() + d2 = a.shape[0] #if the tp flag isn't set we'll calculate whether it is true here @@ -504,6 +515,12 @@ def average_gate_fidelity(a, b, mx_basis='pp', is_tp=None, is_unitary=None): AGI : float The AGI of a to b. """ + from pygsti.modelmembers.operations.linearop import LinearOperator as _LinearOperator + + # Cast to dense to ensure we can extract the shape. + if isinstance(a, _LinearOperator): + a = a.to_dense() + d = int(round(_np.sqrt(a.shape[0]))) PF = entanglement_fidelity(a, b, mx_basis, is_tp, is_unitary) AGF = (d * PF + 1) / (1 + d) @@ -710,6 +727,12 @@ def unitarity(a, mx_basis="gm"): ------- float """ + from pygsti.modelmembers.operations.linearop import LinearOperator as _LinearOperator + + # Cast to dense to ensure we can extract the shape. + if isinstance(a, _LinearOperator): + a = a.to_dense() + d = int(round(_np.sqrt(a.shape[0]))) basisMxs = _bt.basis_matrices(mx_basis, a.shape[0]) diff --git a/scripts/api_names.yaml b/scripts/api_names.yaml index f0b76d1c0..81f4e0d68 100644 --- a/scripts/api_names.yaml +++ b/scripts/api_names.yaml @@ -621,7 +621,7 @@ objects: CircuitPlaquette: __name__: null copy: null - elementvec_to_matrix: null + elementvec_to_array: null expand_aliases: null get_all_strs: all_strs # XXX make property? iter_simplified: null diff --git a/setup.py b/setup.py index 271c6cc91..b16b17669 100644 --- a/setup.py +++ b/setup.py @@ -64,7 +64,7 @@ 'pytest-cov', 'nbval', 'csaps', - 'cvxopt<=1.3.0.1', + 'cvxopt', 'cvxpy', 'cython', 'matplotlib', diff --git a/test/test_packages/algorithms/basecase.py b/test/test_packages/algorithms/basecase.py index da1644196..e66fa9abf 100644 --- a/test/test_packages/algorithms/basecase.py +++ b/test/test_packages/algorithms/basecase.py @@ -18,7 +18,7 @@ def setUp(self): self.op_labels = list(self.model.operations.keys()) # also == std.gates self.lgstStrings = pygsti.circuits.create_lgst_circuits(self.fiducials, self.fiducials, self.op_labels) - self.maxLengthList = [0,1,2,4,8] + self.maxLengthList = [1,2,4,8] self.elgstStrings = pygsti.circuits.create_elgst_lists( self.op_labels, self.germs, self.maxLengthList ) diff --git a/test/test_packages/algorithms/test_autoexperimentdesign.py b/test/test_packages/algorithms/test_autoexperimentdesign.py deleted file mode 100644 index 96e0e817b..000000000 --- a/test/test_packages/algorithms/test_autoexperimentdesign.py +++ /dev/null @@ -1,88 +0,0 @@ -import unittest - -import pygsti.circuits.gstcircuits as gstcircuits -import pygsti.models.modelconstruction as mc -import pygsti.algorithms.fiducialselection as fidsel -import pygsti.algorithms.germselection as germsel -from ..testutils import BaseTestCase - - -class AutoExperimentDesignTestCase(BaseTestCase): - - def setUp(self): - super(AutoExperimentDesignTestCase, self).setUp() - - def test_auto_experiment_design(self): - # Let's construct a 1-qubit $X(\pi/2)$, $Y(\pi/2)$, $I$ model for which we will need to find germs and fiducials. - - target_model = mc.create_explicit_model_from_expressions([('Q0',)], ['Gi', 'Gx', 'Gy'], - ["I(Q0)", "X(pi/2,Q0)", "Y(pi/2,Q0)"]) - - - # ## Hands-off - - # We begin by demonstrating the most hands-off approach. - - # We can generate a germ set simply by providing the target model. (and seed so it's deterministic) - - germs = germsel.find_germs(target_model, seed=2017) - - - # In the same way we can generate preparation and measurement fiducials. - - - prepFiducials, measFiducials = fidsel.find_fiducials(target_model) - - #test return_all - this just prints more info... - p,m = fidsel.find_fiducials(target_model, algorithm_kwargs={'return_all': True}) - - #test invalid algorithm - with self.assertRaises(ValueError): - fidsel.find_fiducials(target_model, algorithm='foobar') - - - # Now that we have germs and fiducials, we can construct the list of experiments we need to perform in - # order to do GST. The only new things to provide at this point are the sizes for the experiments we want - # to perform (in this case we want to perform between 0 and 256 gates between fiducial pairs, going up - # by a factor of 2 at each stage). - - - maxLengths = [0] + [2**n for n in range(8 + 1)] - listOfExperiments = gstcircuits.create_lsgst_circuits(target_model.operations.keys(), prepFiducials, - measFiducials, germs, maxLengths) - - - # The list of `Circuit` that the previous function gave us isn't necessarily the most readable - # form to present the information in, so we can write the experiment list out to an empty data - # file to be filled in after the experiments are performed. - - graspGerms = germsel.find_germs(target_model, algorithm='grasp', - seed=2017, num_gs_copies=2, - candidate_germ_counts={3: 'all upto', 4:10, 5:10, 6:10}, - candidate_seed=2017, - algorithm_kwargs={'iterations': 1}) - slackPrepFids, slackMeasFids = fidsel.find_fiducials(target_model, algorithm='slack', - algorithm_kwargs={'slack_frac': 0.25}) - fidsel.find_fiducials(target_model, algorithm='slack') # slacFrac == 1.0 if don't specify either slack_frac or fixed_slack - - - germsMaxLength3 = germsel.find_germs(target_model, candidate_germ_counts={3: 'all upto'}, seed=2017) - - uniformPrepFids, uniformMeasFids = fidsel.find_fiducials(target_model, max_fid_length=3, - algorithm='grasp', - algorithm_kwargs={'iterations': 100}) - - - incompletePrepFids, incompleteMeasFids = fidsel.find_fiducials(target_model, max_fid_length=1) - - nonSingletonGerms = germsel.find_germs(target_model, num_gs_copies=2, force=None, candidate_germ_counts={4: 'all upto'}, - algorithm='grasp', algorithm_kwargs={'iterations': 5}, - seed=2017) - - - omitIdentityPrepFids, omitIdentityMeasFids = fidsel.find_fiducials(target_model, omit_identity=False, - ops_to_omit=['Gi']) - - -if __name__ == '__main__': - unittest.main(verbosity=2) diff --git a/test/test_packages/algorithms/test_core.py b/test/test_packages/algorithms/test_core.py index 73664ccf2..f3d9a8dac 100644 --- a/test/test_packages/algorithms/test_core.py +++ b/test/test_packages/algorithms/test_core.py @@ -6,9 +6,7 @@ import pygsti import numpy as np -from scipy import polyfit -from ..testutils import compare_files, regenerate_references from .basecase import AlgorithmsBase class TestCoreMethods(AlgorithmsBase): @@ -16,28 +14,13 @@ def test_LGST(self): ds = self.ds - print("GG0 = ",self.model.default_gauge_group) mdl_lgst = pygsti.run_lgst(ds, self.fiducials, self.fiducials, self.model, svd_truncate_to=4, verbosity=0) mdl_lgst_verb = self.runSilent(pygsti.run_lgst, ds, self.fiducials, self.fiducials, self.model, svd_truncate_to=4, verbosity=10) self.assertAlmostEqual(mdl_lgst.frobeniusdist(mdl_lgst_verb),0) - print("GG = ",mdl_lgst.default_gauge_group) mdl_lgst_go = pygsti.gaugeopt_to_target(mdl_lgst, self.model, {'spam':1.0, 'gates': 1.0}, check_jac=True) mdl_clgst = pygsti.contract(mdl_lgst_go, "CPTP") - # RUN BELOW LINES TO SEED SAVED GATESET FILES - if regenerate_references(): - pygsti.io.write_model(mdl_lgst, compare_files + "/lgst.model", "Saved LGST Model before gauge optimization") - pygsti.io.write_model(mdl_lgst_go, compare_files + "/lgst_go.model", "Saved LGST Model after gauge optimization") - pygsti.io.write_model(mdl_clgst, compare_files + "/clgst.model", "Saved LGST Model after G.O. and CPTP contraction") - - mdl_lgst_compare = pygsti.io.load_model(compare_files + "/lgst.model") - mdl_lgst_go_compare = pygsti.io.load_model(compare_files + "/lgst_go.model") - mdl_clgst_compare = pygsti.io.load_model(compare_files + "/clgst.model") - - self.assertAlmostEqual( mdl_lgst.frobeniusdist(mdl_lgst_compare), 0, places=5) - self.assertAlmostEqual( mdl_lgst_go.frobeniusdist(mdl_lgst_go_compare), 0, places=5) - self.assertAlmostEqual( mdl_clgst.frobeniusdist(mdl_clgst_compare), 0, places=5) def test_LGST_no_sample_error(self): #change rep-count type so dataset can hold fractional counts for sampleError = 'none' @@ -48,20 +31,12 @@ def test_LGST_no_sample_error(self): pygsti.data.dataset.Repcount_type = oldType mdl_lgst = pygsti.run_lgst(ds, self.fiducials, self.fiducials, self.model, svd_truncate_to=4, verbosity=0) - print("DATAGEN:") - print(self.datagen_gateset) - print("\nLGST RAW:") - print(mdl_lgst) mdl_lgst = pygsti.gaugeopt_to_target(mdl_lgst, self.datagen_gateset, {'spam':1.0, 'gates': 1.0}, check_jac=False) - print("\nAfter gauge opt:") - print(mdl_lgst) - print(mdl_lgst.strdiff(self.datagen_gateset)) self.assertAlmostEqual( mdl_lgst.frobeniusdist(self.datagen_gateset), 0, places=4) def test_LGST_1overSqrtN_dependence(self): my_datagen_gateset = self.model.depolarize(op_noise=0.05, spam_noise=0) # !!don't depolarize spam or 1/sqrt(N) dependence saturates!! - nSamplesList = np.array([ 16, 128, 1024, 8192 ]) diffs = [] for nSamples in nSamplesList: @@ -72,7 +47,9 @@ def test_LGST_1overSqrtN_dependence(self): diffs.append( my_datagen_gateset.frobeniusdist(mdl_lgst_go) ) diffs = np.array(diffs, 'd') - a, b = polyfit(np.log10(nSamplesList), np.log10(diffs), deg=1) + p = np.polyfit(np.log10(nSamplesList), np.log10(diffs), deg=1) + a = p[0] + b = p[1] #print "\n",nSamplesList; print diffs; print a #DEBUG self.assertLess( a+0.5, 0.05 ) diff --git a/test/test_packages/algorithms/test_fiducialpairreduction.py b/test/test_packages/algorithms/test_fiducialpairreduction.py index 923d00870..1816307ed 100644 --- a/test/test_packages/algorithms/test_fiducialpairreduction.py +++ b/test/test_packages/algorithms/test_fiducialpairreduction.py @@ -3,7 +3,7 @@ import pygsti from pygsti.algorithms import germselection -from pygsti.modelpacks.legacy import std1Q_XYI as std +from pygsti.modelpacks import smq1Q_XYI as std from .algorithmsTestCase import AlgorithmTestCase from ..testutils import compare_files, regenerate_references @@ -12,82 +12,39 @@ class FiducialPairReductionTestCase(AlgorithmTestCase): def test_memlimit(self): with self.assertRaises(MemoryError): # A very low memlimit - pygsti.alg.find_sufficient_fiducial_pairs(std.target_model(), std.fiducials, std.fiducials, - std.germs, test_pair_list=[(0,0),(0,1),(1,0)], + pygsti.alg.find_sufficient_fiducial_pairs(std.target_model(), std.prep_fiducials(), std.meas_fiducials(), + std.germs(lite=True), test_pair_list=[(0,0),(0,1),(1,0)], verbosity=0, mem_limit=100) # 100 bytes! - # A low memlimit - pygsti.alg.find_sufficient_fiducial_pairs(std.target_model(), std.fiducials, std.fiducials, - std.germs, test_pair_list=[(0,0),(0,1),(1,0)], - verbosity=0, mem_limit=40 * 1024**2) # 10MB - # A higher limit - pygsti.alg.find_sufficient_fiducial_pairs(std.target_model(), std.fiducials, std.fiducials, - std.germs, test_pair_list=[(0,0),(0,1),(1,0)], - verbosity=0, mem_limit=80 * 1024**2) # 80MB - - - def test_intelligentFiducialPairReduction(self): - fidPairs = self.runSilent( - pygsti.alg.find_sufficient_fiducial_pairs_per_germ, - std.target_model(), std.fiducials, std.fiducials, - std.germs, pre_povm_tuples="first", - search_mode="sequential", - constrain_to_tp=True, - n_random=100, seed=None, verbosity=3, - mem_limit=None) - - cmpFilenm = compare_files + "/IFPR_fidPairs_dict.pkl" - # Run to SAVE reference fidPairs dictionary - if regenerate_references(): - with open(cmpFilenm,"wb") as pklfile: - pickle.dump(fidPairs, pklfile) - - with open(cmpFilenm,"rb") as pklfile: - fidPairs_cmp = pickle.load(pklfile) - - #On other machines (eg TravisCI) these aren't equal, due to randomness, so don't test - #self.assertEqual(fidPairs, fidPairs_cmp) - - #test out some additional code paths: mem limit, random mode, & no good pair list - fidPairs2 = self.runSilent( - pygsti.alg.find_sufficient_fiducial_pairs_per_germ, - std.target_model(), std.fiducials, std.fiducials, - std.germs, pre_povm_tuples="first", - search_mode="random", - constrain_to_tp=True, - n_random=3, seed=None, verbosity=3, - mem_limit=1024*256) - - fidPairs3 = self.runSilent( #larger n_random - pygsti.alg.find_sufficient_fiducial_pairs_per_germ, - std.target_model(), std.fiducials, std.fiducials, - std.germs, pre_povm_tuples="first", - search_mode="random", - constrain_to_tp=True, - n_random=100, seed=None, verbosity=3, - mem_limit=1024*256) - - fidPairs3b = self.runSilent( #huge n_random (should cap to all pairs) - pygsti.alg.find_sufficient_fiducial_pairs_per_germ, - std.target_model(), std.fiducials, std.fiducials, - std.germs, pre_povm_tuples="first", - search_mode="random", - constrain_to_tp=True, - n_random=1000000, seed=None, verbosity=3, - mem_limit=1024*256) + + #Two out of the three tests that were in the following function were superfluous, and taking + #n_random out to very large values takes a long time to run, so I don't think it is worth the time + #from a testing standpoint. +# def test_intelligentFiducialPairReduction(self): +# +# #test out some additional code paths: random mode, very large n_random +# +# fidPairs = self.runSilent( #huge n_random (should cap to all pairs) +# pygsti.alg.find_sufficient_fiducial_pairs_per_germ, +# std.target_model(), std.prep_fiducials(), std.meas_fiducials(), +# std.germs(lite=True), prep_povm_tuples="first", +# search_mode="random", +# constrain_to_tp=True, +# n_random=1000000, seed=None, verbosity=0, +# mem_limit=1024*256) def test_FPR_test_pairs(self): target_model = std.target_model() - prep_fiducials = std.fiducials - meas_fiducials = std.fiducials - germs = std.germs - maxLengths = [1,2,4,8,16] + prep_fiducials = std.prep_fiducials() + meas_fiducials = std.meas_fiducials() + germs = std.germs(lite = False) op_labels = list(target_model.operations.keys()) fidPairs = pygsti.alg.find_sufficient_fiducial_pairs( target_model, prep_fiducials, meas_fiducials, germs, - search_mode="random", n_random=100, seed=1234, - verbosity=1, mem_limit=int(2*(1024)**3), minimum_pairs=2) + search_mode="random", n_random=10, seed=1234, + verbosity=1, mem_limit=int(2*(1024)**3), minimum_pairs=2, + test_lengths = (64, 512)) # fidPairs is a list of (prepIndex,measIndex) 2-tuples, where # prepIndex indexes prep_fiducials and measIndex indexes meas_fiducials @@ -96,7 +53,8 @@ def test_FPR_test_pairs(self): nAmplified = pygsti.alg.test_fiducial_pairs(fidPairs, target_model, prep_fiducials, meas_fiducials, germs, - verbosity=3, mem_limit=None) + verbosity=3, mem_limit=None, test_lengths=(64, 512), + tol = .5) #Note: can't amplify SPAM params, so don't count them @@ -109,18 +67,17 @@ def test_FPR_test_pairs(self): fidPairsDict = pygsti.alg.find_sufficient_fiducial_pairs_per_germ( target_model, prep_fiducials, meas_fiducials, germs, search_mode="random", constrain_to_tp=True, - n_random=100, seed=1234, verbosity=1, + n_random=10, seed=1234, verbosity=1, mem_limit=int(2*(1024)**3)) nAmplified = pygsti.alg.test_fiducial_pairs(fidPairsDict, target_model, prep_fiducials, meas_fiducials, germs, - verbosity=3, mem_limit=None) + verbosity=3, mem_limit=None, + test_lengths=(64, 512), + tol = .5) print("PFPR: %d AMPLIFIED out of %d total (non-spam non-gauge) params" % (nAmplified, nTotal)) self.assertEqual(nAmplified, 34) - - - if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/test/test_packages/algorithms/test_fogi_gst.py b/test/test_packages/algorithms/test_fogi_gst.py index b39b11963..389865d74 100644 --- a/test/test_packages/algorithms/test_fogi_gst.py +++ b/test/test_packages/algorithms/test_fogi_gst.py @@ -2,7 +2,7 @@ import numpy as np import pygsti -from pygsti.modelpacks import smq1Q_XYI as std +from pygsti.modelpacks import smq1Q_XY as std from pygsti.baseobjs import Basis, CompleteElementaryErrorgenBasis from pygsti.processors import QubitProcessorSpec from pygsti.models import create_crosstalk_free_model @@ -152,7 +152,7 @@ def test_fogi_gst(self): else: pspec = self.create_pspec() circuits = pygsti.circuits.create_cloudnoise_circuits( - pspec, [1,], [(), ('Gxpi2',), ('Gypi2',), ('Gxpi2','Gxpi2')], + pspec, [1,], [('Gxpi2',), ('Gypi2',), ('Gxpi2','Gxpi2')], max_idle_weight=0, extra_gate_weight=1, maxhops=1) print(len(circuits)) edesign = pygsti.protocols.GSTDesign(pspec, circuits) @@ -164,7 +164,7 @@ def test_fogi_gst(self): ar = 0.001 * np.random.rand(len(ar)) mdl_datagen.set_fogi_errorgen_components_array(ar, include_fogv=False, normalized_elem_gens=True) - ds = pygsti.data.simulate_data(mdl_datagen, edesign, 1000, seed=2022) #, sample_error='none') + ds = pygsti.data.simulate_data(mdl_datagen, edesign, 10000, seed=2022) #, sample_error='none') data = pygsti.protocols.ProtocolData(edesign, ds) datagen_2dlogl = pygsti.tools.two_delta_logl(mdl_datagen, ds) @@ -175,7 +175,7 @@ def test_fogi_gst(self): gst_mdl = self.create_model() print("Before FOGI reparam, Np = ", gst_mdl.num_params) gst_mdl.sim = sim_type - proto = pygsti.protocols.GST(gst_mdl, gaugeopt_suite=None, optimizer={'maxiter': 100, 'tol': 1e-7}, verbosity=3) + proto = pygsti.protocols.GST(gst_mdl, gaugeopt_suite=None, optimizer={'maxiter': 10, 'tol': 1e-7}, verbosity=3) results_before = proto.run(data) #Run GST *with* FOGI setup @@ -187,7 +187,7 @@ def test_fogi_gst(self): dependent_fogi_action='drop', include_spam=True) print("After FOGI reparam, Np = ", gst_mdl.num_params) gst_mdl.sim = sim_type - proto = pygsti.protocols.GST(gst_mdl, gaugeopt_suite=None, optimizer={'maxiter': 100, 'tol': 1e-7}, verbosity=3) + proto = pygsti.protocols.GST(gst_mdl, gaugeopt_suite=None, optimizer={'maxiter': 10, 'tol': 1e-7}, verbosity=3) results_after = proto.run(data) #Compute hessian at MLE point for both estimates @@ -261,8 +261,9 @@ def create_pspec(self): nQubits = 2 #pspec = pygsti.processors.QubitProcessorSpec(nQubits, ['Gxpi2', 'Gypi2', 'Gi'], geometry='line') #availability={'Gcnot': [(0,1)]}, # to match smq2Q_XYCNOT - pspec = pygsti.processors.QubitProcessorSpec(nQubits, ['Gxpi2', 'Gypi2', 'Gcnot'], - availability={'Gcnot': [(0,1)]}, geometry='line') + #pspec = pygsti.processors.QubitProcessorSpec(nQubits, ['Gxpi2', 'Gypi2', 'Gcnot'], + # availability={'Gcnot': [(0,1)]}, geometry='line') + pspec = pygsti.processors.QubitProcessorSpec(nQubits, ['Gxpi2', 'Gypi2'], geometry='line') return pspec def create_model(self): diff --git a/test/test_packages/algorithms/test_germselection.py b/test/test_packages/algorithms/test_germselection.py new file mode 100644 index 000000000..eeb7ff867 --- /dev/null +++ b/test/test_packages/algorithms/test_germselection.py @@ -0,0 +1,175 @@ +import pygsti +import numpy as _np +from pygsti.circuits import Circuit +from pygsti.baseobjs import Label +from pygsti.modelpacks import smq1Q_XY as std +from ..algorithms.algorithmsTestCase import AlgorithmTestCase + +class GermSelectionTestData(object): + germs_greedy = {Circuit([Label('Gxpi2',0)]), + Circuit([Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0),Label('Gypi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gypi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gxpi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0)])} + + germs_greedy_alt = {Circuit([Label('Gxpi2',0)]), + Circuit([Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0),Label('Gypi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gypi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gxpi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0),Label('Gxpi2',0),Label('Gypi2',0)])} + + germs_driver_greedy = {Circuit([Label('Gxpi2',0)], line_labels=(0,)), + Circuit([Label('Gypi2',0)], line_labels=(0,)), + Circuit([Label('Gxpi2',0),Label('Gypi2',0)], line_labels=(0,)), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0)], line_labels=(0,)), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gxpi2',0)], line_labels=(0,))} + + germs_driver_greedy_alt = {Circuit([Label('Gxpi2',0)], line_labels=(0,)), + Circuit([Label('Gypi2',0)], line_labels=(0,)), + Circuit([Label('Gxpi2',0),Label('Gypi2',0)], line_labels=(0,)), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0)], line_labels=(0,)), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0)], line_labels=(0,))} + + germs_driver_greedy_alt_1 = {Circuit([Label('Gxpi2',0)], line_labels=(0,)), + Circuit([Label('Gypi2',0)], line_labels=(0,)), + Circuit([Label('Gxpi2',0),Label('Gypi2',0)], line_labels=(0,)), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0)], line_labels=(0,)), + Circuit([Label('Gxpi2',0),Label('Gypi2',0),Label('Gxpi2',0),Label('Gxpi2',0)], line_labels=(0,))} + + germs_driver_grasp = ({Circuit([Label('Gxpi2',0)]), + Circuit([Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0)])}, + [[Circuit([Label('Gxpi2',0)]), Circuit([Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gypi2',0),Label('Gxpi2',0),Label('Gxpi2',0)]), + Circuit([Label('Gypi2',0),Label('Gxpi2',0),Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0)])], + [Circuit([Label('Gxpi2',0)]), Circuit([Label('Gypi2',0)]), Circuit([Label('Gxpi2',0),Label('Gypi2',0),Label('Gxpi2',0),Label('Gxpi2',0)]), + Circuit([Label('Gypi2',0),Label('Gxpi2',0),Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0)])], + [Circuit([Label('Gxpi2',0)]), Circuit([Label('Gypi2',0)]), Circuit([Label('Gxpi2',0),Label('Gypi2',0),Label('Gxpi2',0),Label('Gxpi2',0)]), + Circuit([Label('Gypi2',0),Label('Gxpi2',0),Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0)])], + [Circuit([Label('Gxpi2',0)]), Circuit([Label('Gypi2',0)]), Circuit([Label('Gxpi2',0),Label('Gypi2',0),Label('Gxpi2',0),Label('Gxpi2',0)]), + Circuit([Label('Gypi2',0),Label('Gxpi2',0),Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0)])], + [Circuit([Label('Gxpi2',0)]), Circuit([Label('Gypi2',0)]), Circuit([Label('Gxpi2',0),Label('Gypi2',0),Label('Gxpi2',0),Label('Gxpi2',0)]), + Circuit([Label('Gypi2',0),Label('Gxpi2',0),Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0)])]], + [[Circuit([Label('Gxpi2',0)]), Circuit([Label('Gypi2',0)]), Circuit([Label('Gxpi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0)])], + [Circuit([Label('Gxpi2',0)]), Circuit([Label('Gypi2',0)]), Circuit([Label('Gxpi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0)])], + [Circuit([Label('Gxpi2',0)]), Circuit([Label('Gypi2',0)]), Circuit([Label('Gxpi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0)])], + [Circuit([Label('Gxpi2',0)]), Circuit([Label('Gypi2',0)]), Circuit([Label('Gxpi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0)])], + [Circuit([Label('Gxpi2',0)]), Circuit([Label('Gypi2',0)]), Circuit([Label('Gxpi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0)])]]) + + germs_driver_grasp_alt ={Circuit([Label('Gxpi2',0)]), + Circuit([Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gxpi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0)])} + + germs_driver_grasp_alt_1 ={Circuit([Label('Gxpi2',0)]), + Circuit([Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gypi2',0),Label('Gxpi2',0),Label('Gxpi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0)])} + + + germs_driver_slack = {Circuit([Label('Gxpi2',0)]), + Circuit([Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gxpi2',0)]), + Circuit([Label('Gxpi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gxpi2',0),Label('Gypi2',0),Label('Gypi2',0)])} + + +class GermSelectionTestCase(AlgorithmTestCase, GermSelectionTestData): + + #test with worst score_func + def test_germsel_greedy(self): + threshold = 1e6 + randomizationStrength = 1e-3 + neighborhoodSize = 2 + gatesetNeighborhood = pygsti.alg.randomize_model_list([std.target_model()], + randomization_strength=randomizationStrength, + num_copies=neighborhoodSize, seed=2014) + + max_length = 6 + gates = std.target_model().operations.keys() + superGermSet = pygsti.circuits.list_all_circuits_without_powers_and_cycles(gates, max_length) + + germs = pygsti.alg.find_germs_breadthfirst(gatesetNeighborhood, superGermSet, + randomize=False, seed=2014, score_func='worst', + threshold=threshold, verbosity=1, op_penalty=1.0, + mem_limit=2*1024000) + + print(f'{germs=}') + + self.assertTrue(self.germs_greedy == set(germs) or self.germs_greedy_alt == set(germs)) + + def test_germsel_driver_greedy(self): + #GREEDY + options = {'threshold': 1e6 } + germs = pygsti.alg.find_germs(std.target_model(), randomize=True, randomization_strength=1e-3, + num_gs_copies=2, seed=2017, candidate_germ_counts={3: 'all upto', 4: 10, 5:10, 6:10}, + candidate_seed=2017, force="singletons", algorithm='greedy', + algorithm_kwargs=options, mem_limit=None, comm=None, + profiler=None, verbosity=1) + + self.assertTrue(self.germs_driver_greedy == set(germs) or self.germs_driver_greedy_alt == set(germs) or self.germs_driver_greedy_alt_1 == set(germs)) + + def test_germsel_driver_grasp(self): + #more args + options = {'threshold': 1e6 , 'return_all': True} + germs = pygsti.alg.find_germs(std.target_model(), randomize=True, randomization_strength=1e-3, + num_gs_copies=2, seed=2017, candidate_germ_counts={3: 'all upto', 4: 10, 5:10, 6:10}, + candidate_seed=2017, force="singletons", algorithm='grasp', + algorithm_kwargs=options, mem_limit=None, + profiler=None, verbosity=1) + + self.assertTrue(self.germs_driver_grasp[0] == set(germs[0]) or self.germs_driver_grasp_alt == set(germs[0]) or self.germs_driver_grasp_alt_1 == set(germs[0])) + self.assertTrue(self.germs_driver_grasp[1] == germs[1]) + #TODO re-enable correctness check for initial candidate sets, for now just check it is not None + self.assertTrue(germs[2] is not None) + + def test_germsel_driver_slack(self): + #SLACK + options = dict(fixed_slack=False, slack_frac=0.1) + germs = pygsti.alg.find_germs(std.target_model(), randomize=True, randomization_strength=1e-3, + num_gs_copies=2, seed=2017, candidate_germ_counts={3: 'all upto', 4: 10, 5:10, 6:10}, + candidate_seed=2017, force="singletons", algorithm='slack', + algorithm_kwargs=options, mem_limit=None, comm=None, + profiler=None, verbosity=1) + + self.assertTrue(self.germs_driver_slack == set(germs)) diff --git a/test/test_packages/algorithmsb/__init__.py b/test/test_packages/algorithmsb/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/test/test_packages/algorithmsb/test_germselection.py b/test/test_packages/algorithmsb/test_germselection.py deleted file mode 100644 index de57c3d09..000000000 --- a/test/test_packages/algorithmsb/test_germselection.py +++ /dev/null @@ -1,132 +0,0 @@ -import pygsti -import numpy as _np -from pygsti.modelpacks.legacy import std1Q_XYI as std -from ..algorithms.algorithmsTestCase import AlgorithmTestCase - - -class GermSelectionTestCase(AlgorithmTestCase): - def test_germsel_grasp(self): - threshold = 1e6 - randomizationStrength = 1e-3 - neighborhoodSize = 5 - gatesetNeighborhood = pygsti.alg.randomize_model_list([std.target_model()], - randomization_strength=randomizationStrength, - num_copies=neighborhoodSize, seed=2014) - - # max_length = 6 - gates = list(std.target_model().operations.keys()) - superGermSet = [] #OLD: pygsti.construction.list_all_circuits_without_powers_and_cycles(gates, max_length) - superGermSet.extend( pygsti.circuits.list_all_circuits_without_powers_and_cycles( - gates, max_length=3) ) - superGermSet.extend( pygsti.circuits.list_random_circuits_onelen( - gates, 4, 10, seed=2017)) # add 10 random candidates of length 4 - superGermSet.extend( pygsti.circuits.list_random_circuits_onelen( - gates, 5, 10, seed=2017)) # add 10 random candidates of length 5 - superGermSet.extend( pygsti.circuits.list_random_circuits_onelen( - gates, 6, 10, seed=2017)) # add 10 random candidates of length 6 - superGermSet.extend(std.germs) #so we know we have enough good ones! - - soln = pygsti.alg.find_germs_grasp(model_list=gatesetNeighborhood, germs_list=superGermSet, - alpha=0.1, randomize=False, seed=2014, score_func='all', - threshold=threshold, verbosity=1, iterations=1, - l1_penalty=1.0, return_all=False) - - forceStrs = pygsti.circuits.to_circuits([('Gx',), ('Gy')]) - bestSoln, initialSolns, localSolns = \ - pygsti.alg.find_germs_grasp(model_list=gatesetNeighborhood, germs_list=superGermSet, - alpha=0.1, randomize=False, seed=2014, score_func='all', - threshold=threshold, verbosity=1, iterations=1, - l1_penalty=1.0, return_all=True, force=forceStrs) - - # try case with incomplete initial germ set - incompleteSet = pygsti.circuits.to_circuits([('Gx',), ('Gy')]) - soln = pygsti.alg.find_germs_grasp(model_list=gatesetNeighborhood, germs_list=incompleteSet, - alpha=0.1, randomize=False, seed=2014, score_func='worst', - threshold=threshold, verbosity=1, iterations=1, - l1_penalty=1.0) - - def test_germsel_greedy(self): - threshold = 1e6 - randomizationStrength = 1e-3 - neighborhoodSize = 5 - gatesetNeighborhood = pygsti.alg.randomize_model_list([std.target_model()], - randomization_strength=randomizationStrength, - num_copies=neighborhoodSize, seed=2014) - - max_length = 6 - gates = std.target_model().operations.keys() - superGermSet = pygsti.circuits.list_all_circuits_without_powers_and_cycles(gates, max_length) - - # with small memory limit - with self.assertRaises(MemoryError): - pygsti.alg.find_germs_breadthfirst(gatesetNeighborhood, superGermSet, - randomize=False, seed=2014, score_func='all', - threshold=threshold, verbosity=1, op_penalty=1.0, - mem_limit=1024) - - pygsti.alg.find_germs_breadthfirst(gatesetNeighborhood, superGermSet, - randomize=False, seed=2014, score_func='all', - threshold=threshold, verbosity=1, op_penalty=1.0, - mem_limit=2*1024000) - - - def test_germsel_low_rank(self): - #test greedy search algorithm using low-rank updates - - soln = pygsti.algorithms.germselection.find_germs(std.target_model(), candidate_germ_counts={4:'all upto'}, - randomize=False, algorithm='greedy', mode='compactEVD', - assume_real=True, float_type=_np.double, verbosity=0) - - - def test_germsel_driver(self): - #GREEDY - options = {'threshold': 1e6 } - germs = pygsti.alg.find_germs(std.target_model(), randomize=True, randomization_strength=1e-3, - num_gs_copies=5, seed=2017, candidate_germ_counts={3: 'all upto', 4: 10, 5:10, 6:10}, - candidate_seed=2017, force="singletons", algorithm='greedy', - algorithm_kwargs=options, mem_limit=None, comm=None, - profiler=None, verbosity=1) - - #Greedy Low-Rank Updates - germs = pygsti.algorithms.germselection.find_germs(std.target_model(), seed=2017, - candidate_germ_counts={3: 'all upto', 4: 10, 5:10, 6:10}, - randomize=False, algorithm='greedy', mode='compactEVD', - assume_real=True, float_type=_np.double, verbosity=1) - - - #GRASP - options = dict(l1_penalty=1e-2, - op_penalty=0.1, - score_func='all', - tol=1e-6, threshold=1e6, - iterations=2) - germs = pygsti.alg.find_germs(std.target_model(), randomize=True, randomization_strength=1e-3, - num_gs_copies=2, seed=2017, candidate_germ_counts={3: 'all upto', 4: 10, 5:10, 6:10}, - candidate_seed=2017, force="singletons", algorithm='grasp', - algorithm_kwargs=options, mem_limit=None, comm=None, - profiler=None, verbosity=1) - - #more args - options['return_all'] = True #but doesn't change find_germs return value - germs2 = pygsti.alg.find_germs(std.target_model(), randomize=True, randomization_strength=1e-3, - num_gs_copies=2, seed=2017, candidate_germ_counts={3: 'all upto', 4: 10, 5:10, 6:10}, - candidate_seed=2017, force="singletons", algorithm='grasp', - algorithm_kwargs=options, mem_limit=None, comm=None, - profiler=None, verbosity=1) - - - #SLACK - options = dict(fixed_slack=False, slack_frac=0.1) - germs = pygsti.alg.find_germs(std.target_model(), randomize=True, randomization_strength=1e-3, - num_gs_copies=2, seed=2017, candidate_germ_counts={3: 'all upto', 4: 10, 5:10, 6:10}, - candidate_seed=2017, force="singletons", algorithm='slack', - algorithm_kwargs=options, mem_limit=None, comm=None, - profiler=None, verbosity=1) - - #no options -> use defaults - options = {} - germs = pygsti.alg.find_germs(std.target_model(), randomize=True, randomization_strength=1e-3, - num_gs_copies=2, seed=2017, candidate_germ_counts={3: 'all upto', 4: 10, 5:10, 6:10}, - candidate_seed=2017, force="singletons", algorithm='slack', - algorithm_kwargs=options, mem_limit=None, comm=None, - profiler=None, verbosity=1) diff --git a/test/test_packages/cmp_chk_files/calcMethods1Q.dataset b/test/test_packages/cmp_chk_files/calcMethods1Q.dataset index b90ae6550..990cadddb 100644 Binary files a/test/test_packages/cmp_chk_files/calcMethods1Q.dataset and b/test/test_packages/cmp_chk_files/calcMethods1Q.dataset differ diff --git a/test/test_packages/cmp_chk_files/calcMethods1Q_redmod.dataset b/test/test_packages/cmp_chk_files/calcMethods1Q_redmod.dataset index 4ae81bad0..34d849590 100644 Binary files a/test/test_packages/cmp_chk_files/calcMethods1Q_redmod.dataset and b/test/test_packages/cmp_chk_files/calcMethods1Q_redmod.dataset differ diff --git a/test/test_packages/cmp_chk_files/clgst.model b/test/test_packages/cmp_chk_files/clgst.model deleted file mode 100644 index c430c34d6..000000000 --- a/test/test_packages/cmp_chk_files/clgst.model +++ /dev/null @@ -1,42 +0,0 @@ -# Saved LGST Model after G.O. and CPTP contraction - -PREP: rho0 -LiouvilleVec -0.70710678 0.0040612069 0.0056675083 0.65841422 - -POVM: Mdefault - -EFFECT: 0 -LiouvilleVec -0.70093181 0.0035205525 -0.0029915851 0.6837151 - -EFFECT: 1 -LiouvilleVec -0.71305101 -0.0037111722 0.0032692418 -0.68399421 - -END POVM - -GATE: Gi -LiouvilleMx - 1.00000000 0 0 0 - 0.00016589 0.93699078 -0.02402020 0.00027617 - 0.00169979 0.00317884 0.95310919 -0.00334909 - -0.00456905 -0.00189132 0.01441926 0.95210445 - -GATE: Gx -LiouvilleMx - 1.00000000 0 0 0 - -0.00014920 0.94286416 -0.00501813 -0.00003622 - 0.00200725 0.00138494 -0.01108286 -0.94908754 - 0.00658988 0.00161815 0.94823396 -0.00137454 - -GATE: Gy -LiouvilleMx - 1.00000000 0 0 0 - -0.01045851 -0.00180117 -0.00489781 0.94931118 - 0.00364913 -0.00313114 0.95708953 -0.00246373 - 0.00796882 -0.95008381 0.00027784 0.00091155 - -STATESPACE: Q0(4) -BASIS: pp 4 -GAUGEGROUP: Full diff --git a/test/test_packages/cmp_chk_files/drivers.dataset b/test/test_packages/cmp_chk_files/drivers.dataset deleted file mode 100644 index 78a8a28fc..000000000 Binary files a/test/test_packages/cmp_chk_files/drivers.dataset and /dev/null differ diff --git a/test/test_packages/cmp_chk_files/lgst.model b/test/test_packages/cmp_chk_files/lgst.model deleted file mode 100644 index 9f7fdae2b..000000000 --- a/test/test_packages/cmp_chk_files/lgst.model +++ /dev/null @@ -1,42 +0,0 @@ -# Saved LGST Model before gauge optimization - -PREP: rho0 -LiouvilleVec -0.70709857 -0.0094328727 0.012524185 0.72536492 - -POVM: Mdefault - -EFFECT: 0 -LiouvilleVec -0.71801967 -0.0023470816 -0.0044032243 0.60422949 - -EFFECT: 1 -LiouvilleVec -0.69619389 0.0023470816 0.0044032243 -0.60422949 - -END POVM - -GATE: Gi -LiouvilleMx - 0.99999529 0.00000011 -0.00001083 -0.00000649 - -0.00065013 0.93713228 -0.02389859 0.00011380 - 0.00275112 0.00314663 0.95288269 -0.00351392 - -0.00675272 -0.00201547 0.01349499 0.95218825 - -GATE: Gx -LiouvilleMx - 0.99999767 -0.00000983 0.00000404 -0.00000019 - -0.00118843 0.94288939 -0.00546692 0.00068435 - -0.00970321 0.01602672 -0.01443019 -0.99856350 - -0.03435843 0.00465737 0.90123982 0.00194871 - -GATE: Gy -LiouvilleMx - 0.99999703 0.00000014 0.00000062 -0.00000560 - -0.00404179 -0.01006951 -0.00791309 0.99312553 - 0.00510036 -0.00262383 0.95702862 0.00992925 - -0.03657191 -0.90823441 0.00288320 0.00924041 - -STATESPACE: Q0(4) -BASIS: pp 4 -GAUGEGROUP: Full diff --git a/test/test_packages/cmp_chk_files/lgst_go.model b/test/test_packages/cmp_chk_files/lgst_go.model deleted file mode 100644 index 2b9e30f88..000000000 --- a/test/test_packages/cmp_chk_files/lgst_go.model +++ /dev/null @@ -1,42 +0,0 @@ -# Saved LGST Model after gauge optimization - -PREP: rho0 -LiouvilleVec -0.70734336 0.0040612069 0.0056675083 0.65841422 - -POVM: Mdefault - -EFFECT: 0 -LiouvilleVec -0.70093181 0.0035205525 -0.0029915851 0.6837151 - -EFFECT: 1 -LiouvilleVec -0.71305101 -0.0037111722 0.0032692418 -0.68399421 - -END POVM - -GATE: Gi -LiouvilleMx - 0.99999409 -0.00000951 -0.00000410 -0.00001602 - 0.00016589 0.93699078 -0.02402020 0.00027617 - 0.00169979 0.00317884 0.95310919 -0.00334909 - -0.00456905 -0.00189132 0.01441926 0.95210445 - -GATE: Gx -LiouvilleMx - 0.99999881 -0.00001927 0.00038985 -0.00001154 - -0.00014920 0.94286416 -0.00501813 -0.00003622 - 0.00200725 0.00138494 -0.01108286 -0.94908754 - 0.00658988 0.00161815 0.94823396 -0.00137454 - -GATE: Gy -LiouvilleMx - 0.99999664 -0.00032187 0.00000854 -0.00007509 - -0.01045851 -0.00180117 -0.00489781 0.94931118 - 0.00364913 -0.00313114 0.95708953 -0.00246373 - 0.00796882 -0.95008381 0.00027784 0.00091155 - -STATESPACE: Q0(4) -BASIS: pp 4 -GAUGEGROUP: Full diff --git a/test/test_packages/cmp_chk_files/nqubit_1Q_seqs.json b/test/test_packages/cmp_chk_files/nqubit_1Q_seqs.json index f33dd97a3..532ebdda4 100644 --- a/test/test_packages/cmp_chk_files/nqubit_1Q_seqs.json +++ b/test/test_packages/cmp_chk_files/nqubit_1Q_seqs.json @@ -1 +1,361 @@ -{"_plaquettes": {"__odict__": [[{"__tuple__": [1, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": "[]@(0)", "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]}, {"germ": {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": "[]@(0)", "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, "power": 1, "base": {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": "([])@(0)", "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, "fidpairs": {"__odict__": [[{"__tuple__": [0, 0]}, {"__tuple__": [{"_labels": {"__tuple__": []}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": []}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]}], [{"__tuple__": [1, 0]}, {"__tuple__": [{"_labels": {"__tuple__": []}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]}], [{"__tuple__": [2, 0]}, {"__tuple__": [{"_labels": {"__tuple__": []}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]}], [{"__tuple__": [0, 1]}, {"__tuple__": [{"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]}], [{"__tuple__": [1, 1]}, {"__tuple__": [{"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]}], [{"__tuple__": [2, 1]}, {"__tuple__": [{"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]}]]}, "elements": {"__odict__": [[{"__tuple__": [0, 0]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}], [{"__tuple__": [1, 0]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}], [{"__tuple__": [2, 0]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}], [{"__tuple__": [0, 1]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}], [{"__tuple__": [1, 1]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}], [{"__tuple__": [2, 1]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]]}, "op_label_aliases": null, "num_rows": 3, "num_cols": 2, "__pygstiobj__": ["pygsti.circuits.circuitstructure", "GermFiducialPairPlaquette"]}], [{"__tuple__": [2, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": "[]@(0)", "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]}, {"germ": {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": "[]@(0)", "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, "power": 2, "base": {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": "([])^2@(0)", "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, "fidpairs": {"__odict__": [[{"__tuple__": [0, 0]}, {"__tuple__": [{"_labels": {"__tuple__": []}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": []}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]}], [{"__tuple__": [1, 0]}, {"__tuple__": [{"_labels": {"__tuple__": []}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]}], [{"__tuple__": [2, 0]}, {"__tuple__": [{"_labels": {"__tuple__": []}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]}], [{"__tuple__": [0, 1]}, {"__tuple__": [{"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]}], [{"__tuple__": [1, 1]}, {"__tuple__": [{"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]}], [{"__tuple__": [2, 1]}, {"__tuple__": [{"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]}]]}, "elements": {"__odict__": [[{"__tuple__": [0, 0]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}], [{"__tuple__": [1, 0]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}], [{"__tuple__": [2, 0]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}], [{"__tuple__": [0, 1]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}], [{"__tuple__": [1, 1]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}], [{"__tuple__": [2, 1]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]]}, "op_label_aliases": null, "num_rows": 3, "num_cols": 2, "__pygstiobj__": ["pygsti.circuits.circuitstructure", "GermFiducialPairPlaquette"]}], [{"__tuple__": [1, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": "Gx:0@(0)", "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]}, {"germ": {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": "Gx:0@(0)", "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, "power": 1, "base": {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": "(Gx:0)@(0)", "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, "fidpairs": {"__odict__": [[{"__tuple__": [0, 0]}, {"__tuple__": [{"_labels": {"__tuple__": []}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": []}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]}], [{"__tuple__": [1, 0]}, {"__tuple__": [{"_labels": {"__tuple__": []}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]}], [{"__tuple__": [0, 1]}, {"__tuple__": [{"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]}]]}, "elements": {"__odict__": [[{"__tuple__": [0, 0]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}], [{"__tuple__": [1, 0]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}], [{"__tuple__": [0, 1]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]]}, "op_label_aliases": null, "num_rows": 2, "num_cols": 2, "__pygstiobj__": ["pygsti.circuits.circuitstructure", "GermFiducialPairPlaquette"]}], [{"__tuple__": [2, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": "Gx:0@(0)", "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]}, {"germ": {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": "Gx:0@(0)", "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, "power": 2, "base": {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": "(Gx:0)^2@(0)", "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, "fidpairs": {"__odict__": [[{"__tuple__": [0, 0]}, {"__tuple__": [{"_labels": {"__tuple__": []}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": []}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]}], [{"__tuple__": [1, 0]}, {"__tuple__": [{"_labels": {"__tuple__": []}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]}], [{"__tuple__": [0, 1]}, {"__tuple__": [{"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]}]]}, "elements": {"__odict__": [[{"__tuple__": [0, 0]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}], [{"__tuple__": [1, 0]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}], [{"__tuple__": [0, 1]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]]}, "op_label_aliases": null, "num_rows": 2, "num_cols": 2, "__pygstiobj__": ["pygsti.circuits.circuitstructure", "GermFiducialPairPlaquette"]}], [{"__tuple__": [1, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": "Gy:0@(0)", "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]}, {"germ": {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": "Gy:0@(0)", "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, "power": 1, "base": {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": "(Gy:0)@(0)", "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, "fidpairs": {"__odict__": [[{"__tuple__": [0, 0]}, {"__tuple__": [{"_labels": {"__tuple__": []}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": []}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]}], [{"__tuple__": [1, 0]}, {"__tuple__": [{"_labels": {"__tuple__": []}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]}], [{"__tuple__": [0, 1]}, {"__tuple__": [{"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]}]]}, "elements": {"__odict__": [[{"__tuple__": [0, 0]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}], [{"__tuple__": [1, 0]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}], [{"__tuple__": [0, 1]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]]}, "op_label_aliases": null, "num_rows": 2, "num_cols": 2, "__pygstiobj__": ["pygsti.circuits.circuitstructure", "GermFiducialPairPlaquette"]}], [{"__tuple__": [2, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": "Gy:0@(0)", "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]}, {"germ": {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": "Gy:0@(0)", "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, "power": 2, "base": {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": "(Gy:0)^2@(0)", "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, "fidpairs": {"__odict__": [[{"__tuple__": [0, 0]}, {"__tuple__": [{"_labels": {"__tuple__": []}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": []}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]}], [{"__tuple__": [1, 0]}, {"__tuple__": [{"_labels": {"__tuple__": []}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]}], [{"__tuple__": [0, 1]}, {"__tuple__": [{"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]}]]}, "elements": {"__odict__": [[{"__tuple__": [0, 0]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}], [{"__tuple__": [1, 0]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}], [{"__tuple__": [0, 1]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]]}, "op_label_aliases": null, "num_rows": 2, "num_cols": 2, "__pygstiobj__": ["pygsti.circuits.circuitstructure", "GermFiducialPairPlaquette"]}], [{"__tuple__": [2, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": "Gx:0Gy:0@(0)", "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]}, {"germ": {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": "Gx:0Gy:0@(0)", "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, "power": 1, "base": {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": "(Gx:0Gy:0)@(0)", "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, "fidpairs": {"__odict__": [[{"__tuple__": [0, 0]}, {"__tuple__": [{"_labels": {"__tuple__": []}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": []}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]}], [{"__tuple__": [1, 0]}, {"__tuple__": [{"_labels": {"__tuple__": []}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]}]]}, "elements": {"__odict__": [[{"__tuple__": [0, 0]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}], [{"__tuple__": [1, 0]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]]}, "op_label_aliases": null, "num_rows": 2, "num_cols": 1, "__pygstiobj__": ["pygsti.circuits.circuitstructure", "GermFiducialPairPlaquette"]}]]}, "xs": {"__list__": [1, 2]}, "ys": {"__list__": [{"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": "[]@(0)", "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": "Gx:0@(0)", "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": "Gy:0@(0)", "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": "Gx:0Gy:0@(0)", "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]}, "xlabel": "L", "ylabel": "germ", "_addl_location": "start", "_additional_circuits": {"__tuple__": []}, "_circuits": {"__tuple__": [{"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}, {"_labels": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_line_labels": {"__tuple__": [0]}, "_occurrence_id": null, "_compilable_layer_indices_tup": {"__tuple__": []}, "_static": true, "_name": "", "_str": null, "_times": null, "auxinfo": {"__ndict__": []}, "_alignmarks": {"__tuple__": []}, "__pygstiobj__": ["pygsti.circuits.circuit", "Circuit"]}]}, "op_label_aliases": null, "circuit_weights": null, "name": null, "uuid": {"__uuid__": "b51a55f9a3704c81ac43026c7a1980f2"}, "__pygstiobj__": ["pygsti.circuits.circuitstructure", "PlaquetteGridCircuitStructure"]} \ No newline at end of file +{ + "module": "pygsti.circuits.circuitstructure", + "class": "PlaquetteGridCircuitStructure", + "version": 0, + "name": null, + "xvalues": [ + 1, + 2 + ], + "yvalues": [ + "[]@(0)", + "Gx:0@(0)", + "Gy:0@(0)", + "Gx:0Gy:0@(0)" + ], + "xtype": "int", + "ytype": "circuit", + "xlabel": "L", + "ylabel": "germ", + "op_label_aliases": null, + "circuit_rules": null, + "additional_circuits_location": "start", + "plaquettes": [ + [ + [ + 1, + "[]@(0)" + ], + { + "module": "pygsti.circuits.circuitstructure", + "class": "GermFiducialPairPlaquette", + "version": 0, + "num_rows": 3, + "num_cols": 2, + "base_circuit": "([])@(0)", + "fiducial_pairs": [ + [ + [ + 0, + 0 + ], + "{}@(0)", + "{}@(0)" + ], + [ + [ + 1, + 0 + ], + "{}@(0)", + "Gx:0@(0)" + ], + [ + [ + 2, + 0 + ], + "{}@(0)", + "Gy:0@(0)" + ], + [ + [ + 0, + 1 + ], + "Gx:0@(0)", + "Gx:0@(0)" + ], + [ + [ + 1, + 1 + ], + "Gx:0@(0)", + "Gy:0@(0)" + ], + [ + [ + 2, + 1 + ], + "Gy:0@(0)", + "Gy:0@(0)" + ] + ], + "germ": "[]@(0)", + "power": 1 + } + ], + [ + [ + 2, + "[]@(0)" + ], + { + "module": "pygsti.circuits.circuitstructure", + "class": "GermFiducialPairPlaquette", + "version": 0, + "num_rows": 3, + "num_cols": 2, + "base_circuit": "([])^2@(0)", + "fiducial_pairs": [ + [ + [ + 0, + 0 + ], + "{}@(0)", + "{}@(0)" + ], + [ + [ + 1, + 0 + ], + "{}@(0)", + "Gx:0@(0)" + ], + [ + [ + 2, + 0 + ], + "{}@(0)", + "Gy:0@(0)" + ], + [ + [ + 0, + 1 + ], + "Gx:0@(0)", + "Gx:0@(0)" + ], + [ + [ + 1, + 1 + ], + "Gx:0@(0)", + "Gy:0@(0)" + ], + [ + [ + 2, + 1 + ], + "Gy:0@(0)", + "Gy:0@(0)" + ] + ], + "germ": "[]@(0)", + "power": 2 + } + ], + [ + [ + 1, + "Gx:0@(0)" + ], + { + "module": "pygsti.circuits.circuitstructure", + "class": "GermFiducialPairPlaquette", + "version": 0, + "num_rows": 2, + "num_cols": 2, + "base_circuit": "(Gx:0)@(0)", + "fiducial_pairs": [ + [ + [ + 0, + 0 + ], + "{}@(0)", + "{}@(0)" + ], + [ + [ + 1, + 0 + ], + "{}@(0)", + "Gx:0@(0)" + ], + [ + [ + 0, + 1 + ], + "Gy:0@(0)", + "Gy:0@(0)" + ] + ], + "germ": "Gx:0@(0)", + "power": 1 + } + ], + [ + [ + 2, + "Gx:0@(0)" + ], + { + "module": "pygsti.circuits.circuitstructure", + "class": "GermFiducialPairPlaquette", + "version": 0, + "num_rows": 2, + "num_cols": 2, + "base_circuit": "(Gx:0)^2@(0)", + "fiducial_pairs": [ + [ + [ + 0, + 0 + ], + "{}@(0)", + "{}@(0)" + ], + [ + [ + 1, + 0 + ], + "{}@(0)", + "Gx:0@(0)" + ], + [ + [ + 0, + 1 + ], + "Gy:0@(0)", + "Gy:0@(0)" + ] + ], + "germ": "Gx:0@(0)", + "power": 2 + } + ], + [ + [ + 1, + "Gy:0@(0)" + ], + { + "module": "pygsti.circuits.circuitstructure", + "class": "GermFiducialPairPlaquette", + "version": 0, + "num_rows": 2, + "num_cols": 2, + "base_circuit": "(Gy:0)@(0)", + "fiducial_pairs": [ + [ + [ + 0, + 0 + ], + "{}@(0)", + "{}@(0)" + ], + [ + [ + 1, + 0 + ], + "{}@(0)", + "Gy:0@(0)" + ], + [ + [ + 0, + 1 + ], + "Gx:0@(0)", + "Gx:0@(0)" + ] + ], + "germ": "Gy:0@(0)", + "power": 1 + } + ], + [ + [ + 2, + "Gy:0@(0)" + ], + { + "module": "pygsti.circuits.circuitstructure", + "class": "GermFiducialPairPlaquette", + "version": 0, + "num_rows": 2, + "num_cols": 2, + "base_circuit": "(Gy:0)^2@(0)", + "fiducial_pairs": [ + [ + [ + 0, + 0 + ], + "{}@(0)", + "{}@(0)" + ], + [ + [ + 1, + 0 + ], + "{}@(0)", + "Gy:0@(0)" + ], + [ + [ + 0, + 1 + ], + "Gx:0@(0)", + "Gx:0@(0)" + ] + ], + "germ": "Gy:0@(0)", + "power": 2 + } + ], + [ + [ + 2, + "Gx:0Gy:0@(0)" + ], + { + "module": "pygsti.circuits.circuitstructure", + "class": "GermFiducialPairPlaquette", + "version": 0, + "num_rows": 2, + "num_cols": 1, + "base_circuit": "(Gx:0Gy:0)@(0)", + "fiducial_pairs": [ + [ + [ + 0, + 0 + ], + "{}@(0)", + "{}@(0)" + ], + [ + [ + 1, + 0 + ], + "{}@(0)", + "Gx:0@(0)" + ] + ], + "germ": "Gx:0Gy:0@(0)", + "power": 1 + } + ] + ], + "additional_circuits": [], + "circuit_weights": null +} \ No newline at end of file diff --git a/test/test_packages/cmp_chk_files/nqubit_2Q.dataset b/test/test_packages/cmp_chk_files/nqubit_2Q.dataset new file mode 100644 index 000000000..60c20d4c2 --- /dev/null +++ b/test/test_packages/cmp_chk_files/nqubit_2Q.dataset @@ -0,0 +1,105 @@ +## Columns = 00 count, 01 count, 10 count, 11 count +[]@(0,1) 10000 0 0 0 +[]Gx:1@(0,1) 5039 4961 0 0 +[]Gx:0@(0,1) 5022 0 4978 0 +[]Gy:1@(0,1) 5046 4954 0 0 +[]Gy:0@(0,1) 5111 0 4889 0 +Gx:1[]Gx:1@(0,1) 0 10000 0 0 +Gx:0[]Gx:0@(0,1) 0 0 10000 0 +Gx:1[]Gy:1@(0,1) 5002 4998 0 0 +Gx:0[]Gy:0@(0,1) 4978 0 5022 0 +Gy:1[]Gy:1@(0,1) 0 10000 0 0 +Gy:0[]Gy:0@(0,1) 0 0 10000 0 +[][]@(0,1) 10000 0 0 0 +[][]Gx:1@(0,1) 5007 4993 0 0 +[][]Gx:0@(0,1) 4929 0 5071 0 +[][]Gy:1@(0,1) 5014 4986 0 0 +[][]Gy:0@(0,1) 5029 0 4971 0 +Gx:1[][]Gx:1@(0,1) 0 10000 0 0 +Gx:0[][]Gx:0@(0,1) 0 0 10000 0 +Gx:1[][]Gy:1@(0,1) 5028 4972 0 0 +Gx:0[][]Gy:0@(0,1) 5016 0 4984 0 +Gy:1[][]Gy:1@(0,1) 0 10000 0 0 +Gy:0[][]Gy:0@(0,1) 0 0 10000 0 +Gx:0@(0,1) 4982 0 5018 0 +Gx:0Gx:0@(0,1) 0 0 10000 0 +Gx:0[Gx:0Gx:1]@(0,1) 0 0 5052 4948 +Gx:0[Gy:0Gy:1]@(0,1) 2522 2439 2544 2495 +[Gx:0Gx:1]Gx:0[Gx:0Gx:1]@(0,1) 0 5011 0 4989 +[Gx:0Gx:1]Gx:0[Gy:0Gy:1]@(0,1) 2444 2542 2545 2469 +[Gy:0Gy:1]Gx:0[Gy:0Gy:1]@(0,1) 0 0 0 10000 +Gx:0Gx:0Gx:0@(0,1) 5007 0 4993 0 +Gx:0Gx:0[Gx:0Gx:1]@(0,1) 2458 2579 2488 2475 +Gx:0Gx:0[Gy:0Gy:1]@(0,1) 2404 2511 2509 2576 +[Gx:0Gx:1]Gx:0Gx:0[Gx:0Gx:1]@(0,1) 0 10000 0 0 +[Gx:0Gx:1]Gx:0Gx:0[Gy:0Gy:1]@(0,1) 2542 2454 2498 2506 +[Gy:0Gy:1]Gx:0Gx:0[Gy:0Gy:1]@(0,1) 0 0 0 10000 +Gx:1@(0,1) 4957 5043 0 0 +Gx:1Gx:1@(0,1) 0 10000 0 0 +Gx:1[Gx:0Gx:1]@(0,1) 0 4944 0 5056 +Gx:1[Gy:0Gy:1]@(0,1) 2446 2520 2539 2495 +[Gx:0Gx:1]Gx:1[Gx:0Gx:1]@(0,1) 0 0 5003 4997 +[Gx:0Gx:1]Gx:1[Gy:0Gy:1]@(0,1) 2573 2512 2485 2430 +[Gy:0Gy:1]Gx:1[Gy:0Gy:1]@(0,1) 0 0 0 10000 +Gx:1Gx:1Gx:1@(0,1) 5026 4974 0 0 +Gx:1Gx:1[Gx:0Gx:1]@(0,1) 2513 2488 2545 2454 +Gx:1Gx:1[Gy:0Gy:1]@(0,1) 2449 2448 2533 2570 +[Gx:0Gx:1]Gx:1Gx:1[Gx:0Gx:1]@(0,1) 0 0 10000 0 +[Gx:0Gx:1]Gx:1Gx:1[Gy:0Gy:1]@(0,1) 2472 2535 2475 2518 +[Gy:0Gy:1]Gx:1Gx:1[Gy:0Gy:1]@(0,1) 0 0 0 10000 +Gy:0@(0,1) 4992 0 5008 0 +Gy:0Gy:0@(0,1) 0 0 10000 0 +Gy:0[Gx:0Gx:1]@(0,1) 2522 2475 2499 2504 +Gy:0[Gy:0Gy:1]@(0,1) 0 0 5017 4983 +[Gx:0Gx:1]Gy:0[Gx:0Gx:1]@(0,1) 0 0 0 10000 +[Gx:0Gx:1]Gy:0[Gy:0Gy:1]@(0,1) 2506 2507 2505 2482 +[Gy:0Gy:1]Gy:0[Gy:0Gy:1]@(0,1) 0 5095 0 4905 +Gy:0Gy:0Gy:0@(0,1) 5024 0 4976 0 +Gy:0Gy:0[Gx:0Gx:1]@(0,1) 2577 2515 2436 2472 +Gy:0Gy:0[Gy:0Gy:1]@(0,1) 2529 2453 2488 2530 +[Gx:0Gx:1]Gy:0Gy:0[Gx:0Gx:1]@(0,1) 0 0 0 10000 +[Gx:0Gx:1]Gy:0Gy:0[Gy:0Gy:1]@(0,1) 2540 2449 2540 2471 +[Gy:0Gy:1]Gy:0Gy:0[Gy:0Gy:1]@(0,1) 0 10000 0 0 +Gy:1@(0,1) 5034 4966 0 0 +Gy:1Gy:1@(0,1) 0 10000 0 0 +Gy:1[Gx:0Gx:1]@(0,1) 2532 2538 2483 2447 +Gy:1[Gy:0Gy:1]@(0,1) 0 4969 0 5031 +[Gx:0Gx:1]Gy:1[Gx:0Gx:1]@(0,1) 0 0 0 10000 +[Gx:0Gx:1]Gy:1[Gy:0Gy:1]@(0,1) 2568 2433 2515 2484 +[Gy:0Gy:1]Gy:1[Gy:0Gy:1]@(0,1) 0 0 4924 5076 +Gy:1Gy:1Gy:1@(0,1) 4890 5110 0 0 +Gy:1Gy:1[Gx:0Gx:1]@(0,1) 2492 2526 2520 2462 +Gy:1Gy:1[Gy:0Gy:1]@(0,1) 2504 2443 2525 2528 +[Gx:0Gx:1]Gy:1Gy:1[Gx:0Gx:1]@(0,1) 0 0 0 10000 +[Gx:0Gx:1]Gy:1Gy:1[Gy:0Gy:1]@(0,1) 2544 2501 2503 2452 +[Gy:0Gy:1]Gy:1Gy:1[Gy:0Gy:1]@(0,1) 0 0 10000 0 +Gx:0Gy:0@(0,1) 4948 0 5052 0 +Gx:1Gy:1@(0,1) 5017 4983 0 0 +Gcnot:0:1@(0,1) 10000 0 0 0 +Gcnot:0:1Gx:1@(0,1) 4971 5029 0 0 +Gcnot:0:1Gy:1@(0,1) 5013 4987 0 0 +Gcnot:0:1Gx:0@(0,1) 5059 0 4941 0 +Gcnot:0:1[Gx:0Gx:1]@(0,1) 2519 2466 2470 2545 +Gx:1Gcnot:0:1Gx:1@(0,1) 0 10000 0 0 +Gx:1Gcnot:0:1Gy:1@(0,1) 5004 4996 0 0 +Gx:0Gcnot:0:1[Gx:0Gx:1]@(0,1) 2463 2499 2560 2478 +Gx:0Gcnot:0:1[Gx:0Gy:1]@(0,1) 4911 0 0 5089 +Gx:0Gcnot:0:1[Gy:0Gx:1]@(0,1) 4962 0 0 5038 +Gy:1Gcnot:0:1Gy:1@(0,1) 0 10000 0 0 +Gcnot:0:1Gcnot:0:1@(0,1) 10000 0 0 0 +Gcnot:0:1Gcnot:0:1Gx:1@(0,1) 4923 5077 0 0 +Gcnot:0:1Gcnot:0:1Gx:0@(0,1) 4990 0 5010 0 +Gcnot:0:1Gcnot:0:1Gy:1@(0,1) 5059 4941 0 0 +Gcnot:0:1Gcnot:0:1Gy:0@(0,1) 4972 0 5028 0 +Gx:1Gcnot:0:1Gcnot:0:1Gx:1@(0,1) 0 10000 0 0 +Gx:0Gcnot:0:1Gcnot:0:1Gx:0@(0,1) 0 0 10000 0 +Gx:1Gcnot:0:1Gcnot:0:1Gy:1@(0,1) 4983 5017 0 0 +Gx:0Gcnot:0:1Gcnot:0:1Gy:0@(0,1) 5050 0 4950 0 +Gy:1Gcnot:0:1Gcnot:0:1Gy:1@(0,1) 0 10000 0 0 +Gy:0Gcnot:0:1Gcnot:0:1Gy:0@(0,1) 0 0 10000 0 +Gx:0Gcnot:0:1@(0,1) 4951 0 0 5049 +Gx:0Gcnot:0:1Gx:1@(0,1) 2494 2545 2487 2474 +Gx:1Gx:0Gcnot:0:1Gx:1@(0,1) 0 5033 4967 0 +Gx:1Gcnot:0:1@(0,1) 5013 4987 0 0 +Gy:0Gcnot:0:1Gx:1@(0,1) 2554 2504 2456 2486 +Gx:0Gy:1Gcnot:0:1Gy:0@(0,1) 2549 2453 2459 2539 diff --git a/test/test_packages/cmp_chk_files/nqubit_2Q_dataset.json b/test/test_packages/cmp_chk_files/nqubit_2Q_dataset.json deleted file mode 100644 index be6d474a1..000000000 --- a/test/test_packages/cmp_chk_files/nqubit_2Q_dataset.json +++ /dev/null @@ -1 +0,0 @@ -{"cirIndexKeys": {"__list__": [{"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "[]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "[]Gx:1@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "[]Gx:0@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "[]Gy:1@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "[]Gy:0@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gx:1[]Gx:1@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gx:0[]Gx:0@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gx:1[]Gy:1@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gx:0[]Gy:0@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gy:1[]Gy:1@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gy:0[]Gy:0@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "[][]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "[][]Gx:1@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "[][]Gx:0@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "[][]Gy:1@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "[][]Gy:0@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gx:1[][]Gx:1@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gx:0[][]Gx:0@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gx:1[][]Gy:1@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gx:0[][]Gy:0@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gy:1[][]Gy:1@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": []}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gy:0[][]Gy:0@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gx:0@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gx:0Gx:0@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "Gx:0[Gx:0Gx:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "Gx:0[Gy:0Gy:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "[Gx:0Gx:1]Gx:0[Gx:0Gx:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "[Gx:0Gx:1]Gx:0[Gy:0Gy:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "[Gy:0Gy:1]Gx:0[Gy:0Gy:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gx:0Gx:0Gx:0@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "Gx:0Gx:0[Gx:0Gx:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "Gx:0Gx:0[Gy:0Gy:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "[Gx:0Gx:1]Gx:0Gx:0[Gx:0Gx:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "[Gx:0Gx:1]Gx:0Gx:0[Gy:0Gy:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "[Gy:0Gy:1]Gx:0Gx:0[Gy:0Gy:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gx:1@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gx:1Gx:1@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "Gx:1[Gx:0Gx:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "Gx:1[Gy:0Gy:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "[Gx:0Gx:1]Gx:1[Gx:0Gx:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "[Gx:0Gx:1]Gx:1[Gy:0Gy:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "[Gy:0Gy:1]Gx:1[Gy:0Gy:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gx:1Gx:1Gx:1@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "Gx:1Gx:1[Gx:0Gx:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "Gx:1Gx:1[Gy:0Gy:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "[Gx:0Gx:1]Gx:1Gx:1[Gx:0Gx:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "[Gx:0Gx:1]Gx:1Gx:1[Gy:0Gy:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "[Gy:0Gy:1]Gx:1Gx:1[Gy:0Gy:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gy:0@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gy:0Gy:0@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "Gy:0[Gx:0Gx:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "Gy:0[Gy:0Gy:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "[Gx:0Gx:1]Gy:0[Gx:0Gx:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "[Gx:0Gx:1]Gy:0[Gy:0Gy:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "[Gy:0Gy:1]Gy:0[Gy:0Gy:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gy:0Gy:0Gy:0@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "Gy:0Gy:0[Gx:0Gx:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "Gy:0Gy:0[Gy:0Gy:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "[Gx:0Gx:1]Gy:0Gy:0[Gx:0Gx:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "[Gx:0Gx:1]Gy:0Gy:0[Gy:0Gy:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "[Gy:0Gy:1]Gy:0Gy:0[Gy:0Gy:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gy:1@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gy:1Gy:1@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "Gy:1[Gx:0Gx:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "Gy:1[Gy:0Gy:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "[Gx:0Gx:1]Gy:1[Gx:0Gx:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "[Gx:0Gx:1]Gy:1[Gy:0Gy:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "[Gy:0Gy:1]Gy:1[Gy:0Gy:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gy:1Gy:1Gy:1@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "Gy:1Gy:1[Gx:0Gx:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "Gy:1Gy:1[Gy:0Gy:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "[Gx:0Gx:1]Gy:1Gy:1[Gx:0Gx:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "[Gx:0Gx:1]Gy:1Gy:1[Gy:0Gy:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "[Gy:0Gy:1]Gy:1Gy:1[Gy:0Gy:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gx:0Gy:0@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gx:1Gy:1@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gcnot:0:1@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gcnot:0:1Gx:1@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gcnot:0:1Gy:1@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gcnot:0:1Gx:0@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "Gcnot:0:1[Gx:0Gx:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gx:1Gcnot:0:1Gx:1@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gx:1Gcnot:0:1Gy:1@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "Gx:0Gcnot:0:1[Gx:0Gx:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "Gx:0Gcnot:0:1[Gx:0Gy:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTupTup"]}]}, "_str": "Gx:0Gcnot:0:1[Gy:0Gx:1]@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gy:1Gcnot:0:1Gy:1@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gcnot:0:1Gcnot:0:1@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gcnot:0:1Gcnot:0:1Gx:1@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gcnot:0:1Gcnot:0:1Gx:0@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gcnot:0:1Gcnot:0:1Gy:1@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gcnot:0:1Gcnot:0:1Gy:0@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gx:1Gcnot:0:1Gcnot:0:1Gx:1@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gx:0Gcnot:0:1Gcnot:0:1Gx:0@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gx:1Gcnot:0:1Gcnot:0:1Gy:1@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gx:0Gcnot:0:1Gcnot:0:1Gy:0@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gy:1Gcnot:0:1Gcnot:0:1Gy:1@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gy:0Gcnot:0:1Gcnot:0:1Gy:0@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gx:0Gcnot:0:1@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gx:0Gcnot:0:1Gx:1@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gx:1Gx:0Gcnot:0:1Gx:1@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gx:1Gcnot:0:1@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gy:0Gcnot:0:1Gx:1@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}, {"_tup": {"__tuple__": [{"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gx", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gcnot", 0, 1]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}, {"__state_obj__": {"__tuple__": []}, "__init_args__": {"__tuple__": [{"__tuple__": ["Gy", 0]}]}, "__pygstiobj__": ["pygsti.baseobjs.label", "LabelTup"]}]}, "_str": "Gx:0Gy:1Gcnot:0:1Gy:0@(0,1)", "_line_labels": {"__tuple__": [0, 1]}, "_occurrence_id": null, "__pygstiobj__": ["pygsti.circuits.circuit", "CompressedCircuit"]}]}, "cirIndexVals": {"__list__": [{"__slice__": [0, 4, null]}, {"__slice__": [4, 8, null]}, {"__slice__": [8, 12, null]}, {"__slice__": [12, 16, null]}, {"__slice__": [16, 20, null]}, {"__slice__": [20, 24, null]}, {"__slice__": [24, 28, null]}, {"__slice__": [28, 32, null]}, {"__slice__": [32, 36, null]}, {"__slice__": [36, 40, null]}, {"__slice__": [40, 44, null]}, {"__slice__": [44, 48, null]}, {"__slice__": [48, 52, null]}, {"__slice__": [52, 56, null]}, {"__slice__": [56, 60, null]}, {"__slice__": [60, 64, null]}, {"__slice__": [64, 68, null]}, {"__slice__": [68, 72, null]}, {"__slice__": [72, 76, null]}, {"__slice__": [76, 80, null]}, {"__slice__": [80, 84, null]}, {"__slice__": [84, 88, null]}, {"__slice__": [88, 92, null]}, {"__slice__": [92, 96, null]}, {"__slice__": [96, 100, null]}, {"__slice__": [100, 104, null]}, {"__slice__": [104, 108, null]}, {"__slice__": [108, 112, null]}, {"__slice__": [112, 116, null]}, {"__slice__": [116, 120, null]}, {"__slice__": [120, 124, null]}, {"__slice__": [124, 128, null]}, {"__slice__": [128, 132, null]}, {"__slice__": [132, 136, null]}, {"__slice__": [136, 140, null]}, {"__slice__": [140, 144, null]}, {"__slice__": [144, 148, null]}, {"__slice__": [148, 152, null]}, {"__slice__": [152, 156, null]}, {"__slice__": [156, 160, null]}, {"__slice__": [160, 164, null]}, {"__slice__": [164, 168, null]}, {"__slice__": [168, 172, null]}, {"__slice__": [172, 176, null]}, {"__slice__": [176, 180, null]}, {"__slice__": [180, 184, null]}, {"__slice__": [184, 188, null]}, {"__slice__": [188, 192, null]}, {"__slice__": [192, 196, null]}, {"__slice__": [196, 200, null]}, {"__slice__": [200, 204, null]}, {"__slice__": [204, 208, null]}, {"__slice__": [208, 212, null]}, {"__slice__": [212, 216, null]}, {"__slice__": [216, 220, null]}, {"__slice__": [220, 224, null]}, {"__slice__": [224, 228, null]}, {"__slice__": [228, 232, null]}, {"__slice__": [232, 236, null]}, {"__slice__": [236, 240, null]}, {"__slice__": [240, 244, null]}, {"__slice__": [244, 248, null]}, {"__slice__": [248, 252, null]}, {"__slice__": [252, 256, null]}, {"__slice__": [256, 260, null]}, {"__slice__": [260, 264, null]}, {"__slice__": [264, 268, null]}, {"__slice__": [268, 272, null]}, {"__slice__": [272, 276, null]}, {"__slice__": [276, 280, null]}, {"__slice__": [280, 284, null]}, {"__slice__": [284, 288, null]}, {"__slice__": [288, 292, null]}, {"__slice__": [292, 296, null]}, {"__slice__": [296, 300, null]}, {"__slice__": [300, 304, null]}, {"__slice__": [304, 308, null]}, {"__slice__": [308, 312, null]}, {"__slice__": [312, 316, null]}, {"__slice__": [316, 320, null]}, {"__slice__": [320, 324, null]}, {"__slice__": [324, 328, null]}, {"__slice__": [328, 332, null]}, {"__slice__": [332, 336, null]}, {"__slice__": [336, 340, null]}, {"__slice__": [340, 344, null]}, {"__slice__": [344, 348, null]}, {"__slice__": [348, 352, null]}, {"__slice__": [352, 356, null]}, {"__slice__": [356, 360, null]}, {"__slice__": [360, 364, null]}, {"__slice__": [364, 368, null]}, {"__slice__": [368, 372, null]}, {"__slice__": [372, 376, null]}, {"__slice__": [376, 380, null]}, {"__slice__": [380, 384, null]}, {"__slice__": [384, 388, null]}, {"__slice__": [388, 392, null]}, {"__slice__": [392, 396, null]}, {"__slice__": [396, 400, null]}, {"__slice__": [400, 404, null]}, {"__slice__": [404, 408, null]}, {"__slice__": [408, 412, null]}, {"__slice__": [412, 416, null]}]}, "olIndex": {"__odict__": [[{"__tuple__": ["00"]}, 0], [{"__tuple__": ["01"]}, 1], [{"__tuple__": ["10"]}, 2], [{"__tuple__": ["11"]}, 3]]}, "olIndex_max": 3, "ol": {"__odict__": [[0, {"__tuple__": ["00"]}], [1, {"__tuple__": ["01"]}], [2, {"__tuple__": ["10"]}], [3, {"__tuple__": ["11"]}]]}, "bStatic": true, "oliData": {"__ndarray__": "AAAAAAEAAAACAAAAAwAAAAAAAAABAAAAAgAAAAMAAAAAAAAAAQAAAAIAAAADAAAAAAAAAAEAAAACAAAAAwAAAAAAAAABAAAAAgAAAAMAAAAAAAAAAQAAAAIAAAADAAAAAAAAAAEAAAACAAAAAwAAAAAAAAABAAAAAgAAAAMAAAAAAAAAAQAAAAIAAAADAAAAAAAAAAEAAAACAAAAAwAAAAAAAAABAAAAAgAAAAMAAAAAAAAAAQAAAAIAAAADAAAAAAAAAAEAAAACAAAAAwAAAAAAAAABAAAAAgAAAAMAAAAAAAAAAQAAAAIAAAADAAAAAAAAAAEAAAACAAAAAwAAAAAAAAABAAAAAgAAAAMAAAAAAAAAAQAAAAIAAAADAAAAAAAAAAEAAAACAAAAAwAAAAAAAAABAAAAAgAAAAMAAAAAAAAAAQAAAAIAAAADAAAAAAAAAAEAAAACAAAAAwAAAAAAAAABAAAAAgAAAAMAAAAAAAAAAQAAAAIAAAADAAAAAAAAAAEAAAACAAAAAwAAAAAAAAABAAAAAgAAAAMAAAAAAAAAAQAAAAIAAAADAAAAAAAAAAEAAAACAAAAAwAAAAAAAAABAAAAAgAAAAMAAAAAAAAAAQAAAAIAAAADAAAAAAAAAAEAAAACAAAAAwAAAAAAAAABAAAAAgAAAAMAAAAAAAAAAQAAAAIAAAADAAAAAAAAAAEAAAACAAAAAwAAAAAAAAABAAAAAgAAAAMAAAAAAAAAAQAAAAIAAAADAAAAAAAAAAEAAAACAAAAAwAAAAAAAAABAAAAAgAAAAMAAAAAAAAAAQAAAAIAAAADAAAAAAAAAAEAAAACAAAAAwAAAAAAAAABAAAAAgAAAAMAAAAAAAAAAQAAAAIAAAADAAAAAAAAAAEAAAACAAAAAwAAAAAAAAABAAAAAgAAAAMAAAAAAAAAAQAAAAIAAAADAAAAAAAAAAEAAAACAAAAAwAAAAAAAAABAAAAAgAAAAMAAAAAAAAAAQAAAAIAAAADAAAAAAAAAAEAAAACAAAAAwAAAAAAAAABAAAAAgAAAAMAAAAAAAAAAQAAAAIAAAADAAAAAAAAAAEAAAACAAAAAwAAAAAAAAABAAAAAgAAAAMAAAAAAAAAAQAAAAIAAAADAAAAAAAAAAEAAAACAAAAAwAAAAAAAAABAAAAAgAAAAMAAAAAAAAAAQAAAAIAAAADAAAAAAAAAAEAAAACAAAAAwAAAAAAAAABAAAAAgAAAAMAAAAAAAAAAQAAAAIAAAADAAAAAAAAAAEAAAACAAAAAwAAAAAAAAABAAAAAgAAAAMAAAAAAAAAAQAAAAIAAAADAAAAAAAAAAEAAAACAAAAAwAAAAAAAAABAAAAAgAAAAMAAAAAAAAAAQAAAAIAAAADAAAAAAAAAAEAAAACAAAAAwAAAAAAAAABAAAAAgAAAAMAAAAAAAAAAQAAAAIAAAADAAAAAAAAAAEAAAACAAAAAwAAAAAAAAABAAAAAgAAAAMAAAAAAAAAAQAAAAIAAAADAAAAAAAAAAEAAAACAAAAAwAAAAAAAAABAAAAAgAAAAMAAAAAAAAAAQAAAAIAAAADAAAAAAAAAAEAAAACAAAAAwAAAAAAAAABAAAAAgAAAAMAAAAAAAAAAQAAAAIAAAADAAAAAAAAAAEAAAACAAAAAwAAAAAAAAABAAAAAgAAAAMAAAAAAAAAAQAAAAIAAAADAAAAAAAAAAEAAAACAAAAAwAAAAAAAAABAAAAAgAAAAMAAAAAAAAAAQAAAAIAAAADAAAAAAAAAAEAAAACAAAAAwAAAAAAAAABAAAAAgAAAAMAAAAAAAAAAQAAAAIAAAADAAAAAAAAAAEAAAACAAAAAwAAAAAAAAABAAAAAgAAAAMAAAAAAAAAAQAAAAIAAAADAAAAAAAAAAEAAAACAAAAAwAAAAAAAAABAAAAAgAAAAMAAAAAAAAAAQAAAAIAAAADAAAAAAAAAAEAAAACAAAAAwAAAAAAAAABAAAAAgAAAAMAAAAAAAAAAQAAAAIAAAADAAAAAAAAAAEAAAACAAAAAwAAAAAAAAABAAAAAgAAAAMAAAAAAAAAAQAAAAIAAAADAAAAAAAAAAEAAAACAAAAAwAAAAAAAAABAAAAAgAAAAMAAAAAAAAAAQAAAAIAAAADAAAAAAAAAAEAAAACAAAAAwAAAAAAAAABAAAAAgAAAAMAAAA=", "dtype": " 2 and geometry == "ring": - self.add(nQubits-1,0) - elif geometry in ("grid","torus"): - s = int(round(_np.sqrt(nQubits))) - assert(nQubits >= 4 and s*s == nQubits), \ - "`nQubits` must be a perfect square >= 4" - #row links - for irow in range(s): - for icol in range(s): - if icol+1 < s: - self.add(irow*s+icol, irow*s+icol+1) #link right - elif geometry == "torus" and s > 2: - self.add(irow*s+icol, irow*s+0) - - if irow+1 < s: - self.add(irow*s+icol, (irow+1)*s+icol) #link down - elif geometry == "torus" and s > 2: - self.add(irow*s+icol, 0+icol) - else: - raise ValueError("Invalid `geometry`: %s" % geometry) - - def add_connections(self, connections): - """ Add connections (list of tuple pairs) to graph """ - for node1, node2 in connections: - self.add(node1, node2) - - def add(self, node1, node2): - """ Add connection between node1 and node2 """ - self._graph[node1].add(node2) - self._graph[node2].add(node1) - - def edges(self): - ret = set() - for node,neighbors in self._graph.items(): - for neighbor in neighbors: - if node < neighbor: # all edge tuples have lower index first - ret.add( (node,neighbor) ) - else: - ret.add( (neighbor,node) ) - return sorted(list(ret)) - - def radius(self, base_indices, max_hops): - """ - Returns a (sorted) array of indices that can be reached - from traversing at most `max_hops` edges starting - from a vertex in base_indices - """ - ret = set() - assert(max_hops >= 0) - - def traverse(start, hops_left): - ret.add(start) - if hops_left <= 0: return - for i in self._graph[start]: - traverse(i,hops_left-1) - - for node in base_indices: - traverse(node,max_hops) - return _np.array(sorted(list(ret)),'i') - - def connected_combos(self, possible_indices, size): - count = 0 - for selected_inds in _itertools.combinations(possible_indices, size): - if self.are_connected(selected_inds): count += 1 - return count - -# def remove(self, node): -# """ Remove all references to node """ -# for n, cxns in self._graph.iteritems(): -# try: -# cxns.remove(node) -# except KeyError: -# pass -# try: -# del self._graph[node] -# except KeyError: -# pass - - def is_connected(self, node1, node2): - """ Is node1 directly connected to node2 """ - return node1 in self._graph and node2 in self._graph[node1] - - def are_connected(self, indices): - """ - Are all the nodes in `indices` connected to at least - one other node in `indices`? - """ - if len(indices) < 2: return True # 0 or 1 indices are "connected" - - for node in indices: #check - if node not in self._graph: return False - - glob = set() - def add_to_glob(node): - glob.add(node) - for neighbor in self._graph[node].intersection(indices): - if neighbor not in glob: - add_to_glob(neighbor) - - add_to_glob(indices[0]) - return bool(glob == set(indices)) - -# def find_path(self, node1, node2, path=[]): -# """ Find any path between node1 and node2 (may not be shortest) """ -# path = path + [node1] -# if node1 == node2: -# return path -# if node1 not in self._graph: -# return None -# for node in self._graph[node1]: -# if node not in path: -# new_path = self.find_path(node, node2, path) -# if new_path: -# return new_path -# return None - - def __str__(self): - return '{}({})'.format(self.__class__.__name__, dict(self._graph)) - - -## Pauli basis matrices -sqrt2 = _np.sqrt(2) -id2x2 = _np.array([[1,0],[0,1]]) -sigmax = _np.array([[0,1],[1,0]]) -sigmay = _np.array([[0,-1.0j],[1.0j,0]]) -sigmaz = _np.array([[1,0],[0,-1]]) - -sigmaVec = (id2x2/sqrt2, sigmax/sqrt2, sigmay/sqrt2, sigmaz/sqrt2) - - -def iter_basis_inds(weight): - basisIndList = [ [1,2,3] ]*weight #assume pauli 1Q basis, and only iterate over non-identity els - for basisInds in _itertools.product(*basisIndList): - yield basisInds - -def basisProductMatrix(sigmaInds, sparse): - M = _np.identity(1,'complex') - for i in sigmaInds: - M = _np.kron(M,sigmaVec[i]) - return _sps.csr_matrix(M) if sparse else M - -def nparams_nqubit_gateset(nQubits, geometry="line", maxIdleWeight=1, maxhops=0, - extraWeight1Hops=0, extraGateWeight=0, requireConnected=False, - independent1Qgates=True, ZZonly=False, verbosity=0): - # noise can be either a seed or a random array that is long enough to use - - printer = pygsti.baseobjs.VerbosityPrinter.create_printer(verbosity) - printer.log("Computing parameters for a %d-qubit %s model" % (nQubits,geometry)) - - qubitGraph = QubitGraph(nQubits, geometry) - #printer.log("Created qubit graph:\n"+str(qubitGraph)) - - def idle_count_nparams(maxWeight): - ret = 0 - possible_err_qubit_inds = _np.arange(nQubits) - for wt in range(1,maxWeight+1): - nErrTargetLocations = qubitGraph.connected_combos(possible_err_qubit_inds,wt) - if ZZonly and wt > 1: basisSizeWoutId = 1**wt # ( == 1) - else: basisSizeWoutId = 3**wt # (X,Y,Z)^wt - nErrParams = 2*basisSizeWoutId # H+S terms - ret += nErrTargetLocations * nErrParams - return ret - - def op_count_nparams(target_qubit_inds,weight_maxhops_tuples,debug=False): - ret = 0 - #Note: no contrib from idle noise (already parameterized) - for wt, maxHops in weight_maxhops_tuples: - possible_err_qubit_inds = qubitGraph.radius(target_qubit_inds, maxHops) - if requireConnected: - nErrTargetLocations = qubitGraph.connected_combos(possible_err_qubit_inds,wt) - else: - nErrTargetLocations = _scipy.misc.comb(len(possible_err_qubit_inds),wt) #matches actual initial stud - if ZZonly and wt > 1: basisSizeWoutId = 1**wt # ( == 1) - else: basisSizeWoutId = 3**wt # (X,Y,Z)^wt - nErrParams = 2*basisSizeWoutId # H+S terms - if debug: - print(" -- wt%d, hops%d: inds=%s locs = %d, eparams=%d, total contrib = %d" % - (wt,maxHops,str(possible_err_qubit_inds),nErrTargetLocations,nErrParams,nErrTargetLocations*nErrParams)) - ret += nErrTargetLocations * nErrParams - return ret - - nParams = _collections.OrderedDict() - - printer.log("Creating Idle:") - nParams['Gi'] = idle_count_nparams(maxIdleWeight) - - #1Q gates: X(pi/2) & Y(pi/2) on each qubit - weight_maxhops_tuples_1Q = [(1,maxhops+extraWeight1Hops)] + \ - [ (1+x,maxhops) for x in range(1,extraGateWeight+1) ] - - if independent1Qgates: - for i in range(nQubits): - printer.log("Creating 1Q X(pi/2) and Y(pi/2) gates on qubit %d!!" % i) - nParams["Gx%d"%i] = op_count_nparams((i,), weight_maxhops_tuples_1Q) - nParams["Gy%d"%i] = op_count_nparams((i,), weight_maxhops_tuples_1Q) - else: - printer.log("Creating common 1Q X(pi/2) and Y(pi/2) gates") - rep = int(nQubits / 2) - nParams["Gxrep"] = op_count_nparams((rep,), weight_maxhops_tuples_1Q) - nParams["Gyrep"] = op_count_nparams((rep,), weight_maxhops_tuples_1Q) - - #2Q gates: CNOT gates along each graph edge - weight_maxhops_tuples_2Q = [(1,maxhops+extraWeight1Hops),(2,maxhops)] + \ - [ (2+x,maxhops) for x in range(1,extraGateWeight+1) ] - for i,j in qubitGraph.edges(): #note: all edges have i error basis of length %d" % (err_qubit_inds,len(errbasis)), 3) - errbasis = pygsti.baseobjs.Basis(matrices=errbasis, sparse=sparse) #single element basis (plus identity) - termErr = Lindblad(wtId, ham_basis=errbasis, nonham_basis=errbasis, cptp=True, - nonham_diagonal_only=True, truncate=True, mx_basis=wtBasis) - - err_qubit_global_inds = err_qubit_inds - fullTermErr = Embedded(ssAllQ, [('Q%d'%i) for i in err_qubit_global_inds], - termErr, basisAllQ.dim) - assert(fullTermErr.num_params() == termErr.num_params()) - printer.log("Lindblad gate w/dim=%d and %d params -> embedded to gate w/dim=%d" % - (termErr.dim, termErr.num_params(), fullTermErr.dim)) - - termgates.append( fullTermErr ) - - return Composed(termgates) - - - -#def create_noncomposed_gate(target_op, target_qubit_inds, qubitGraph, max_weight, maxHops, -# spectatorMaxWeight=1, mode="embed"): -# -# assert(spectatorMaxWeight <= 1) #only 0 and 1 are currently supported -# -# errinds = [] # list of basis indices for all error terms -# possible_err_qubit_inds = qubitGraph.radius(target_qubit_inds, maxHops) -# nPossible = len(possible_err_qubit_inds) -# for wt in range(max_weight+1): -# if mode == "no-embedding": # make an error term for the entire gate -# for err_qubit_inds in _itertools.combinations(possible_err_qubit_inds, wt): -# # err_qubit_inds are global qubit indices -# #Future: check that err_qubit_inds marks qubits that are connected -# -# for err_basis_inds in iter_basis_inds(wt): -# error = _np.zeros(nQubits) -# error[ possible_err_qubit_inds[err_qubit_inds] ] = err_basis_inds -# errinds.append( error ) -# -# elif mode == "embed": # make an error term for only the "possible error" qubits -# # which will get embedded to form a full gate -# for err_qubit_inds in _itertools.combinations(list(range(nPossible)), wt): -# # err_qubit_inds are indices into possible_err_qubit_inds -# #Future: check that err_qubit_inds marks qubits that are connected -# -# for err_basis_inds in iter_basis_inds(wt): -# error = _np.zeros(nPossible) -# error[ err_qubit_inds ] = err_basis_inds -# errinds.append( error ) -# -# errbasis = [ basisProductMatrix(err) for err in errinds] -# -# ssAllQ = ['Q%d'%i for i in range(qubitGraph.nQubits)] -# basisAllQ = pygsti.objects.Basis('pp', 2**qubitGraph.nQubits) -# -# if mode == "no-embedding": -# fullTargetOp = EmbeddedDenseOp(ssAllQ, ['Q%d'%i for i in target_qubit_inds], -# target_op, basisAllQ) -# fullTargetOp = StaticArbitraryOp( fullTargetOp ) #Make static -# fullLocalErr = LindbladDenseOp(fullTargetOp, fullTargetOp, -# ham_basis=errbasis, nonham_basis=errbasis, cptp=True, -# nonham_diagonal_only=True, truncate=True, mx_basis=basisAllQ) -# # gate on full qubit space that accounts for error on the "local qubits", that is, -# # those local to the qubits being operated on -# elif mode == "embed": -# possible_list = list(possible_err_qubit_inds) -# loc_target_inds = [possible_list.index(i) for i in target_qubit_inds] -# -# ssLocQ = ['Q%d'%i for i in range(nPossible)] -# basisLocQ = pygsti.objects.Basis('pp', 2**nPossible) -# locTargetOp = StaticArbitraryOp( EmbeddedDenseOp(ssLocQ, ['Q%d'%i for i in loc_target_inds], -# target_op, basisLocQ) ) -# localErr = LindbladDenseOp(locTargetOp, locTargetOp, -# ham_basis=errbasis, nonham_basis=errbasis, cptp=True, -# nonham_diagonal_only=True, truncate=True, mx_basis=basisLocQ) -# fullLocalErr = EmbeddedDenseOp(ssAllQ, ['Q%d'%i for i in possible_err_qubit_inds], -# localErr, basisAllQ) -# else: -# raise ValueError("Invalid Mode: %s" % mode) -# -# #Now add errors on "non-local" i.e. spectator gates -# if spectatorMaxWeight == 0: -# pass -# #STILL in progress -- maybe just non-embedding case, since if we embed we'll -# # need to compose (in general) - - - -def create_composed_gate(targetOp, target_qubit_inds, qubitGraph, weight_maxhops_tuples, - idle_noise=False, loc_noise_type="onebig", - apply_idle_noise_to="all", sparse=False, verbosity=0): - """ - Final gate is a composition of: - targetOp(target qubits) -> idle_noise(all_qubits) -> loc_noise(local_qubits) - - where `idle_noise` is given by the `idle_noise` parameter and loc_noise is given - by the other params. loc_noise can be implemented either by - a single embedded LindbladDenseOp with all relevant error generators, - or as a composition of embedded-single-error-term gates (see param `loc_noise_type`) - - Parameters - ---------- - - idle_noise : LinearOperator or boolean - either given as an existing gate (on all qubits) or a boolean indicating - whether a composition of weight-1 noise terms (separately on all the qubits), - is created. If `apply_idle_noise_to == "nonlocal"` then `idle_noise` is *only* - applied to the non-local qubits and `idle_noise` must be a ComposedDenseOp or - ComposedMap with nQubits terms so that individual terms for each qubit can - be extracted as needed. - - TODO - """ - if sparse: - Lindblad = _objs.LindbladOp - Composed = _objs.ComposedOp - Embedded = _objs.EmbeddedOp - Static = _objs.StaticDenseOp # TODO: create StaticGateMap - else: - Lindblad = _objs.LindbladDenseOp - Composed = _objs.ComposedDenseOp - Embedded = _objs.EmbeddedDenseOp - Static = _objs.StaticDenseOp - - printer = pygsti.baseobjs.VerbosityPrinter.create_printer(verbosity) - printer.log("*** Creating composed gate ***") - - #Factor1: target operation - printer.log("Creating %d-qubit target op factor on qubits %s" % - (len(target_qubit_inds),str(target_qubit_inds)),2) - ssAllQ = [tuple(['Q%d'%i for i in range(qubitGraph.nQubits)])] - basisAllQ = pygsti.objects.Basis('pp', 2 ** qubitGraph.nQubits, sparse=sparse) - fullTargetOp = Embedded(ssAllQ, ['Q%d'%i for i in target_qubit_inds], - Static(targetOp), basisAllQ.dim) - - #Factor2: idle_noise operation - printer.log("Creating idle error factor",2) - if apply_idle_noise_to == "all": - if isinstance(idle_noise, pygsti.baseobjs.LinearOperator): - printer.log("Using supplied full idle gate",3) - fullIdleErr = idle_noise - elif idle_noise == True: - #build composition of 1Q idle ops - printer.log("Constructing independend weight-1 idle gate",3) - # Id_1Q = _sps.identity(4**1,'d','csr') if sparse else _np.identity(4**1,'d') - Id_1Q = _np.identity(4**1,'d') #always dense for now... - fullIdleErr = Composed( - [ Embedded(ssAllQ, ('Q%d'%i,), Lindblad(Id_1Q.copy()),basisAllQ.dim) - for i in range(qubitGraph.nQubits)] ) - elif idle_noise == False: - printer.log("No idle factor",3) - fullIdleErr = None - else: - raise ValueError("Invalid `idle_noise` argument") - - elif apply_idle_noise_to == "nonlocal": - pass #TODO: only apply (1Q) idle noise to qubits that don't have 1Q local noise. - assert(False) - - else: - raise ValueError('Invalid `apply_idle_noise_to` argument: %s' % apply_idle_noise_to) - - - #Factor3: local_noise operation - printer.log("Creating local-noise error factor (%s)" % loc_noise_type,2) - if loc_noise_type == "onebig": - # make a single embedded Lindblad-gate containing all specified error terms - loc_noise_errinds = [] # list of basis indices for all local-error terms - all_possible_err_qubit_inds = qubitGraph.radius( - target_qubit_inds, max([hops for _,hops in weight_maxhops_tuples]) ) - nLocal = len(all_possible_err_qubit_inds) - basisEl_Id = basisProductMatrix(_np.zeros(nPossible,'i'),sparse) #identity basis el - - for wt, maxHops in weight_maxhops_tuples: - possible_err_qubit_inds = qubitGraph.radius(target_qubit_inds, maxHops) - nPossible = len(possible_err_qubit_inds) - possible_to_local = [ all_possible_err_qubit_inds.index( - possible_err_qubit_inds[i]) for i in range(nPossible)] - printer.log("Weight %d, max-hops %d: %d possible qubits of %d local" % - (wt,maxHops,nPossible,nLocal),3) - - for err_qubit_inds in _itertools.combinations(list(range(nPossible)), wt): - # err_qubit_inds are in range [0,nPossible-1] qubit indices - #Future: check that err_qubit_inds marks qubits that are connected - err_qubit_local_inds = possible_to_local[err_qubit_inds] - - for err_basis_inds in iter_basis_inds(wt): - error = _np.zeros(nLocal,'i') - error[ err_qubit_local_inds ] = err_basis_inds - loc_noise_errinds.append( error ) - - printer.log("Error on qubits %s -> error basis now at length %d" % - (all_possible_err_qubit_inds[err_qubit_local_inds],1+len(loc_noise_errinds)), 4) - - errbasis = [basisEl_Id] + \ - [ basisProductMatrix(err,sparse) for err in loc_noise_errinds] - errbasis = pygsti.baseobjs.Basis(matrices=errbasis, sparse=sparse) #single element basis (plus identity) - - #Construct one embedded Lindblad-gate using all `errbasis` terms - ssLocQ = [tuple(['Q%d'%i for i in range(nLocal)])] - basisLocQ = pygsti.objects.Basis('pp', 2 ** nLocal, sparse=sparse) - locId = _sps.identity(4**nLocal,'d','csr') if sparse else _np.identity(4**nLocal,'d') - localErr = Lindblad(locId, ham_basis=errbasis, - nonham_basis=errbasis, cptp=True, - nonham_diagonal_only=True, truncate=True, - mx_basis=basisLocQ) - fullLocalErr = Embedded(ssAllQ, ['Q%d'%i for i in all_possible_err_qubit_inds], - localErr, basisAllQ.dim) - printer.log("Lindblad gate w/dim=%d and %d params (from error basis of len %d) -> embedded to gate w/dim=%d" % - (localErr.dim, localErr.num_params(), len(errbasis), fullLocalErr.dim),2) - - - elif loc_noise_type == "manylittle": - # make a composed-gate of embedded single-basis-element Lindblad-gates, - # one for each specified error term - - loc_noise_termgates = [] #list of gates to compose - - for wt, maxHops in weight_maxhops_tuples: - - ## loc_noise_errinds = [] # list of basis indices for all local-error terms - possible_err_qubit_inds = qubitGraph.radius(target_qubit_inds, maxHops) - nPossible = len(possible_err_qubit_inds) # also == "nLocal" in this case - basisEl_Id = basisProductMatrix(_np.zeros(wt,'i'),sparse) #identity basis el - - wtId = _sps.identity(4**wt,'d','csr') if sparse else _np.identity(4**wt,'d') - wtBasis = pygsti.objects.Basis('pp', 2 ** wt, sparse=sparse) - - printer.log("Weight %d, max-hops %d: %d possible qubits" % (wt,maxHops,nPossible),3) - - for err_qubit_local_inds in _itertools.combinations(list(range(nPossible)), wt): - # err_qubit_inds are in range [0,nPossible-1] qubit indices - #Future: check that err_qubit_inds marks qubits that are connected - - errbasis = [basisEl_Id] - for err_basis_inds in iter_basis_inds(wt): - error = _np.array(err_basis_inds,'i') #length == wt - basisEl = basisProductMatrix(error, sparse) - errbasis.append(basisEl) - - err_qubit_global_inds = possible_err_qubit_inds[list(err_qubit_local_inds)] - printer.log("Error on qubits %s -> error basis of length %d" % (err_qubit_global_inds,len(errbasis)), 4) - errbasis = pygsti.baseobjs.Basis(matrices=errbasis, sparse=sparse) #single element basis (plus identity) - termErr = Lindblad(wtId, ham_basis=errbasis, - nonham_basis=errbasis, cptp=True, - nonham_diagonal_only=True, truncate=True, - mx_basis=wtBasis) - - fullTermErr = Embedded(ssAllQ, ['Q%d'%i for i in err_qubit_global_inds], - termErr, basisAllQ.dim) - assert(fullTermErr.num_params() == termErr.num_params()) - printer.log("Lindblad gate w/dim=%d and %d params -> embedded to gate w/dim=%d" % - (termErr.dim, termErr.num_params(), fullTermErr.dim)) - - loc_noise_termgates.append( fullTermErr ) - - fullLocalErr = Composed(loc_noise_termgates) - - else: - raise ValueError("Invalid `loc_noise_type` arguemnt: %s" % loc_noise_type) - - if fullIdleErr is not None: - return Composed([fullTargetOp,fullIdleErr,fullLocalErr]) - else: - return Composed([fullTargetOp,fullLocalErr]) - diff --git a/test/test_packages/drivers/test_calcmethods1Q.py b/test/test_packages/drivers/test_calcmethods1Q.py index 1d1517899..c5c40969d 100644 --- a/test/test_packages/drivers/test_calcmethods1Q.py +++ b/test/test_packages/drivers/test_calcmethods1Q.py @@ -10,11 +10,11 @@ import pygsti import pygsti.models.modelconstruction as mc from pygsti.processors.processorspec import QubitProcessorSpec as _ProcessorSpec -from pygsti.modelpacks import smq1Q_XYI as std -from pygsti.modelpacks.legacy import std1Q_XY +from pygsti.modelpacks import smq1Q_XY as std from pygsti.baseobjs import Label as L from pygsti.circuits import Circuit from pygsti.serialization import json +from pygsti.models import ExplicitOpModel, CloudNoiseModel import os @@ -28,19 +28,9 @@ def build_XYCNOT_cloudnoise_model(nQubits, geometry="line", cnot_edges=None, spamtype="lindblad", addIdleNoiseToAllGates=True, errcomp_type="gates", evotype="default", return_clouds=False, verbosity=0): - #from pygsti.modelpacks.legacy import std1Q_XY # the base model for 1Q gates - #from pygsti.modelpacks.legacy import std2Q_XYICNOT # the base model for 2Q (CNOT) gate - # - #tgt1Q = std1Q_XY.target_model() - #tgt2Q = std2Q_XYICNOT.target_model() - #Gx = tgt1Q.operations['Gx'] - #Gy = tgt1Q.operations['Gy'] - #Gcnot = tgt2Q.operations['Gcnot'] - #gatedict = _collections.OrderedDict([('Gx',Gx),('Gy',Gy),('Gcnot',Gcnot)]) - availability = {}; nonstd_gate_unitaries = {} if cnot_edges is not None: availability['Gcnot'] = cnot_edges - pspec = _ProcessorSpec(nQubits, ['Gidle', 'Gx','Gy','Gcnot'], nonstd_gate_unitaries, availability, geometry) + pspec = _ProcessorSpec(nQubits, ['Gidle', 'Gxpi2','Gypi2','Gcnot'], nonstd_gate_unitaries, availability, geometry) assert(spamtype == "lindblad") # unused and should remove this arg, but should always be "lindblad" mdl = mc.create_cloud_crosstalk_model_from_hops_and_weights( pspec, None, @@ -76,14 +66,17 @@ def setUpClass(cls): #Standard GST dataset cls.maxLengths = [1,2,4] - cls.mdl_datagen = std.target_model().depolarize(op_noise=0.03, spam_noise=0.001) + min_prep_fids = std.prep_fiducials()[0:4] #Use a minimally informationally complete set of fiducials + min_meas_fids = std.meas_fiducials()[0:3] + + cls.mdl_datagen = std.target_model().depolarize(op_noise=0.05, spam_noise=0.01) cls.listOfExperiments = pygsti.circuits.create_lsgst_circuits( - std.target_model(), std.prep_fiducials(), std.meas_fiducials(), std.germs(), cls.maxLengths) + std.target_model(), min_prep_fids, min_meas_fids, std.germs(), cls.maxLengths) #RUN BELOW FOR DATAGEN (SAVE) if regenerate_references(): ds = pygsti.data.simulate_data(cls.mdl_datagen, cls.listOfExperiments, - num_samples=1000, sample_error="multinomial", seed=1234) + num_samples=10000, sample_error="multinomial", seed=1234) ds.save(compare_files + "/calcMethods1Q.dataset") #DEBUG TEST- was to make sure data files have same info -- seemed ultimately unnecessary @@ -102,12 +95,12 @@ def setUpClass(cls): simulator="matrix", verbosity=1, roughNoise=(1234,0.01)) #Create a reduced set of fiducials and germs - op_labels = [ L('Gx',0), L('Gy',0) ] # 1Q gate labels - fids1Q = std1Q_XY.fiducials[1:2] # for speed, just take 1 non-empty fiducial + op_labels = [ L('Gxpi2',0), L('Gypi2',0) ] # 1Q gate labels + fids1Q = std.prep_fiducials()[1:2] # for speed, just take 1 non-empty fiducial cls.redmod_fiducials = [ Circuit([], line_labels=(0,)) ] # special case for empty fiducial (need to change line label) for i in range(cls.nQubits): cls.redmod_fiducials.extend( pygsti.circuits.manipulate_circuits( - fids1Q, [ ( (L('Gx'),) , (L('Gx',i),) ), ( (L('Gy'),) , (L('Gy',i),) ) ]) ) + fids1Q, [ ( (L('Gxpi2', 0),) , (L('Gxpi2',i),) ), ( (L('Gypi2',0),) , (L('Gypi2',i),) ) ]) ) #print(redmod_fiducials, "Fiducials") cls.redmod_germs = pygsti.circuits.to_circuits([(gl,) for gl in op_labels]) @@ -150,11 +143,10 @@ def assert_outcomes(self, probs, expected): def test_stdgst_matrix(self): # Using matrix-based calculations - target_model = std.target_model() - target_model.set_all_parameterizations("CPTP") + target_model = std.target_model('CPTPLND') target_model.sim = 'matrix' # the default for 1Q, so we could remove this line results = pygsti.run_long_sequence_gst(self.ds, target_model, std.prep_fiducials(), std.meas_fiducials(), - std.germs(), self.maxLengths, verbosity=4) + std.germs(), self.maxLengths, verbosity=4, disable_checkpointing=True) #CHECK that copy gives identical models - this is checked by other # unit tests but here we're using a true "GST model" - so do it again: @@ -166,12 +158,11 @@ def test_stdgst_matrix(self): #RUN BELOW LINES TO SAVE GATESET (SAVE) if regenerate_references(): - pygsti.serialization.json.dump(results.estimates[results.name].models['go0'], - open(compare_files + "/test1Qcalc_std_exact.model",'w')) + results.estimates[results.name].models['go0'].write(compare_files + "/test1Qcalc_std_exact.json") print("MISFIT nSigma = ",results.estimates[results.name].misfit_sigma()) self.assertAlmostEqual( results.estimates[results.name].misfit_sigma(), 1.0, delta=2.0) - mdl_compare = pygsti.serialization.json.load(open(compare_files + "/test1Qcalc_std_exact.model")) + mdl_compare = ExplicitOpModel.read(compare_files + "/test1Qcalc_std_exact.json") #gauge opt before compare gsEstimate = results.estimates[results.name].models['go0'].copy() @@ -183,15 +174,15 @@ def test_stdgst_matrix(self): def test_stdgst_map(self): # Using map-based calculation - target_model = std.target_model() - target_model.set_all_parameterizations("CPTP") + target_model = std.target_model('CPTPLND') target_model.sim = 'map' results = pygsti.run_long_sequence_gst(self.ds, target_model, std.prep_fiducials(), std.meas_fiducials(), - std.germs(), self.maxLengths, verbosity=4) + std.germs(), self.maxLengths, verbosity=4, + disable_checkpointing=True) print("MISFIT nSigma = ",results.estimates[results.name].misfit_sigma()) self.assertAlmostEqual( results.estimates[results.name].misfit_sigma(), 1.0, delta=2.0) - mdl_compare = pygsti.serialization.json.load(open(compare_files + "/test1Qcalc_std_exact.model")) + mdl_compare = ExplicitOpModel.read(compare_files + "/test1Qcalc_std_exact.json") gsEstimate = results.estimates[results.name].models['go0'].copy() gsEstimate.set_all_parameterizations("full") @@ -210,16 +201,16 @@ def test_stdgst_terms(self): target_model._print_gpindices() target_model.from_vector(1e-10 * np.ones(target_model.num_params)) # to seed term calc (starting with perfect zeros causes trouble) results = pygsti.run_long_sequence_gst(self.ds, target_model, std.prep_fiducials(), std.meas_fiducials(), - std.germs(), self.maxLengths, verbosity=4) + std.germs(lite=False), self.maxLengths, verbosity=0, + disable_checkpointing=True) #RUN BELOW LINES TO SAVE GATESET (SAVE) if regenerate_references(): - pygsti.serialization.json.dump(results.estimates[results.name].models['go0'], - open(compare_files + "/test1Qcalc_std_terms.model",'w')) - + results.estimates[results.name].models['go0'].write(compare_files + "/test1Qcalc_std_terms.json") + print("MISFIT nSigma = ",results.estimates[results.name].misfit_sigma()) - self.assertAlmostEqual( results.estimates[results.name].misfit_sigma(), 1, delta=1.0) - mdl_compare = pygsti.serialization.json.load(open(compare_files + "/test1Qcalc_std_terms.model")) + self.assertAlmostEqual( results.estimates[results.name].misfit_sigma(), 1, delta=12) + mdl_compare = ExplicitOpModel.read(compare_files + "/test1Qcalc_std_terms.json") # can't easily gauge opt b/c term-based models can't be converted to "full" #mdl_compare.set_all_parameterizations("full") @@ -248,15 +239,15 @@ def test_stdgst_prunedpath(self): perr_heuristic='meanscaled', max_term_stages=5) target_model.from_vector(1e-10 * np.ones(target_model.num_params)) # to seed term calc (starting with perfect zeros causes trouble) results = pygsti.run_long_sequence_gst(self.ds, target_model, std.prep_fiducials(), std.meas_fiducials(), - std.germs(), self.maxLengths, verbosity=3) + std.germs(lite=False), self.maxLengths, verbosity=3, + disable_checkpointing=True) #RUN BELOW LINES TO SAVE GATESET (SAVE) if regenerate_references(): - pygsti.serialization.json.dump(results.estimates[results.name].models['go0'], - open(compare_files + "/test1Qcalc_std_prunedpath.model",'w')) + results.estimates[results.name].models['go0'].write(compare_files + "/test1Qcalc_std_prunedpath.json") print("MISFIT nSigma = ",results.estimates[results.name].misfit_sigma()) - self.assertAlmostEqual( results.estimates[results.name].misfit_sigma(), 1, delta=1.0) + self.assertAlmostEqual( results.estimates[results.name].misfit_sigma(), 1, delta=2) #mdl_compare = pygsti.io.json.load(open(compare_files + "/test1Qcalc_std_prunedpath.model")) # Note: can't easily gauge opt b/c term-based models can't be converted to "full" @@ -283,16 +274,16 @@ def test_reducedmod_matrix(self): target_model.from_vector(self.rand_start25) results = pygsti.run_long_sequence_gst(self.redmod_ds, target_model, self.redmod_fiducials, self.redmod_fiducials, self.redmod_germs, self.redmod_maxLs, - verbosity=4, advanced_options={'tolerance': 1e-3}) + verbosity=4, advanced_options={'tolerance': 1e-3}, + disable_checkpointing=True) #RUN BELOW LINES TO SAVE GATESET (SAVE) if regenerate_references(): - pygsti.serialization.json.dump(results.estimates[results.name].models['go0'], - open(compare_files + "/test1Qcalc_redmod_exact.model",'w')) + results.estimates[results.name].models['go0'].write(compare_files + "/test1Qcalc_redmod_exact.json") print("MISFIT nSigma = ",results.estimates[results.name].misfit_sigma()) self.assertAlmostEqual( results.estimates[results.name].misfit_sigma(), 0.0, delta=1.0) - #mdl_compare = pygsti.io.json.load( open(compare_files + "/test1Qcalc_redmod_exact.model")) + #mdl_compare = pygsti.io.json.load( open(compare_files + "/test1Qcalc_redmod_exact.json")) #self.assertAlmostEqual( results.estimates[results.name].models['go0'].frobeniusdist(mdl_compare), 0, places=3) #NO frobeniusdist for implicit models (yet) @@ -305,11 +296,12 @@ def test_reducedmod_map1(self): target_model.from_vector(self.rand_start25) results = pygsti.run_long_sequence_gst(self.redmod_ds, target_model, self.redmod_fiducials, self.redmod_fiducials, self.redmod_germs, self.redmod_maxLs, - verbosity=4, advanced_options={'tolerance': 1e-3}) + verbosity=4, advanced_options={'tolerance': 1e-3}, + disable_checkpointing=True) print("MISFIT nSigma = ",results.estimates[results.name].misfit_sigma()) self.assertAlmostEqual( results.estimates[results.name].misfit_sigma(), 0.0, delta=1.0) - #mdl_compare = pygsti.io.json.load( open(compare_files + "/test1Qcalc_redmod_exact.model")) + #mdl_compare = pygsti.io.json.load( open(compare_files + "/test1Qcalc_redmod_exact.json")) #self.assertAlmostEqual( results.estimates[results.name].models['go0'].frobeniusdist(mdl_compare), 0, places=1) #NO frobeniusdist for implicit models (yet) #Note: models aren't necessarily exactly equal given gauge freedoms that we don't know @@ -326,7 +318,8 @@ def test_reducedmod_map1_errorgens(self): target_model.from_vector(self.rand_start25) results = pygsti.run_long_sequence_gst(self.redmod_ds, target_model, self.redmod_fiducials, self.redmod_fiducials, self.redmod_germs, self.redmod_maxLs, - verbosity=4, advanced_options={'tolerance': 1e-3}) + verbosity=4, advanced_options={'tolerance': 1e-3}, + disable_checkpointing=True) print("MISFIT nSigma = ",results.estimates[results.name].misfit_sigma()) self.assertAlmostEqual( results.estimates[results.name].misfit_sigma(), 0.0, delta=1.0) @@ -346,7 +339,7 @@ def test_reducedmod_map2(self): print("MISFIT nSigma = ",results.estimates[results.name].misfit_sigma()) self.assertAlmostEqual( results.estimates[results.name].misfit_sigma(), 0.0, delta=1.0) - mdl_compare = pygsti.serialization.json.load(open(compare_files + "/test1Qcalc_redmod_exact.model")) + mdl_compare = CloudNoiseModel.read(compare_files + "/test1Qcalc_redmod_exact.json") self.assertAlmostEqual( np.linalg.norm(results.estimates[results.name].models['go0'].to_vector() - mdl_compare.to_vector()), 0, places=1) #Note: models aren't necessarily exactly equal given gauge freedoms that we don't know @@ -363,7 +356,8 @@ def test_reducedmod_map2_errorgens(self): target_model.from_vector(self.rand_start25) results = pygsti.run_long_sequence_gst(self.redmod_ds, target_model, self.redmod_fiducials, self.redmod_fiducials, self.redmod_germs, self.redmod_maxLs, - verbosity=4, advanced_options={'tolerance': 1e-3}) + verbosity=4, advanced_options={'tolerance': 1e-3}, + disable_checkpointing=True) print("MISFIT nSigma = ",results.estimates[results.name].misfit_sigma()) self.assertAlmostEqual( results.estimates[results.name].misfit_sigma(), 0.0, delta=1.0) @@ -381,16 +375,16 @@ def test_reducedmod_svterm(self): target_model.from_vector(self.rand_start36) results = pygsti.run_long_sequence_gst(self.redmod_ds, target_model, self.redmod_fiducials, self.redmod_fiducials, self.redmod_germs, self.redmod_maxLs, - verbosity=4, advanced_options={'tolerance': 1e-3}) + verbosity=4, advanced_options={'tolerance': 1e-3}, + disable_checkpointing=True) #RUN BELOW LINES TO SAVE GATESET (SAVE) if regenerate_references(): - pygsti.serialization.json.dump(results.estimates[results.name].models['go0'], - open(compare_files + "/test1Qcalc_redmod_terms.model",'w')) + results.estimates[results.name].models['go0'].write(compare_files + "/test1Qcalc_redmod_terms.json") print("MISFIT nSigma = ",results.estimates[results.name].misfit_sigma()) self.assertAlmostEqual( results.estimates[results.name].misfit_sigma(), 0.0, delta=1.0) - mdl_compare = pygsti.serialization.json.load(open(compare_files + "/test1Qcalc_redmod_terms.model")) + mdl_compare = CloudNoiseModel.read(compare_files + "/test1Qcalc_redmod_terms.json") self.assertAlmostEqual( np.linalg.norm(results.estimates[results.name].models['go0'].to_vector() - mdl_compare.to_vector()), 0, places=3) @@ -406,7 +400,8 @@ def test_reducedmod_svterm_errorgens(self): target_model.from_vector(self.rand_start36) results = pygsti.run_long_sequence_gst(self.redmod_ds, target_model, self.redmod_fiducials, self.redmod_fiducials, self.redmod_germs, self.redmod_maxLs, - verbosity=4, advanced_options={'tolerance': 1e-3}) + verbosity=4, advanced_options={'tolerance': 1e-3}, + disable_checkpointing=True) print("MISFIT nSigma = ",results.estimates[results.name].misfit_sigma()) self.assertAlmostEqual( results.estimates[results.name].misfit_sigma(), 0.0, delta=1.0) @@ -428,7 +423,8 @@ def test_reducedmod_prunedpath_svterm_errorgens(self): target_model.from_vector(self.rand_start36) results = pygsti.run_long_sequence_gst(self.redmod_ds, target_model, self.redmod_fiducials, self.redmod_fiducials, self.redmod_germs, self.redmod_maxLs, - verbosity=4, advanced_options={'tolerance': 1e-3}) + verbosity=4, advanced_options={'tolerance': 1e-3}, + disable_checkpointing=True) print("MISFIT nSigma = ",results.estimates[results.name].misfit_sigma()) self.assertAlmostEqual( results.estimates[results.name].misfit_sigma(), 0.0, delta=1.0) @@ -452,7 +448,7 @@ def test_reducedmod_cterm(self): print("MISFIT nSigma = ",results.estimates[results.name].misfit_sigma()) self.assertAlmostEqual( results.estimates[results.name].misfit_sigma(), 0.0, delta=1.0) - mdl_compare = pygsti.serialization.json.load(open(compare_files + "/test1Qcalc_redmod_terms.model")) + mdl_compare = CloudNoiseModel.read(compare_files + "/test1Qcalc_redmod_terms.json") self.assertAlmostEqual( np.linalg.norm(results.estimates[results.name].models['go0'].to_vector() - mdl_compare.to_vector()), 0, places=1) #TODO: why this isn't more similar to svterm case?? diff --git a/test/test_packages/drivers/test_continuousgates.py b/test/test_packages/drivers/test_continuousgates.py index f0d217499..e8fe88e99 100644 --- a/test/test_packages/drivers/test_continuousgates.py +++ b/test/test_packages/drivers/test_continuousgates.py @@ -5,7 +5,7 @@ import unittest import pygsti import numpy as np -from pygsti.modelpacks.legacy import std1Q_XYI +from pygsti.modelpacks import smq1Q_XY from ..testutils import BaseTestCase @@ -78,35 +78,37 @@ def test_continuous_gates_gst(self): nQubits = 1 #Create some sequences: - smq1Q_XYI = pygsti.modelpacks.stdtarget.stdmodule_to_smqmodule(std1Q_XYI) maxLens = [1] - seqStructs = pygsti.circuits.make_lsgst_structs( - smq1Q_XYI.target_model(), smq1Q_XYI.prepStrs, smq1Q_XYI.effectStrs, smq1Q_XYI.germs, maxLens) + #use minimally IC set of prep and measurement fiducials + min_prep_fids = smq1Q_XY.prep_fiducials()[0:4] #Use a minimally informationally complete set of fiducials + min_meas_fids = smq1Q_XY.meas_fiducials()[0:3] + seqStructs = pygsti.circuits.create_lsgst_circuit_lists( + smq1Q_XY.target_model(), min_prep_fids, min_meas_fids, smq1Q_XY.germs(lite=True), maxLens) #Add random X-rotations via label arguments np.random.seed(1234) def sub_Gxrots(circuit): - ret = circuit.replace_layer( ('Gx',0), ('Gxrot',0,';',np.pi/2 + 0.02*(np.random.random()-0.5)) ) + ret = circuit.replace_layer( ('Gxpi2',0), ('Gxrot',0,';',np.pi/2 + 0.02*(np.random.random()-0.5)) ) return ret ss0 = seqStructs[0].copy() ss1 = ss0.process_circuits(sub_Gxrots) allStrs = pygsti.tools.remove_duplicates(ss0[:] + ss1[:]) print(len(allStrs),"sequences ") - self.assertEqual(len(allStrs), 209) # Was 167 when process_circuits acted on *list* rather than individual plaquettes + self.assertEqual(len(allStrs), 47) # Was 167 when process_circuits acted on *list* rather than individual plaquettes #Generate some data for these sequences (simulates an implicit model with factory) - pspec = pygsti.processors.QubitProcessorSpec(nQubits, ('Gi','Gx','Gy')) + pspec = pygsti.processors.QubitProcessorSpec(nQubits, ('Gxpi2','Gypi2')) mdl_datagen = pygsti.models.create_crosstalk_free_model(pspec, ideal_gate_type='H+S', ideal_spam_type='H+S') mdl_datagen.factories['layers'][('Gxrot', 0)] = ParamXRotationOpFactory() print(mdl_datagen.num_params, "model params") - self.assertEqual(mdl_datagen.num_params, 32) + self.assertEqual(mdl_datagen.num_params, 26) np.random.seed(4567) datagen_vec = 0.001 * np.random.random(mdl_datagen.num_params) mdl_datagen.from_vector(datagen_vec) - ds = pygsti.data.simulate_data(mdl_datagen, allStrs, 1000, seed=1234) + ds = pygsti.data.simulate_data(mdl_datagen, allStrs, 10000, seed=1234) #Run GST mdl = pygsti.models.create_crosstalk_free_model(pspec, ideal_gate_type='H+S', ideal_spam_type='H+S') diff --git a/test/test_packages/drivers/test_drivers.py b/test/test_packages/drivers/test_drivers.py index 9b3f8533b..9542971ee 100644 --- a/test/test_packages/drivers/test_drivers.py +++ b/test/test_packages/drivers/test_drivers.py @@ -3,7 +3,7 @@ from pygsti.forwardsims.mapforwardsim import MapForwardSimulator from numpy.linalg import norm import pygsti -from pygsti.modelpacks.legacy import std1Q_XYI as std +from pygsti.modelpacks import smq1Q_XY as std from ..testutils import BaseTestCase, compare_files, temp_files, regenerate_references class DriversTestCase(BaseTestCase): @@ -13,43 +13,42 @@ def setUp(self): self.model = std.target_model() - self.germs = std.germs - self.fiducials = std.fiducials - self.maxLens = [1,2,4] + self.germs = std.germs(lite=True) + self.prep_fiducials = std.prep_fiducials()[0:4] + self.meas_fiducials = std.meas_fiducials()[0:3] + self.maxLens = [1,2] self.op_labels = list(self.model.operations.keys()) self.lsgstStrings = pygsti.circuits.create_lsgst_circuit_lists( - self.op_labels, self.fiducials, self.fiducials, self.germs, self.maxLens ) + self.op_labels, self.prep_fiducials, self.meas_fiducials, self.germs, self.maxLens) - ## RUN BELOW LINES TO GENERATE SAVED DATASETS - if regenerate_references(): - datagen_gateset = self.model.depolarize(op_noise=0.05, spam_noise=0.1) - ds = pygsti.data.simulate_data( - datagen_gateset, self.lsgstStrings[-1], - num_samples=1000,sample_error='binomial', seed=100) - ds.save(compare_files + "/drivers.dataset") + datagen_gateset = self.model.copy() + datagen_gateset = datagen_gateset.depolarize(op_noise=0.05, spam_noise=0.1) + self.ds = pygsti.data.simulate_data( + datagen_gateset, self.lsgstStrings[-1], + num_samples=1000,sample_error='binomial', seed=100) class TestDriversMethods(DriversTestCase): def test_longSequenceGST_fiducialPairReduction(self): - ds = pygsti.data.DataSet(file_to_load_from=compare_files + "/drivers.dataset") + ds = self.ds maxLens = self.maxLens #Make list-of-lists of GST operation sequences - fullStructs = pygsti.circuits.make_lsgst_structs( - std.target_model(), std.fiducials, std.fiducials, std.germs, maxLens) + fullStructs = pygsti.circuits.create_lsgst_circuit_lists( + self.model, self.prep_fiducials, self.meas_fiducials, self.germs, self.maxLens) lens = [ len(strct) for strct in fullStructs ] - self.assertEqual(lens, [92,168,450]) # ,817,1201, 1585] - + self.assertEqual(lens, [19, 33]) #Global FPR fidPairs = pygsti.alg.find_sufficient_fiducial_pairs( - std.target_model(), std.fiducials, std.fiducials, std.germs, - search_mode="random", n_random=100, seed=1234, - verbosity=1, mem_limit=int(2*(1024)**3), minimum_pairs=2) + self.model, self.prep_fiducials, self.meas_fiducials, self.germs, + search_mode="random", n_random=10, seed=1234, + verbosity=0, mem_limit=int(2*(1024)**3), minimum_pairs=2, + test_lengths = (64, 512)) - gfprStructs = pygsti.circuits.make_lsgst_structs( - std.target_model(), std.fiducials, std.fiducials, std.germs, maxLens, + gfprStructs = pygsti.circuits.create_lsgst_circuit_lists( + self.model, self.prep_fiducials, self.meas_fiducials, self.germs, maxLens, fid_pairs=fidPairs) lens = [ len(strct) for strct in gfprStructs ] @@ -58,24 +57,23 @@ def test_longSequenceGST_fiducialPairReduction(self): # means different answers on different systems gfprExperiments = pygsti.circuits.create_lsgst_circuits( - std.target_model(), std.fiducials, std.fiducials, std.germs, maxLens, + self.model, self.prep_fiducials, self.prep_fiducials, self.germs, maxLens, fid_pairs=fidPairs) - result = pygsti.run_long_sequence_gst_base(ds, std.target_model(), gfprStructs, verbosity=0, - disable_checkpointing = True) - pygsti.report.create_standard_report(result, temp_files + "/full_report_GFPR", - "GFPR report", verbosity=2) - + result = pygsti.run_long_sequence_gst_base(ds, self.model, gfprStructs, verbosity=0, + disable_checkpointing = True, + advanced_options= {'max_iterations':3}) + pygsti.report.construct_standard_report(result, title ="GFPR report", verbosity=0).write_html(temp_files + "/full_report_GFPR") #Per-germ FPR fidPairsDict = pygsti.alg.find_sufficient_fiducial_pairs_per_germ( - std.target_model(), std.fiducials, std.fiducials, std.germs, + self.model, self.prep_fiducials, self.meas_fiducials, self.germs, search_mode="random", constrain_to_tp=True, - n_random=100, seed=1234, verbosity=1, + n_random=10, seed=1234, verbosity=0, mem_limit=int(2*(1024)**3)) - pfprStructs = pygsti.circuits.make_lsgst_structs( - std.target_model(), std.fiducials, std.fiducials, std.germs, maxLens, + pfprStructs = pygsti.circuits.create_lsgst_circuit_lists( + self.model, self.prep_fiducials, self.meas_fiducials, self.germs, maxLens, fid_pairs=fidPairsDict) #note: fidPairs arg can be a dict too! lens = [ len(strct) for strct in pfprStructs ] @@ -85,87 +83,68 @@ def test_longSequenceGST_fiducialPairReduction(self): pfprExperiments = pygsti.circuits.create_lsgst_circuits( - std.target_model(), std.fiducials, std.fiducials, std.germs, maxLens, + self.model, self.prep_fiducials, self.meas_fiducials, self.germs, maxLens, fid_pairs=fidPairsDict) - result = pygsti.run_long_sequence_gst_base(ds, std.target_model(), pfprStructs, verbosity=0, - disable_checkpointing = True) - pygsti.report.create_standard_report(result, temp_files + "/full_report_PFPR", - "PFPR report", verbosity=2) - - + result = pygsti.run_long_sequence_gst_base(ds, self.model, pfprStructs, verbosity=0, + disable_checkpointing = True, + advanced_options= {'max_iterations':3}) + pygsti.report.construct_standard_report(result, title="PFPR report", verbosity=0).write_html(temp_files + "/full_report_PFPR") def test_longSequenceGST_randomReduction(self): - ds = pygsti.data.DataSet(file_to_load_from=compare_files + "/drivers.dataset") + ds = self.ds ts = "whole germ powers" maxLens = self.maxLens #Without fixed initial fiducial pairs fidPairs = None - reducedLists = pygsti.circuits.make_lsgst_structs( - std.target_model().operations.keys(), std.fiducials, std.fiducials, std.germs, - maxLens, fidPairs, ts, keep_fraction=0.5, keep_seed=1234) + reducedLists = pygsti.circuits.create_lsgst_circuit_lists( + self.model.operations.keys(), self.prep_fiducials, self.meas_fiducials, self.germs, + maxLens, fidPairs, ts, keep_fraction=0.25, keep_seed=1234) result = self.runSilent(pygsti.run_long_sequence_gst_base, - ds, std.target_model(), reducedLists, + ds, self.model, reducedLists, advanced_options={'truncScheme': ts}, disable_checkpointing=True) #create a report... - pygsti.report.create_standard_report(result, temp_files + "/full_report_RFPR", - "RFPR report", verbosity=2) - - #With fixed initial fiducial pairs - fidPairs = pygsti.alg.find_sufficient_fiducial_pairs( - std.target_model(), std.fiducials, std.fiducials, std.germs, verbosity=0) - reducedLists = pygsti.circuits.make_lsgst_structs( - std.target_model().operations.keys(), std.fiducials, std.fiducials, std.germs, - maxLens, fidPairs, ts, keep_fraction=0.5, keep_seed=1234) - result2 = self.runSilent(pygsti.run_long_sequence_gst_base, - ds, std.target_model(), reducedLists, - advanced_options={'truncScheme': ts}, - disable_checkpointing=True) - - #create a report... - pygsti.report.create_standard_report(result2, temp_files + "/full_report_RFPR2.html", - verbosity=2) + pygsti.report.construct_standard_report(result, title="RFPR report", verbosity=0).write_html(temp_files + "/full_report_RFPR") def test_longSequenceGST_CPTP(self): - ds = pygsti.data.DataSet(file_to_load_from=compare_files + "/drivers.dataset") + ds = self.ds - target_model = std.target_model() + target_model = self.model target_model.set_all_parameterizations("CPTPLND") maxLens = self.maxLens result = self.runSilent(pygsti.run_long_sequence_gst, - ds, target_model, std.fiducials, std.fiducials, - std.germs, maxLens, disable_checkpointing=True) + ds, target_model, self.prep_fiducials, self.meas_fiducials, + self.germs, maxLens, disable_checkpointing=True, + advanced_options= {'max_iterations':3}) #create a report... - pygsti.report.create_standard_report(result, temp_files + "/full_report_CPTPGates", - "CPTP Gates report", verbosity=2) + pygsti.report.construct_standard_report(result, title="CPTP Gates report", verbosity=0).write_html(temp_files + "/full_report_CPTPGates") def test_longSequenceGST_Sonly(self): - ds = pygsti.data.DataSet(file_to_load_from=compare_files + "/drivers.dataset") - - target_model = std.target_model() + ds = self.ds + + target_model = self.model.copy() target_model.set_all_parameterizations("S") maxLens = self.maxLens result = self.runSilent(pygsti.run_long_sequence_gst, - ds, target_model, std.fiducials, std.fiducials, - std.germs, maxLens, disable_checkpointing=True) + ds, target_model, self.prep_fiducials, self.meas_fiducials, + self.germs, maxLens, disable_checkpointing=True, advanced_options= {'max_iterations':3}) #create a report... - pygsti.report.create_standard_report(result, temp_files + "/full_report_SGates.html", - "SGates report", verbosity=2) + pygsti.report.construct_standard_report(result, title="SGates report", verbosity=0).write_html(temp_files + "/full_report_SGates") def test_longSequenceGST_GLND(self): #General Lindbladian parameterization (allowed to be non-CPTP) - ds = pygsti.data.DataSet(file_to_load_from=compare_files + "/drivers.dataset") - - target_model = std.target_model() + ds = self.ds + + target_model = self.model.copy() #No set_all_parameterizations option for this one, since it probably isn't so useful for lbl,gate in target_model.operations.items(): @@ -176,99 +155,98 @@ def test_longSequenceGST_GLND(self): maxLens = self.maxLens result = self.runSilent(pygsti.run_long_sequence_gst, - ds, target_model, std.fiducials, std.fiducials, - std.germs, maxLens, disable_checkpointing=True) + ds, target_model, self.prep_fiducials, self.meas_fiducials, + self.germs, maxLens, disable_checkpointing=True, advanced_options= {'max_iterations':3}) #create a report... - pygsti.report.create_standard_report(result, temp_files + "/full_report_SGates", - "SGates report", verbosity=2) + pygsti.report.construct_standard_report(result, title="GLND report", verbosity=0).write_html( temp_files + "/full_report_GLND") def test_longSequenceGST_HplusS(self): - ds = pygsti.data.DataSet(file_to_load_from=compare_files + "/drivers.dataset") - - target_model = std.target_model() + ds = self.ds + + target_model = self.model.copy() target_model.set_all_parameterizations("H+S") maxLens = self.maxLens result = self.runSilent(pygsti.run_long_sequence_gst, - ds, target_model, std.fiducials, std.fiducials, - std.germs, maxLens, disable_checkpointing=True) + ds, target_model, self.prep_fiducials, self.meas_fiducials, + self.germs, maxLens, disable_checkpointing=True, advanced_options= {'max_iterations':3}) #create a report... - pygsti.report.create_standard_report(result, temp_files + "/full_report_HplusSGates", - "HpS report", verbosity=2) - - + pygsti.report.construct_standard_report(result, title= "HpS report", verbosity=0).write_html(temp_files + "/full_report_HplusSGates") def test_longSequenceGST_badfit(self): - ds = pygsti.data.DataSet(file_to_load_from=compare_files + "/drivers.dataset") + ds = self.ds #lower bad-fit threshold to zero to trigger bad-fit additional processing maxLens = self.maxLens result = self.runSilent(pygsti.run_long_sequence_gst, - ds, std.target_model(), std.fiducials, std.fiducials, - std.germs, maxLens, advanced_options={'bad_fit_threshold': -100}, + ds, self.model.copy(), self.prep_fiducials, self.meas_fiducials, + self.germs, maxLens, advanced_options={'bad_fit_threshold': -100, 'max_iterations':3}, disable_checkpointing=True) - pygsti.report.create_standard_report(result, temp_files + "/full_report_badfit", - "badfit report", verbosity=2) + pygsti.report.construct_standard_report(result, title="badfit report", verbosity=0).write_html(temp_files + "/full_report_badfit") def test_stdpracticeGST(self): - ds = pygsti.data.DataSet(file_to_load_from=compare_files + "/drivers.dataset") - mdl_guess = std.target_model().depolarize(op_noise=0.01,spam_noise=0.01) + ds = self.ds + mdl_guess = self.model.copy() + mdl_guess = mdl_guess.depolarize(op_noise=0.01,spam_noise=0.01) #lower bad-fit threshold to zero to trigger bad-fit additional processing maxLens = self.maxLens result = self.runSilent(pygsti.run_stdpractice_gst, - ds, std.target_model().create_processor_spec(), std.fiducials, std.fiducials, - std.germs, maxLens, modes=['full TP','CPTPLND','Test','Target'], + ds, self.model.copy(), self.prep_fiducials, self.meas_fiducials, + self.germs, maxLens, modes=['CPTPLND','Test','Target'], models_to_test = {"Test": mdl_guess}, - comm=None, mem_limit=None, verbosity=5, - disable_checkpointing=True) - pygsti.report.create_standard_report(result, temp_files + "/full_report_stdpractice", - "Std Practice Test Report", verbosity=2) + comm=None, mem_limit=None, verbosity=0, + disable_checkpointing=True, advanced_options= {'max_iterations':3}) + pygsti.report.construct_standard_report(result, title= "Std Practice Test Report", verbosity=2).write_html(temp_files + "/full_report_stdpractice") def test_bootstrap(self): """Test bootstrap model generation""" - ds = pygsti.data.DataSet(file_to_load_from=compare_files + "/drivers.dataset") - tp_target = std.target_model() + ds = self.ds + tp_target = self.model.copy() tp_target.set_all_parameterizations("full TP") - mdl = pygsti.run_lgst(ds, std.fiducials, std.fiducials, target_model=tp_target, svd_truncate_to=4, verbosity=0) + mdl = pygsti.run_lgst(ds, self.prep_fiducials, self.meas_fiducials, target_model=tp_target, svd_truncate_to=4, verbosity=0) - default_maxLens = [0]+[2**k for k in range(5)] + default_maxLens = [2**k for k in range(4)] circuits = pygsti.circuits.create_lsgst_circuits( - self.op_labels, self.fiducials, self.fiducials, self.germs, + self.op_labels, self.prep_fiducials, self.meas_fiducials, self.germs, default_maxLens, fid_pairs=None, trunc_scheme="whole germ powers") ds_defaultMaxLens = pygsti.data.simulate_data( mdl, circuits, num_samples=10000, sample_error='round') bootgs_p_defaultMaxLens = \ pygsti.drivers.create_bootstrap_models( - 2, ds_defaultMaxLens, 'parametric', std.fiducials, std.fiducials, - std.germs, default_maxLens, input_model=mdl, target_model=tp_target, + 2, ds_defaultMaxLens, 'parametric', self.prep_fiducials, self.meas_fiducials, + self.germs, default_maxLens, input_model=mdl, target_model=tp_target, return_data=False) #test when max_lengths == None ? def test_GST_checkpointing(self): - ds = pygsti.data.DataSet(file_to_load_from=compare_files + "/drivers.dataset") + ds= self.ds maxLens = self.maxLens + + target_model = self.model.copy() #Make list-of-lists of GST operation sequences - fullStructs = pygsti.circuits.make_lsgst_structs( - std.target_model(), std.fiducials, std.fiducials, std.germs, maxLens) + fullStructs = pygsti.circuits.create_lsgst_circuit_lists( + target_model, self.prep_fiducials, self.meas_fiducials, self.germs, maxLens) #Test GateSetTomographyCheckpoint: #First run from scratch: - result_gst = pygsti.run_long_sequence_gst_base(ds, std.target_model(), fullStructs, verbosity=0, - checkpoint_path= temp_files + '/checkpoint_testing/GateSetTomography') + result_gst = pygsti.run_long_sequence_gst_base(ds, target_model.copy(), fullStructs, verbosity=0, + checkpoint_path= temp_files + '/checkpoint_testing/GateSetTomography', + advanced_options= {'max_iterations':3}) #double check that we can read in this checkpoint object correctly: gst_checkpoint = pygsti.protocols.GateSetTomographyCheckpoint.read(temp_files + '/checkpoint_testing/GateSetTomography_iteration_0.json') #run GST using this checkpoint - result_gst_warmstart = pygsti.run_long_sequence_gst_base(ds, std.target_model(), fullStructs, verbosity=0, + result_gst_warmstart = pygsti.run_long_sequence_gst_base(ds, target_model.copy(), fullStructs, verbosity=0, checkpoint = gst_checkpoint, - checkpoint_path= temp_files + '/checkpoint_testing/GateSetTomography') + checkpoint_path= temp_files + '/checkpoint_testing/GateSetTomography', + advanced_options= {'max_iterations':3}) diff = norm(result_gst.estimates['GateSetTomography'].models['final iteration estimate'].to_vector()- result_gst_warmstart.estimates['GateSetTomography'].models['final iteration estimate'].to_vector()) @@ -277,13 +255,15 @@ def test_GST_checkpointing(self): def test_ModelTest_checkpointing(self): - ds = pygsti.data.DataSet(file_to_load_from=compare_files + "/drivers.dataset") + ds = self.ds maxLens = self.maxLens - + + target_model = self.model.copy() + #Next test ModelTestCheckpoint #First run from scratch: - result_modeltest = pygsti.run_model_test(std.target_model(), ds,std.target_model().create_processor_spec(), - std.fiducials, std.fiducials, std.germs, + result_modeltest = pygsti.run_model_test(target_model.copy(), ds, target_model.create_processor_spec(), + self.prep_fiducials, self.meas_fiducials, self.germs, maxLens, verbosity=0, checkpoint_path= temp_files + '/checkpoint_testing/ModelTest') @@ -291,8 +271,8 @@ def test_ModelTest_checkpointing(self): model_test_checkpoint = pygsti.protocols.ModelTestCheckpoint.read(temp_files + '/checkpoint_testing/ModelTest_iteration_0.json') #run GST using this checkpoint - result_modeltest_warmstart = pygsti.run_model_test(std.target_model(), ds,std.target_model().create_processor_spec(), - std.fiducials, std.fiducials, std.germs, + result_modeltest_warmstart = pygsti.run_model_test(target_model.copy(), ds,target_model.create_processor_spec(), + self.prep_fiducials, self.meas_fiducials, self.germs, maxLens, verbosity=0, checkpoint = model_test_checkpoint, checkpoint_path= temp_files + '/checkpoint_testing/ModelTest') @@ -301,33 +281,35 @@ def test_ModelTest_checkpointing(self): np.array(result_modeltest_warmstart.estimates['ModelTest'].parameters['model_test_values'])) #Assert that this gives the same result as before: self.assertTrue(diff<=1e-10) - - - + + def test_StandardGST_checkpointing(self): - ds = pygsti.data.DataSet(file_to_load_from=compare_files + "/drivers.dataset") + ds= self.ds maxLens = self.maxLens #Finally test StandardGSTCheckpoint #First run from scratch: - mdl_guess = std.target_model().depolarize(op_noise=0.01,spam_noise=0.01) + mdl_guess = self.model.copy() + mdl_guess = mdl_guess.depolarize(op_noise=0.01,spam_noise=0.01) - result_standardgst = pygsti.run_stdpractice_gst(ds, std.target_model().create_processor_spec(), std.fiducials, std.fiducials, - std.germs, maxLens, modes=['full TP','CPTPLND','Test','Target'], + result_standardgst = pygsti.run_stdpractice_gst(ds, self.model.copy(), self.prep_fiducials, self.meas_fiducials, + self.germs, maxLens, modes=['full TP','CPTPLND','Test','Target'], models_to_test = {"Test": mdl_guess}, comm=None, mem_limit=None, verbosity=0, - checkpoint_path= temp_files + '/checkpoint_testing/StandardGST') + checkpoint_path= temp_files + '/checkpoint_testing/StandardGST', + advanced_options= {'max_iterations':3}) #double check that we can read in this checkpoint object correctly: standardgst_checkpoint = pygsti.protocols.StandardGSTCheckpoint.read(temp_files + '/checkpoint_testing/StandardGST_CPTPLND_iteration_1.json') #run GST using this checkpoint - result_standardgst_warmstart = pygsti.run_stdpractice_gst(ds, std.target_model().create_processor_spec(), std.fiducials, std.fiducials, - std.germs, maxLens, modes=['full TP','CPTPLND','Test','Target'], + result_standardgst_warmstart = pygsti.run_stdpractice_gst(ds, self.model.copy(), self.prep_fiducials, self.meas_fiducials, + self.germs, maxLens, modes=['full TP','CPTPLND','Test','Target'], models_to_test = {"Test": mdl_guess}, comm=None, mem_limit=None, verbosity=0, checkpoint = standardgst_checkpoint, - checkpoint_path= temp_files + '/checkpoint_testing/StandardGST') + checkpoint_path= temp_files + '/checkpoint_testing/StandardGST', + advanced_options= {'max_iterations':3}) #Assert that this gives the same result as before: #diff = norm(result_standardgst.estimates['CPTPLND'].models['final iteration estimate'].to_vector()- @@ -341,6 +323,5 @@ def test_StandardGST_checkpointing(self): self.assertTrue(abs(diff)<=1e-6) self.assertTrue(diff1<=1e-10) - if __name__ == "__main__": unittest.main(verbosity=2) diff --git a/test/test_packages/drivers/test_nqubit.py b/test/test_packages/drivers/test_nqubit.py index 012f195a3..afc3aefc8 100644 --- a/test/test_packages/drivers/test_nqubit.py +++ b/test/test_packages/drivers/test_nqubit.py @@ -1,7 +1,3 @@ -import logging -mpl_logger = logging.getLogger('matplotlib') -mpl_logger.setLevel(logging.WARNING) - import unittest import pygsti import numpy as np @@ -15,10 +11,9 @@ from ..testutils import BaseTestCase, compare_files, regenerate_references from pygsti.models import modelconstruction from pygsti.circuits import cloudcircuitconstruction +from pygsti.circuits.circuitstructure import PlaquetteGridCircuitStructure -#from .nqubitconstruction import * - #Mimics a function that used to be in pyGSTi, replaced with create_cloudnoise_model_from_hops_and_weights def build_XYCNOT_cloudnoise_model(nQubits, geometry="line", cnot_edges=None, maxIdleWeight=1, maxSpamWeight=1, maxhops=0, @@ -53,16 +48,13 @@ def setUp(self): super(NQubitTestCase, self).setUp() def test_construction(self): - print("TEST1") mdl_test = build_XYCNOT_cloudnoise_model( - nQubits=1, geometry="line", maxIdleWeight=1, maxhops=0, verbosity=10) - print("TEST2") + nQubits=1, geometry="line", maxIdleWeight=1, maxhops=0, verbosity=0) mdl_test = build_XYCNOT_cloudnoise_model( - nQubits=2, geometry="line", maxIdleWeight=1, maxhops=0, verbosity=10) - print("TEST3") + nQubits=2, geometry="line", maxIdleWeight=1, maxhops=0, verbosity=0) mdl_test = build_XYCNOT_cloudnoise_model( nQubits=3, geometry="line", maxIdleWeight=1, maxhops=1, - extraWeight1Hops=0, extraGateWeight=1, simulator="map", verbosity=10) + extraWeight1Hops=0, extraGateWeight=1, simulator="map", verbosity=0) # roughNoise=(1234,0.1)) #print("Constructed model with %d gates, dim=%d, and n_params=%d. Norm(paramvec) = %g" % @@ -82,23 +74,23 @@ def test_sequential_sequenceselection(self): mdl_datagen = build_XYCNOT_cloudnoise_model(nQubits, "line", cnot_edges, maxIdleWeight=2, maxhops=1, extraWeight1Hops=0, extraGateWeight=0, - verbosity=1, - simulator="map", parameterization="H+S", + verbosity=0, + simulator="matrix", parameterization="H+S", roughNoise=(1234,0.01)) cache = {} gss = cloudcircuitconstruction._create_xycnot_cloudnoise_circuits( nQubits, maxLengths, 'line', cnot_edges, max_idle_weight=2, maxhops=1, - extra_weight_1_hops=0, extra_gate_weight=0, verbosity=4, cache=cache, algorithm="sequential") + extra_weight_1_hops=0, extra_gate_weight=0, verbosity=0, cache=cache, algorithm="sequential") expList = list(gss) #[ tup[0] for tup in expList_tups] - + #RUN to SAVE list & dataset if regenerate_references(): - pygsti.serialization.json.dump(gss, open(compare_files + "/nqubit_2Q_seqs.json", 'w')) - ds = pygsti.data.simulate_data(mdl_datagen, expList, 1000, "multinomial", seed=1234) - pygsti.serialization.json.dump(ds, open(compare_files + "/nqubit_2Q_dataset.json", 'w')) + gss.write(compare_files + "/nqubit_2Q_seqs.json") + ds = pygsti.data.simulate_data(mdl_datagen, expList, 10000, "multinomial", seed=1234) + pygsti.io.write_dataset(compare_files + "/nqubit_2Q.dataset", ds) - compare_gss = pygsti.serialization.json.load(open(compare_files + "/nqubit_2Q_seqs.json")) + compare_gss = PlaquetteGridCircuitStructure.read(compare_files + "/nqubit_2Q_seqs.json") self.assertEqual(set(gss), set(compare_gss)) @@ -109,7 +101,7 @@ def test_greedy_sequenceselection(self): mdl_datagen = build_XYCNOT_cloudnoise_model(nQubits, "line", cnot_edges, maxIdleWeight=1, maxhops=0, extraWeight1Hops=0, extraGateWeight=0, - verbosity=1, simulator="map", parameterization="H+S", + verbosity=1, simulator="matrix", parameterization="H+S", roughNoise=(1234,0.01)) cache = {} @@ -120,9 +112,9 @@ def test_greedy_sequenceselection(self): #RUN to SAVE list if regenerate_references(): - pygsti.serialization.json.dump(gss, open(compare_files + "/nqubit_1Q_seqs.json", 'w')) + gss.write(compare_files + "/nqubit_1Q_seqs.json") - compare_gss = pygsti.serialization.json.load(open(compare_files + "/nqubit_1Q_seqs.json")) + compare_gss = PlaquetteGridCircuitStructure.read(compare_files + "/nqubit_1Q_seqs.json") #expList_tups_mod = [tuple( etup[0:3] + ('XX','XX')) for etup in expList_tups ] #for etup in expList_tups: @@ -146,11 +138,10 @@ def test_2Q(self): # warnings.warn("Skipping test_2Q b/c no fastreps!") # return - gss = pygsti.serialization.json.load(open(compare_files + "/nqubit_2Q_seqs.json")) + gss = PlaquetteGridCircuitStructure.read(compare_files + "/nqubit_2Q_seqs.json") expList = list(gss) - ds = pygsti.serialization.json.load(open(compare_files + "/nqubit_2Q_dataset.json")) - print(len(expList)," sequences") + ds = pygsti.io.read_dataset(compare_files + "/nqubit_2Q.dataset") nQubits = 2 maxLengths = [1] #,2] @@ -166,10 +157,13 @@ def test_2Q(self): mdl_to_optimize = build_XYCNOT_cloudnoise_model(nQubits, "line", cnot_edges, maxIdleWeight=2, maxhops=1, extraWeight1Hops=0, extraGateWeight=1, verbosity=1, - simulator="map", parameterization="H+S") + simulator="matrix", parameterization="H+S") + #switching the to matrix forward simulator made the tests run way faster it seems. results = pygsti.run_long_sequence_gst_base(ds, mdl_to_optimize, lsgstLists, gauge_opt_params=False, - advanced_options={'tolerance': 1e-1}, verbosity=4) + advanced_options={'tolerance': 1e-1, 'max_iterations': 5}, verbosity=0, + disable_checkpointing= True) #probably don't care about convergence for same reason we + #don't for the 3Q case? def test_2Q_terms(self): @@ -179,11 +173,10 @@ def test_2Q_terms(self): # warnings.warn("Skipping test_2Q_terms b/c no fastreps!") # return - gss = pygsti.serialization.json.load(open(compare_files + "/nqubit_2Q_seqs.json")) + gss = PlaquetteGridCircuitStructure.read(compare_files + "/nqubit_2Q_seqs.json") expList = list(gss) - ds = pygsti.serialization.json.load(open(compare_files + "/nqubit_2Q_dataset.json")) - print(len(expList)," sequences") + ds = pygsti.io.read_dataset(compare_files + "/nqubit_2Q.dataset") nQubits = 2 maxLengths = [1,2] @@ -202,21 +195,12 @@ def test_2Q_terms(self): extraWeight1Hops=0, extraGateWeight=1, verbosity=1, simulator=termsim, parameterization="H+S", evotype='statevec') - #RUN to create cache (SAVE) - if regenerate_references(): - calc_cache = {} - mdl_to_optimize.sim = pygsti.forwardsims.TermForwardSimulator(mode='taylor-order', max_order=1, cache=calc_cache) - mdl_to_optimize.sim.bulk_probs(gss) #lsgstLists[-1] - pygsti.serialization.json.dump(calc_cache, open(compare_files + '/nqubit_2Qterms.cache', 'w')) - - #Just load precomputed cache (we test run_long_sequence_gst_base here, not cache computation) - calc_cache = pygsti.serialization.json.load(open(compare_files + '/nqubit_2Qterms.cache')) - mdl_to_optimize.sim = pygsti.forwardsims.TermForwardSimulator(mode='taylor-order', max_order=1, cache=calc_cache) + mdl_to_optimize.sim = pygsti.forwardsims.TermForwardSimulator(mode='taylor-order', max_order=1) results = pygsti.run_long_sequence_gst_base(ds, mdl_to_optimize, lsgstLists, gauge_opt_params=False, - advanced_options={'tolerance': 1e-3}, verbosity=4) - + advanced_options={'tolerance': 1e-3}, verbosity=0, + disable_checkpointing= True) def test_3Q(self): @@ -227,7 +211,6 @@ def test_3Q(self): # return nQubits = 3 - print("Constructing Target LinearOperator Set") target_model = build_XYCNOT_cloudnoise_model( nQubits, geometry="line", maxIdleWeight=1, maxhops=1, extraWeight1Hops=0, extraGateWeight=1, simulator="map",verbosity=1) @@ -235,14 +218,11 @@ def test_3Q(self): #print("nParams test = ",target_model.num_params) #print("nNonGaugeParams test = ",target_model.num_nongauge_params) - print("Constructing Datagen LinearOperator Set") mdl_datagen = build_XYCNOT_cloudnoise_model( nQubits, geometry="line", maxIdleWeight=1, maxhops=1, - extraWeight1Hops=0, extraGateWeight=1, verbosity=1, roughNoise=(1234,0.1), simulator="map") + extraWeight1Hops=0, extraGateWeight=1, verbosity=0, roughNoise=(1234,0.1), simulator="matrix") mdl_test = mdl_datagen - print("Constructed model with %d op-blks, dim=%d, and nParams=%d. Norm(paramvec) = %g" % - (len(mdl_test.operation_blks),mdl_test.dim,mdl_test.num_params, np.linalg.norm(mdl_test.to_vector()) )) op_labels = target_model.primitive_op_labels line_labels = tuple(range(nQubits)) @@ -251,7 +231,6 @@ def test_3Q(self): for i in range(nQubits): fiducials.extend( pygsti.circuits.manipulate_circuits( fids1Q, [ ( (L('Gx'),) , (L('Gx',i),) ), ( (L('Gy'),) , (L('Gy',i),) ) ], line_labels=line_labels) ) - print(len(fiducials), "Fiducials") prep_fiducials = meas_fiducials = fiducials #TODO: add fiducials for 2Q pairs (edges on graph) @@ -261,7 +240,6 @@ def test_3Q(self): self.assertTrue( Circuit((),line_labels) in expList) ds = pygsti.data.simulate_data(mdl_datagen, expList, 1000, "multinomial", seed=1234) - print("Created Dataset with %d strings" % len(ds)) logL = pygsti.tools.logl(mdl_datagen, ds, expList) max_logL = pygsti.tools.logl_max(mdl_datagen, ds, expList) @@ -270,17 +248,11 @@ def test_3Q(self): dof = ds.degrees_of_freedom() nParams = mdl_datagen.num_params - print("Datagen 2DeltaLogL = 2(%g-%g) = %g" % (logL,max_logL,twoDeltaLogL)) - print("Datagen chi2 = ",chi2) - print("Datagen expected DOF = ",dof) - print("nParams = ",nParams) - print("Expected 2DeltaLogL or chi2 ~= %g-%g =%g" % (dof,nParams,dof-nParams)) #print("EXIT"); exit() return results = pygsti.run_long_sequence_gst(ds, target_model, prep_fiducials, meas_fiducials, germs, maxLs, verbosity=5, advanced_options={'max_iterations': 2}) #keep this short; don't care if it doesn't converge. - print("DONE!") @@ -293,14 +265,10 @@ def test_SPAM(self): effects = [(l, modelconstruction.create_spam_vector(l, "Q0", basis1Q)) for l in ["0", "1"]] factorPOVMs.append(pygsti.modelmembers.povms.TPPOVM(effects, evotype='default')) povm = pygsti.modelmembers.povms.TensorProductPOVM(factorPOVMs) - print(list(povm.keys())) - print("params = ",povm.num_params,"dim = ",povm.state_space.dim) - print(povm) v = povm.to_vector() v += np.random.random( len(v) ) povm.from_vector(v) - print("Post adding noise:"); print(povm) mdl = pygsti.models.ExplicitOpModel(['Q0', 'Q1', 'Q2']) prepFactors = [pygsti.modelmembers.states.TPState(modelconstruction.create_spam_vector("0", "Q0", basis1Q)) diff --git a/test/test_packages/drivers/test_timedep.py b/test/test_packages/drivers/test_timedep.py index 631525e07..73e7e78be 100644 --- a/test/test_packages/drivers/test_timedep.py +++ b/test/test_packages/drivers/test_timedep.py @@ -5,7 +5,9 @@ import unittest import pygsti import numpy as np -from pygsti.modelpacks.legacy import std1Q_XYI +from pygsti.modelpacks import smq1Q_XYI +from pygsti.circuits import Circuit +from pygsti.baseobjs import Label from ..testutils import BaseTestCase @@ -55,59 +57,71 @@ def setUp(self): super(TimeDependentTestCase, self).setUp() def test_time_dependent_datagen(self): - mdl = std1Q_XYI.target_model("full TP",sim_type="map") - mdl.operations['Gi'] = MyTimeDependentIdle(1.0) + mdl = smq1Q_XYI.target_model("full TP") + mdl.sim = 'map' + mdl.operations['Gi',0] = MyTimeDependentIdle(1.0) #Create a time-dependent dataset (simulation of time-dependent model): - circuits = std1Q_XYI.prepStrs + pygsti.circuits.to_circuits([('Gi',), ('Gi', 'Gx', 'Gi', 'Gx')]) # just pick some circuits + circuits = smq1Q_XYI.prep_fiducials() + [Circuit([Label('Gi',0)], line_labels=(0,)), + Circuit([Label('Gi',0), Label('Gxpi2',0), Label('Gi',0), Label('Gxpi2',0)], line_labels=(0,))] + # just pick some circuits ds = pygsti.data.simulate_data(mdl, circuits, num_samples=100, - sample_error='none', seed=1234, times=[0,0.1,0.2]) + sample_error='none', seed=1234, times=[0,0.1,0.2]) - self.assertArraysEqual(ds[('Gi',)].time, np.array([0., 0., 0.1, 0.1, 0.2, 0.2])) - self.assertArraysEqual(ds[('Gi',)].reps, np.array([100., 0., 95., 5., 90., 10.])) - self.assertArraysEqual(ds[('Gi',)].outcomes, [('0',), ('1',), ('0',), ('1',), ('0',), ('1',)]) + self.assertArraysEqual(ds[Circuit([Label('Gi',0)], line_labels=(0,))].time, np.array([0., 0., 0.1, 0.1, 0.2, 0.2])) + self.assertArraysEqual(ds[Circuit([Label('Gi',0)], line_labels=(0,))].reps, np.array([100., 0., 95., 5., 90., 10.])) + self.assertArraysEqual(ds[Circuit([Label('Gi',0)], line_labels=(0,))].outcomes, [('0',), ('1',), ('0',), ('1',), ('0',), ('1',)]) # sparse data ds2 = pygsti.data.simulate_data(mdl, circuits, num_samples=100, - sample_error='none', seed=1234, times=[0,0.1,0.2], - record_zero_counts=False) - self.assertArraysEqual(ds2[('Gi',)].time, np.array([0., 0.1, 0.1, 0.2, 0.2])) - self.assertArraysEqual(ds2[('Gi',)].reps, np.array([100., 95., 5., 90., 10.])) - self.assertArraysEqual(ds2[('Gi',)].outcomes, [('0',), ('0',), ('1',), ('0',), ('1',)]) + sample_error='none', seed=1234, times=[0,0.1,0.2], + record_zero_counts=False) + self.assertArraysEqual(ds2[Circuit([Label('Gi',0)], line_labels=(0,))].time, np.array([0., 0.1, 0.1, 0.2, 0.2])) + self.assertArraysEqual(ds2[Circuit([Label('Gi',0)], line_labels=(0,))].reps, np.array([100., 95., 5., 90., 10.])) + self.assertArraysEqual(ds2[Circuit([Label('Gi',0)], line_labels=(0,))].outcomes, [('0',), ('0',), ('1',), ('0',), ('1',)]) def test_time_dependent_gst_staticdata(self): - + #run GST in a time-dependent mode: - prep_fiducials, meas_fiducials = std1Q_XYI.prepStrs, std1Q_XYI.effectStrs - germs = std1Q_XYI.germs + prep_fiducials, meas_fiducials = smq1Q_XYI.prep_fiducials()[0:4], smq1Q_XYI.meas_fiducials()[0:3] + germs = smq1Q_XYI.germs(lite=True) + germs[0] = Circuit([Label('Gi',0)], line_labels=(0,)) maxLengths = [1, 2] - target_model = std1Q_XYI.target_model("full TP", sim_type="map") - mdl_datagen = target_model.depolarize(op_noise=0.01, spam_noise=0.001) + target_model = smq1Q_XYI.target_model("full TP") + target_model.sim = "map" + + del target_model.operations[Label(())] + target_model.operations['Gi',0] = np.eye(4) + + mdl_datagen = target_model.depolarize(op_noise=0.05, spam_noise=0.01) edesign = pygsti.protocols.StandardGSTDesign(target_model.create_processor_spec(), prep_fiducials, meas_fiducials, germs, maxLengths) # *sparse*, time-independent data - ds = pygsti.data.simulate_data(mdl_datagen, edesign.all_circuits_needing_data, num_samples=10, - sample_error="binomial", seed=1234, times=[0], - record_zero_counts=False) + ds = pygsti.data.simulate_data(mdl_datagen, edesign.all_circuits_needing_data, num_samples=1000, + sample_error="binomial", seed=1234, times=[0], + record_zero_counts=False) data = pygsti.protocols.ProtocolData(edesign, ds) - target_model.sim = pygsti.forwardsims.MapForwardSimulator(max_cache_size=0) # No caching allowed for time-dependent calcs - self.assertEqual(ds.degrees_of_freedom(aggregate_times=False), 126) - + self.assertEqual(ds.degrees_of_freedom(aggregate_times=False), 57) + builders = pygsti.protocols.GSTObjFnBuilders([pygsti.objectivefns.TimeDependentPoissonPicLogLFunction.builder()], []) gst = pygsti.protocols.GateSetTomography(target_model, gaugeopt_suite=None, - objfn_builders=builders) + objfn_builders=builders, + optimizer={'maxiter':2,'tol': 1e-4}) results = gst.run(data) # Normal GST used as a check - should get same answer since data is time-independent - results2 = pygsti.run_long_sequence_gst(ds, target_model, prep_fiducials, meas_fiducials, - germs, maxLengths, verbosity=3, - advanced_options={'starting_point': 'target', - 'always_perform_mle': True, - 'only_perform_mle': True}, gauge_opt_params=False) - + #We aren't actually doing this comparison atm (relevant tests are commented out) so no point + #doing the computation. For some reason this fit also took very long to run, which is strange (I don't see + #any reason why it would) + #results2 = pygsti.run_long_sequence_gst(ds, target_model, prep_fiducials, meas_fiducials, + # germs, maxLengths, verbosity=3, + # advanced_options={'starting_point': 'target', + # 'always_perform_mle': True, + # 'only_perform_mle': True}, gauge_opt_params=False) + #These check FAIL on some TravisCI machines for an unknown reason (but passes on Eriks machines) -- figure out why this is in FUTURE. #Check that "timeDependent=True" mode matches behavior or "timeDependent=False" mode when model and data are time-independent. #self.assertAlmostEqual(pygsti.tools.chi2(results.estimates['default'].models['iteration estimates'][0], results.dataset, results.circuit_lists['iteration'][0]), @@ -122,36 +136,40 @@ def test_time_dependent_gst_staticdata(self): def test_time_dependent_gst(self): #run GST in a time-dependent mode: - prep_fiducials, meas_fiducials = std1Q_XYI.prepStrs, std1Q_XYI.effectStrs - germs = std1Q_XYI.germs + #use minimally informationally complete set + prep_fiducials, meas_fiducials = smq1Q_XYI.prep_fiducials()[0:4], smq1Q_XYI.meas_fiducials()[0:3] + germs = smq1Q_XYI.germs(lite=True) + germs[0] = Circuit([Label('Gi',0)], line_labels=(0,)) maxLengths = [1, 2] - target_model = std1Q_XYI.target_model("full TP",sim_type="map") - mdl_datagen = target_model.depolarize(op_noise=0.01, spam_noise=0.001) - mdl_datagen.operations['Gi'] = MyTimeDependentIdle(1.0) + target_model = smq1Q_XYI.target_model("full TP") + target_model.sim = 'map' + del target_model.operations[Label(())] + mdl_datagen = target_model.depolarize(op_noise=0.05, spam_noise=0.01) + mdl_datagen.operations['Gi',0] = MyTimeDependentIdle(1.0) edesign = pygsti.protocols.StandardGSTDesign(target_model.create_processor_spec(), prep_fiducials, meas_fiducials, germs, maxLengths) # *sparse*, time-independent data - ds = pygsti.data.simulate_data(mdl_datagen, edesign.all_circuits_needing_data, num_samples=1000, - sample_error="binomial", seed=1234, times=[0, 0.1, 0.2], + ds = pygsti.data.simulate_data(mdl_datagen, edesign.all_circuits_needing_data, num_samples=2000, + sample_error="binomial", seed=1234, times=[0, 0.2], record_zero_counts=False) - self.assertEqual(ds.degrees_of_freedom(aggregate_times=False), 500) + self.assertEqual(ds.degrees_of_freedom(aggregate_times=False), 114) - target_model.operations['Gi'] = MyTimeDependentIdle(0.0) # start assuming no time dependent decay 0 + target_model.operations['Gi',0] = MyTimeDependentIdle(0) # start assuming no time dependent decay target_model.sim = pygsti.forwardsims.MapForwardSimulator(max_cache_size=0) # No caching allowed for time-dependent calcs builders = pygsti.protocols.GSTObjFnBuilders([pygsti.objectivefns.TimeDependentPoissonPicLogLFunction.builder()], []) gst = pygsti.protocols.GateSetTomography(target_model, gaugeopt_suite=None, - objfn_builders=builders, optimizer={'tol': 1e-4}) + objfn_builders=builders, optimizer={'maxiter':10,'tol': 1e-4}) data = pygsti.protocols.ProtocolData(edesign, ds) results = gst.run(data) #we should recover the 1.0 decay we put into mdl_datagen['Gi']: final_mdl = results.estimates['GateSetTomography'].models['final iteration estimate'] - print("Final decay rate = ", final_mdl.operations['Gi'].to_vector()) - #self.assertAlmostEqual(final_mdl.operations['Gi'].to_vector()[0], 1.0, places=1) - self.assertAlmostEqual(final_mdl.operations['Gi'].to_vector()[0], 1.0, delta=0.1) # weaker b/c of unknown TravisCI issues + print("Final decay rate = ", final_mdl.operations['Gi',0].to_vector()) + #self.assertAlmostEqual(final_mdl.operations['Gi',0].to_vector()[0], 1.0, places=1) + self.assertAlmostEqual(final_mdl.operations['Gi',0].to_vector()[0], 1.0, delta=0.1) # weaker b/c of unknown TravisCI issues if __name__ == "__main__": unittest.main(verbosity=2) diff --git a/test/test_packages/objects/test_hessian.py b/test/test_packages/objects/test_hessian.py index 0bdb48f7f..2a1f3bcfc 100644 --- a/test/test_packages/objects/test_hessian.py +++ b/test/test_packages/objects/test_hessian.py @@ -6,8 +6,8 @@ import pygsti from pygsti import protocols as proto -from pygsti.modelpacks.legacy import std1Q_XY as stdxy -from pygsti.modelpacks.legacy import std1Q_XYI as stdxyi +from pygsti.modelpacks import smq1Q_XY +from pygsti.modelpacks import smq1Q_XYI from pygsti.baseobjs import Label as L from pygsti.report import modelfunction as gsf from ..testutils import BaseTestCase, compare_files @@ -18,27 +18,34 @@ class TestHessianMethods(BaseTestCase): def setUp(self): super(TestHessianMethods, self).setUp() - self.model = pygsti.io.load_model(compare_files + "/analysis.model") - self.ds = pygsti.data.DataSet(file_to_load_from=compare_files + "/analysis.dataset") + self.model = smq1Q_XY.target_model() + self.model = self.model.depolarize(spam_noise = .01, op_noise = .001) + self.model = self.model.rotate(max_rotate=.005, seed=1234) - - fiducials = stdxyi.fiducials - germs = stdxyi.germs + prep_fiducials = smq1Q_XY.prep_fiducials() + meas_fiducials = smq1Q_XY.meas_fiducials() + germs = smq1Q_XY.germs() op_labels = list(self.model.operations.keys()) # also == std.gates - self.maxLengthList = [1,2] - self.gss = pygsti.circuits.make_lsgst_structs(op_labels, fiducials, fiducials, germs, self.maxLengthList) + self.maxLengthList = [1] + #circuits for XY model. + self.gss = pygsti.circuits.make_lsgst_structs(op_labels, prep_fiducials[0:4], + meas_fiducials[0:3], smq1Q_XY.germs(), self.maxLengthList) + + self.edesign = proto.CircuitListsDesign([pygsti.circuits.CircuitList(circuit_struct) for circuit_struct in self.gss]) + + self.ds = pygsti.data.simulate_data(self.model, self.edesign.all_circuits_needing_data, 1000, seed = 1234) def test_parameter_counting(self): #XY Model: SPAM=True - n = stdxy.target_model().num_params + n = smq1Q_XY.target_model().num_params self.assertEqual(n,44) # 2*16 + 3*4 = 44 - n = stdxy.target_model().num_nongauge_params + n = smq1Q_XY.target_model().num_nongauge_params self.assertEqual(n,28) # full 16 gauge params #XY Model: SPAM=False - tst = stdxy.target_model() + tst = smq1Q_XY.target_model() del tst.preps['rho0'] del tst.povms['Mdefault'] n = tst.num_params @@ -49,14 +56,14 @@ def test_parameter_counting(self): #XYI Model: SPAM=True - n = stdxyi.target_model().num_params + n = smq1Q_XYI.target_model().num_params self.assertEqual(n,60) # 3*16 + 3*4 = 60 - n = stdxyi.target_model().num_nongauge_params + n = smq1Q_XYI.target_model().num_nongauge_params self.assertEqual(n,44) # full 16 gauge params: SPAM gate + 3 others #XYI Model: SPAM=False - tst = stdxyi.target_model() + tst = smq1Q_XYI.target_model() del tst.preps['rho0'] del tst.povms['Mdefault'] n = tst.num_params @@ -66,7 +73,7 @@ def test_parameter_counting(self): self.assertEqual(n,34) # gates are all unital & TP => only 14 gauge params (2 casimirs) #XYI Model: SP0=False - tst = stdxyi.target_model() + tst = smq1Q_XYI.target_model() tst.preps['rho0'] = pygsti.modelmembers.states.TPState(tst.preps['rho0']) n = tst.num_params self.assertEqual(n,59) # 3*16 + 2*4 + 3 = 59 @@ -75,9 +82,9 @@ def test_parameter_counting(self): self.assertEqual(n,44) # 15 gauge params (minus one b/c can't change rho?) #XYI Model: G0=SP0=False - tst.operations['Gi'] = pygsti.modelmembers.operations.FullTPOp(tst.operations['Gi']) - tst.operations['Gx'] = pygsti.modelmembers.operations.FullTPOp(tst.operations['Gx']) - tst.operations['Gy'] = pygsti.modelmembers.operations.FullTPOp(tst.operations['Gy']) + tst.operations[L(())] = pygsti.modelmembers.operations.FullTPOp(tst.operations[L(())]) + tst.operations['Gxpi2',0] = pygsti.modelmembers.operations.FullTPOp(tst.operations['Gxpi2',0]) + tst.operations['Gypi2',0] = pygsti.modelmembers.operations.FullTPOp(tst.operations['Gypi2',0]) n = tst.num_params self.assertEqual(n,47) # 3*12 + 2*4 + 3 = 47 @@ -88,36 +95,27 @@ def test_hessian_projection(self): chi2Hessian = pygsti.chi2_hessian(self.model, self.ds) proj_non_gauge = self.model.compute_nongauge_projector() - projectedHessian = np.dot(proj_non_gauge, - np.dot(chi2Hessian, proj_non_gauge)) + projectedHessian = proj_non_gauge@chi2Hessian@proj_non_gauge - print(self.model.num_params) - print(proj_non_gauge.shape) - self.assertEqual( projectedHessian.shape, (60,60) ) - #print("Evals = ") - #print("\n".join( [ "%d: %g" % (i,ev) for i,ev in enumerate(np.linalg.eigvals(projectedHessian))] )) - self.assertEqual( np.linalg.matrix_rank(proj_non_gauge), 44) - self.assertEqual( np.linalg.matrix_rank(projectedHessian), 44) + self.assertEqual( projectedHessian.shape, (44,44) ) + self.assertEqual( np.linalg.matrix_rank(proj_non_gauge), 28) + self.assertEqual( np.linalg.matrix_rank(projectedHessian), 28) eigvals = np.sort(abs(np.linalg.eigvals(projectedHessian))) print("eigvals = ",eigvals) - eigvals_chk = np.array([2.51663034e-10, 2.51663034e-10, 6.81452335e-10, 7.72039792e-10, - 8.76915081e-10, 8.76915081e-10, 1.31455011e-09, 3.03808236e-09, - 3.03808236e-09, 3.13457752e-09, 3.21805358e-09, 3.21805358e-09, - 4.78549720e-09, 7.83389490e-09, 1.82493106e-08, 1.82493106e-08, - 9.23087831e+05, 1.05783101e+06, 1.16457705e+06, 1.39492929e+06, - 1.84015484e+06, 2.10613947e+06, 2.37963392e+06, 2.47192689e+06, - 2.64566761e+06, 2.68722871e+06, 2.82383377e+06, 2.86584033e+06, - 2.94590436e+06, 2.96180212e+06, 3.08322015e+06, 3.29389050e+06, - 3.66581786e+06, 3.76266448e+06, 3.81921738e+06, 3.86624688e+06, - 3.89045873e+06, 4.72831630e+06, 4.96416855e+06, 6.53286834e+06, - 1.01424911e+07, 1.11347312e+07, 1.26152967e+07, 1.30081040e+07, - 1.36647082e+07, 1.49293583e+07, 1.58234599e+07, 1.80999182e+07, - 2.09155048e+07, 2.17444267e+07, 2.46870311e+07, 2.64427393e+07, - 2.72410297e+07, 3.34988002e+07, 3.45005948e+07, 3.69040745e+07, - 5.08647137e+07, 9.43153151e+07, 1.36088308e+08, 6.30304807e+08]) + eigvals_chk = np.array([ 5.45537035e-13, 5.45537035e-13, 1.47513013e-12, 1.47513013e-12, + 1.57813273e-12, 4.87695508e-12, 1.22061302e-11, 3.75982961e-11, + 5.49796401e-11, 5.62019047e-11, 5.62019047e-11, 7.06418308e-11, + 1.44881858e-10, 1.48934891e-10, 1.48934891e-10, 2.06194475e-10, + 1.91727543e+01, 2.26401298e+02, 5.23331036e+02, 1.16447879e+03, + 1.45737904e+03, 1.93375238e+03, 2.02017169e+03, 3.55570313e+03, + 3.95986905e+03, 5.52173250e+03, 8.20436174e+03, 9.93573257e+03, + 1.36092721e+04, 1.87334336e+04, 2.07723720e+04, 2.17070806e+04, + 2.72168569e+04, 3.31886655e+04, 3.72430633e+04, 4.64233389e+04, + 6.35672652e+04, 8.61196820e+04, 1.08248150e+05, 1.65647618e+05, + 5.72597674e+05, 9.44823397e+05, 1.45785061e+06, 6.85705713e+06]) TOL = 1e-7 for val,chk in zip(eigvals,eigvals_chk): @@ -128,16 +126,14 @@ def test_hessian_projection(self): def test_confidenceRegion(self): - edesign = proto.CircuitListsDesign([pygsti.circuits.CircuitList(circuit_struct) - for circuit_struct in self.gss]) - data = proto.ProtocolData(edesign, self.ds) + data = proto.ProtocolData(self.edesign, self.ds) res = proto.ModelEstimateResults(data, proto.StandardGST(modes="full TP")) #Add estimate for hessian-based CI -------------------------------------------------- builder = pygsti.objectivefns.PoissonPicDeltaLogLFunction.builder() res.add_estimate( proto.estimate.Estimate.create_gst_estimate( - res, stdxyi.target_model(), stdxyi.target_model(), + res, smq1Q_XY.target_model(), smq1Q_XY.target_model(), [self.model] * len(self.maxLengthList), parameters={'final_objfn_builder': builder}), estimate_key="default" ) @@ -181,7 +177,7 @@ def test_confidenceRegion(self): #Add estimate for linresponse-based CI -------------------------------------------------- res.add_estimate( proto.estimate.Estimate.create_gst_estimate( - res, stdxyi.target_model(), stdxyi.target_model(), + res, smq1Q_XY.target_model(), smq1Q_XY.target_model(), [self.model]*len(self.maxLengthList), parameters={'final_objfn_builder': builder}), estimate_key="linresponse" ) @@ -215,7 +211,7 @@ def __init__(self): res.add_estimate( proto.estimate.Estimate.create_gst_estimate( - res, stdxyi.target_model(), stdxyi.target_model(), + res, smq1Q_XY.target_model(), smq1Q_XY.target_model(), [self.model]*len(self.maxLengthList), parameters={'final_objfn_builder': FooBar()}), estimate_key="foo" ) @@ -225,8 +221,6 @@ def __init__(self): with self.assertRaises(ValueError): # bad objective est.create_confidence_region_factory('final iteration estimate', 'final').compute_hessian() - - # Now test each of the views we created above ------------------------------------------------ for ci_cur in (ci_std, ci_noproj, ci_opt, ci_intrinsic, ci_linresponse): @@ -235,7 +229,7 @@ def __init__(self): #linear response CI doesn't support profile likelihood intervals if ci_cur is not ci_linresponse: # (profile likelihoods not implemented in this case) - ar_of_intervals_Gx = ci_cur.retrieve_profile_likelihood_confidence_intervals(L("Gx")) + ar_of_intervals_Gx = ci_cur.retrieve_profile_likelihood_confidence_intervals(L("Gxpi2", 0)) ar_of_intervals_rho0 = ci_cur.retrieve_profile_likelihood_confidence_intervals(L("rho0")) ar_of_intervals_M0 = ci_cur.retrieve_profile_likelihood_confidence_intervals(L("Mdefault")) ar_of_intervals = ci_cur.retrieve_profile_likelihood_confidence_intervals() @@ -265,7 +259,7 @@ def fnOfGate_3D(mx,b): for fnOfOp in fns: FnClass = gsf.opfn_factory(fnOfOp) - FnObj = FnClass(self.model, 'Gx') + FnObj = FnClass(self.model, L('Gxpi2',0)) if fnOfOp is fnOfGate_3D: with self.assertRaises(ValueError): df = ci_cur.compute_confidence_interval(FnObj, verbosity=0) @@ -339,13 +333,13 @@ def fnOfSpam_3D(rhoVecs, povms): def fnOfGateSet_float(mdl): - return float( mdl.operations['Gx'][0,0] ) + return float( mdl.operations['Gxpi2',0][0,0] ) def fnOfGateSet_0D(mdl): - return np.array( mdl.operations['Gx'][0,0] ) + return np.array( mdl.operations['Gxpi2',0][0,0] ) def fnOfGateSet_1D(mdl): - return np.array( mdl.operations['Gx'][0,:] ) + return np.array( mdl.operations['Gxpi2',0][0,:] ) def fnOfGateSet_2D(mdl): - return np.array( mdl.operations['Gx'] ) + return np.array( mdl.operations['Gxpi2',0] ) def fnOfGateSet_3D(mdl): return np.zeros( (2,2,2), 'd') #just to test for error @@ -363,14 +357,13 @@ def fnOfGateSet_3D(mdl): #TODO: assert values of df & f0 ?? def test_pickle_ConfidenceRegion(self): - edesign = proto.CircuitListsDesign([pygsti.circuits.CircuitList(circuit_struct) - for circuit_struct in self.gss]) - data = proto.ProtocolData(edesign, self.ds) + + data = proto.ProtocolData(self.edesign, self.ds) res = proto.ModelEstimateResults(data, proto.StandardGST(modes="full TP")) res.add_estimate( proto.estimate.Estimate.create_gst_estimate( - res, stdxyi.target_model(), stdxyi.target_model(), + res, smq1Q_XY.target_model(), smq1Q_XY.target_model(), [self.model]*len(self.maxLengthList), parameters={'objective': 'logl'}), estimate_key="default" ) diff --git a/test/test_packages/report/reportBaseCase.py b/test/test_packages/report/reportBaseCase.py index 78a2d25dc..e380ddd53 100644 --- a/test/test_packages/report/reportBaseCase.py +++ b/test/test_packages/report/reportBaseCase.py @@ -2,10 +2,9 @@ import os import pygsti -from pygsti.modelpacks.legacy import std1Q_XYI as std +from pygsti.modelpacks import smq1Q_XY as std from ..testutils import BaseTestCase, compare_files, temp_files, regenerate_references - class ReportBaseCase(BaseTestCase): @classmethod @@ -28,14 +27,16 @@ def setUpClass(cls): #cls.specs = pygsti.construction.build_spam_specs(std.fiducials, effect_labels=['E0']) # #only use the first EVec - op_labels = std.gates - cls.lgstStrings = pygsti.circuits.create_lgst_circuits(std.fiducials, std.fiducials, op_labels) - cls.maxLengthList = [1,2,4,8] + op_labels = list(target_model.operations.keys()) + #use minimally informationally complete prep and measurement fids + cls.min_prep_fids = std.prep_fiducials()[0:4] + cls.min_meas_fids = std.meas_fiducials()[0:3] + + cls.lgstStrings = pygsti.circuits.create_lgst_circuits(cls.min_prep_fids, cls.min_meas_fids, op_labels) + cls.maxLengthList = [1,2,4] cls.lsgstStrings = pygsti.circuits.create_lsgst_circuit_lists( - op_labels, std.fiducials, std.fiducials, std.germs, cls.maxLengthList) - cls.lsgstStructs = pygsti.circuits.make_lsgst_structs( - op_labels, std.fiducials, std.fiducials, std.germs, cls.maxLengthList) + op_labels, cls.min_prep_fids, cls.min_meas_fids, std.germs(), cls.maxLengthList) # RUN BELOW LINES TO GENERATE ANALYSIS DATASET (SAVE) @@ -51,7 +52,7 @@ def setUpClass(cls): cls.ds = pygsti.data.DataSet(file_to_load_from=compare_files + "/reportgen.dataset") cls.ds2 = pygsti.data.DataSet(file_to_load_from=compare_files + "/reportgen2.dataset") - mdl_lgst = pygsti.run_lgst(cls.ds, std.fiducials, std.fiducials, target_model, svd_truncate_to=4, verbosity=0) + mdl_lgst = pygsti.run_lgst(cls.ds, cls.min_prep_fids, cls.min_meas_fids, target_model, svd_truncate_to=4, verbosity=0) mdl_lgst_go = pygsti.gaugeopt_to_target(mdl_lgst, target_model, {'gates': 1.0, 'spam': 0.0}) cls.mdl_clgst = pygsti.contract(mdl_lgst_go, "CPTP") cls.mdl_clgst_tp = pygsti.contract(cls.mdl_clgst, "vSPAM") @@ -68,7 +69,7 @@ def setUpClass(cls): ) experiment_design = pygsti.protocols.StandardGSTDesign( - target_model.create_processor_spec(), std.fiducials, std.fiducials, std.germs, cls.maxLengthList + target_model.create_processor_spec(), cls.min_prep_fids, cls.min_meas_fids, std.germs(lite=True), cls.maxLengthList ) data = pygsti.protocols.ProtocolData(experiment_design, cls.ds) protocol = pygsti.protocols.StandardGST() @@ -105,12 +106,12 @@ def setUpClass(cls): cls.ds3.add_counts_from_dataset(cls.ds2) cls.ds3.done_adding_data() - cls.results_logL = pygsti.run_long_sequence_gst(cls.ds3, tp_target, std.fiducials, std.fiducials, - std.germs, cls.maxLengthList, verbosity=0, + cls.results_logL = pygsti.run_long_sequence_gst(cls.ds3, tp_target, cls.min_prep_fids, cls.min_meas_fids, + std.germs(), cls.maxLengthList, verbosity=0, advanced_options={'tolerance': 1e-6, 'starting_point': 'LGST', 'on_bad_fit': ["robust","Robust","robust+","Robust+"], - 'bad_fit_threshold': -1.0, - 'germ_length_limits': {('Gx','Gi','Gi'): 2} }) + 'bad_fit_threshold': -1.0}, + disable_checkpointing= True) #OLD #lsgst_gatesets_TP = pygsti.do_iterative_mlgst(cls.ds, cls.mdl_clgst_tp, cls.lsgstStrings, verbosity=0, @@ -140,17 +141,16 @@ def setUpClass(cls): os.chdir(orig_cwd) - - def setUp(self): super(ReportBaseCase, self).setUp() cls = self.__class__ self.target_model = std.target_model() - self.fiducials = std.fiducials[:] - self.germs = std.germs[:] - self.op_labels = std.gates + self.prep_fids = cls.min_prep_fids + self.meas_fids = cls.min_meas_fids + self.germs = std.germs() + self.op_labels = list(std.target_model().operations.keys()) #self.specs = cls.specs self.maxLengthList = cls.maxLengthList[:] diff --git a/test/test_packages/report/test_report.py b/test/test_packages/report/test_report.py index e7256a460..037e02450 100644 --- a/test/test_packages/report/test_report.py +++ b/test/test_packages/report/test_report.py @@ -7,7 +7,7 @@ import numpy as np import pygsti -from pygsti.modelpacks.legacy import std1Q_XYI as std +from pygsti.modelpacks import smq1Q_XY as std # Inherit setup from here from .reportBaseCase import ReportBaseCase from ..testutils import compare_files, temp_files @@ -55,33 +55,30 @@ def test_std_clifford_comp(self): def test_reports_chi2_noCIs(self): - pygsti.report.create_standard_report(self.results, temp_files + "/general_reportA", - confidence_level=None, verbosity=3, auto_open=False) # omit title as test + + pygsti.report.construct_standard_report(self.results, confidence_level=None, verbosity=3).write_html(temp_files + "/general_reportA", auto_open=False) # omit title as test #Test advanced options linkto = () if bLatex: linkto = ('tex','pdf') + linkto #Note: can't render as 'tex' without matplotlib b/c of figs if bPandas: linkto = ('pkl',) + linkto results_odict = collections.OrderedDict([("One", self.results), ("Two",self.results)]) - pygsti.report.create_standard_report(results_odict, temp_files + "/general_reportA_adv1", - confidence_level=None, verbosity=3, auto_open=False, + pygsti.report.construct_standard_report(results_odict, + confidence_level=None, verbosity=3, advanced_options={'errgen_type': "logG-logT", - 'precision': {'normal': 2, 'polar': 1, 'sci': 1}}, - link_to=linkto) + 'precision': {'normal': 2, 'polar': 1, 'sci': 1}}).write_html(temp_files + "/general_reportA_adv1",auto_open=False) - pygsti.report.create_standard_report({"One": self.results, "Two": self.results_logL}, temp_files + "/general_reportA_adv2", - confidence_level=None, verbosity=3, auto_open=False, + pygsti.report.construct_standard_report({"One": self.results, "Two": self.results_logL}, + confidence_level=None, verbosity=3, advanced_options={'errgen_type': "logTiG", 'precision': 2, #just a single int 'resizable': False, - 'autosize': 'none'}) + 'autosize': 'none'}).write_html(temp_files + "/general_reportA_adv2", auto_open=False) #test latex reporting if bLatex: - pygsti.report.create_standard_report(self.results.view("default", "go0"), temp_files + "/general_reportA.pdf", - confidence_level=None, verbosity=3, auto_open=False) - - + pygsti.report.construct_standard_report(self.results.view("default", "go0"), + confidence_level=None, verbosity=3, auto_open=False).write_pdf(temp_files + "/general_reportA.pdf") #Compare the html files? #self.checkFile("general_reportA%s.html" % vs) @@ -92,8 +89,8 @@ def test_reports_chi2_wCIs(self): crfact.compute_hessian(comm=None) crfact.project_hessian('intrinsic error') - pygsti.report.create_standard_report(self.results, temp_files + "/general_reportB", - "Report B", confidence_level=95, verbosity=3, auto_open=False) + pygsti.report.construct_standard_report(self.results, + "Report B", confidence_level=95, verbosity=3).write_html( temp_files + "/general_reportB", auto_open=False) #Compare the html files? #self.checkFile("general_reportB%s.html" % vs) @@ -105,9 +102,8 @@ def test_reports_chi2_nonMarkCIs(self): crfact.project_hessian('std') #Note: Negative confidence levels no longer trigger non-mark error bars; this is done via "nm threshold" - pygsti.report.create_standard_report(self.results, temp_files + "/general_reportE", - "Report E", confidence_level=95, verbosity=3, auto_open=False, - advanced_options={'nm threshold': -10}) + pygsti.report.construct_standard_report(self.results,"Report E", confidence_level=95, verbosity=3, + advanced_options={'nm threshold': -10}).write_html(temp_files + "/general_reportE", auto_open=False) #Compare the html files? #self.checkFile("general_reportC%s.html" % vs) @@ -120,9 +116,9 @@ def test_reports_logL_TP_noCIs(self): #Note: this report will have (un-combined) Robust estimates too - pygsti.report.create_standard_report(results, temp_files + "/general_reportC", - "Report C", confidence_level=None, verbosity=3, auto_open=False, - advanced_options={'combine_robust': False}) + pygsti.report.construct_standard_report(results, + "Report C", confidence_level=None, verbosity=3, + advanced_options={'combine_robust': False}).write_html(temp_files + "/general_reportC", auto_open=False) #Compare the html files? #self.checkFile("general_reportC%s.html" % vs) @@ -137,27 +133,24 @@ def test_reports_logL_TP_wCIs(self): crfact.project_hessian('optimal gate CIs') #Note: this report will have Robust estimates too - pygsti.report.create_standard_report(self.results_logL, temp_files + "/general_reportD", - "Report D", confidence_level=95, verbosity=3, auto_open=False) + pygsti.report.construct_standard_report(self.results_logL, + "Report D", confidence_level=95, verbosity=3).write_html(temp_files + "/general_reportD", auto_open=False) #Compare the html files? #self.checkFile("general_reportD%s.html" % vs) def test_reports_multiple_ds(self): #Note: this report will have (un-combined) Robust estimates too - pygsti.report.create_standard_report({"chi2": self.results, "logl": self.results_logL}, - temp_files + "/general_reportF", - "Report F", confidence_level=None, verbosity=3, auto_open=False) + pygsti.report.construct_standard_report({"chi2": self.results, "logl": self.results_logL}, + "Report F", confidence_level=None, verbosity=3).write_html(temp_files + "/general_reportF", auto_open=False) #Compare the html files? #self.checkFile("general_reportC%s.html" % vs) def test_report_notebook(self): - pygsti.report.create_report_notebook(self.results_logL, temp_files + "/report_notebook.ipynb", None, - verbosity=3) - pygsti.report.create_report_notebook({'one': self.results_logL, 'two': self.results_logL}, - temp_files + "/report_notebook.ipynb", None, - verbosity=3) # multiple comparable data - + pygsti.report.construct_standard_report(self.results_logL, None, + verbosity=3).write_notebook(temp_files + "/report_notebook.ipynb") + pygsti.report.construct_standard_report({'one': self.results_logL, 'two': self.results_logL}, + None, verbosity=3).write_notebook(temp_files + "/report_notebook.ipynb") # multiple comparable data def test_inline_template(self): #Generate some results (quickly) diff --git a/test/test_packages/reportb/test_workspace.py b/test/test_packages/reportb/test_workspace.py index ebda5112e..0c08b3b2b 100644 --- a/test/test_packages/reportb/test_workspace.py +++ b/test/test_packages/reportb/test_workspace.py @@ -9,6 +9,7 @@ from pygsti.modelpacks.legacy import stdQT_XYIMS from ..report.reportBaseCase import ReportBaseCase from ..testutils import compare_files, temp_files +from pygsti.baseobjs import Label bLatex = bool('PYGSTI_LATEX_TESTING' in os.environ and os.environ['PYGSTI_LATEX_TESTING'].lower() in ("yes","1","true")) @@ -103,7 +104,7 @@ def test_table_creation(self): gsMultiSpam = self.mdl.copy() gsMultiSpam.povms['Msecondpovm'] = self.mdl.povms['Mdefault'].copy() gsTP = self.tgt.depolarize(0.01,0.01); gsTP.set_all_parameterizations("full TP") - gsCPTP = self.tgt.depolarize(0.01,0.01); gsCPTP.set_all_parameterizations("CPTP") + gsCPTP = self.tgt.depolarize(0.01,0.01); gsCPTP.set_all_parameterizations("CPTPLND") gsGM = self.mdl.depolarize(0.01,0.01); gsGM.basis = pygsti.baseobjs.Basis.cast("gm", 4) gsSTD = self.mdl.depolarize(0.01,0.01); gsSTD.basis = pygsti.baseobjs.Basis.cast("std", 4) gsQT = stdQT_XYIMS.target_model().depolarize(0.01,0.01) @@ -171,7 +172,7 @@ def make_cr(mdl): #tbls.append( w.GateEigenvalueTable(self.mdl, self.tgt, cr) ) #tbls.append( w.GateEigenvalueTable(self.mdl, None, cr, display=("polar",) ) ) # polar with no target model tbls.append(w.GateEigenvalueTable(self.mdl, self.tgt, cr, display=("evdm","evinf","rel"), - virtual_ops=[pygsti.circuits.Circuit(('Gx', 'Gx'))])) + virtual_ops=[pygsti.circuits.Circuit([Label('Gxpi2',0), Label('Gxpi2',0)])])) with self.assertRaises(ValueError): tbls.append( w.GateEigenvalueTable(self.mdl, self.tgt, cr, display=("foobar",)) ) @@ -200,7 +201,7 @@ def make_cr(mdl): metric, [self.mdl,self.mdl],[self.tgt,self.tgt], ['one','two'])) #1D tbls.append( w.GatesSingleMetricTable( metric, [[self.mdl],[self.mdl]],[[self.tgt],[self.tgt]], - ['column one'], ['row one','row two'], op_label="Gx")) #2D + ['column one'], ['row one','row two'], op_label=Label("Gxpi2",0))) #2D tbls.append( w.GatesSingleMetricTable( metric, [self.mdl,None],[self.tgt,self.tgt], ['one','two'])) #1D w/None model @@ -236,9 +237,10 @@ def make_cr(mdl): w.ProfilerTable(profiler,"foobar") #OLD tables - tbls.append( w.old_RotationAxisVsTargetTable(self.mdl, self.tgt) ) - tbls.append( w.old_GateDecompTable(self.mdl) ) - tbls.append( w.old_RotationAxisTable(self.mdl) ) + #These don't look to be fully compatible with modern pygsti, so disable these tests. + #tbls.append( w.old_RotationAxisVsTargetTable(self.mdl, self.tgt) ) + #tbls.append( w.old_GateDecompTable(self.mdl) ) + #tbls.append( w.old_RotationAxisTable(self.mdl) ) #Now test table rendering in html @@ -289,7 +291,7 @@ def test_plot_creation(self): mds = pygsti.data.MultiDataSet() mds.add_dataset("DS0",self.ds) mds.add_dataset("DS1",self.ds) - dsc = pygsti.data.DataComparator([self.ds, self.ds], op_exclusions=['Gfoo'], op_inclusions=['Gx', 'Gy', 'Gi']) + dsc = pygsti.data.DataComparator([self.ds, self.ds], op_exclusions=['Gfoo'], op_inclusions=['Gxpi2', 'Gypi2', '[]']) dsc2 = pygsti.data.DataComparator(mds) dsc.run() dsc2.run() @@ -318,8 +320,16 @@ def test_plot_creation(self): # effect_labels=self.mdl.get_effect_labels() ) baseStrs = [plaq.base for _, plaq in self.gss.iter_plaquettes()] + #print(f'{baseStrs=}') + #print(f'{prepStrs=}') + #print(f'{effectStrs=}') + #print(self.ds) + #print(f'{list(self.gss)=}') + #print(self.mdl) + directModels = dx.direct_mlgst_models( baseStrs, self.ds, prepStrs, effectStrs, self.tgt, svd_truncate_to=4) + #print(f'{directModels=}') plts.append( w.ColorBoxPlot(["chi2","logl","blank"], self.gss, self.ds, self.mdl, box_labels=False, direct_gst_models=directModels) ) plts.append( w.ColorBoxPlot(["errorrate"], self.gss, diff --git a/test/test_packages/tools/test_logl.py b/test/test_packages/tools/test_logl.py index a4e75251d..8e73a9f1a 100644 --- a/test/test_packages/tools/test_logl.py +++ b/test/test_packages/tools/test_logl.py @@ -2,20 +2,36 @@ import psutil import pygsti +from pygsti.modelpacks import smq1Q_XY +import pygsti.protocols as proto from ..testutils import BaseTestCase, compare_files class LogLTestCase(BaseTestCase): def test_memory(self): + model = smq1Q_XY.target_model() + model = model.depolarize(spam_noise = .01, op_noise = .001) + model = model.rotate(max_rotate=.005, seed=1234) + + prep_fiducials = smq1Q_XY.prep_fiducials() + meas_fiducials = smq1Q_XY.meas_fiducials() + germs = smq1Q_XY.germs() + op_labels = list(model.operations.keys()) # also == std.gates + maxLengthList = [1] + #circuits for XY model. + gss = pygsti.circuits.make_lsgst_structs(op_labels, prep_fiducials[0:4], + meas_fiducials[0:3], smq1Q_XY.germs(), maxLengthList) + + edesign = proto.CircuitListsDesign([pygsti.circuits.CircuitList(circuit_struct) for circuit_struct in gss]) + + ds = pygsti.data.simulate_data(model, edesign.all_circuits_needing_data, 1000, seed = 1234) + def musage(prefix): p = psutil.Process(os.getpid()) print(prefix, p.memory_info()[0]) current_mem = pygsti.baseobjs.profiler._get_mem_usage - musage("Initial") - ds = pygsti.data.DataSet(file_to_load_from=compare_files + "/analysis.dataset") - model = pygsti.io.load_model(compare_files + "/analysis.model") musage("Pt1") with self.assertRaises(MemoryError): diff --git a/test/unit/algorithms/test_fiducialpairreduction.py b/test/unit/algorithms/test_fiducialpairreduction.py index 29d84c89f..1378a144b 100644 --- a/test/unit/algorithms/test_fiducialpairreduction.py +++ b/test/unit/algorithms/test_fiducialpairreduction.py @@ -70,8 +70,6 @@ def test_find_sufficient_fiducial_pairs_per_germ_sequential(self): min_iterations=1, verbosity=0 ) - print(fiducial_pairs) - self.assertTrue(fiducial_pairs == self.fiducial_pairs_per_germ or fiducial_pairs == self.fiducial_pairs_per_germ_alt) def test_find_sufficient_fiducial_pairs_per_germ_random(self): @@ -80,8 +78,6 @@ def test_find_sufficient_fiducial_pairs_per_germ_random(self): search_mode='random', n_random=10, seed=_SEED ) - print(fiducial_pairs) - self.assertTrue(fiducial_pairs == self.fiducial_pairs_per_germ_random or fiducial_pairs == self.fiducial_pairs_per_germ_random_alt) diff --git a/test/unit/algorithms/test_fiducialselection.py b/test/unit/algorithms/test_fiducialselection.py index 343cd4757..36dfe77ad 100644 --- a/test/unit/algorithms/test_fiducialselection.py +++ b/test/unit/algorithms/test_fiducialselection.py @@ -4,6 +4,7 @@ import pygsti.circuits as pc from pygsti.circuits import Circuit from pygsti.baseobjs import Label +import pygsti.models.modelconstruction as mc from . import fixtures from ..util import BaseCase @@ -238,3 +239,12 @@ def test_find_fiducials_clifford_dedupe(self): # TODO assert correctness # for now at least check it is not None self.assertTrue(fiducials is not None) + + def test_find_fiducials_end_to_end_default(self): + prepFiducials, measFiducials = fs.find_fiducials(self.model) + + def find_fiducials_omit_operations(self): + target_model_idle = mc.create_explicit_model_from_expressions([('Q0',)], ['Gi','Gx','Gy'], + ["I(Q0)", "X(pi/2,Q0)", "Y(pi/2,Q0)"]) + omitIdentityPrepFids, omitIdentityMeasFids = fs.find_fiducials(target_model_idle, omit_identity=False, + ops_to_omit=['Gi']) diff --git a/test/unit/algorithms/test_gaugeopt.py b/test/unit/algorithms/test_gaugeopt.py index 6cc95c8ce..c8799b101 100644 --- a/test/unit/algorithms/test_gaugeopt.py +++ b/test/unit/algorithms/test_gaugeopt.py @@ -10,8 +10,9 @@ class GaugeOptMethodBase(object): def setUp(self): super(GaugeOptMethodBase, self).setUp() self.options = dict( - verbosity=10, - check_jac=True + verbosity=0, + check_jac=False, + tol = 1e-5 ) def test_gaugeopt(self): @@ -158,7 +159,7 @@ def setUpClass(cls): super(CPTPGaugeOptTester, cls).setUpClass() # TODO construct directly mdl_lgst_target = go.gaugeopt_to_target(fixtures.mdl_lgst, fixtures.model, check_jac=True) - mdl_clgst_cptp = alg.contract(mdl_lgst_target, "CPTP", verbosity=10, tol=10.0) + mdl_clgst_cptp = alg.contract(mdl_lgst_target, "CPTP", verbosity=0, tol=10.0) cls._model = mdl_clgst_cptp @@ -210,6 +211,16 @@ def setUp(self): spam_penalty_factor=1.0 ) +class GaugeOptCheckJacTester(GaugeOptMethodBase, LGSTGaugeOptInstance, BaseCase): + def setUp(self): + super(GaugeOptCheckJacTester, self).setUp() + self.options.update( + check_jac = True + ) -class LGSTGaugeOptAllPenaltyTester(LGSTGaugeOptCPTPPenaltyTester, LGSTGaugeOptSPAMPenaltyTester): - pass + +#I think the only difference between this and CPTPGaugeOptAllPenaltyTester is the initial model used. +#For the purposed of testing the use of both penalty functions simultaneously I don't think this is +#important. +#class LGSTGaugeOptAllPenaltyTester(LGSTGaugeOptCPTPPenaltyTester, LGSTGaugeOptSPAMPenaltyTester): +# pass diff --git a/test/unit/algorithms/test_germselection.py b/test/unit/algorithms/test_germselection.py index 63a8cf28a..6415717bb 100644 --- a/test/unit/algorithms/test_germselection.py +++ b/test/unit/algorithms/test_germselection.py @@ -34,7 +34,7 @@ class GermSelectionWithNeighbors(GermSelectionData): def setUpClass(cls): super(GermSelectionWithNeighbors, cls).setUpClass() cls.neighbors = germsel.randomize_model_list( - [fixtures.model], randomization_strength=1e-3, num_copies=5, seed=_SEED + [fixtures.model], randomization_strength=1e-3, num_copies=2, seed=_SEED ) @@ -383,4 +383,8 @@ class EndToEndGermSelectionTester(GermSelectionData, BaseCase): def lite_germ_selection_end_to_end_test(self): liteGerms = germsel.find_germs(self.target_model, randomize=False, algorithm='greedy', verbosity=1, assume_real=True, float_type=np.double) - # TODO assert correctness \ No newline at end of file + # TODO assert correctness + + def robust_germ_selection_end_to_end_test(self): + robust_germs = germsel.find_germs(self.target_model, seed=2017) + #todo assert correctness \ No newline at end of file diff --git a/test/unit/construction/test_qutrit.py b/test/unit/construction/test_qutrit.py index abd51b7ed..166695be8 100644 --- a/test/unit/construction/test_qutrit.py +++ b/test/unit/construction/test_qutrit.py @@ -11,7 +11,7 @@ def test_ideal_qutrit(self): def test_noisy_qutrit(self): mdl_sim = qutrit.create_qutrit_model(error_scale=0.1, similarity=True, seed=1234, basis='qt') mdl_ideal = qutrit.create_qutrit_model(error_scale=0.1, similarity=True, seed=1234, basis='qt') - self.assertArraysAlmostEqual(mdl_sim['Gi'], mdl_ideal['Gi']) + self.assertArraysAlmostEqual(mdl_sim['Gi', 'QT'], mdl_ideal['Gi', 'QT']) #just test building a gate in the qutrit basis # Can't do this b/c need a 'T*' triplet space designator for "triplet space" and it doesn't seem diff --git a/test/unit/drivers/test_longsequence.py b/test/unit/drivers/test_longsequence.py index 1945d5427..03a41e743 100644 --- a/test/unit/drivers/test_longsequence.py +++ b/test/unit/drivers/test_longsequence.py @@ -1,5 +1,6 @@ from io import BytesIO +import pytest import pygsti.data as pdata from pygsti import io from pygsti.drivers import longsequence as ls @@ -12,7 +13,7 @@ # TODO optimize everything -class LongSequenceBase(BaseCase): +class LongSequenceBasePlain: @classmethod def setUpClass(cls): cls.pspec = pkg.pspec @@ -29,44 +30,73 @@ def setUp(self): self.model = self.model.copy() self.ds = self.ds.copy() +class LongSequenceBase(LongSequenceBasePlain, BaseCase): + # just wrap the version that doesn't inherit from BaseCase + pass + + +class MapForwardSimulatorWrapper(mapforwardsim.MapForwardSimulator): + + Message = """ + Hit the forward simulator wrapper! + """ + + def _bulk_fill_probs(self, array_to_fill, layout): + print(self.Message) + super(MapForwardSimulatorWrapper, self)._bulk_fill_probs(array_to_fill, layout) + + def _bulk_fill_probs_atom(self, array_to_fill, layout_atom, resource_alloc): + print(self.Message) + super(MapForwardSimulatorWrapper, self)._bulk_fill_probs_atom(array_to_fill, layout_atom, resource_alloc) + + + +class ModelTestTester(LongSequenceBasePlain): -class ModelTestTester(LongSequenceBase): def setUp(self): + super(ModelTestTester, self).setUpClass() super(ModelTestTester, self).setUp() self.mdl_guess = self.model.depolarize(op_noise=0.01, spam_noise=0.01) def test_model_test(self): + self.setUp() result = ls.run_model_test( self.mdl_guess, self.ds, self.pspec, self.prep_fids, self.meas_fids, self.germs, self.maxLens ) # TODO assert correctness - def test_model_test_advanced_options(self): + def test_model_test_advanced_options(self, capfd: pytest.LogCaptureFixture): + self.setUp() result = ls.run_model_test( - self.mdl_guess, self.ds, self.pspec, self.prep_fids, - self.meas_fids, self.germs, self.maxLens, - advanced_options=dict(objective='chi2', profile=2) - ) + self.mdl_guess, self.ds, self.pspec, self.prep_fids, + self.meas_fids, self.germs, self.maxLens, + advanced_options=dict(objective='chi2', profile=2), + simulator=MapForwardSimulatorWrapper + ) + stdout, _ = capfd.readouterr() + assert MapForwardSimulatorWrapper.Message in stdout # TODO assert correctness def test_model_test_pickle_output(self): + self.setUp() with BytesIO() as pickle_stream: result = ls.run_model_test( self.mdl_guess, self.ds, self.pspec, self.prep_fids, self.meas_fids, self.germs, self.maxLens, output_pkl=pickle_stream ) - self.assertTrue(len(pickle_stream.getvalue()) > 0) + assert len(pickle_stream.getvalue()) > 0 # TODO assert correctness def test_model_test_raises_on_bad_options(self): - with self.assertRaises(ValueError): + self.setUp() + with pytest.raises(ValueError): ls.run_model_test( self.mdl_guess, self.ds, self.pspec, self.prep_fids, self.meas_fids, self.germs, self.maxLens, advanced_options=dict(objective='foobar') ) - with self.assertRaises(ValueError): + with pytest.raises(ValueError): ls.run_model_test( self.mdl_guess, self.ds, self.pspec, self.prep_fids, self.meas_fids, self.germs, self.maxLens, diff --git a/test/unit/modelmembers/test_kraus_interface.py b/test/unit/modelmembers/test_kraus_interface.py index 16e7b2139..625e55df7 100644 --- a/test/unit/modelmembers/test_kraus_interface.py +++ b/test/unit/modelmembers/test_kraus_interface.py @@ -4,7 +4,7 @@ import numpy as np from pygsti.modelpacks import smq1Q_XYI from pygsti.baseobjs import QubitSpace, Basis -from pygsti.modelmembers.operations import StochasticNoiseOp +from pygsti.modelmembers.operations import StochasticNoiseOp, DepolarizeOp from pygsti.circuits import Circuit from pygsti.models import create_explicit_model from pygsti.modelmembers.operations.composedop import ComposedOp @@ -79,6 +79,18 @@ def test_dense_op(self): kkdag = [kop @ kop.conjugate().T for kop in op.kraus_operators] assert(np.allclose(sum(kkdag), np.identity(2))) + def test_kraus_ops(self): + # test that kraus operators for a depolarization op can recover that depolarization op + op = DepolarizeOp(QubitSpace(1), initial_rate=0.1) + kraus_ops = op.kraus_operators + test = FullArbitraryOp.from_kraus_operators(kraus_ops) + assert np.allclose(op.to_dense(), test.to_dense()) + + op = FullArbitraryOp(op.to_dense(), 'pp') + kraus_ops = op.kraus_operators + test = FullArbitraryOp.from_kraus_operators(kraus_ops) + assert np.allclose(op.to_dense(), test.to_dense()) + def test_stochastic_errorgen_equivalence_single(self): #Check that StochasticOp and 'S'-type elementary errorgen give the same op B = Basis.cast('PP', 4) diff --git a/test/unit/modelmembers/test_operation.py b/test/unit/modelmembers/test_operation.py index 9dea06334..720c3ee91 100644 --- a/test/unit/modelmembers/test_operation.py +++ b/test/unit/modelmembers/test_operation.py @@ -3,7 +3,6 @@ import sys import numpy as np import scipy.sparse as sps - import pygsti.modelmembers.operations as op import pygsti.tools.internalgates as itgs import pygsti.tools.lindbladtools as lt @@ -22,7 +21,7 @@ SKIP_DIAMONDIST_ON_WIN = True -class OpBase(object): +class OpBase: def setUp(self): ExplicitOpModel._strict = False self.gate = self.build_gate() @@ -220,12 +219,6 @@ def test_rotate(self): self.gate.rotate([0.01, 0.02, 0.03], 'gm') # TODO assert correctness - #REMOVED - we don't have compose methods anymore - #def test_compose(self): - # cgate = self.gate.compose(self.gate) - # # TODO assert correctness - - class ImmutableDenseOpBase(DenseOpBase): def test_raises_on_set_value(self): M = np.asarray(self.gate) # gate as a matrix @@ -326,28 +319,6 @@ class FullOpTester(MutableDenseOpBase, BaseCase): def build_gate(): return create_operation("X(pi/8,Q0)", [('Q0',)], "gm", parameterization="full") - #REMOVED - we don't support .compose methods anymore - #def test_composition(self): - # gate_linear = LinearlyParamOpTester.build_gate() - # gate_tp = TPOpTester.build_gate() - # gate_static = StaticOpTester.build_gate() - # - # c = op.compose(self.gate, self.gate, "gm", "full") - # self.assertArraysAlmostEqual(c, np.dot(self.gate, self.gate)) - # self.assertEqual(type(c), op.FullArbitraryOp) - # - # c = op.compose(self.gate, gate_tp, "gm") - # self.assertArraysAlmostEqual(c, np.dot(self.gate, gate_tp)) - # self.assertEqual(type(c), op.FullArbitraryOp) - # - # c = op.compose(self.gate, gate_static, "gm") - # self.assertArraysAlmostEqual(c, np.dot(self.gate, gate_static)) - # self.assertEqual(type(c), op.FullArbitraryOp) - # - # c = op.compose(self.gate, gate_linear, "gm") - # self.assertArraysAlmostEqual(c, np.dot(self.gate, gate_linear)) - # self.assertEqual(type(c), op.FullArbitraryOp) - def test_convert_to_linear(self): converted = op.convert(self.gate, "linear", "gm") self.assertArraysAlmostEqual(converted.to_dense(), self.gate.to_dense()) @@ -394,26 +365,6 @@ def test_constructor_raises_on_real_param_constraint_violation(self): op.LinearlyParamArbitraryOp(baseMx, np.array([1.0 + 1j, 1.0]), parameterToBaseIndicesMap, real=True) # must be real - #REMOVED - we don't support .compose methods anymore - #def test_composition(self): - # gate_full = FullOpTester.build_gate() - # - # c = op.compose(self.gate, gate_full, "gm") - # self.assertArraysAlmostEqual(c, np.dot(self.gate, gate_full)) - # self.assertEqual(type(c), op.FullArbitraryOp) - # - # #c = op.compose(self.gate, gate_tp, "gm") - # #self.assertArraysAlmostEqual(c, np.dot(self.gate,gate_tp) ) - # #self.assertEqual(type(c), op.FullTPOp) - # - # #c = op.compose(self.gate, gate_static, "gm") - # #self.assertArraysAlmostEqual(c, np.dot(self.gate,gate_static) ) - # #self.assertEqual(type(c), op.LinearlyParamArbitraryOp) - # - # #c = op.compose(self.gate, self.gate, "gm") - # #self.assertArraysAlmostEqual(c, np.dot(self.gate,self.gate) ) - # #self.assertEqual(type(c), op.LinearlyParamArbitraryOp) - def test_build_from_scratch(self): # TODO what is actually being tested here? baseMx = np.zeros((4, 4)) @@ -438,27 +389,6 @@ class TPOpTester(MutableDenseOpBase, BaseCase): def build_gate(): return create_operation("Y(pi/4,Q0)", [('Q0',)], "gm", parameterization="full TP") - #REMOVED - we don't support .compose methods anymore - #def test_composition(self): - # gate_full = FullOpTester.build_gate() - # gate_static = StaticOpTester.build_gate() - # - # c = op.compose(self.gate, gate_full, "gm") - # self.assertArraysAlmostEqual(c, np.dot(self.gate, gate_full)) - # self.assertEqual(type(c), op.FullArbitraryOp) - # - # c = op.compose(self.gate, self.gate, "gm") - # self.assertArraysAlmostEqual(c, np.dot(self.gate, self.gate)) - # self.assertEqual(type(c), op.FullTPOp) - # - # c = op.compose(self.gate, gate_static, "gm") - # self.assertArraysAlmostEqual(c, np.dot(self.gate, gate_static)) - # self.assertEqual(type(c), op.FullTPOp) - # - # #c = op.compose(self.gate, gate_linear, "gm") - # #self.assertArraysAlmostEqual(c, np.dot(self.gate,gate_linear) ) - # #self.assertEqual(type(c), op.FullTPOp) - def test_convert(self): conv = op.convert(self.gate, "full", "gm") conv = op.convert(self.gate, "full TP", "gm") @@ -480,6 +410,49 @@ def test_first_row_read_only(self): with self.assertRaises(ValueError): self.gate[0][1:2] = [0] +class AffineShiftOpTester(DenseOpBase, BaseCase): + n_params = 3 + + @staticmethod + def build_gate(): + mat = np.array([[1,0,0,0],[.1, 1, 0, 0], [.1, 0, 1, 0], [.1, 0, 0, 1]]) + return op.AffineShiftOp(mat) + + def test_set_dense(self): + M = np.asarray(self.gate) # gate as a matrix + self.gate.set_dense(M) + + def test_transform(self): + gate_copy = self.gate.copy() + T = FullGaugeGroupElement(np.identity(4, 'd')) + gate_copy.transform_inplace(T) + self.assertArraysAlmostEqual(gate_copy, self.gate) + + def test_element_accessors(self): + e1 = self.gate[1, 1] + e2 = self.gate[1][1] + self.assertAlmostEqual(e1, e2) + + s1 = self.gate[1, :] + s2 = self.gate[1] + s3 = self.gate[1][:] + a1 = self.gate[:] + self.assertArraysAlmostEqual(s1, s2) + self.assertArraysAlmostEqual(s1, s3) + + s4 = self.gate[2:4, 1] + + def test_set_elements(self): + gate_copy = self.gate.copy() + + #allowed sets: + gate_copy[1,0] = 2 + gate_copy[2,0] = 2 + + #unallowed sets: + with self.assertRaises(ValueError): + gate_copy[1,1] = 2 + class StaticOpTester(ImmutableDenseOpBase, BaseCase): n_params = 0 @@ -488,27 +461,6 @@ class StaticOpTester(ImmutableDenseOpBase, BaseCase): def build_gate(): return create_operation("Z(pi/3,Q0)", [('Q0',)], "gm", parameterization="static") - #REMOVED - we don't support .compose methods anymore - #def test_compose(self): - # gate_full = FullOpTester.build_gate() - # gate_tp = TPOpTester.build_gate() - # - # c = op.compose(self.gate, gate_full, "gm") - # self.assertArraysAlmostEqual(c, np.dot(self.gate, gate_full)) - # self.assertEqual(type(c), op.FullArbitraryOp) - # - # c = op.compose(self.gate, gate_tp, "gm") - # self.assertArraysAlmostEqual(c, np.dot(self.gate, gate_tp)) - # self.assertEqual(type(c), op.FullTPOp) - # - # c = op.compose(self.gate, self.gate, "gm") - # self.assertArraysAlmostEqual(c, np.dot(self.gate, self.gate)) - # self.assertEqual(type(c), op.StaticArbitraryOp) - # - # #c = op.compose(self.gate, gate_linear, "gm") - # #self.assertArraysAlmostEqual(c, np.dot(self.gate,gate_linear) ) - # #self.assertEqual(type(c), op.LinearlyParamArbitraryOp) - def test_convert(self): conv = op.convert(self.gate, "static", "gm") # TODO assert correctness @@ -827,7 +779,6 @@ def build_gate(): return inst['plus'] def test_vector_conversion(self): - #with self.assertRaises(ValueError): self.gate.to_vector() # now to_vector is allowed def test_deriv_wrt_params(self): diff --git a/test/unit/objects/test_circuit.py b/test/unit/objects/test_circuit.py index b65a76f61..710349040 100644 --- a/test/unit/objects/test_circuit.py +++ b/test/unit/objects/test_circuit.py @@ -496,6 +496,116 @@ def test_convert_to_quil(self): s = c.convert_to_quil() self.assertEqual(quil_str, s) + def test_convert_to_openqasm(self): + ckt = circuit.Circuit([Label('Gxpi2',0), Label(()), Label([Label('Gh',0), Label('Gtdag',1)]), + Label('Gcnot', (0,1))], line_labels=(0,1)) + + converted_qasm = ckt.convert_to_openqasm() + #this is really just doing a check if anything has changed. I.e. an integration test. + expected_qasm = 'OPENQASM 2.0;\ninclude "qelib1.inc";\n\nopaque delay(t) q;\n\nqreg q[2];'\ + +'\ncreg cr[2];\n\nu3(1.570796326794897, 4.71238898038469, 1.570796326794897) q[0];\ndelay(0) q[1];'\ + +'\nbarrier q[0], q[1];\ndelay(0) q[0];\ndelay(0) q[1];\nbarrier q[0], q[1];\nh q[0];\ntdg q[1];'\ + +'\nbarrier q[0], q[1];\ncx q[0], q[1];\nbarrier q[0], q[1];\nmeasure q[0] -> cr[0];\nmeasure q[1] -> cr[1];\n' + + self.assertEqual(converted_qasm, expected_qasm) + + def test_convert_to_cirq(self): + try: + import cirq + except ImportError: + self.skipTest("Cirq is required for this operation, and it does not appear to be installed.") + + ckt = circuit.Circuit([Label('Gxpi2',0), Label(()), Label('Gn',0), Label([Label('Gh',0), Label('Gtdag',1)]), + Label('Gcnot', (0,1))], line_labels=(0,1)) + + qubit_conversion = {0: cirq.GridQubit(0,0), 1: cirq.GridQubit(0,1)} + cirq_circuit_converted = ckt.convert_to_cirq(qubit_conversion) + + #Manually build this circuit directly in cirq and compare. + qubit_00 = cirq.GridQubit(0,0) + qubit_01 = cirq.GridQubit(0,1) + moment1 = cirq.Moment([cirq.XPowGate(exponent=.5).on(qubit_00), cirq.I(qubit_01)]) + moment2 = cirq.Moment([cirq.I(qubit_00), cirq.I(qubit_01)]) + moment3 = cirq.Moment([cirq.PhasedXZGate(axis_phase_exponent=0.14758361765043326, + x_exponent=0.4195693767448338, + z_exponent=-0.2951672353008665).on(qubit_00), + cirq.I(qubit_01)]) + moment4 = cirq.Moment([cirq.H(qubit_00), (cirq.T**-1).on(qubit_01)]) + moment5 = cirq.Moment([cirq.CNOT.on(qubit_00, qubit_01)]) + cirq_circuit_direct = cirq.Circuit([moment1, moment2, moment3, moment4, moment5]) + + self.assertTrue(cirq_circuit_direct == cirq_circuit_converted) + + def test_from_cirq(self): + try: + import cirq + except ImportError: + self.skipTest("Cirq is required for this operation, and it does not appear to be installed.") + + qubit_00 = cirq.GridQubit(0,0) + qubit_01 = cirq.GridQubit(0,1) + moment1 = cirq.Moment([cirq.XPowGate(exponent=.5).on(qubit_00), cirq.I(qubit_01)]) + moment2 = cirq.Moment([cirq.I(qubit_00), cirq.I(qubit_01)]) + moment3 = cirq.Moment([cirq.PhasedXZGate(axis_phase_exponent=0.14758361765043326, + x_exponent=0.4195693767448338, + z_exponent=-0.2951672353008665).on(qubit_00), + cirq.I(qubit_01)]) + moment4 = cirq.Moment([cirq.H(qubit_00), (cirq.T**-1).on(qubit_01)]) + moment5 = cirq.Moment([cirq.CNOT.on(qubit_00, qubit_01)]) + cirq_circuit = cirq.Circuit([moment1, moment2, moment3, moment4, moment5]) + + converted_pygsti_circuit = circuit.Circuit.from_cirq(cirq_circuit, + qubit_conversion= {qubit_00: 0, qubit_01: 1}) + + ckt = circuit.Circuit([Label('Gxpi2',0), Label(()), Label('Gn',0), Label([Label('Gh',0), Label('Gtdag',1)]), + Label('Gcnot', (0,1))], line_labels=(0,1)) + + self.assertEqual(ckt, converted_pygsti_circuit) + + #test without stripping implied idles: + converted_pygsti_circuit_implied_idles = circuit.Circuit.from_cirq(cirq_circuit, + qubit_conversion= {qubit_00: 0, qubit_01: 1}, + remove_implied_idles= False) + + ckt_implied_idles = circuit.Circuit([Label([Label('Gxpi2',0), Label('Gi',1)]), + Label(()), + Label([Label('Gn',0), Label('Gi',1)]), + Label([Label('Gh',0), Label('Gtdag',1)]), + Label('Gcnot', (0,1))], line_labels=(0,1)) + + self.assertEqual(ckt_implied_idles, converted_pygsti_circuit_implied_idles) + + #test w/replacement of global idle + ckt_global_idle = circuit.Circuit([Label('Gxpi2',0), Label(()), Label('Gn',0), Label([Label('Gh',0), Label('Gtdag',1)]), + Label('Gcnot', (0,1))], line_labels=(0,1)) + ckt_global_idle_custom = circuit.Circuit([Label('Gxpi2',0), Label('Gbanana', (0,1)), Label('Gn',0), Label([Label('Gh',0), Label('Gtdag',1)]), + Label('Gcnot', (0,1))], line_labels=(0,1)) + + ckt_global_idle_none = circuit.Circuit([Label('Gxpi2',0), Label([Label('Gi',0), Label('Gi',1)]), Label('Gn',0), Label([Label('Gh',0), Label('Gtdag',1)]), + Label('Gcnot', (0,1))], line_labels=(0,1)) + + converted_pygsti_circuit_global_idle = circuit.Circuit.from_cirq(cirq_circuit, + qubit_conversion= {qubit_00: 0, qubit_01: 1}, + global_idle_replacement_label='auto') + + converted_pygsti_circuit_global_idle_custom = circuit.Circuit.from_cirq(cirq_circuit, + qubit_conversion= {qubit_00: 0, qubit_01: 1}, + global_idle_replacement_label='Gbanana') + + converted_pygsti_circuit_global_idle_custom_1 = circuit.Circuit.from_cirq(cirq_circuit, + qubit_conversion= {qubit_00: 0, qubit_01: 1}, + global_idle_replacement_label=Label('Gbanana', (0,1))) + + converted_pygsti_circuit_global_idle_none = circuit.Circuit.from_cirq(cirq_circuit, + qubit_conversion= {qubit_00: 0, qubit_01: 1}, + global_idle_replacement_label=None) + + + self.assertEqual(ckt_global_idle, converted_pygsti_circuit_global_idle) + self.assertEqual(ckt_global_idle_custom, converted_pygsti_circuit_global_idle_custom) + self.assertEqual(ckt_global_idle_custom, converted_pygsti_circuit_global_idle_custom_1) + self.assertEqual(ckt_global_idle_none, converted_pygsti_circuit_global_idle_none) + def test_done_editing(self): self.c.done_editing() with self.assertRaises(AssertionError): @@ -623,6 +733,10 @@ def test_read_only(self): def test_raise_on_add_non_circuit(self): with self.assertRaises(AssertionError): self.s1 + ("Gx",) # can't add non-Circuit to circuit + + def test_raise_on_add_incompatible_circuit_labels(self): + with self.assertRaises(ValueError): + self.s1 + circuit.Circuit([Label('Gy',0)], line_labels=(0,)) def test_clear(self): c = self.s1.copy(editable=True) diff --git a/test/unit/objects/test_modelnoise.py b/test/unit/objects/test_modelnoise.py new file mode 100644 index 000000000..1a53ae785 --- /dev/null +++ b/test/unit/objects/test_modelnoise.py @@ -0,0 +1,30 @@ +from pygsti.processors import QubitProcessorSpec +from pygsti.models import create_crosstalk_free_model +from pygsti.circuits import Circuit +from pygsti.modelmembers.operations.opfactory import ComposedOpFactory +from pygsti.modelmembers.operations.depolarizeop import DepolarizeOp + +from ..util import BaseCase + + +class ModelNoiseTester(BaseCase): + def test_linblad_agrees_with_depol(self): + pspec = QubitProcessorSpec(1, ["Gi"], geometry="line") + + mdl1 = create_crosstalk_free_model( + pspec, + depolarization_parameterization="lindblad", + depolarization_strengths={'Gi': 0.02} + ) + + mdl2 = create_crosstalk_free_model( + pspec, + depolarization_parameterization="depolarize", + depolarization_strengths={'Gi': 0.02} + ) + + c = Circuit("Gi:0@(0)") + p1 = mdl1.probabilities(c) + p2 = mdl2.probabilities(c) + self.assertAlmostEqual(p1['0'], p2['0'], places=3) + self.assertAlmostEqual(p1['1'], p2['1'], places=3) diff --git a/test/unit/objects/test_protectedarray.py b/test/unit/objects/test_protectedarray.py index 5a5fb8737..a1272f76f 100644 --- a/test/unit/objects/test_protectedarray.py +++ b/test/unit/objects/test_protectedarray.py @@ -15,12 +15,21 @@ def test_construction(self): #protect first row # TODO assert correctness - pa5 = pa.ProtectedArray(np.zeros((3, 3), 'd'), (0, [0, 1])) + pa5 = pa.ProtectedArray(np.zeros((3, 3), 'd'), ((0,0), (0, 1))) #protect (0,0) and (0,1) elements s1 = pa5[0, :] # slice s1 should have first two elements protected: - self.assertEqual(s1.indicesToProtect, ([0, 1],)) - + self.assertTrue(np.all(s1.protected_index_mask == np.array([1, 1, 0]))) + + def test_construction_from_mask_and_invalid_set(self): + mask = np.eye(3, dtype=np.bool_) + pa1 = pa.ProtectedArray(np.zeros((3,3)), protected_index_mask= mask) + #check that accessing a protected element of this raises an + #exception + + with self.assertRaises(ValueError): + pa1[0,0] = 1 + def test_raises_on_index_out_of_range(self): pa5 = pa.ProtectedArray(np.zeros((3, 3), 'd'), (0, [0, 1])) with self.assertRaises(IndexError): @@ -28,7 +37,7 @@ def test_raises_on_index_out_of_range(self): def test_raises_on_bad_index_type(self): pa5 = pa.ProtectedArray(np.zeros((3, 3), 'd'), (0, [0, 1])) - with self.assertRaises(TypeError): + with self.assertRaises(IndexError): pa5["str"] = 4 def test_raises_on_construct_index_out_of_range(self): @@ -36,5 +45,5 @@ def test_raises_on_construct_index_out_of_range(self): pa.ProtectedArray(np.zeros((3, 3), 'd'), (0, 10)) def test_raises_on_construct_bad_index_type(self): - with self.assertRaises(TypeError): + with self.assertRaises(IndexError): pa.ProtectedArray(np.zeros((3, 3), 'd'), (0, "str")) diff --git a/test/unit/protocols/test_gst.py b/test/unit/protocols/test_gst.py index 9ac5ddea2..8a0b03b82 100644 --- a/test/unit/protocols/test_gst.py +++ b/test/unit/protocols/test_gst.py @@ -1,4 +1,5 @@ from pygsti.data import simulate_data +from pygsti.forwardsims.mapforwardsim import MapForwardSimulator from pygsti.modelpacks import smq1Q_XYI from pygsti.modelpacks.legacy import std1Q_XYI, std2Q_XYICNOT from pygsti.objectivefns.objectivefns import PoissonPicDeltaLogLFunction @@ -11,6 +12,7 @@ from pygsti.protocols.gst import GSTGaugeOptSuite from pygsti.tools import two_delta_logl from ..util import BaseCase +import pytest class GSTUtilTester(BaseCase): @@ -215,19 +217,69 @@ def setUpClass(cls): cls.gst_data = ProtocolData(cls.gst_design, ds) -class GateSetTomographyTester(BaseProtocolData, BaseCase): +class MapForwardSimulatorWrapper(MapForwardSimulator): + + Message = """ + Hit the forward simulator wrapper! + """ + + def _bulk_fill_probs(self, array_to_fill, layout): + print(self.Message) + super(MapForwardSimulatorWrapper, self)._bulk_fill_probs(array_to_fill, layout) + + def _bulk_fill_probs_atom(self, array_to_fill, layout_atom, resource_alloc): + print(self.Message) + super(MapForwardSimulatorWrapper, self)._bulk_fill_probs_atom(array_to_fill, layout_atom, resource_alloc) + + +class TestGateSetTomography(BaseProtocolData): """ Tests for methods in the GateSetTomography class. + + We can't subclass BaseCase since we use some advanced PyTest features. """ def test_run(self): + self.setUpClass() proto = gst.GateSetTomography(smq1Q_XYI.target_model("CPTPLND"), 'stdgaugeopt', name="testGST") results = proto.run(self.gst_data) mdl_result = results.estimates["testGST"].models['stdgaugeopt'] twoDLogL = two_delta_logl(mdl_result, self.gst_data.dataset) - self.assertLessEqual(twoDLogL, 1.0) # should be near 0 for perfect data + assert twoDLogL <= 1.0 # should be near 0 for perfect data + def test_run_custom_sim(self, capfd: pytest.LogCaptureFixture): + self.setUpClass() + proto = gst.GateSetTomography(smq1Q_XYI.target_model("CPTPLND"), 'stdgaugeopt', name="testGST") + results = proto.run(self.gst_data, simulator=MapForwardSimulatorWrapper()) + stdout, _ = capfd.readouterr() + assert MapForwardSimulatorWrapper.Message in stdout + + mdl_result = results.estimates["testGST"].models['stdgaugeopt'] + twoDLogL = two_delta_logl(mdl_result, self.gst_data.dataset) + assert twoDLogL <= 1.0 # should be near 0 for perfect data + + for estimate in results.estimates.values(): + for model in estimate.models.values(): + assert isinstance(model, MapForwardSimulatorWrapper) + pass + + + def test_write_and_read_to_dir(self): + #integration test to at least confirm we are writing and reading + #to and from the directory serializations. + proto = gst.GateSetTomography(smq1Q_XYI.target_model("CPTPLND"), 'stdgaugeopt', name="testGST") + proto.write('../../test_packages/temp_test_files/test_GateSetTomography_serialization') + #then read this back in + proto_read = gst.GateSetTomography.from_dir('../../test_packages/temp_test_files/test_GateSetTomography_serialization') + + #spot check some of the values of the protocol objects + assert all([elem1==elem2 for elem1, elem2 in + zip(proto_read.initial_model.model.to_vector(), + proto.initial_model.model.to_vector())]) + assert proto_read.gaugeopt_suite.gaugeopt_suite_names == proto.gaugeopt_suite.gaugeopt_suite_names + assert proto_read.name == proto.name + assert proto_read.badfit_options.actions == proto.badfit_options.actions class LinearGateSetTomographyTester(BaseProtocolData, BaseCase): """ @@ -249,23 +301,77 @@ def test_run(self): twoDLogL = two_delta_logl(mdl_result, self.gst_data.dataset, self.gst_design.circuit_lists[0]) self.assertLessEqual(twoDLogL, 1.0) # should be near 0 for perfect data - -class StandardGSTTester(BaseProtocolData, BaseCase): + def test_write_and_read_to_dir(self): + #integration test to at least confirm we are writing and reading + #to and from the directory serializations. + proto = gst.LinearGateSetTomography(self.mdl_target.copy(), 'stdgaugeopt', name="testGST") + proto.write('../../test_packages/temp_test_files/test_LinearGateSetTomography_serialization') + #then read this back in + proto_read = gst.LinearGateSetTomography.from_dir('../../test_packages/temp_test_files/test_LinearGateSetTomography_serialization') + + #spot check some of the values of the protocol objects + assert all([elem1==elem2 for elem1, elem2 in + zip(proto_read.target_model.to_vector(), + proto.target_model.to_vector())]) + assert proto_read.gaugeopt_suite.gaugeopt_suite_names == proto.gaugeopt_suite.gaugeopt_suite_names + assert proto_read.name == proto.name + assert proto_read.badfit_options.actions == proto.badfit_options.actions + +class TestStandardGST(BaseProtocolData): """ Tests for methods in the StandardGST class. + + We can't subclass BaseCase since we use some advanced PyTest features. """ def test_run(self): + self.setUpClass() proto = gst.StandardGST(modes=["full TP","CPTPLND","Target"]) results = proto.run(self.gst_data) mdl_result = results.estimates["full TP"].models['stdgaugeopt'] twoDLogL = two_delta_logl(mdl_result, self.gst_data.dataset) - self.assertLessEqual(twoDLogL, 1.0) # should be near 0 for perfect data + assert twoDLogL <= 1.0 # should be near 0 for perfect data mdl_result = results.estimates["CPTPLND"].models['stdgaugeopt'] twoDLogL = two_delta_logl(mdl_result, self.gst_data.dataset) - self.assertLessEqual(twoDLogL, 1.0) # should be near 0 for perfect data + assert twoDLogL <= 1.0 # should be near 0 for perfect data + + def test_run_custom_sim(self, capfd: pytest.LogCaptureFixture): + self.setUpClass() + # We have to test GST modes separately, since we aren't sure how many times + # the forward simulator's methods will be called. + self._test_run_custom_sim('full TP', capfd, True) + self._test_run_custom_sim('Target', capfd, False) + + def _test_run_custom_sim(self, mode, parent_capfd, check_output): + proto = gst.StandardGST(modes=[mode]) + results = proto.run(self.gst_data, simulator=MapForwardSimulatorWrapper) + stdout, _ = parent_capfd.readouterr() + assert MapForwardSimulatorWrapper.Message in stdout + if check_output: + mdl_result = results.estimates[mode].models['stdgaugeopt'] + twoDLogL = two_delta_logl(mdl_result, self.gst_data.dataset) + assert twoDLogL <= 1.0 # should be near 0 for perfect data + for estimate in results.estimates.values(): + for model in estimate.models.values(): + assert isinstance(model, MapForwardSimulatorWrapper) + pass + + def test_write_and_read_to_dir(self): + #integration test to at least confirm we are writing and reading + #to and from the directory serializations. + proto = gst.StandardGST(modes=["full TP","CPTPLND","Target"]) + proto.write('../../test_packages/temp_test_files/test_StandardGateSetTomography_serialization') + #then read this back in + proto_read = gst.StandardGST.from_dir('../../test_packages/temp_test_files/test_StandardGateSetTomography_serialization') + + #spot check some of the values of the protocol objects + assert proto_read.gaugeopt_suite.gaugeopt_suite_names == proto.gaugeopt_suite.gaugeopt_suite_names + assert proto_read.name == proto.name + assert proto_read.modes == proto.modes + assert proto_read.badfit_options.actions == proto.badfit_options.actions + #Unit tests are currently performed in objects/test_results.py - TODO: move these tests here diff --git a/test/unit/tools/test_edesigntools.py b/test/unit/tools/test_edesigntools.py index 660c615e4..05084643f 100644 --- a/test/unit/tools/test_edesigntools.py +++ b/test/unit/tools/test_edesigntools.py @@ -12,7 +12,7 @@ class ExperimentDesignTimeEstimationTester(BaseCase): def test_time_estimation(self): - edesign = smq2Q_XYICNOT.create_gst_experiment_design(256) + edesign = smq2Q_XYICNOT.create_gst_experiment_design(8) # Dummy test: No time time0 = et.calculate_edesign_estimated_runtime(